Main Page | Modules | File List | Globals | Related Pages

scrmode.c

Go to the documentation of this file.
00001 
00009 #include <string.h>
00010 
00011 #include "alleggl.h"
00012 #include "allglint.h"
00013 #include "glvtable.h"
00014 
00015 
00016 
00017 /* C write/unwrite line routines -- defined in full later on */
00018 static unsigned long agl_write_line_c(BITMAP * bmp, int line);
00019 static void agl_unwrite_line_c(BITMAP * bmp);
00020 
00021 
00022 /* Now if Allegro is in assembler mode, it'll call these
00023  * functions using a special calling convention.  We need to
00024  * wrap them, in that case. */
00025 #ifdef ALLEGRO_NO_ASM
00026     /* Cool, we can just use our C routines directly */
00027        static void *agl_write_line = agl_write_line_c;
00028        static void *agl_unwrite_line = agl_unwrite_line_c;
00029 #else
00030     /* Oh well, we need to wrap the C routines. */
00031 #ifdef ALLEGRO_ASM_PREFIX
00032 #define PREFIX ALLEGRO_ASM_PREFIX
00033 #else
00034 #define PREFIX
00035 #endif
00036 #if defined ALLEGRO_I386
00037         /* i386 is all we support at the moment */
00038 #if defined ALLEGRO_GCC && !defined USE_PREASSEMBLED
00039             /* GCC syntax */
00040 asm("\n"
00041     PREFIX "agl_write_line_asm:\n"
00042     "   pushl %ecx\n"
00043     "   pushl %eax\n"
00044     "   pushl %edx\n"
00045     "   call " PREFIX "agl_write_line_c\n"
00046     "   popl %edx\n"
00047     "   popl %ecx\n"    /* note: dummy pop */
00048     "   popl %ecx\n"
00049     "   ret\n"
00050     "\n"
00051     PREFIX "agl_unwrite_line_asm:\n"
00052     "   pushl %eax\n"
00053     "   pushl %ecx\n"
00054     "   pushl %edx\n"
00055     "   call " PREFIX "agl_unwrite_line_c\n"
00056     "   popl %edx\n"
00057     "   popl %ecx\n"
00058     "   popl %eax\n"
00059     "   ret\n"
00060 );
00061 
00062 extern void agl_write_line_asm();
00063 extern void agl_unwrite_line_asm();
00064 static void *agl_write_line = agl_write_line_asm;
00065 static void *agl_unwrite_line = agl_unwrite_line_asm;
00066 #else
00067             /* Unsupported syntax -- use preassembled code
00068              * block.  This may or may not work. */
00069 unsigned char preassembled_code[] = {
00070     0x51, 0x50, 0x52,
00071     0xe8, 0, 0, 0, 0,
00072     0x5a, 0x59, 0x59,
00073     0xc3,
00074     0x50, 0x51, 0x52,
00075     0xe8, 0, 0, 0, 0,
00076     0x5a, 0x59, 0x58,
00077     0xc3
00078 };
00079 #define PREASM
00080 #define PREASM_OFFSET_WRITE_FUNC 4
00081 #define PREASM_OFFSET_UNWRITE_FUNC 16
00082 static void *agl_write_line = preassembled_code;
00083 static void *agl_unwrite_line = preassembled_code + 12;
00084 #endif
00085 #else
00086         /* Not i386 -- assembler not supported.  Allegro
00087          * will never let us get here anyway. */
00088 static void *agl_write_line = NULL, *agl_unwrite_line = NULL;
00089 #endif /* i386 */
00090 #endif /* !no_asm */
00091 
00092 
00093 
00094 static int screen_w, screen_h;
00095 
00096 /* buffers screen image in some modes */
00097 static BITMAP *__allegro_gl_memory = NULL;
00098 static GFX_VTABLE memory_vtable;    /* vtable for accessing above bitmap */
00099 static int *dirty_flags = NULL;     /* flags showing dirty lines in bitmap */
00100 static int dirty_size = 0;          /* size (in bytes) of `dirty_flags' */
00101 
00102 
00103 int __allegro_gl_screen_mode = AGL_MODE_DIRECT;
00104 
00105 
00106 static int lastline = -1;
00107 
00108 /* agl_write_line_c:
00109  *  This routine will be called by Allegro whenever the user
00110  *  tries to write to a line of the `__allegro_gl_memory' bitmap.
00111  */
00112 static unsigned long agl_write_line_c(BITMAP * bmp, int line)
00113 {
00114     switch (__allegro_gl_screen_mode) {
00115 
00116         case AGL_MODE_DIRECT:
00117             break;
00118 
00119         case AGL_MODE_DUPLEX:
00120             /* copy the line from the framebuffer using OpenGL */
00121             if (lastline != -1)
00122                 agl_unwrite_line_c(bmp);
00123             lastline = line;
00124 
00125             glReadPixels(0, screen_h - lastline, screen_w, 1,
00126                          __allegro_gl_get_bitmap_color_format(screen, 0),
00127                          __allegro_gl_get_bitmap_type(screen, 0),
00128                          bmp->line[lastline]);
00129 
00130             break;
00131 
00132         case AGL_MODE_OPAQUE:
00133         case AGL_MODE_MASKED:
00134             /* mark the line as dirty */
00135             dirty_flags[line] = 1;
00136             break;
00137 
00138         case AGL_MODE_OPAQUE_RT:
00139         case AGL_MODE_MASKED_RT:
00140             if (lastline != -1)
00141                 agl_unwrite_line_c(bmp);
00142             lastline = line;
00143             break;
00144 
00145     }
00146     return (int) bmp->line[line];
00147 }
00148 
00149 
00150 
00151 /* agl_unwrite_line_c:
00152  *  This is called by Allegro when the user has finished with a
00153  *  line of the `__allegro_gl_memory' bitmap.
00154  */
00155 static void agl_unwrite_line_c(BITMAP * bmp)
00156 {
00157     switch (__allegro_gl_screen_mode) {
00158 
00159         case AGL_MODE_DIRECT:
00160             break;
00161 
00162         case AGL_MODE_DUPLEX:
00163         case AGL_MODE_OPAQUE_RT:
00164             /* paste the line back to the framebuffer using OpenGL */
00165             if (lastline != -1) {
00166                 allegro_gl_begin();
00167                 glRasterPos2i(0, lastline);
00168                 glDrawPixels(screen_w, 1,
00169                     __allegro_gl_get_bitmap_color_format(screen, 0),
00170                     __allegro_gl_get_bitmap_type(screen, 0),
00171                     bmp->line[lastline]);
00172                 allegro_gl_end();
00173                 lastline = -1;
00174             }
00175             break;
00176 
00177         case AGL_MODE_MASKED_RT:
00178             /* Should be like above, but with a masked draw */
00179             break;
00180 
00181         case AGL_MODE_OPAQUE:
00182         case AGL_MODE_MASKED:
00183             break;
00184 
00185     }
00186 }
00187 
00188 
00189 
00190 /* prepare_for_blitting:
00191  *  This routine is meant to streamline everything for calls to 
00192  *  glDrawPixels.
00193  */
00194 static void prepare_for_blitting(void)
00195 {
00196     allegro_gl_begin();
00197 
00198 //      glPushAttrib (GL_ENABLE_BIT | GL_PIXEL_MODE_BIT);
00199 
00200     glDisable(GL_ALPHA_TEST);
00201     glDisable(GL_BLEND);
00202     glDisable(GL_DEPTH_TEST);
00203     glDisable(GL_FOG);
00204     glDisable(GL_LIGHTING);
00205 #ifdef GL_COLOR_LOGIC_OP
00206     glDisable(GL_COLOR_LOGIC_OP);
00207 #endif
00208     glDisable(GL_STENCIL_TEST);
00209     glDisable(GL_TEXTURE_1D);
00210     glDisable(GL_TEXTURE_2D);
00211 
00212     glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
00213     glPixelTransferi(GL_RED_SCALE, 1);
00214     glPixelTransferi(GL_RED_BIAS, 0);
00215     glPixelTransferi(GL_GREEN_SCALE, 1);
00216     glPixelTransferi(GL_GREEN_BIAS, 0);
00217     glPixelTransferi(GL_BLUE_SCALE, 1);
00218     glPixelTransferi(GL_BLUE_BIAS, 0);
00219     glPixelTransferi(GL_ALPHA_SCALE, 1);
00220     glPixelTransferi(GL_ALPHA_BIAS, 0);
00221 
00222     glPixelZoom(1.0, 1.0);
00223 
00224     allegro_gl_end();
00225 }
00226 
00227 
00228 
00229 /* init_screen_mode:
00230  *  Initialises the given update mode.  0 = success.
00231  */
00232 static int init_screen_mode(int newmode)
00233 {
00234     switch (newmode) {
00235 
00236         case AGL_MODE_DIRECT:
00237             screen = allegro_gl_screen;
00238             return 0;
00239 
00240         case AGL_MODE_DUPLEX:
00241             screen = __allegro_gl_memory;
00242             prepare_for_blitting();
00243             return 0;
00244 
00245         case AGL_MODE_OPAQUE:
00246         case AGL_MODE_OPAQUE_RT:
00247             screen = __allegro_gl_memory;
00248             clear_bitmap(screen);
00249             memset(dirty_flags, 0, dirty_size);
00250             return 0;
00251 
00252         case AGL_MODE_MASKED:
00253         case AGL_MODE_MASKED_RT:
00254             screen = __allegro_gl_memory;
00255             clear_to_color(screen, bitmap_mask_color(screen));
00256             memset(dirty_flags, 0, dirty_size);
00257             return 0;
00258 
00259         default:
00260             return -1;
00261 
00262     }
00263 }
00264 
00265 
00266 
00267 /* shutdown_screen_mode:
00268  *  Cleans up, if necessary, after the given update mode.  0 = success.
00269  */
00270 static int shutdown_screen_mode(int oldmode)
00271 {
00272     switch (oldmode) {
00273 
00274         case AGL_MODE_DIRECT:
00275             return 0;
00276 
00277         case AGL_MODE_DUPLEX:
00278         case AGL_MODE_OPAQUE_RT:
00279         case AGL_MODE_MASKED_RT:
00280             if (lastline != -1)
00281                 agl_unwrite_line_c(screen);
00282             return 0;
00283 
00284         case AGL_MODE_OPAQUE:
00285             glRasterPos2i(0, 0);
00286             glDrawPixels(screen_w, screen_h,
00287                 __allegro_gl_get_bitmap_color_format(screen, 0),
00288                 __allegro_gl_get_bitmap_type(screen, 0), screen->line[0]);
00289             return 0;
00290 
00291         case AGL_MODE_MASKED:
00292             /* as above but masked */
00293             return 0;
00294 
00295         default:
00296             return -1;
00297 
00298     }
00299 }
00300 
00301 
00302 
00392 int allegro_gl_screen_mode(int newmode)
00393 {
00394     return shutdown_screen_mode(__allegro_gl_screen_mode)
00395         || init_screen_mode(__allegro_gl_screen_mode = newmode);
00396 }
00397 
00398 
00399 
00400 /* create_memory_screen:
00401  *  Creates the memory screen bitmap and sets up the write/unwrite line
00402  *  functions.
00403  */
00404 static void create_memory_screen(void)
00405 {
00406     __allegro_gl_memory = create_bitmap(screen_w, screen_h);
00407     if (!__allegro_gl_memory)
00408         return;
00409 
00410     clear_bitmap(__allegro_gl_memory);
00411 
00412     dirty_size = screen_h * sizeof *dirty_flags;
00413     dirty_flags = malloc(dirty_size);
00414     if (!dirty_flags) {
00415         destroy_bitmap(__allegro_gl_memory);
00416         __allegro_gl_memory = NULL;
00417         return;
00418     }
00419 
00420     {
00421         int i;
00422         for (i = 0; i < screen_h; i++)
00423             dirty_flags[i] = 0;
00424     }
00425 
00426     memcpy(&memory_vtable, __allegro_gl_memory->vtable, sizeof memory_vtable);
00427     __allegro_gl_memory->vtable = &memory_vtable;
00428     __allegro_gl_memory->write_bank = agl_write_line;
00429     __allegro_gl_memory->vtable->unwrite_bank = agl_unwrite_line;
00430 }
00431 
00432 
00433 
00434 /* __allegro_gl_init_screen_mode:
00435  *  Initialise this module.
00436  */
00437 void __allegro_gl_init_screen_mode(void)
00438 {
00439     static int initialised = 0;
00440     if (initialised) {
00441         /* Shut down before reinitialising */
00442         if (__allegro_gl_memory) {
00443             destroy_bitmap(__allegro_gl_memory);
00444             __allegro_gl_memory = NULL;
00445             free(dirty_flags);
00446             dirty_flags = NULL;
00447         }
00448     }
00449     else {
00450         /* One-off initialisation */
00451         initialised = 1;
00452 
00453 #ifdef PREASM
00454         /* In the preassembled code, we can't use the linker
00455          * directly to fill in the addresses of the C routines,
00456          * so we have to do it indirectly like this. */
00457         *(int *) (preassembled_code + PREASM_OFFSET_WRITE_FUNC) =
00458             (int) agl_write_line_c - (int) preassembled_code -
00459             PREASM_OFFSET_WRITE_FUNC - 4;
00460         *(int *) (preassembled_code + PREASM_OFFSET_UNWRITE_FUNC) =
00461             (int) agl_unwrite_line_c - (int) preassembled_code -
00462             PREASM_OFFSET_UNWRITE_FUNC - 4;
00463 #else
00464         /* Suppress warnings. */
00465         (void) agl_write_line_c;
00466         (void) agl_unwrite_line_c;
00467 #endif
00468     }
00469 
00470     screen_w = allegro_gl_display_info.w;
00471     screen_h = allegro_gl_display_info.h;
00472     create_memory_screen();
00473 
00474     init_screen_mode(AGL_MODE_DIRECT);
00475 }
00476 
00477 
00478 
00479 /* __allegro_gl_release_screen:
00480  * Check the screen update mode and free whichever of __allegro_gl_memory
00481  * and allegro_gl_screen isn't active.
00482  */
00483  void __allegro_gl_release_screen(void)
00484  {
00485     switch(__allegro_gl_screen_mode) {
00486 
00487         case AGL_MODE_DIRECT:
00488             /* screen == allegro_gl_screen */
00489             if (__allegro_gl_memory)
00490                 destroy_bitmap(__allegro_gl_memory);
00491             break;
00492 
00493         case AGL_MODE_DUPLEX:
00494         case AGL_MODE_OPAQUE_RT:
00495         case AGL_MODE_MASKED_RT:
00496         case AGL_MODE_OPAQUE:
00497         case AGL_MODE_MASKED:
00498             /* screen == __allegro_gl_memory */
00499             if (allegro_gl_screen)
00500                 destroy_bitmap(allegro_gl_screen);
00501             break;
00502 
00503         default:
00504             return;
00505             
00506     }
00507     
00508     if (dirty_flags)
00509         free(dirty_flags);
00510     dirty_flags = NULL;
00511 
00512     /* Allegro will destroy the screen bitmap,
00513        so the pointers are now useless */
00514     __allegro_gl_memory = NULL;
00515     allegro_gl_screen = NULL;
00516  }
00517 

Generated on Wed Jun 30 23:59:52 2004 for AllegroGL by doxygen 1.3.5