Re: Fast image manipulation : the truth about it (I hope)
- From: luther maxime u-strasbg fr
- To: "D. Diederen" <D Diederen student ulg ac be>, gnome-list gnome org
- Subject: Re: Fast image manipulation : the truth about it (I hope)
- Date: Fri, 20 Nov 1998 12:02:17 +0100
Please someone check this (function names and such) and put it in the FAQ ...
Friendly,
Sven LUTHER
On Fri, Nov 20, 1998 at 11:10:27AM +0100, D. Diederen wrote:
> > De : SEGV <mlepage@cgocable.net>
> > A : gnome-list@gnome.org
> > Cc : George <jirka@5z.com>
> > Objet : Re: Fast Image Manipulation?
> > Date : mercredi 18 novembre 1998 14:58
>
> [clip]
>
> > Sorry, I realize I can't play with the actual display bits. In fact, they may
> > not even be on this side of the earth. Although, I don't anticipate this
> working
> > on non-local displays. Really I'm using X because I'm lazy and don't feel the
> > need to learn SVGALIB or something like that. I'll scale back my requirements
> > quite a bit before investigating other avenues.
> >
> > If I use gdk_draw_pixmap, I'll need to keep separate ones though, right? I
> don't
> > see how I can draw just a part of one. Is that much overhead, in practice?
> I'd
> > assume no more than a dozen or so bytes...
>
> [clip]
>
> > --
> > SEGV http://www.cgocable.net/~mlepage/
> >
>
> Hello everybody,
>
> As this is a subject that pops up quite often, It think I'll devote some time
> to explain the whole thing (or at least what I'm understanding of it) ...
>
> [ GENERAL INTRODUCTION ]
>
> As Gtk/Gnome use gdk, which is basically a thin layer over X calls, the
> reasoning in this document also applies to raw X programming. Il will list the
> X equivalents to Gdk calls between brackets, e.g. gdk_draw_line()
> [XDrawLine()]. The name of the function calls/structures may also be wrong,
> since I'm not on my Linux machine to write this...
>
> So, we will consider three things : the GdkImage [XImage], the GdkPixmap
> [XPixmap] and another player, the GdkImlibImage [ImlibImage].
>
> [ WHAT'S A GdkImage ? ]
>
> A GdkImage is an image (as you should have guessed) that resides in the adress
> space of your application. You can therefore manipulate it yourself. It has the
> same byte/bit organization that the video memory of the graphic mode your X
> server is currently using. That means you _must_ have your own manipulation
> routines to be able to draw in it, for any mode the server may support (even
> the _very_ exotic ones), or your app is basically broken.
>
> Some people (read : game coders) therefore require that you put your server in
> a particular mode (e.g. 8bpp) before running their apps because they were
> unable to code the other modes (for speed or laziness reasons). But keep in
> mind this is not possible for everyone, since a given mode is not even
> guaranteed to exist on a particular platform.
>
> Another problem with the GdkImage model is that at _any_ time you want to
> update the screen, you _must_ transfer the (whole ?) image in the server's
> adress space. When using X trough a network, or in the case of some old/broken
> servers, this has to be done using TCP/IP (uck !). However most of the new X
> servers support another way to transfer the image : it's the famous MITSHM
> (M.I.T. shared memory) extension to the X server. Note that even in this case
> your image has to be copied two times : first to the memory the two processes
> share, and then in the video memory.
>
> Games like XQuake or XDoom do use XImages to do their work (however restricting
> you to a 8bpp server only - at least last time I checked), because their major
> task is the rendering of the image. When the calculated image is ready, they
> just have to flip it on the screen, and they're done.
>
> [ WHAT'S A GdkPixmap ? ]
>
> A GdkPixmap is a server side image. You _can't_ manipulate its byte/bits
> directly since it is not in the adress space of your program (you _cannot_ get
> a pointer to its data). These pixmaps are the main reason an X server can grow
> fairly large memory-wise : it contains _every_ pixmap of _every_ X app in its
> own memory. But don't be afraid, this is just displacing memory, since you no
> longer need it in your app, so there's no waste.
>
> The advantage is that since the X server owns the pixmaps, you can use any
> gdk_draw_*() [XDraw*()] calls on them. The server may even cache some pixmaps
> in video memory, and use the graphic board's accelerator to draw line/boxes on
> them (1). When the times comes to update the screen, the server only has to do
> one memory copy from the pixmap to the screen memory. If the pixmaps were
> already in video memory, the server could even use the board's accelerator (1).
>
>
> Platform games (or any game that contains sprites) should use the pixmap
> approach : When starting, they transfer the sprites as pixmaps on the server,
> and then they only have to use gdk_draw_pixmap() [XDrawPixmap()] calls to put
> them on the screen. Also note that a pixmap using game should also perform very
> well on a network (or a broken/old X server that doesn't support SHM), since
> the only wire traffic consists in the X calls.
>
> 1) This is of course X server implementation dependant !
>
> [ WHAT'S A GdkImlibImage ]
>
> Well, this one has _nothing_ to do with the previous ones. It doesn't even
> even belong to gdk or X, but rather comes from the gdk_imlib [Imlib] library. A
> GdkImlibImage basically stores an array of RGB triples describing an image (and
> also some private things). You can load various image formats into them using
> gdk_imlib, and you can render them to GdkPixmaps [XPixmaps] using gdk_imlib too
> (the latter takes care of the pixmap format, as well as palette and dithering
> issues).
>
> Please don't even try to implement a game using GdkImlibImages ! While Raster's
> (Imlib's author) scaling/rendering code is Great Stuff [TM], the GdkImlibImages
> were not created for that purpose. Only imagine the CPU overhead of converting
> your RGB data to a screen image (including two memory copies in the shared
> memory's case - which is the better), using arbitrarily complex
> conversion/dithering bit manipulations (you don't know on what server you're
> running), the whole thing at 30+ fps !
>
> Gdk version 1.1.2 ? and higher also contain gdk_rgb*() calls to draw a rgb
> image on the screen. But it has to be used _only_ when other methods are not
> possible (e.g. if the data comes from a RGB video source (1), you need to
> convert it anyway, so chances are gdk_rgb functions are already optimized for
> that).
>
> 1) Does such a thing exist ? Perhaps we'll need gdk_yuv*() calls ;).
>
> [ YOUR VERY OWN CASE ]
>
> In the case of a StarCr*ft-like game, I would suggest the following approach :
>
> Say we are creating a new game, called Star Conquer. The two opposite camps are
> be the humans and the fromens (I put a lot of imagination in that one ;). The
> whole set of baground tiles is stored in a file (tiles.png). All the sprites
> are stored in humans.png and fromens.png. Of course whe have a table describing
> at which coordinates we can find any frame in any file.
>
> The game startup looks like :
>
> - Init everything.
> - Load the three .png files in GdkImlibImages using gdk_imlib.
> - Convert the three GdkImlibImages to GdkPixmaps using gdk_imlib.
> - Destroy the three GdkImlibImages since we'll never need them again (you need
> to take care of pixmap referencing if you want them not to be destroyed -
> perhaps having a look at imlib's source code would help ?)
> - Load all the sprite coordinate tables into appropriates structures - please
> don't hardcode them in your program (1).
> - Create a new GdkPixmap of the size of your game area. It will be your virtual
> screen buffer.
> - Create your main window, with a GdkDrawingArea of the size of the game area.
>
> Ok, now what we need is the main game loop. It should look like the following
> function :
>
> /* NOTE: this is pseudo-but-looks-like-real-code,
> so cut'n'paste won't work :) */
> void game_loop_do_one_iteration(void)
> {
> /* tile the background */
> for(first_tile; last_tile; tile++) {
> tid = get_tile_from_map_at_coordinates(x, y);
> get_tile_coordinates_from_table(tid, tile_table,
> &tile_x, &tile_y);
> gdk_draw_pixmap(double_buffer, scr_x, scr_y, tile_pixmap,
> tile_x, tile_y, TILE_WIDTH, TILE_HEIGHT);
> }
> /* draw the buddies */
> for(first_buddy; last_buddy; buddy++) {
> get_buddy_frame_from_table(buddy->type, buddy->frame++,
> buddy->table, &buddy_x, &buddy_y,
> &buddy_width, &buddy_height);
> /* of course, since buddies are not rectangular, there should
> be a bit of masking, etc., but ... */
> gdk_draw_pixmap(double_buffer, buddy->pos_x, buddy->pos_y,
> buddy->pixmap, buddy_x, buddy_y,
> buddy_width, buddy_height);
> }
> /* update the screen */
> gdk_draw_pixmap(drawing_area->window, 0, 0, double_buffer, 0, 0,
> game_area_width, game_area_height);
> /* this will be the trickier part */
> move_buddies_with_at_least_a_bit_of_AI();
> }
>
> Then you connect that function to a timeout, and you're done. The AI part is
> left as an exercise to the reader :). There are some facts you should examine :
> - Full resolution/bit depth independance : Thanks to Raster's code (the
> oh-so-great Imlib), your game will run on _any_ X server Imlib can understand
> (many if not all of them - you should examine the code).
> - Without doing anything, you do the best thing to support hardware
> acceleration. In the case of a great server running on great graphic hardware
> (read : with a lot memory and clever acceleration), every pixmap would be
> cached in the video card (as they're frequently used), and the server would
> only have to issue 'blit' accel commands to the hardware (write some magic
> numbers).
>
> 1) Since don't hardcoding them would save me a lot of work when converting your
> game into a Kdemen/Gnomes wargame - hmm ... pleasing scenario, I would be ROTFL
>:)
>
> [ CONCLUSION ]
>
> Well, I hope all this will be of use for somebody. Since these are questions
> that pop up very often, I hope this document will enlighten some X/Gdk
> 'newbies' (1) :).
>
> Of course the function/structure names in this document may be wrong, since I
> don't do much X programming for now and I'm not in front of my Linux (2) box.
> But hey man, man is your man.
>
> Feel free to correct this and distribute at will - even commercially and
> without releasing the source code (3) if you wish ... I'm also sorry for my bad
> english, but I would be glad to hear of corrections - that's the way I learn !
>
> Cu,
> Damien.
>
> 1) Note that I'm one of them, I just collected pieces of information around.
> 2) Especially for RMS : read GNU/Linux :)
> 3) Oh my, I'm tired of these licence flamewars.
>
> --
> char *info[] = {
> "Diederen Damien",
> "D.Diederen@student.ulg.ac.be",
> "http://www.geocities.com/SiliconValley/Haven/6226/",
> };
>
>
>
> --
> To unsubscribe: mail gnome-list-request@gnome.org with
> "unsubscribe" as the Subject.
>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]