PDA

View Full Version : porting my virtua girl player to qt



JeanC
30th January 2008, 10:31
Hello,

After my 2 initial projects with Qt have been succesfull it's time to wet my feet a little with graphics programming.

In windows I succeeded in making my own virtuagirl player, it plays animations of stripping girls in the corner above the tray.

I like to port this to linux, I miss it :)
The data for the animations is in some kind of run length encoding. But in stead of a normal bitmap, each frame is build using the windows mechanismes CreateRectRgn(), CombineRgn() in order to have a transparant image on the desktop.

I like to have some advice on how to go about this.

Thank you. Jean.

elcuco
30th January 2008, 13:43
Dud, when you finish it, please give me a download link :)

pherthyl
30th January 2008, 16:19
Hmm.. This might be quite difficult, if the file format is composed of basically commands to the Windows graphics system. I suppose it depends on the complexity of the commands. If there are only a few commands that are used, I would reimplement them using QPainter equivalents, but if they run the full gamut of GDI commands then I would look into using Wine to port your existing application to Linux, or even run it outright.

JeanC
30th January 2008, 17:44
The Create/Add Rgn stuff in windows is basically a way to have a *window* which is not a pure rectangle, but an irregular shape, like a girl for instance. :) Because of it being a window in itself, it is automatically transparent from the underlying background, the desktop. If the girl moves her arm, the background under the previous armshape is restored because the window shape changes. That painting is done automatically by the os. This is about what I'm looking for. Can qpainter do (something like) this?

spud
30th January 2008, 17:48
Not QPainter, but QWidget.
QWidget::setMask ( const QBitmap & bitmap )

JeanC
30th January 2008, 18:27
setMask() looks promising. I'm gonna invest, thanks.
I'll let you guys know when there's a download link, may take a while though. :)

JeanC
31st January 2008, 17:15
Well, the graphics system is something which is not learned in a day, overwhelming. :)

My questions:

In the shaped clock example the actual drawing is done in the paint event by using QPainter. But I would like to use a QImage and setPixel() because in that way I hope I can set a mask from the pixelmap I have build on that QImage

How do I do that?

Note, I don't use the paintevent like in that example, I use a frame() function triggered by a timer. The window has FramelessWindowHint attribute so a paintevent is not needed.

Also, I don't think scanLine() will be faster because the pixel data comes in vertical rows, am I correct?

Thanks.

spud
31st January 2008, 17:33
I'm not completely sure I understood most of your post, so I'll just tell you how I would go about this problem. It really shouldn't be to complicated.

First prepare the data:
For each frame you should have a QPixmap of the girl and a QBitmap of the mask. I don't now in which format you have the images, but once you've loaded the data into a QImage or QPixmap QPixmap::createMaskFromColor() should help you create the mask.

Make your QWidget subclass a frameless window and connect a timer to a slot(which you seem to have done)

You do need paintEvent(), painting outside paintEvent is not allowed! All you need to do in frame() is to select which new QPixmap/QBitmap pair to use and call setMask().

paintEvent will be called automatically when needed and all you have to do is paint the QPixmap at (0,0)

Don't complicate things more than necessary! You won't need scanLine() unless you are reading binary data into a QImage.

wysota
31st January 2008, 19:43
Have a look at this:

http://zrusin.blogspot.com/2006/10/argb-windows.html

JeanC
1st February 2008, 13:02
Thank you both.

I'm trying to go the way spud describes.

in constructor (I need to construct it on the stack, else cannot set width / height):


image = new QPixmap(400, 400);


in frame()


void Girl::frame()
{
image->fill(Qt::red);
setMask(image->createMaskFromColor(Qt::black, Qt::MaskOutColor));
}

in paintEvent()


void Girl::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap(QPoint(0, 0), *image);
}


Program crashes with segmentation fault. Not a smooth ride yet. :)
p.s. the pixeldata comes from a run length encoded file and is presented in vertical lines of 1 pixel width each which than can be put on the pixmap with drawLine().

wysota
1st February 2008, 17:28
You meant something like this? :)

JeanC
1st February 2008, 17:41
Grin, what have you got there? :)
Can it zoom?
My eyes are bad, that's a reason I wanted to write a player myself in the first place so I could add 2 , 3 and 4 times zoom.

wysota
1st February 2008, 18:09
Zooming is not a problem, but the resolution of the animations I have is hmm... bad :) It's 160x120, so zooming will make it look terrible. If you have larger anims, they shouldn't pose a problem.

By the way - I implemented both approaches - using setMask and using ARGB display and the latter works much much better.

JeanC
1st February 2008, 18:25
Well I have a bunch of files with a resolution of about 240 x 200 and zooming 3 times is acceptible for me, this in my windows player.

So you wrote it yourself? :)

Can you help me with mine, or do you want to share?

P.s. that project you gave me a link to is a bit over my head at the moment.

wysota
1st February 2008, 18:35
So you wrote it yourself? :)
Yep. Took about 5 minutes.


Can you help me with mine, or do you want to share?
There is not much to share, I'm just displaying a bunch of images at 16fps :) I downloaded an app to convert BK3 files into a series of still images, so the "player" only has code to display those images in a proper way. Total amount of code including some commented lines and opening the ARGB visual (that takes about 50 lines of code) is 150 lines of code.


I could share some stuff too if there's a demand.
If you could PM me a link to some higher resolution stuff, I'd check how it goes with my "player".


P.s. that project you gave me a link to did not do very much here, only showed that bitmap.
The point is it allows you to have transparent windows without using setMask() that slows down the whole app. Using ARGB display two instances of the player running together use about 4% of my Athlon CPU power. The version using setMask() uses more power and introduces some flicker from time to time.

JeanC
1st February 2008, 18:56
Well, I could share my code for decoding the stream so conversion to images is not needed. The stream starts with a header containing info like size, number of frames and such.
Then comes a table with frame info.

But I cannot yet show Qt code for the second part.
Maybe we could share the project? :)

Maybe if I make a minimal app to play the frames on a QImage without any transparancy, just a clear inbetween and you could build the transparancy from there. Just hinking aloud. I don't know if you have time or are willing to do this at all.

wysota
1st February 2008, 19:08
Well, I could share my code for decoding the stream so conversion to images is not needed. The stream starts with a header containing info like size, number of frames and such.
Then comes a table with frame info.
Probably so, I didn't want to waste time for that. I wrote the program only to check how it would work :)


But I cannot yet show Qt code for the second part.
Maybe we could share the project? :)

No problem, I can give you my code.

wysota
1st February 2008, 19:38
Ok, if I'm playing around, maybe I could implement an image format for BK3 if you sent me your decoding code :)

JeanC
1st February 2008, 19:41
Nice!
Will do so, give me a day or 2 and I''ll get back.

JeanC
2nd February 2008, 08:58
Sigh, I don't get it, only a black square shows up. Could somebody please help me on my way. Gee this ought to be simple. What's wrong with me. :)



image = new QImage(400, 400, QImage::Format_RGB32);




void Girl::frame()
{
image->fill(Qt::white);
QPainter painter(image);
painter.drawLine(QPoint(0, 0), QPoint(400, 4400));
update();
}



void Girl::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawImage(QPoint(0, 0), *image);
}

ashukla
2nd February 2008, 11:45
QPainter painter(this);
Try with QPainter painter(viewport()); or QPainter painter(window());

wysota
2nd February 2008, 13:30
But what is the problem exactly?

Oh, by the way. I upgraded my program. Now it scales, moves and changes opacity of the animation. The only thing I don't have is BK3 decoding :) If you have it (and I think you do), could you please mail it to me?

JeanC
2nd February 2008, 14:36
@Wysota, the problem was I had to replace


image->fill(Qt::white);

with


image->fill(qRgb(255, 255, 255));

Now I have a white background and I can see what I'm plotting.

Yes I will fix that bk1 / bk3 encoding and I will get back to you. May take a day or two.

What I would like in the end is a program with an icon in the tray so one can set options for zoom en timer intervals and some commands like get girl / close girl :) We'll see how far we get.

@ashukla
Thanks for your suggestion.

wysota
2nd February 2008, 14:58
What I would like in the end is a program with an icon in the tray so one can set options for zoom en timer intervals and some commands like get girl / close girl :) We'll see how far we get.
Great. Mine already does that :cool: I don't have girl choosing because I load a bunch of images instead of one file, but the rest is there.

JeanC
2nd February 2008, 15:44
Looks great :)
I had a options screen like that yes in the windoze version. Also did let me browse my girls. :)
I have the encoding ready, I\ll mail you in pm.