Graphics modes routines are implemented in <lua_mode.c>. Header file is: <lua_mode.h>.

Most of graphics modes routines are ready.

 

 

Graphics modes

 

Graphics modes are the common denominator for most Allegro programs. While it is possible to write platform specific programs using Allegro which don't set a graphic mode through the routines provided in this chapter, these are not very common.

The first thing to note is that due to the wide range of supported platforms, a graphic mode is the only way to safely communicate with the user. When Allegro was a DOS only library (versions 3.x and previous), it was frequent for programmers to use functions from the C standard library to communicate with the user, like calling printf() before setting a graphic mode or maybe scanf() to read the user's input. However, what would happen for such a game running under Windows where there is no default console output or it may be hidden from the user? Even if the game compiled successfully, it would be unplayable, especially if there was vital information for the user in those text only messages.

Allegro provides the allegro.message( ) function to deal with this problem, but this is not a very user friendly method of communicating with the user and its main purpose is displaying small error like messages when no graphic mode is available. Therefore, the first thing your Allegro program should do is set a graphic mode, and from there on, use Allegro's text output routines to display messages to the user, just like `allegro/examples/exhello.c' does.

Setting a graphic mode involves deciding how to allocate the memory of the video card for your program. On some platforms this means creating a virtual screen bigger than the physical resolution to do hardware scrolling or page flipping. Virtual screens can cause a lot of confusion, but they are really quite simple. Warning: patronising explanation coming up, so you may wish to skip the rest of this paragraph. Think of video memory as a rectangular piece of paper which is being viewed through a small hole (your monitor) in a bit of cardboard. Since the paper is bigger than the hole you can only see part of it at any one time, but by sliding the cardboard around you can alter which portion of the image is visible. You could just leave the hole in one position and ignore the parts of video memory that aren't visible, but you can get all sorts of useful effects by sliding the screen window around, or by drawing images in a hidden part of video memory and then flipping across to display them.

For example, you could select a 640x480 mode in which the monitor acts as a window onto a 1024x1024 virtual screen, and then move the visible screen around in this larger area (hardware scrolling). Initially, with the visible screen positioned at the top left corner of video memory, this setup would look like:

      (0,0)------------(640,0)----(1024,0)
        |                  |           |
        |  visible screen  |           |
        |                  |           |
      (0,480)----------(640,480)       |
        |                              |
        |   the rest of video memory   |
        |                              |
      (0,1024)--------------------(1024,1024)
With a virtual screen bigger than the visible screen you can perform smooth CPU inexpensive scrolling: you draw your graphics once, and then only tell the video card to show a different portion of the screen. However, virtual screens are not supported on all platforms, and on some they might be emulated through software, losing any performance. On top of that, many video cards only allow horizontal scrolling in steps of 32 bytes. This is not a problem if your game runs in 24 or 32 bit, but it tends to mean jerky scrolling for other color depths.

The other reason you could use virtual screens for is page flipping. This means showing one portion of the virtual screen while your program draws to the hidden one. When you finish, you show the part you have been drawing to and repeat the process with the area now hidden. The result is a perfectly smooth screen update without flickering or other graphical artifacts.

Scrolling manually to one part of the video memory is one non portable way to accomplish this. The portable way is to use functions like allegro.create_system_bitmap(), allegro.create_video_bitmap(), allegro.show_video_bitmap(), etc. These functions divide the memory of the video card in areas and switch between them, a feature supported on all platforms and video cards (given that they have enough memory for the screen resolutions you asked for).

The last thing you need to know about setting a graphic mode are drivers. Each platform has a number of graphic drivers wich support a different range of hardware or behave in different ways. To avoid cluttering your own code with #ifdefs and dealing with drivers added after you release your program, Allegro provides several so called magic drivers. These magic drivers don't really exists, they wrap around a specific kind of functionality.

The magic drivers you can use are:

 

 

allegro.set_color_depth(depth)


Sets the pixel format to be used by subsequent calls to allegro.set_gfx_mode() and allegro.create_bitmap(). 

Valid depths are 8 (the default), 15, 16, 24, and 32 bits. 

Example:

 

      allegro.set_color_depth(32);
      if not allegro.set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) then
         abort_on_error("Couldn't set a 32 bit color resolution") end
Note that the screen color depth won't change until the next successful call to allegro.set_gfx_mode().
color_depth = allegro.get_color_depth( )

Returns the current pixel format. This can be very useful to know in order to write generic functions which select a different code path internally depending on the color depth being used.

Note that the function returns whatever value you may have set previously with allegro.set_color_depth(), which can be different from the current color depth of the screen global variable. If you really need to know the color depth of the screen, use allegro.bitmap_color_depth().

 

allegro.request_refresh_rate(rate);

Requests that the next call to allegro.set_gfx_mode() try to use the specified refresh rate, if possible. Not all drivers are able to control this at all, and even when they can, not all rates will be possible on all hardware, so the actual settings may differ from what you requested. After you call allegro.set_gfx_mode(), you can use allegro.get_refresh_rate() to find out what was actually selected. At the moment only the DOS VESA 3.0, X DGA 2.0 and some Windows DirectX drivers support this function. The speed is specified in Hz, eg. 60, 70. To return to the normal default selection, pass a rate value of zero. 

Example:

      allegro.request_refresh_rate(60);
      if not allegro.set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) then
         abort_on_error("Couldn't set graphic mode!"); end
      if (allegro.get_refresh_rate() ~= 60) then
         abort_on_error("Couldn't set refresh rate to 60Hz!"); end
 
refresh_rate = allegro.get_refresh_rate( )

Returns the current refresh rate, if known (not all drivers are able to report this information). Returns zero if the actual rate is unknown.

 

table mode_list = allegro.get_gfx_mode_list(int card)

Creates a table where each entry is a record (also Lua table) containing width, height and bpp (bits per pixel)

Please notice that you have to specify integer parameter equal to card code. 

Note that the card parameter must refer to a _real_ driver. 

This function fails if you pass GFX_SAFE, GFX_AUTODETECT, or any other "magic" driver. 

(Not only. Also when you pass GFX_DIRECTX_WIN then allegro.get_gfx_mode_list() will return nil) (Peter)

 

That is the example result what happens when I call on my computer (graphics card is NVIDIA GForce 2):

modelist = allegro.get_gfx_mode_list(allegro.GFX_DIRECTX_WIN)

After that line modelist will equal to table of tables:

 

 

{{height=200,bpp=8,width=320},{height=200,bpp=16,width=320},

{height=200,bpp=32,width=320},{height=240,bpp=8,width=320},

{height=240,bpp=16,width=320},{height=240,bpp=32,width=320},

{height=300,bpp=8,width=400},{height=300,bpp=16,width=400},

{height=300,bpp=32,width=400},{height=360,bpp=8,width=480},

{height=360,bpp=16,width=480},{height=360,bpp=32,width=480},

{height=384,bpp=8,width=512},{height=384,bpp=16,width=512},

{height=384,bpp=32,width=512},{height=400,bpp=8,width=640},

{height=400,bpp=16,width=640},{height=400,bpp=32,width=640},

{height=480,bpp=8,width=640},{height=480,bpp=16,width=640},

{height=480,bpp=32,width=640},{height=480,bpp=8,width=720},

{height=480,bpp=16,width=720},{height=480,bpp=32,width=720},

{height=576,bpp=8,width=720},{height=576,bpp=16,width=720},

{height=576,bpp=32,width=720},{height=600,bpp=8,width=800},

{height=600,bpp=16,width=800},{height=600,bpp=32,width=800},

{height=480,bpp=8,width=848},{height=480,bpp=16,width=848},

{height=480,bpp=32,width=848},{height=768,bpp=8,width=1024},

{height=768,bpp=16,width=1024},{height=768,bpp=32,width=1024}}

 

Here is an implementation (a bug has been removed in version 0.33) :
//------------------------------------------------------------------------------------------
//GFX_MODE_LIST* get_gfx_mode_list(int card);
static int l_get_gfx_mode_list (lua_State *L) 
{
   int card=lua_tonumber(L,1);
   int i=0;
   GFX_MODE_LIST* list;
   char* param1;
Code marked on red has been commented out in version 0.33.

   /*if (lua_isstring(L,1))
      {
      param1=(char*) lua_tostring (L,1);
      

      }
   else*/
      card=lua_tonumber(L,1);
   
   list=get_gfx_mode_list(card);
   if (!list) return 0;

   lua_newtable (L);

   while ( (list->mode[i].width) && (list->mode[i].height) && (list->mode[i].bpp) )
      {
      //new_record:
      lua_pushnumber(L, i+1 );
      lua_newtable(L);

      set_field_i(L, "width"  , list->mode[i].width  );
      set_field_i(L, "height" , list->mode[i].height );
      set_field_i(L, "bpp"    , list->mode[i].bpp    );

      //store_record:
      lua_settable(L, -3);

      i++;
      }

   destroy_gfx_mode_list(list);
       
   return 1;  /* number of results */
}

 

void destroy_gfx_mode_list(GFX_MODE_LIST *mode_list);

That function is unnecessary, since we use Lua. We destroy table just by writing nil to it:

mytable = nil; 

By the way, destroy_gfx_mode_list is used in the internal C implementation of allegro.get_gfx_mode_list(card)

 

 

bool allegro.set_gfx_mode( card , width , height , v_w , v_h );

Switches into graphics mode. The card parameter should usually be one of the Allegro magic drivers (read introduction of chapter "Graphics modes") or see the platform specific documentation for a list of the available drivers. The w and h parameters specify what screen resolution you want. The color depth of the graphic mode has to be specified before calling this function with allegro.set_color_depth().

The v_w and v_h optional parameters specify the minimum virtual screen size, in case you need a large virtual screen for hardware scrolling or page flipping. You should set them to zero (or don't pass them at all) if you don't care about the virtual screen size.

When you call allegro.set_gfx_mode(), the v_w and v_h parameters represent the minimum size of virtual screen that is acceptable for your program. The range of possible sizes is usually very restricted, and Allegro may end up creating a virtual screen much larger than the one you request. Allowed sizes are driver dependent and some drivers do not allow virtual screens that are larger than the visible screen at all: don't assume that whatever you pass will always work.

In mode-X the virtual width can be any multiple of eight greater than or equal to the physical screen width, and the virtual height will be set accordingly (the VGA has 256k of vram, so the virtual height will be 256*1024/virtual_width).

Currently, using a big virtual screen for page flipping is considered bad practice. There are platforms which don't support virtual screens bigger than the physical screen but can create different video pages to flip back and forth. This means that, if you want page flipping and aren't going to use hardware scrolling, you should call allegro.set_gfx_mode() with (0,0) as the virtual screen size and later create the different video pages with allegro.create_video_bitmap(). Otherwise your program will be limited to the platforms supporting hardware scrolling.

After you select a graphics mode, the physical and virtual screen sizes can be checked with the macros SCREEN_W, SCREEN_H, VIRTUAL_W, and VIRTUAL_H.

Return value: Returns true on success. On failure returns false and sets internal allegro_error variable. You can retrieve a description of the problem by calling allegro.error( ) .

 

Not implemented yet

int set_display_switch_mode(int mode);


Sets how the program should handle being switched into the background, if the user tabs away from it. Not all of the possible modes will be supported by every graphics driver on every platform. The available modes are:

Note that you should be very careful when you are using graphics routines in the switching context: you must always call acquire_screen() before the start of any drawing code onto the screen and not release it until you are completely finished, because the automatic locking mechanism may not be good enough to work when the program runs in the background or has just been raised in the foreground.

Return value: Returns true on success, invalidating at the same time all callbacks previously registered with allegro.set_display_switch_callback(). Returns false if the requested mode is not currently possible.

Not implemented yet

int set_display_switch_callback(int dir, void (*cb)());


Installs a notification callback for the switching mode that was previously selected by calling set_display_switch_mode(). The direction parameter can either be SWITCH_IN or SWITCH_OUT, depending whether you want to be notified about switches away from your program or back to your program. You can sometimes install callbacks for both directions at the same time, but not every platform supports this. You can install several switch callbacks, but no more than eight on any platform.

Return value: Returns zero on success, decreasing the number of empty callback slots by one. Returns -1 if the request is impossible for the current platform or you have reached the maximum number of allowed callbacks.

 

Not implemented yet

void remove_display_switch_callback(void (*cb)());


Removes a notification callback that was previously installed by calling set_display_switch_callback(). All the callbacks will automatically be removed when you call set_display_switch_mode(). You can safely call this function even if the callback you want to remove is not installed.

 

Not implemented yet

int get_display_switch_mode();


Returns the current display switching mode, in the same format passed to allegro.set_display_switch_mode().

 

Implemented, but commented out. That is because I have started with 4.0 version of allegro.

int is_windowed_mode(void);


This function can be used to detect wether or not set_gfx_mode() selected a windowed mode. Example:
      if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0)
         abort_on_error("Couldn't set graphic mode!");
      if (is_windowed_mode()) {
         /* Windowed mode stuff. */
      } else {
         /* Fullscreen mode stuff. */
      }

Return value: Returns true if the current graphics mode is a windowed mode, or zero if it is a fullscreen mode. You should not call this function if you are not in graphics mode.

 

int allegro.gfx_capabilities( )

Notice that LuAllegro should provide a way of reading bits since Lua doesn't have "&" bitwise operator.

Bitfield describing the capabilities of the current graphics driver and video hardware. This may contain combination any of the flags:

These constants are not yet provided by LuAllegro:

GFX_CAN_SCROLL:
Indicates that the scroll_screen() function may be used with this driver.

GFX_CAN_TRIPLE_BUFFER:
Indicates that the request_scroll() and poll_scroll() functions may be used with this driver. If this flag is not set, it is possible that the enable_triple_buffer() function may be able to activate it.

GFX_HW_CURSOR:
Indicates that a hardware mouse cursor is in use. When this flag is set, it is safe to draw onto the screen without hiding the mouse pointer first. Note that not every cursor graphic can be implemented in hardware: in particular VBE/AF only supports 2-color images up to 32x32 in size, where the second color is an exact inverse of the first. This means that Allegro may need to switch between hardware and software cursors at any point during the execution of your program, so you should not assume that this flag will remain constant for long periods of time. It only tells you whether a hardware cursor is in use at the current time, and may change whenever you hide/redisplay the pointer.

GFX_SYSTEM_CURSOR
Indicates that the mouse cursor is the default system cursor, not Allegro's custom cursor.

GFX_HW_HLINE:
Indicates that the normal opaque version of the hline() function is implemented using a hardware accelerator. This will improve the performance not only of hline() itself, but also of many other functions that use it as a workhorse, for example circlefill(), triangle(), and floodfill().

GFX_HW_HLINE_XOR:
Indicates that the XOR version of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator.

GFX_HW_HLINE_SOLID_PATTERN:
Indicates that the solid and masked pattern modes of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator (see note below).

GFX_HW_HLINE_COPY_PATTERN:
Indicates that the copy pattern mode of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator (see note below).

GFX_HW_FILL:
Indicates that the opaque version of the rectfill() function, the clear_bitmap() routine, and clear_to_color(), are implemented using a hardware accelerator.

GFX_HW_FILL_XOR:
Indicates that the XOR version of the rectfill() function is implemented using a hardware accelerator.

GFX_HW_FILL_SOLID_PATTERN:
Indicates that the solid and masked pattern modes of the rectfill() function are implemented using a hardware accelerator (see note below).

GFX_HW_FILL_COPY_PATTERN:
Indicates that the copy pattern mode of the rectfill() function is implemented using a hardware accelerator (see note below).

GFX_HW_LINE:
Indicates that the opaque mode line() and vline() functions are implemented using a hardware accelerator.

GFX_HW_LINE_XOR:
Indicates that the XOR version of the line() and vline() functions are implemented using a hardware accelerator.

GFX_HW_TRIANGLE:
Indicates that the opaque mode triangle() function is implemented using a hardware accelerator.

GFX_HW_TRIANGLE_XOR:
Indicates that the XOR version of the triangle() function is implemented using a hardware accelerator.

GFX_HW_GLYPH:
Indicates that monochrome character expansion (for text drawing) is implemented using a hardware accelerator.

GFX_HW_VRAM_BLIT:
Indicates that blitting from one part of the screen to another is implemented using a hardware accelerator. If this flag is set, blitting within the video memory will almost certainly be the fastest possible way to display an image, so it may be worth storing some of your more frequently used graphics in an offscreen portion of the video memory.

GFX_HW_VRAM_BLIT_MASKED:
Indicates that the masked_blit() routine is capable of a hardware accelerated copy from one part of video memory to another, and that draw_sprite() will use a hardware copy when given a sub-bitmap of the screen or a video memory bitmap as the source image. If this flag is set, copying within the video memory will almost certainly be the fastest possible way to display an image, so it may be worth storing some of your more frequently used sprites in an offscreen portion of the video memory.

Warning: if this flag is not set, masked_blit() and draw_sprite() will not work correctly when used with a video memory source image! You must only try to use these functions to copy within the video memory if they are supported in hardware.

GFX_HW_MEM_BLIT:
Indicates that blitting from a memory bitmap onto the screen is being accelerated in hardware.

GFX_HW_MEM_BLIT_MASKED:
Indicates that the masked_blit() and draw_sprite() functions are being accelerated in hardware when the source image is a memory bitmap and the destination is the physical screen.

GFX_HW_SYS_TO_VRAM_BLIT:
Indicates that blitting from a system bitmap onto the screen is being accelerated in hardware. Note that some acceleration may be present even if this flag is not set, because system bitmaps can benefit from normal memory to screen blitting as well. This flag will only be set if system bitmaps have further acceleration above and beyond what is provided by GFX_HW_MEM_BLIT.

GFX_HW_SYS_TO_VRAM_BLIT_MASKED:
Indicates that the masked_blit() and draw_sprite() functions are being accelerated in hardware when the source image is a system bitmap and the destination is the physical screen. Note that some acceleration may be present even if this flag is not set, because system bitmaps can benefit from normal memory to screen blitting as well. This flag will only be set if system bitmaps have further acceleration above and beyond what is provided by GFX_HW_MEM_BLIT_MASKED.

Note: even if the capabilities information says that patterned drawing is supported by the hardware, it will not be possible for every size of pattern. VBE/AF only supports patterns up to 8x8 in size, so Allegro will fall back on the original non-accelerated drawing routines whenever you use a pattern larger than this.

Note2: these hardware acceleration features will only take effect when you are drawing directly onto the screen bitmap, a video memory bitmap, or a sub-bitmap thereof. Accelerated hardware is most useful in a page flipping or triple buffering setup, and is unlikely to make any difference to the classic "draw onto a memory bitmap, then blit to the screen" system.

 

Not implemented yet

int enable_triple_buffer();


If the GFX_CAN_TRIPLE_BUFFER bit of the gfx_capabilities field is not set, you can attempt to enable it by calling this function. In particular if you are running in mode-X in a clean DOS environment, this routine will enable the timer retrace simulator, which will activate the triple buffering functions.

Return value: Returns zero if triple buffering is enabled, -1 otherwise.

See also: gfx_capabilities, request_scroll, request_video_bitmap.
Examples using this: ex3buf, exupdate.
bool allegro.scroll_screen( x , y )

Attempts to scroll the hardware screen to display a different part of the virtual screen (initially it will be positioned at 0, 0, which is the top left corner). You can use this to move the screen display around in a large virtual screen space, or to page flip back and forth between two non-overlapping areas of the virtual screen. Note that to draw outside the original position in the screen bitmap you will have to alter the clipping rectangle with set_clip_rect().

Mode-X scrolling is reliable and will work on any card, other drivers may not work or not work reliably. See the platform-specific section of the docs for more information.

Allegro will handle any necessary vertical retrace synchronisation when scrolling the screen, so you don't need to call vsync() before it. This means that scroll_screen() has the same time delay effects as vsync().

Return value: Returns true on success. Returns false if the graphics driver can't handle hardware scrolling or the virtual screen is not large enough.

 

bool allegro.request_scroll( x , y )

This function is used for triple buffering. It requests a hardware scroll to the specified position, but returns immediately rather than waiting for a retrace. The scroll will then take place during the next vertical retrace, but you can carry on running other code in the meantime and use the allegro.poll_scroll() routine to detect when the flip has actually taken place.

Triple buffering is only possible with certain drivers: you can look at the GFX_CAN_TRIPLE_BUFFER bit in the gfx_capabilities flag to see if it will work with the current driver.

Return value: This function returns true on success, false otherwise.

 

bool allegro.poll_scroll( )

This function is used for triple buffering. It checks the status of a hardware scroll previously initiated by the allegro.request_scroll() routine.

Return value: Returns true if it is still waiting to take place, and false if the requested scroll has already happened.

 

bool allegro.show_video_bitmap(userdata AL_BITMAP bitmap);

Attempts to page flip the hardware screen to display the specified video bitmap object, which must be the same size as the physical screen, and should have been obtained by calling the allegro.create_video_bitmap() function.

Allegro will handle any necessary vertical retrace synchronisation when page flipping, so you don't need to call allegro.vsync() before it. This means that allegro.show_video_bitmap() has the same time delay effects as allegro.vsync() by default. This can be adjusted with the "disable_vsync" config key in the [graphics] section of allegro.cfg. Example:

      int current_page;
      BITMAP *video_page[2];
      ...
      /* Create pages for page flipping */
      video_page[0] = create_video_bitmap(SCREEN_W, SCREEN_H);
      video_page[1] = create_video_bitmap(SCREEN_W, SCREEN_H);
      current_page = 0;
      ...
      /* draw the screen and flip pages */
      draw_screen(video_page[current_page]);
      show_video_bitmap(video_page[current_page]);
      current_page = (current_page+1)%2;
      ...

Return value: Returns true on success and false on failure.

 

bool allegro.request_video_bitmap(userdata AL_BITMAP *bitmap);

This function is used for triple buffering. It requests a page flip to display the specified video bitmap object, but returns immediately rather than waiting for a retrace. The flip will then take place during the next vertical retrace, but you can carry on running other code in the meantime and use the allegro.poll_scroll() routine to detect when the flip has actually taken place. Triple buffering is only possible on certain hardware: see the comments about allegro.request_scroll(). You can pass nil as a bitmap or don't pass any value at all and then request_video_bitmap(screen) will be called.

Return value: Returns zero on success and non-zero on failure.

 

allegro.vsync( )

Waits for a vertical retrace to begin. The retrace happens when the electron beam in your monitor has reached the bottom of the screen and is moving back to the top ready for another scan. During this short period the graphics card isn't sending any data to the monitor, so you can do things to it that aren't possible at other times, such as altering the palette without causing flickering (snow). Allegro will automatically wait for a retrace before altering the palette or doing any hardware scrolling, though, so you don't normally need to bother with this function.

 


Back to main page