videovtb.c

Go to the documentation of this file.
00001 /* This code is (C) AllegroGL contributors, and double licensed under
00002  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
00003  */
00009 #include <string.h>
00010 #include <limits.h>
00011 
00012 #include <allegro.h>
00013 
00014 #ifdef ALLEGRO_WINDOWS
00015 #include <winalleg.h>
00016 #endif
00017 
00018 #include "alleggl.h"
00019 #include "allglint.h"
00020 #include "glvtable.h"
00021 #include <allegro/internal/aintern.h>
00022 #ifdef ALLEGRO_MACOSX
00023 #include <OpenGL/glu.h>
00024 #else
00025 #include <GL/glu.h>
00026 #endif
00027 
00028 
00029 #define MASKED_BLIT 1
00030 #define BLIT        2
00031 #define TRANS       3
00032 
00033 
00034 static GFX_VTABLE allegro_gl_video_vtable;
00035 
00036 /* Counter for video bitmaps. screen = 1 */
00037 static int video_bitmap_count = 2;
00038 
00039 static int __allegro_gl_video_bitmap_bpp = -1;
00040 
00041 
00042 void allegro_gl_destroy_video_bitmap(BITMAP *bmp);
00043 
00044 
00045 
00046 static int allegro_gl_make_video_bitmap_helper1(int w, int h, int x, int y,
00047                                    GLint target, AGL_VIDEO_BITMAP **pvid) {
00048 
00049     int internal_format;
00050     int bpp;
00051 
00052     if (__allegro_gl_video_bitmap_bpp == -1) {
00053         bpp = bitmap_color_depth(screen);
00054     }
00055     else {
00056         bpp = __allegro_gl_video_bitmap_bpp;
00057     }
00058 
00059     (*pvid) = malloc(sizeof(AGL_VIDEO_BITMAP));
00060 
00061     if (!(*pvid))
00062         return -1;
00063 
00064     memset(*pvid, 0, sizeof(AGL_VIDEO_BITMAP));
00065 
00066     /* Create associated bitmap */
00067     (*pvid)->memory_copy = create_bitmap_ex(bpp, w, h);
00068     if (!(*pvid)->memory_copy)
00069         return -1;
00070     
00071     (*pvid)->format = __allegro_gl_get_bitmap_color_format((*pvid)->memory_copy, AGL_TEXTURE_HAS_ALPHA);
00072     (*pvid)->type = __allegro_gl_get_bitmap_type((*pvid)->memory_copy, 0);
00073     internal_format = __allegro_gl_get_texture_format_ex((*pvid)->memory_copy, AGL_TEXTURE_HAS_ALPHA);
00074 
00075     (*pvid)->target = target;
00076 
00077     /* Fill in some values in the bitmap to make it act as a subbitmap
00078      */
00079     (*pvid)->width  = w;
00080     (*pvid)->height = h;
00081     (*pvid)->x_ofs = x;
00082     (*pvid)->y_ofs = y;
00083 
00084     /* Make a texture out of it */
00085     glGenTextures(1, &((*pvid)->tex));
00086     if (!((*pvid)->tex))
00087         return -1;
00088 
00089     glEnable((*pvid)->target);
00090     glBindTexture((*pvid)->target, ((*pvid)->tex));
00091 
00092     glTexImage2D((*pvid)->target, 0, internal_format, w, h,
00093                  0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
00094 
00095     /* By default, use the Allegro filtering mode - ie: Nearest */
00096     glTexParameteri((*pvid)->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00097     glTexParameteri((*pvid)->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00098 
00099     /* Clamp to edge */
00100     {   GLenum clamp = GL_CLAMP_TO_EDGE;
00101         if (!allegro_gl_extensions_GL.SGIS_texture_edge_clamp) {
00102             clamp = GL_CLAMP;
00103         }
00104         glTexParameteri((*pvid)->target, GL_TEXTURE_WRAP_S, clamp);
00105         glTexParameteri((*pvid)->target, GL_TEXTURE_WRAP_T, clamp);
00106     }
00107 
00108     glDisable((*pvid)->target);
00109 
00110     if (allegro_gl_extensions_GL.EXT_framebuffer_object) {
00111         glGenFramebuffersEXT(1, &((*pvid)->fbo));
00112         if (!(*pvid)->fbo) {
00113             glDeleteTextures(1, &((*pvid)->tex));
00114             return -1;
00115         }
00116 
00117         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (*pvid)->fbo);
00118         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, (*pvid)->target, (*pvid)->tex, 0);
00119         if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
00120             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00121             glDeleteFramebuffersEXT(1, &((*pvid)->fbo));
00122             glDeleteTextures(1, &((*pvid)->tex));
00123             return -1;
00124         }
00125         
00126         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00127     }
00128     else {
00129         (*pvid)->fbo = 0;
00130     }
00131 
00132     return 0;
00133 }
00134 
00135 
00136 
00137 static int allegro_gl_make_video_bitmap_helper0(int w, int h, int x, int y,
00138                                                 AGL_VIDEO_BITMAP **pvid) {
00139         
00140     int is_power_of_2 = (!(w & (w - 1)) && !(h & (h - 1)));
00141     int texture_rect_available = allegro_gl_extensions_GL.ARB_texture_rectangle
00142 #ifdef ALLEGRO_MACOSX
00143                              || allegro_gl_extensions_GL.EXT_texture_rectangle
00144 #endif
00145                              || allegro_gl_extensions_GL.NV_texture_rectangle;
00146     GLint max_rect_texture_size = 0;
00147 
00148     if (texture_rect_available) {
00149         glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &max_rect_texture_size);
00150     }
00151 
00152     if (w <= allegro_gl_info.max_texture_size &&
00153         h <= allegro_gl_info.max_texture_size) {
00154         if (allegro_gl_extensions_GL.ARB_texture_non_power_of_two ||
00155             is_power_of_2) {
00156             if (allegro_gl_make_video_bitmap_helper1(w, h, x, y,
00157                                             GL_TEXTURE_2D, pvid)) {
00158                 return -1;
00159             }
00160         }
00161         else if (texture_rect_available &&
00162                  w <= max_rect_texture_size &&
00163                  h <= max_rect_texture_size) {
00164             if (allegro_gl_make_video_bitmap_helper1(w, h, x, y,
00165                                             GL_TEXTURE_RECTANGLE_ARB, pvid)) {
00166                 return -1;
00167             }
00168         }
00169         else {
00170             /* NPO2 textures are not suppored by the driver in any way.
00171              * Split the bitmap into smaller POT bitmaps. */
00172             const unsigned int BITS = sizeof(int) * CHAR_BIT;
00173             unsigned int i, j;
00174             unsigned int w1, h1;
00175             unsigned int x1, y1;
00176             unsigned int p1, p2;
00177 
00178             /* Find the POTs using bits. */
00179             y1 = 0;
00180             for (i = 0; i < BITS; i++) {
00181                 p1 = 1 << i;
00182                 if (h & p1)
00183                     h1 = p1;
00184                 else
00185                     continue;
00186 
00187                 x1 = 0;
00188                 for (j = 0; j < BITS; j++) {
00189                     p2 = 1 << j;
00190                     if (w & p2)
00191                         w1 = p2;
00192                     else
00193                         continue;
00194 
00195                     if (allegro_gl_make_video_bitmap_helper0(w1, h1, x + x1,
00196                                                         y + y1, pvid)) {
00197                         return -1;
00198                     }
00199                     do {
00200                         pvid = &((*pvid)->next);
00201                     } while (*pvid);
00202 
00203                     x1 += w1;
00204                 }
00205 
00206                 y1 += h1;
00207             }
00208         }
00209     }
00210     else {
00211         /* Texture is too big to fit. Split it in 4 and try again. */
00212         int w1, w2, h1, h2;
00213 
00214         w2 = w / 2;
00215         w1 = w - w2;
00216 
00217         h2 = h / 2;
00218         h1 = h - h2;
00219 
00220         /* Even a 1x1 texture didn't work? Bail*/
00221         if (!w2 && !h2) {
00222             return -1;
00223         }
00224 
00225         /* Top-left corner */
00226         if (allegro_gl_make_video_bitmap_helper0(w1, h1, x, y, pvid)) {
00227             return -1;
00228         }
00229         do {
00230             pvid = &((*pvid)->next);
00231         } while (*pvid);
00232 
00233         /* Top-right corner */
00234         if (w2) {
00235             if (allegro_gl_make_video_bitmap_helper0(w2, h1, x + w1, y, pvid)) {
00236                 return -1;
00237             }
00238             do {
00239                 pvid = &((*pvid)->next);
00240             } while (*pvid);
00241         }
00242         /* Bottom-left corner */
00243         if (h2) {
00244             if (allegro_gl_make_video_bitmap_helper0(w1, h2, x, y + h1, pvid)) {
00245                 return -1;
00246             }
00247             do {
00248                 pvid = &((*pvid)->next);
00249             } while (*pvid);
00250         }
00251         /* Bottom-right corner */
00252         if (w2 && h2) {
00253             if (allegro_gl_make_video_bitmap_helper0(w2, h2, x + w1, y + h1, pvid)) {
00254                 return -1;
00255             }
00256             do {
00257                 pvid = &((*pvid)->next);
00258             } while (*pvid);
00259         }
00260     }
00261 
00262     return 0;
00263 }
00264 
00265 
00266 
00267 /* Will make a (potentially piece-wise) texture out of the specified bitmap
00268  * Source -must- be a memory bitmap or memory subbitmap (created by Allegro
00269  * only).
00270  *
00271  */
00272 static BITMAP *allegro_gl_make_video_bitmap(BITMAP *bmp) {
00273     
00274     /* Grab a pointer to the bitmap data to patch */
00275     void *ptr = &bmp->extra;
00276     AGL_VIDEO_BITMAP **pvid = (AGL_VIDEO_BITMAP**)ptr;
00277     
00278     /* Convert bitmap to texture */
00279     if (allegro_gl_make_video_bitmap_helper0(bmp->w, bmp->h, 0, 0, pvid)) {
00280         goto agl_error;
00281     }
00282 
00283     return bmp;
00284     
00285 agl_error:
00286     allegro_gl_destroy_video_bitmap(bmp);
00287     return NULL;
00288 }
00289 
00290 
00291 
00292 /* void allegro_gl_destroy_video_bitmap(BITMAP *bmp) */
00297 void allegro_gl_destroy_video_bitmap(BITMAP *bmp) {
00298 
00299     AGL_VIDEO_BITMAP *vid = bmp ? bmp->extra : NULL, *next;
00300     
00301     if (!bmp)
00302         return;
00303     
00304     while (vid) {
00305         if (vid->memory_copy)
00306             destroy_bitmap(vid->memory_copy);
00307     
00308         if (vid->tex)
00309             glDeleteTextures(1, &vid->tex);
00310 
00311         if (vid->fbo)
00312             glDeleteFramebuffersEXT(1, &vid->fbo);
00313                                 
00314         next = vid->next;
00315         free(vid);
00316         vid = next;
00317     }
00318 
00319     free(bmp->vtable);
00320     free(bmp);
00321     
00322     return;
00323 }
00324 
00325 
00326 
00327 /* BITMAP *allegro_gl_create_video_bitmap(int w, int h) */
00333 BITMAP *allegro_gl_create_video_bitmap(int w, int h) {
00334     GFX_VTABLE *vtable;
00335     BITMAP *bitmap;
00336 
00337     bitmap = malloc(sizeof(BITMAP) + sizeof(char *));
00338     
00339     if (!bitmap)
00340         return NULL;
00341 
00342     bitmap->dat = NULL;
00343     bitmap->w = bitmap->cr = w;
00344     bitmap->h = bitmap->cb = h;
00345     bitmap->clip = TRUE;
00346     bitmap->cl = bitmap->ct = 0;
00347     bitmap->write_bank = bitmap->read_bank = NULL;
00348     /* We should keep tracks of allocated bitmaps for the ref counter */
00349     bitmap->id = BMP_ID_VIDEO | video_bitmap_count;
00350     bitmap->extra = NULL;
00351     bitmap->x_ofs = 0;
00352     bitmap->y_ofs = 0;
00353     bitmap->seg = _default_ds();
00354     bitmap->line[0] = NULL;
00355 
00356     if (!allegro_gl_make_video_bitmap(bitmap)) {
00357         return NULL;
00358     }
00359     video_bitmap_count++;
00360     
00361     /* XXX <rohannessian> We ought to leave the Allegro values intact
00362      * Avoids bad interaction with correct Allegro programs.
00363      */
00364     vtable = malloc(sizeof(struct GFX_VTABLE));
00365     *vtable = allegro_gl_video_vtable;
00366     if (__allegro_gl_video_bitmap_bpp == -1) {
00367         vtable->color_depth = bitmap_color_depth(screen);
00368     }
00369     else {
00370         vtable->color_depth = __allegro_gl_video_bitmap_bpp;
00371     }
00372     switch (vtable->color_depth) {
00373         case 8:
00374             vtable->mask_color = MASK_COLOR_8;
00375         break;
00376         case 15:
00377             vtable->mask_color = MASK_COLOR_15;
00378         break;
00379         case 16:
00380             vtable->mask_color = MASK_COLOR_16;
00381         break;
00382         case 24:
00383             vtable->mask_color = MASK_COLOR_24;
00384         break;
00385         case 32:
00386             vtable->mask_color = MASK_COLOR_32;
00387         break;
00388     }
00389     bitmap->vtable = vtable;
00390 
00391     return bitmap;
00392 }
00393 
00394 
00395 
00396 /* allegro_gl_set_video_bitmap_color_depth(int bpp) */
00411 GLint allegro_gl_set_video_bitmap_color_depth(int bpp) {
00412     GLint old_val = __allegro_gl_video_bitmap_bpp;
00413     __allegro_gl_video_bitmap_bpp = bpp;
00414     return old_val;
00415 }
00416 
00417 
00418 /* static void allegro_gl_video_acquire(struct BITMAP *bmp) */
00425 static void allegro_gl_video_acquire(struct BITMAP *bmp) {}
00426 
00427 
00428 
00429 /* static void allegro_gl_video_release(struct BITMAP *bmp) */
00436 static void allegro_gl_video_release(struct BITMAP *bmp) {}
00437 
00438 
00439 
00440 static int allegro_gl_video_getpixel(struct BITMAP *bmp, int x, int y)
00441 {
00442     int pix = -1;
00443     AGL_VIDEO_BITMAP *vid;
00444     AGL_LOG(2, "glvtable.c:allegro_gl_screen_getpixel\n");  
00445     
00446     if (is_sub_bitmap(bmp)) {
00447         x += bmp->x_ofs;
00448         y += bmp->y_ofs;
00449     }
00450     if (x < bmp->cl || x >= bmp->cr || y < bmp->ct || y >= bmp->cb) {
00451         return -1;
00452     }
00453 
00454     vid = bmp->extra;
00455     
00456     while (vid) {
00457         if (vid->x_ofs <= x && vid->y_ofs <= y
00458          && vid->x_ofs + vid->memory_copy->w > x
00459          && vid->y_ofs + vid->memory_copy->h > y) {
00460             
00461             pix = getpixel(vid->memory_copy, x - vid->x_ofs, y - vid->y_ofs);
00462             break;
00463         }
00464         vid = vid->next;
00465     }
00466     
00467     if (pix != -1) {
00468         return pix;
00469     }
00470     
00471     return -1;
00472 }
00473 
00474 
00475 
00476 static void update_texture_memory(AGL_VIDEO_BITMAP *vid, int x1, int y1,
00477                                   int x2, int y2) {
00478     GLint saved_row_length;
00479     GLint saved_alignment;
00480     GLint type;
00481     GLint format;
00482     int bpp;
00483     BITMAP *temp = NULL;
00484     BITMAP *vbmp = vid->memory_copy;;
00485 
00486     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &saved_row_length);
00487     glGetIntegerv(GL_UNPACK_ALIGNMENT, &saved_alignment);
00488 
00489     bpp = BYTES_PER_PIXEL(bitmap_color_depth(vid->memory_copy));
00490     format = vid->format;
00491     type = vid->type;
00492 
00493     /* If packed pixels (or GL 1.2) isn't supported, then we need to convert
00494      * the bitmap into something GL can understand - 24-bpp should do it.
00495      */
00496     if (!allegro_gl_extensions_GL.EXT_packed_pixels
00497                                           && bitmap_color_depth(vbmp) < 24) {
00498         temp = create_bitmap_ex(24, vbmp->w, vbmp->h);
00499         if (!temp)
00500             return;
00501 
00502         blit(vbmp, temp, 0, 0, 0, 0, temp->w, temp->h);
00503         vbmp = temp;
00504         bpp = BYTES_PER_PIXEL(bitmap_color_depth(vbmp));
00505         format = __allegro_gl_get_bitmap_color_format(vbmp, 0);
00506         type = __allegro_gl_get_bitmap_type(vbmp, 0);
00507     }
00508 
00509     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00510     glPixelStorei(GL_UNPACK_ROW_LENGTH,
00511                   vbmp->h > 1
00512                  ? (vbmp->line[1] - vbmp->line[0]) / bpp
00513                  : vbmp->w);
00514 
00515     glEnable(vid->target);
00516     glBindTexture(vid->target, vid->tex);
00517     glTexSubImage2D(vid->target, 0,
00518         x1, y1, x2 - x1 + 1, y2 - y1 + 1, format,
00519         type, vbmp->line[y1] + x1 * bpp);
00520     glBindTexture(vid->target, 0);
00521     glDisable(vid->target);
00522 
00523     if (temp)
00524         destroy_bitmap(temp);
00525 
00526     glPixelStorei(GL_UNPACK_ROW_LENGTH, saved_row_length);
00527     glPixelStorei(GL_UNPACK_ALIGNMENT, saved_alignment);
00528 }
00529 
00530 
00531 
00532 static void allegro_gl_video_putpixel(struct BITMAP *bmp, int x, int y,
00533                                       int color) {
00534     AGL_VIDEO_BITMAP *vid;
00535 
00536     if (is_sub_bitmap(bmp)) {
00537         x += bmp->x_ofs;
00538         y += bmp->y_ofs;
00539     }
00540     if (x < bmp->cl || x >= bmp->cr || y < bmp->ct || y >= bmp->cb) {
00541         return;
00542     }
00543 
00544     vid = bmp->extra;
00545 
00546     while (vid) {
00547         if (vid->x_ofs <= x && vid->y_ofs <= y
00548          && vid->x_ofs + vid->memory_copy->w > x
00549          && vid->y_ofs + vid->memory_copy->h > y) {
00550 
00551             putpixel(vid->memory_copy, x - vid->x_ofs, y - vid->y_ofs, color);
00552             update_texture_memory(vid, x - vid->x_ofs, y - vid->y_ofs, x - vid->x_ofs, y - vid->y_ofs);
00553             break;
00554         }
00555         vid = vid->next;
00556     }
00557     
00558     return;
00559 }
00560 
00561 
00562 
00563 static void allegro_gl_video_vline(BITMAP *bmp, int x, int y1, int y2,
00564                                    int color) {
00565 
00566     AGL_VIDEO_BITMAP *vid;
00567     
00568     AGL_LOG(2, "glvtable.c:allegro_gl_video_vline\n");
00569     vid = bmp->extra;
00570     
00571     if (is_sub_bitmap(bmp)) {
00572         x  += bmp->x_ofs;
00573         y1 += bmp->y_ofs;
00574         y2 += bmp->y_ofs;
00575     }
00576     if (x < bmp->cl || x >= bmp->cr) {
00577         return;
00578     }
00579     
00580     if (y1 > y2) {
00581         int temp = y1;
00582         y1 = y2;
00583         y2 = temp;
00584     }
00585 
00586     if (y1 < bmp->ct) {
00587         y1 = bmp->ct;
00588     }
00589     if (y2 >= bmp->cb) {
00590         y2 = bmp->cb - 1;
00591     }
00592 
00593     while (vid) {
00594         BITMAP *vbmp = vid->memory_copy;
00595         
00596         int _y1, _y2, _x;
00597         if (vid->x_ofs > x || vid->y_ofs > y2
00598          || vid->x_ofs + vbmp->w <= x
00599          || vid->y_ofs + vbmp->h <= y1) {
00600             
00601             vid = vid->next;
00602             continue;
00603         }
00604         
00605         _y1 = MAX(y1, vid->y_ofs) - vid->y_ofs;
00606         _y2 = MIN(y2, vid->y_ofs + vbmp->h - 1) - vid->y_ofs;
00607         _x = x - vid->x_ofs;
00608 
00609         vline(vbmp, _x, _y1, _y2, color);
00610         update_texture_memory(vid, _x, _y1, _x, _y2);
00611 
00612         vid = vid->next;
00613     }
00614     
00615     return;
00616 }
00617 
00618 
00619 
00620 static void allegro_gl_video_hline(BITMAP *bmp, int x1, int y, int x2,
00621                                    int color) {
00622 
00623     AGL_VIDEO_BITMAP *vid;
00624     
00625     AGL_LOG(2, "glvtable.c:allegro_gl_video_hline\n");
00626     vid = bmp->extra;
00627 
00628     if (is_sub_bitmap(bmp)) {
00629         x1 += bmp->x_ofs;
00630         x2 += bmp->x_ofs;
00631         y  += bmp->y_ofs;
00632     }
00633 
00634     if (y < bmp->ct || y >= bmp->cb) {
00635         return;
00636     }
00637     
00638     if (x1 > x2) {
00639         int temp = x1;
00640         x1 = x2;
00641         x2 = temp;
00642     }
00643 
00644     if (x1 < bmp->cl) {
00645         x1 = bmp->cl;
00646     }
00647     if (x2 >= bmp->cr) {
00648         x2 = bmp->cr - 1;
00649     }
00650 
00651     while (vid) {
00652         BITMAP *vbmp = vid->memory_copy;
00653         
00654         int _x1, _x2, _y;
00655         if (vid->y_ofs > y || vid->x_ofs > x2
00656          || vid->x_ofs + vbmp->w <= x1
00657          || vid->y_ofs + vbmp->h <= y) {
00658             
00659             vid = vid->next;
00660             continue;
00661         }
00662         
00663         _x1 = MAX(x1, vid->x_ofs) - vid->x_ofs;
00664         _x2 = MIN(x2, vid->x_ofs + vbmp->w - 1) - vid->x_ofs;
00665         _y = y - vid->y_ofs;
00666 
00667         hline(vbmp, _x1, _y, _x2, color);   
00668         update_texture_memory(vid, _x1, _y, _x2, _y);
00669 
00670         vid = vid->next;
00671     }
00672     
00673     return;
00674 }
00675 
00676 
00677 
00678 static void allegro_gl_video_line(struct BITMAP *bmp, int x1, int y1, int x2,
00679                                   int y2, int color) {
00680     
00681     /* Note: very very slow */                      
00682     do_line(bmp, x1, y1, x2, y2, color, allegro_gl_video_putpixel);
00683     
00684     return;
00685 }
00686     
00687 
00688 
00689 static void allegro_gl_video_rectfill(struct BITMAP *bmp, int x1, int y1,
00690                                       int x2, int y2, int color) {
00691 
00692     AGL_VIDEO_BITMAP *vid;
00693 
00694     AGL_LOG(2, "glvtable.c:allegro_gl_video_rectfill\n");
00695     vid = bmp->extra;
00696 
00697     if (is_sub_bitmap(bmp)) {
00698         x1 += bmp->x_ofs;
00699         x2 += bmp->x_ofs;
00700         y1 += bmp->y_ofs;
00701         y2 += bmp->y_ofs;
00702     }
00703     
00704     if (y1 > y2) {
00705         int temp = y1;
00706         y1 = y2;
00707         y2 = temp;
00708     }
00709 
00710     if (x1 > x2) {
00711         int temp = x1;
00712         x1 = x2;
00713         x2 = temp;
00714     }
00715 
00716     if (x1 < bmp->cl) {
00717         x1 = bmp->cl;
00718     }
00719     if (x2 >= bmp->cr) {
00720         x2 = bmp->cr - 1;
00721     }
00722     if (y1 < bmp->ct) {
00723         y1 = bmp->ct;
00724     }
00725     if (y1 >= bmp->cb) {
00726         y1 = bmp->cb - 1;
00727     }
00728 
00729     while (vid) {
00730         BITMAP *vbmp = vid->memory_copy;
00731         
00732         int _y1, _y2, _x1, _x2;
00733         if (vid->x_ofs > x2 || vid->y_ofs > y2
00734          || vid->x_ofs + vbmp->w <= x1
00735          || vid->y_ofs + vbmp->h <= y1) {
00736             
00737             vid = vid->next;
00738             continue;
00739         }
00740         
00741         _y1 = MAX(y1, vid->y_ofs) - vid->y_ofs;
00742         _y2 = MIN(y2, vid->y_ofs + vbmp->h - 1) - vid->y_ofs;
00743         _x1 = MAX(x1, vid->x_ofs) - vid->x_ofs;
00744         _x2 = MIN(x2, vid->x_ofs + vbmp->w - 1) - vid->x_ofs;
00745 
00746         rectfill(vbmp, _x1, _y1, _x2, _y2, color);
00747 
00748         update_texture_memory(vid, _x1, _y1, _x2, _y2);
00749 
00750         vid = vid->next;
00751     }
00752 
00753     return;
00754 }
00755 
00756 
00757 static void allegro_gl_video_triangle(struct BITMAP *bmp, int x1, int y1,
00758                                       int x2, int y2, int x3, int y3, int color)
00759 {   
00760     AGL_VIDEO_BITMAP *vid;
00761     int min_y, max_y, min_x, max_x;
00762 
00763     AGL_LOG(2, "glvtable.c:allegro_gl_video_triangle\n");
00764     vid = bmp->extra;
00765 
00766     if (is_sub_bitmap(bmp)) {
00767         x1 += bmp->x_ofs;
00768         x2 += bmp->x_ofs;
00769         x3 += bmp->x_ofs;
00770         y1 += bmp->y_ofs;
00771         y2 += bmp->y_ofs;
00772         y3 += bmp->y_ofs;
00773     }
00774 
00775     min_y = MIN(y1, MIN(y2, y3));
00776     min_x = MIN(x1, MIN(x2, x3));
00777     max_y = MAX(y1, MAX(y2, y3));
00778     max_x = MAX(x1, MAX(x2, x3));
00779 
00780     while (vid) {
00781         BITMAP *vbmp = vid->memory_copy;
00782         
00783         int _y1, _y2, _x1, _x2, _x3, _y3;
00784         if (vid->x_ofs > max_x || vid->y_ofs > max_y
00785          || vid->x_ofs + vbmp->w <= min_x
00786          || vid->y_ofs + vbmp->h <= min_y) {
00787             
00788             vid = vid->next;
00789             continue;
00790         }
00791         
00792         _y1 = y1 - vid->y_ofs;
00793         _y2 = y2 - vid->y_ofs;
00794         _y3 = y3 - vid->y_ofs;
00795         _x1 = x1 - vid->x_ofs;
00796         _x2 = x2 - vid->x_ofs;
00797         _x3 = x3 - vid->x_ofs;
00798 
00799         set_clip_rect(vbmp, bmp->cl - vid->x_ofs, bmp->ct - vid->y_ofs,
00800                             bmp->cr - vid->x_ofs - 1, bmp->cb - vid->y_ofs - 1);
00801 
00802         triangle(vbmp, _x1, _y1, _x2, _y2, _x3, _y3, color);
00803 
00804         set_clip_rect(vbmp, 0, 0, vbmp->w - 1, vbmp->h - 1);
00805 
00806         /* Not quite the minimal rectangle occupied by the triangle, but
00807         * pretty close */
00808         _y1 = MAX(0, min_y - vid->y_ofs);
00809         _y2 = MIN(vbmp->h - 1, max_y - vid->y_ofs);
00810         _x1 = MAX(0, min_x - vid->x_ofs);
00811         _x2 = MIN(vbmp->w - 1, max_x - vid->x_ofs);
00812 
00813         update_texture_memory(vid, _x1, _y1, _x2, _y2);
00814 
00815         vid = vid->next;
00816     }
00817 }
00818 
00819 
00820 
00821 static void allegro_gl_video_blit_from_memory_ex(BITMAP *source, BITMAP *dest,
00822                     int source_x, int source_y, int dest_x, int dest_y,
00823                     int width, int height, int draw_type) {
00824 
00825     AGL_VIDEO_BITMAP *vid;
00826     BITMAP *dest_parent = dest;
00827     
00828     if (is_sub_bitmap (dest)) {
00829        dest_x += dest->x_ofs;
00830        dest_y += dest->y_ofs;
00831        while (dest_parent->id & BMP_ID_SUB)
00832           dest_parent = (BITMAP *)dest_parent->extra;
00833     }
00834 
00835     if (dest_x < dest->cl) {
00836         dest_x = dest->cl;
00837     }
00838     if (dest_y < dest->ct) {
00839         dest_y = dest->ct;
00840     }
00841     if (dest_x + width >= dest->cr) {
00842         width = dest->cr - dest_x;
00843     }
00844     if (dest_y + height >= dest->cb) {
00845         height = dest->cb - dest_y;
00846     }
00847     if (width < 1 || height < 1) {
00848         return;
00849     }
00850     
00851     vid = dest_parent->extra;
00852 
00853     while (vid) {
00854         BITMAP *vbmp = vid->memory_copy;
00855 
00856         int _x, _y, _w, _h, _sx, _sy;
00857         if (vid->x_ofs >= dest_x + width || vid->y_ofs >= dest_y + height
00858          || vid->x_ofs + vbmp->w <= dest_x
00859          || vid->y_ofs + vbmp->h <= dest_y) {
00860             
00861             vid = vid->next;
00862             continue;
00863         }
00864 
00865         _x = MAX (vid->x_ofs, dest_x) - vid->x_ofs;
00866         _w = MIN (vid->x_ofs + vbmp->w, dest_x + width)
00867            - vid->x_ofs - _x;
00868         _y = MAX (vid->y_ofs, dest_y) - vid->y_ofs;
00869         _h = MIN (vid->y_ofs + vbmp->h, dest_y + height)
00870            - vid->y_ofs - _y;
00871 
00872         _sx = source_x + vid->x_ofs + _x - dest_x;
00873         _sy = source_y + vid->y_ofs + _y - dest_y;
00874 
00875         if (draw_type == BLIT) {
00876             blit(source, vbmp, _sx, _sy, _x, _y, _w, _h);
00877         }
00878         else if (draw_type == MASKED_BLIT) {
00879             masked_blit(source, vbmp, _sx, _sy, _x, _y, _w, _h);
00880         }
00881         else if (draw_type == TRANS) {
00882             BITMAP *clip = create_sub_bitmap(source, _sx, _sy, _w, _h);
00883             if (!clip)
00884                 return;
00885             draw_trans_sprite(vbmp, clip, _x, _y);
00886             destroy_bitmap(clip);
00887         }
00888 
00889         update_texture_memory(vid, _x, _y, _x + _w - 1, _y + _h - 1);
00890 
00891         vid = vid->next;
00892     }
00893 
00894     return; 
00895 }
00896 
00897 
00898 void allegro_gl_video_blit_from_memory(BITMAP *source, BITMAP *dest,
00899                     int source_x, int source_y, int dest_x, int dest_y,
00900                     int width, int height) {
00901 
00902     allegro_gl_video_blit_from_memory_ex(source, dest, source_x, source_y,
00903                                          dest_x, dest_y, width, height, BLIT);
00904     return;
00905 }
00906 
00907 
00908 
00909 void allegro_gl_video_blit_to_memory(struct BITMAP *source, struct BITMAP *dest,
00910                          int source_x, int source_y, int dest_x, int dest_y,
00911                          int width, int height) {
00912 
00913     AGL_VIDEO_BITMAP *vid;
00914     BITMAP *source_parent = source;
00915     
00916     AGL_LOG(2, "glvtable.c:allegro_gl_video_blit_to_memory\n");
00917     
00918     if (is_sub_bitmap(source)) {
00919        source_x += source->x_ofs;
00920        source_y += source->y_ofs;
00921        while (source_parent->id & BMP_ID_SUB)
00922           source_parent = (BITMAP *)source_parent->extra;
00923     }
00924 
00925     vid = source_parent->extra;
00926     
00927     while (vid) {
00928         BITMAP *vbmp = vid->memory_copy;
00929         int x, y, dx, dy, w, h;
00930 
00931         x = MAX(source_x, vid->x_ofs) - vid->x_ofs;
00932         y = MAX(source_y, vid->y_ofs) - vid->y_ofs;
00933         w = MIN(vid->x_ofs + vbmp->w, source_x + width) - vid->x_ofs;
00934         h = MIN(vid->y_ofs + vbmp->h, source_y + height) - vid->y_ofs;
00935         dx = MAX(0, vid->x_ofs - source_x) + dest_x;
00936         dy = MAX(0, vid->y_ofs - source_y) + dest_y;
00937 
00938         blit(vbmp, dest, x, y, dx, dy, w, h);
00939     
00940         vid = vid->next;
00941     }
00942 
00943     return; 
00944 }
00945 
00946 
00947 
00948 /* Just like allegro_gl_video_blit_from_memory(), except that draws only to the
00949  * memory copy.
00950  */
00951 static void __video_update_memory_copy(BITMAP *source, BITMAP *dest,
00952                             int source_x, int source_y, int dest_x, int dest_y,
00953                             int width, int height, int draw_type) {
00954     AGL_VIDEO_BITMAP *vid;
00955     BITMAP *dest_parent = dest;
00956     
00957     if (is_sub_bitmap (dest)) {
00958        dest_x += dest->x_ofs;
00959        dest_y += dest->y_ofs;
00960        while (dest_parent->id & BMP_ID_SUB)
00961           dest_parent = (BITMAP *)dest_parent->extra;
00962     }
00963 
00964     if (dest_x < dest->cl) {
00965         dest_x = dest->cl;
00966     }
00967     if (dest_y < dest->ct) {
00968         dest_y = dest->ct;
00969     }
00970     if (dest_x + width >= dest->cr) {
00971         width = dest->cr - dest_x;
00972     }
00973     if (dest_y + height >= dest->cb) {
00974         height = dest->cb - dest_y;
00975     }
00976     if (width < 1 || height < 1) {
00977         return;
00978     }
00979     
00980     vid = dest_parent->extra;
00981 
00982     while (vid) {
00983         int sx, sy;
00984         BITMAP *vbmp = vid->memory_copy;
00985 
00986         int dx, dy, w, h;
00987         if (vid->x_ofs >= dest_x + width || vid->y_ofs >= dest_y + height
00988          || vid->x_ofs + vbmp->w <= dest_x
00989          || vid->y_ofs + vbmp->h <= dest_y) {
00990             
00991             vid = vid->next;
00992             continue;
00993         }
00994 
00995         dx = MAX (vid->x_ofs, dest_x) - vid->x_ofs;
00996         w = MIN (vid->x_ofs + vbmp->w, dest_x + width)
00997            - vid->x_ofs - dx;
00998         dy = MAX (vid->y_ofs, dest_y) - vid->y_ofs;
00999         h = MIN (vid->y_ofs + vbmp->h, dest_y + height)
01000            - vid->y_ofs - dy;
01001 
01002         sx = source_x + vid->x_ofs + dx - dest_x;
01003         sy = source_y + vid->y_ofs + dy - dest_y;
01004 
01005         if (draw_type == MASKED_BLIT) {
01006             masked_blit(source, vbmp, sx, sy, dx, dy, w, h);
01007         }
01008         else if (draw_type == BLIT) {
01009             blit(source, vbmp, sx, sy, dx, dy, w, h);
01010         }
01011         else if (draw_type == TRANS) {
01012             BITMAP *clip = create_sub_bitmap(source, sx, sy, w, h);
01013             if (!clip)
01014                 return;
01015             draw_trans_sprite(vbmp, clip, dx, dy);
01016             destroy_bitmap(clip);
01017         }
01018 
01019         vid = vid->next;
01020     }
01021     
01022     return;
01023 }
01024 
01025 
01026 #define FOR_EACH_TEXTURE_FRAGMENT(  \
01027     screen_blit_from_vid,           \
01028     screen_blit_from_mem,           \
01029     mem_copy_blit_from_vid,         \
01030     mem_copy_blit_from_mem,         \
01031     vid_and_mem_copy_blit_from_vid, \
01032     vid_and_mem_copy_blit_from_mem) \
01033                                     \
01034                                     \
01035 {                                   \
01036     int used_fbo = FALSE;                                  \
01037                                                            \
01038     if (allegro_gl_extensions_GL.EXT_framebuffer_object) { \
01039         int sx, sy;                                        \
01040         int dx, dy;                                        \
01041         int w, h;                                          \
01042                                                            \
01043         AGL_VIDEO_BITMAP *vid;                             \
01044                                                            \
01045         static GLint v[4];                                 \
01046         static double allegro_gl_projection_matrix[16];    \
01047         static double allegro_gl_modelview_matrix[16];     \
01048                                                            \
01049         glGetIntegerv(GL_VIEWPORT, &v[0]);                 \
01050         glMatrixMode(GL_MODELVIEW);                        \
01051         glGetDoublev(GL_MODELVIEW_MATRIX, allegro_gl_modelview_matrix);   \
01052         glMatrixMode(GL_PROJECTION);                                      \
01053         glGetDoublev(GL_PROJECTION_MATRIX, allegro_gl_projection_matrix); \
01054                                                                           \
01055         vid = dest->extra;                                                \
01056                                                                           \
01057         while (vid) {                                                     \
01058             if (dest_x >= vid->x_ofs + vid->memory_copy->w ||             \
01059                 dest_y >= vid->y_ofs + vid->memory_copy->h ||             \
01060                 vid->x_ofs >= dest_x + width ||          \
01061                 vid->y_ofs >= dest_y + height) {         \
01062                 vid = vid->next;                         \
01063                 continue;                                \
01064             }                                            \
01065                                                          \
01066             dx = MAX(vid->x_ofs, dest_x) - vid->x_ofs;                  \
01067             w = MIN(vid->x_ofs + vid->memory_copy->w, dest_x + width)   \
01068               - vid->x_ofs - dx;                                        \
01069             dy = MAX(vid->y_ofs, dest_y) - vid->y_ofs;                  \
01070             h = MIN(vid->y_ofs + vid->memory_copy->h, dest_y + height)  \
01071               - vid->y_ofs - dy;                                        \
01072                                                                         \
01073             sx = source_x + vid->x_ofs + dx - dest_x;                   \
01074             sy = source_y + vid->y_ofs + dy - dest_y;                   \
01075                                                                         \
01076             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, vid->fbo);         \
01077                                                                         \
01078             glViewport(0, 0, vid->memory_copy->w, vid->memory_copy->h); \
01079             glMatrixMode(GL_PROJECTION);                                \
01080             glLoadIdentity();                                           \
01081             gluOrtho2D(0, vid->memory_copy->w, 0, vid->memory_copy->h); \
01082             glMatrixMode(GL_MODELVIEW);                                 \
01083                                              \
01084             if (is_memory_bitmap(source)) {  \
01085                 screen_blit_from_mem;        \
01086             }                                \
01087             else {                           \
01088                 screen_blit_from_vid;        \
01089             }                                \
01090                                 \
01091             vid = vid->next;    \
01092         }                       \
01093                                 \
01094         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); \
01095                                                      \
01096         glViewport(v[0], v[1], v[2], v[3]);          \
01097         glMatrixMode(GL_PROJECTION);                 \
01098         glLoadMatrixd(allegro_gl_projection_matrix); \
01099         glMatrixMode(GL_MODELVIEW);                  \
01100         glLoadMatrixd(allegro_gl_modelview_matrix);  \
01101                                           \
01102         used_fbo = TRUE;                  \
01103     }                                     \
01104                                           \
01105     if (is_video_bitmap(source)) {        \
01106         int sx, sy;      \
01107         int dx, dy;      \
01108         int w, h;        \
01109                          \
01110         AGL_VIDEO_BITMAP *vid; \
01111         vid = source->extra;   \
01112                                \
01113         while (vid) {          \
01114             if (source_x >= vid->x_ofs + vid->memory_copy->w ||  \
01115                 source_y >= vid->y_ofs + vid->memory_copy->h ||  \
01116                 vid->x_ofs >= source_x + width ||                \
01117                 vid->y_ofs >= source_y + height) {               \
01118                 vid = vid->next;                                 \
01119                 continue;                                        \
01120             }                                                    \
01121                                                                  \
01122             sx = MAX(vid->x_ofs, source_x) - vid->x_ofs;         \
01123             w = MIN(vid->x_ofs + vid->memory_copy->w, source_x + width)  \
01124               - vid->x_ofs - sx;                                         \
01125             sy = MAX(vid->y_ofs, source_y) - vid->y_ofs;                 \
01126             h = MIN(vid->y_ofs + vid->memory_copy->h, source_y + height) \
01127               - vid->y_ofs - sy;                                         \
01128                                                                          \
01129             dx = dest_x + vid->x_ofs + sx - source_x;  \
01130             dy = dest_y + vid->y_ofs + sy - source_y;  \
01131                                                        \
01132             if (used_fbo) {                            \
01133                 mem_copy_blit_from_vid;                \
01134             }                                          \
01135             else {                                     \
01136                 vid_and_mem_copy_blit_from_vid;        \
01137             }                                  \
01138                                                \
01139             vid = vid->next;                   \
01140         }                                      \
01141     }                                          \
01142     else if (is_memory_bitmap(source)) {       \
01143         if (used_fbo) {                        \
01144             mem_copy_blit_from_mem;            \
01145         }                                      \
01146         else {                                 \
01147             vid_and_mem_copy_blit_from_mem;    \
01148         }                                      \
01149     }                                          \
01150 }
01151 
01152 
01153 /* allegro_gl_video_blit_to_self:
01154  * blit() overload for video -> video blits
01155  */
01156 void allegro_gl_video_blit_to_self(struct BITMAP *source, struct BITMAP *dest,
01157     int source_x, int source_y, int dest_x, int dest_y, int width, int height) {
01158 
01159     FOR_EACH_TEXTURE_FRAGMENT (
01160         allegro_gl_screen_blit_to_self(source, screen, sx, sy, dx, dy, w, h),
01161         allegro_gl_screen_blit_to_self(source, screen, sx, sy, dx, dy, w, h),
01162         __video_update_memory_copy(vid->memory_copy, dest, sx, sy, dx, dy, w, h, BLIT),
01163         __video_update_memory_copy(source, dest, source_x, source_y, dest_x, dest_y, width, height, BLIT),
01164         allegro_gl_video_blit_from_memory(vid->memory_copy, dest, sx, sy, dx, dy, w, h),
01165         allegro_gl_video_blit_from_memory(source, dest, source_x, source_y, dest_x, dest_y, width, height)
01166     )
01167 }
01168 
01169 
01170 static void do_masked_blit_video(struct BITMAP *source, struct BITMAP *dest,
01171             int source_x, int source_y, int dest_x, int dest_y,
01172             int width, int height, int flip_dir, int blit_type) {
01173 
01174     FOR_EACH_TEXTURE_FRAGMENT (
01175         do_masked_blit_screen(source, screen, sx, sy, dx, dy, w, h, flip_dir, blit_type),
01176         do_masked_blit_screen(source, screen, sx, sy, dx, dy, w, h, flip_dir, blit_type),
01177         __video_update_memory_copy(vid->memory_copy, dest, sx, sy, dx, dy, w, h, MASKED_BLIT),
01178         __video_update_memory_copy(source, dest, source_x, source_y, dest_x, dest_y, width, height, MASKED_BLIT),
01179         allegro_gl_video_blit_from_memory_ex(vid->memory_copy, dest, sx, sy, dx, dy, w, h, MASKED_BLIT),
01180         allegro_gl_video_blit_from_memory_ex(source, dest, source_x, source_y, dest_x, dest_y, width, height, MASKED_BLIT)
01181     )
01182 }
01183 
01184 
01185 /* allegro_gl_video_masked_blit:
01186  * masked_blit() overload for video -> video masked blits
01187  */
01188 static void allegro_gl_video_masked_blit(struct BITMAP *source,
01189                 struct BITMAP *dest, int source_x, int source_y,
01190                 int dest_x, int dest_y, int width, int height) {
01191     do_masked_blit_video(source, dest, source_x, source_y, dest_x, dest_y,
01192                          width, height, FALSE, AGL_REGULAR_BMP | AGL_NO_ROTATION);
01193 
01194     return;
01195 }
01196 
01197 
01198 /* allegro_gl_video_draw_sprite:
01199  * draw_sprite() overload for video -> video sprite drawing
01200  */
01201 static void allegro_gl_video_draw_sprite(struct BITMAP *bmp,
01202                         struct BITMAP *sprite, int x, int y) {
01203 
01204     do_masked_blit_video(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h,
01205                          FALSE, AGL_NO_ROTATION);
01206 
01207     return;
01208 }
01209 
01210 
01211 /* allegro_gl_video_draw_sprite_v_flip:
01212  * draw_sprite_v_flip() overload for video -> video blits
01213  * FIXME: Broken if the bitmap was split into multiple textures.
01214  * FIXME: Doesn't apply rotation and scale to the memory copy
01215  */
01216 static void allegro_gl_video_draw_sprite_v_flip(struct BITMAP *bmp,
01217                         struct BITMAP *sprite, int x, int y) {
01218 
01219     do_masked_blit_video(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h,
01220                          AGL_V_FLIP, AGL_NO_ROTATION);
01221 
01222     return;
01223 }
01224 
01225 
01226 /* allegro_gl_video_draw_sprite_h_flip:
01227  * draw_sprite_v_flip() overload for video -> video blits
01228  * FIXME: Broken if the bitmap was split into multiple textures.
01229  * FIXME: Doesn't apply rotation and scale to the memory copy
01230  */
01231 static void allegro_gl_video_draw_sprite_h_flip(struct BITMAP *bmp,
01232                         struct BITMAP *sprite, int x, int y) {
01233 
01234     do_masked_blit_video(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h,
01235                          AGL_H_FLIP, AGL_NO_ROTATION);
01236 
01237     return;
01238 }
01239 
01240 
01241 /* allegro_gl_video_draw_sprite_vh_flip:
01242  * draw_sprite_vh_flip() overload for video -> video blits
01243  * FIXME: Broken if the bitmap was split into multiple textures.
01244  * FIXME: Doesn't apply rotation and scale to the memory copy
01245  */
01246 static void allegro_gl_video_draw_sprite_vh_flip(struct BITMAP *bmp,
01247                         struct BITMAP *sprite, int x, int y) {
01248 
01249     do_masked_blit_video(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h,
01250                          AGL_V_FLIP | AGL_H_FLIP, AGL_NO_ROTATION);
01251 
01252     return;
01253 }
01254 
01255 
01256 /* allegro_gl_video_pivot_scaled_sprite_flip:
01257  * FIXME: Broken if the bitmap was split into multiple textures.
01258  * FIXME: Doesn't apply rotation and scale to the memory copy
01259  * FIXME: Doesn't work for when FBO is not available.
01260  */
01261 static void allegro_gl_video_pivot_scaled_sprite_flip(struct BITMAP *bmp,
01262             struct BITMAP *sprite, fixed x, fixed y, fixed cx, fixed cy,
01263             fixed angle, fixed scale, int v_flip) {
01264     double dscale = fixtof(scale);
01265     GLint matrix_mode;
01266     
01267 #define BIN_2_DEG(x) (-(x) * 180.0 / 128)
01268     
01269     glGetIntegerv(GL_MATRIX_MODE, &matrix_mode);
01270     glMatrixMode(GL_MODELVIEW);
01271     glPushMatrix();
01272     glTranslated(fixtof(x), fixtof(y), 0.);
01273     glRotated(BIN_2_DEG(fixtof(angle)), 0., 0., -1.);
01274     glScaled(dscale, dscale, dscale);
01275     glTranslated(-fixtof(x+cx), -fixtof(y+cy), 0.);
01276     
01277     do_masked_blit_video(sprite, bmp, 0, 0, fixtoi(x), fixtoi(y),
01278                           sprite->w, sprite->h, v_flip ? AGL_V_FLIP : FALSE, FALSE);
01279     glPopMatrix();
01280     glMatrixMode(matrix_mode);
01281 
01282 #undef BIN_2_DEG
01283 
01284     return;
01285 }
01286 
01287 
01288 /* allegro_gl_video_do_stretch_blit:
01289  * overload for all kind of video -> video and video -> screen stretchers
01290  * FIXME: Doesn't apply scale to the memory copy
01291  * FIXME: Doesn't work for video->video when FBO is not available.
01292  */
01293 static void allegro_gl_video_do_stretch_blit(BITMAP *source, BITMAP *dest,
01294                int source_x, int source_y, int source_width, int source_height,
01295                int dest_x, int dest_y, int dest_width, int dest_height,
01296                int masked) {
01297     /* note: src is a video bitmap, dest is not a memory bitmap */
01298 
01299     double scalew = ((double)dest_width) / source_width;
01300     double scaleh = ((double)dest_height) / source_height;
01301     
01302     GLint matrix_mode;
01303 
01304     /* BITMAP_BLIT_CLIP macro from glvtable.c is no good for scaled images. */
01305     if (dest->clip) {
01306         if ((dest_x >= dest->cr) || (dest_y >= dest->cb)
01307          || (dest_x + dest_width < dest->cl) || (dest_y + dest_height < dest->ct)) {
01308             return;
01309         }
01310         if (dest_x < dest->cl) {
01311             source_x -= (dest_x - dest->cl) / scalew;
01312             dest_x = dest->cl;
01313         }
01314         if (dest_y < dest->ct) {
01315             source_y -= (dest_y - dest->ct) / scaleh;
01316             dest_y = dest->ct;
01317         }
01318     }
01319 
01320     glGetIntegerv(GL_MATRIX_MODE, &matrix_mode);
01321     glMatrixMode(GL_MODELVIEW);
01322     glPushMatrix();
01323     glTranslated(dest_x, dest_y, 0.);
01324     glScaled(scalew, scaleh, 1.);
01325     glTranslated(-dest_x, -dest_y, 0.);
01326 
01327     if (masked) {
01328         if (is_screen_bitmap(dest)) {
01329             do_masked_blit_screen(source, dest, source_x, source_y,
01330                                   dest_x, dest_y, source_width, source_height,
01331                                   FALSE, AGL_REGULAR_BMP);
01332         }
01333         else {
01334             do_masked_blit_video(source, dest, source_x, source_y,
01335                                  dest_x, dest_y, source_width, source_height,
01336                                  FALSE, AGL_REGULAR_BMP);
01337         }
01338     }
01339     else {
01340         allegro_gl_screen_blit_to_self(source, dest, source_x, source_y,
01341                            dest_x, dest_y, source_width, source_height);
01342     }
01343 
01344     glPopMatrix();
01345     glMatrixMode(matrix_mode);
01346 
01347     return;
01348 }
01349 
01350 
01351 
01352 /* allegro_gl_video_draw_trans_rgba_sprite:
01353  * draw_trans_sprite() overload for video -> video drawing
01354  */
01355 static void allegro_gl_video_draw_trans_rgba_sprite(BITMAP *bmp,
01356                                 BITMAP *sprite, int x, int y) {
01357     /* Adapt variables for FOR_EACH_TEXTURE_FRAGMENT macro. */
01358     BITMAP *source = sprite;
01359     BITMAP *dest = bmp;
01360     int dest_x = x;
01361     int dest_y = y;
01362     int source_x = 0;
01363     int source_y = 0;
01364     int width = sprite->w;
01365     int height = sprite->h;
01366     GLint format = __allegro_gl_get_bitmap_color_format(sprite, AGL_TEXTURE_HAS_ALPHA);
01367     GLint type = __allegro_gl_get_bitmap_type(sprite, 0);
01368 
01369     if (__allegro_gl_blit_operation == AGL_OP_LOGIC_OP)
01370         glEnable(GL_COLOR_LOGIC_OP);
01371     else
01372         glEnable(GL_BLEND);
01373 
01374     FOR_EACH_TEXTURE_FRAGMENT (
01375         allegro_gl_screen_blit_to_self(source, screen, sx, sy, dx, dy, w, h),
01376         allegro_gl_upload_and_display_texture(sprite, sx, sy, dx, dy, w, h, 0, format, type),
01377         __video_update_memory_copy(vid->memory_copy, dest, sx, sy, dx, dy, w, h, TRANS),
01378         __video_update_memory_copy(source, dest, 0, 0, x, y, sprite->w, sprite->h, TRANS),
01379         allegro_gl_video_blit_from_memory_ex(vid->memory_copy, dest, sx, sy, dx, dy, w, h, TRANS),
01380         allegro_gl_video_blit_from_memory_ex(source, dest, 0, 0, x, y, sprite->w, sprite->h, TRANS)
01381     )
01382 
01383     if (__allegro_gl_blit_operation == AGL_OP_LOGIC_OP)
01384         glDisable(GL_COLOR_LOGIC_OP);
01385     else
01386         glDisable(GL_BLEND);
01387 
01388     return;
01389 }
01390 
01391 
01392 
01393 static void allegro_gl_video_clear_to_color(BITMAP *bmp, int color) {
01394     if (allegro_gl_extensions_GL.EXT_framebuffer_object) {
01395         AGL_VIDEO_BITMAP *vid = bmp->extra;
01396 
01397         static GLint v[4];
01398         static double allegro_gl_projection_matrix[16];
01399         static double allegro_gl_modelview_matrix[16];
01400 
01401         glGetIntegerv(GL_VIEWPORT, &v[0]);
01402         glMatrixMode(GL_MODELVIEW);
01403         glGetDoublev(GL_MODELVIEW_MATRIX, allegro_gl_modelview_matrix);
01404         glMatrixMode(GL_PROJECTION);
01405         glGetDoublev(GL_PROJECTION_MATRIX, allegro_gl_projection_matrix);
01406 
01407         while (vid) {
01408             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, vid->fbo);
01409 
01410             glViewport(0, 0, vid->memory_copy->w, vid->memory_copy->h);
01411             glMatrixMode(GL_PROJECTION);
01412             glLoadIdentity();
01413             gluOrtho2D(0, vid->memory_copy->w, 0, vid->memory_copy->h);
01414             glMatrixMode(GL_MODELVIEW);
01415 
01416             allegro_gl_screen_clear_to_color(screen, color);
01417             clear_to_color(vid->memory_copy, color);
01418             vid = vid->next;
01419         }
01420 
01421         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
01422     
01423         glViewport(v[0], v[1], v[2], v[3]);
01424         glMatrixMode(GL_PROJECTION);
01425         glLoadMatrixd(allegro_gl_projection_matrix);
01426         glMatrixMode(GL_MODELVIEW);
01427         glLoadMatrixd(allegro_gl_modelview_matrix);
01428     }
01429     else {
01430         allegro_gl_video_rectfill(bmp, 0, 0, bmp->w, bmp->h, color);
01431     }
01432             
01433     return;
01434 }
01435 
01436 
01437 
01438 /* FIXME: Doesn't work when FBO is not available.
01439  * FIXME: Doesn't care for segmented video bitmaps.
01440  */
01441 static void allegro_gl_video_draw_color_glyph(struct BITMAP *bmp,
01442     struct BITMAP *sprite, int x, int y, int color, int bg)
01443 {
01444     AGL_VIDEO_BITMAP *vid = bmp->extra;
01445 
01446     static GLint v[4];
01447     static double allegro_gl_projection_matrix[16];
01448     static double allegro_gl_modelview_matrix[16];
01449 
01450     if (allegro_gl_extensions_GL.EXT_framebuffer_object)
01451         return;
01452 
01453     glGetIntegerv(GL_VIEWPORT, &v[0]);
01454     glMatrixMode(GL_MODELVIEW);
01455     glGetDoublev(GL_MODELVIEW_MATRIX, allegro_gl_modelview_matrix);
01456     glMatrixMode(GL_PROJECTION);
01457     glGetDoublev(GL_PROJECTION_MATRIX, allegro_gl_projection_matrix);
01458 
01459     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, vid->fbo);
01460 
01461     glViewport(0, 0, vid->memory_copy->w, vid->memory_copy->h);
01462     glMatrixMode(GL_PROJECTION);
01463     glLoadIdentity();
01464     gluOrtho2D(0, vid->memory_copy->w, 0, vid->memory_copy->h);
01465     glMatrixMode(GL_MODELVIEW);
01466 
01467     allegro_gl_screen_draw_color_glyph_ex(screen, sprite, x, y, color, bg, 0);
01468 
01469     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
01470 
01471     glViewport(v[0], v[1], v[2], v[3]);
01472     glMatrixMode(GL_PROJECTION);
01473     glLoadMatrixd(allegro_gl_projection_matrix);
01474     glMatrixMode(GL_MODELVIEW);
01475     glLoadMatrixd(allegro_gl_modelview_matrix);
01476 
01477     vid->memory_copy->vtable->draw_character(vid->memory_copy, sprite, x, y, color, bg);
01478 }
01479 
01480 
01481 
01482 static void allegro_gl_video_draw_256_sprite(BITMAP *bmp, BITMAP *sprite,
01483                                       int x, int y) {
01484     allegro_gl_video_draw_color_glyph(bmp, sprite, x, y, -1, _textmode);
01485 }
01486 
01487 
01488 
01489 static void allegro_gl_video_draw_character(BITMAP *bmp, BITMAP *sprite,
01490                                             int x, int y, int color, int bg) {
01491     allegro_gl_video_draw_color_glyph(bmp, sprite, x, y, color, bg);
01492 }
01493 
01494 
01495 
01496 /* FIXME: Doesn't work when FBO is not available.
01497  * FIXME: Doesn't care for segmented video bitmaps.
01498  */
01499 static void allegro_gl_video_draw_glyph(struct BITMAP *bmp,
01500                                AL_CONST struct FONT_GLYPH *glyph, int x, int y,
01501                                int color, int bg) {
01502     AGL_VIDEO_BITMAP *vid = bmp->extra;
01503 
01504     static GLint v[4];
01505     static double allegro_gl_projection_matrix[16];
01506     static double allegro_gl_modelview_matrix[16];
01507 
01508     if (!allegro_gl_extensions_GL.EXT_framebuffer_object)
01509         return;
01510 
01511     glGetIntegerv(GL_VIEWPORT, &v[0]);
01512     glMatrixMode(GL_MODELVIEW);
01513     glGetDoublev(GL_MODELVIEW_MATRIX, allegro_gl_modelview_matrix);
01514     glMatrixMode(GL_PROJECTION);
01515     glGetDoublev(GL_PROJECTION_MATRIX, allegro_gl_projection_matrix);
01516 
01517     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, vid->fbo);
01518 
01519     glViewport(0, 0, vid->memory_copy->w, vid->memory_copy->h);
01520     glMatrixMode(GL_PROJECTION);
01521     glLoadIdentity();
01522     gluOrtho2D(0, vid->memory_copy->w, 0, vid->memory_copy->h);
01523     glMatrixMode(GL_MODELVIEW);
01524 
01525     allegro_gl_screen_draw_glyph_ex(screen, glyph, x, y, color, bg, 1);
01526 
01527     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
01528 
01529     glViewport(v[0], v[1], v[2], v[3]);
01530     glMatrixMode(GL_PROJECTION);
01531     glLoadMatrixd(allegro_gl_projection_matrix);
01532     glMatrixMode(GL_MODELVIEW);
01533     glLoadMatrixd(allegro_gl_modelview_matrix);
01534 
01535     vid->memory_copy->vtable->draw_glyph(vid->memory_copy, glyph, x, y, color, bg);
01536 }
01537 
01538 
01539 
01540 static void dummy_unwrite_bank(void)
01541 {
01542 }
01543 
01544 
01545 
01546 static GFX_VTABLE allegro_gl_video_vtable = {
01547     0,
01548     0,
01549     dummy_unwrite_bank,         //void *unwrite_bank;  /* C function on some machines, asm on i386 */
01550     NULL,                       //AL_METHOD(void, set_clip, (struct BITMAP *bmp));
01551     allegro_gl_video_acquire,
01552     allegro_gl_video_release,
01553     NULL,                       //AL_METHOD(struct BITMAP *, create_sub_bitmap, (struct BITMAP *parent, int x, int y, int width, int height));
01554     allegro_gl_created_sub_bitmap,
01555     allegro_gl_video_getpixel,
01556     allegro_gl_video_putpixel,
01557     allegro_gl_video_vline,
01558     allegro_gl_video_hline,
01559     allegro_gl_video_hline,
01560     allegro_gl_video_line,
01561     allegro_gl_video_line,
01562     allegro_gl_video_rectfill,
01563     allegro_gl_video_triangle,
01564     allegro_gl_video_draw_sprite,
01565     allegro_gl_video_draw_256_sprite,
01566     allegro_gl_video_draw_sprite_v_flip,
01567     allegro_gl_video_draw_sprite_h_flip,
01568     allegro_gl_video_draw_sprite_vh_flip,
01569     allegro_gl_video_draw_trans_rgba_sprite,
01570     allegro_gl_video_draw_trans_rgba_sprite,
01571     NULL,                       //AL_METHOD(void, draw_lit_sprite, (struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color));
01572     NULL,                       //AL_METHOD(void, allegro_gl_video_draw_rle_sprite, (struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y));
01573     NULL,                       //AL_METHOD(void, draw_trans_rle_sprite, (struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y));
01574     NULL,                       //AL_METHOD(void, draw_trans_rgba_rle_sprite, (struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y));
01575     NULL,                       //AL_METHOD(void, draw_lit_rle_sprite, (struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color));
01576     allegro_gl_video_draw_character,
01577     allegro_gl_video_draw_glyph,
01578     allegro_gl_video_blit_from_memory,
01579     allegro_gl_video_blit_to_memory,
01580     NULL,                       //AL_METHOD(void, blit_from_system, (struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height));
01581     NULL,                       //AL_METHOD(void, blit_to_system, (struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height));
01582     allegro_gl_screen_blit_to_self, /* Video bitmaps use same method as screen */
01583     allegro_gl_screen_blit_to_self, /* ..._forward */
01584     allegro_gl_screen_blit_to_self, /* ..._backward */
01585     allegro_gl_memory_blit_between_formats,
01586     allegro_gl_video_masked_blit,
01587     allegro_gl_video_clear_to_color,
01588     allegro_gl_video_pivot_scaled_sprite_flip,
01589     allegro_gl_video_do_stretch_blit,
01590     NULL,                       //AL_METHOD(void, draw_gouraud_sprite, (struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int c1, int c2, int c3, int c4));
01591     NULL,                       //AL_METHOD(void, draw_sprite_end, (void));
01592     NULL,                       //AL_METHOD(void, blit_end, (void));
01593     _soft_polygon,              //AL_METHOD(void, polygon, (struct BITMAP *bmp, int vertices, AL_CONST int *points, int color));
01594     _soft_rect,                 //AL_METHOD(void, rect, (struct BITMAP *bmp, int x1, int y1, int x2, int y2, int color));
01595     _soft_circle,               //AL_METHOD(void, circle, (struct BITMAP *bmp, int x, int y, int radius, int color));
01596     _soft_circlefill,           //AL_METHOD(void, circlefill, (struct BITMAP *bmp, int x, int y, int radius, int color));
01597     _soft_ellipse,              //AL_METHOD(void, ellipse, (struct BITMAP *bmp, int x, int y, int rx, int ry, int color));
01598     _soft_ellipsefill,          //AL_METHOD(void, ellipsefill, (struct BITMAP *bmp, int x, int y, int rx, int ry, int color));
01599     _soft_arc,                  //AL_METHOD(void, arc, (struct BITMAP *bmp, int x, int y, fixed ang1, fixed ang2, int r, int color));
01600     _soft_spline,               //AL_METHOD(void, spline, (struct BITMAP *bmp, AL_CONST int points[8], int color));
01601     _soft_floodfill,            //AL_METHOD(void, floodfill, (struct BITMAP *bmp, int x, int y, int color));
01602     _soft_polygon3d,            //AL_METHOD(void, polygon3d, (struct BITMAP *bmp, int type, struct BITMAP *texture, int vc, V3D *vtx[]));
01603     _soft_polygon3d_f,          //AL_METHOD(void, polygon3d_f, (struct BITMAP *bmp, int type, struct BITMAP *texture, int vc, V3D_f *vtx[]));
01604     _soft_triangle3d,           //AL_METHOD(void, triangle3d, (struct BITMAP *bmp, int type, struct BITMAP *texture, V3D *v1, V3D *v2, V3D *v3));
01605     _soft_triangle3d_f,         //AL_METHOD(void, triangle3d_f, (struct BITMAP *bmp, int type, struct BITMAP *texture, V3D_f *v1, V3D_f *v2, V3D_f *v3));
01606     _soft_quad3d,               //AL_METHOD(void, quad3d, (struct BITMAP *bmp, int type, struct BITMAP *texture, V3D *v1, V3D *v2, V3D *v3, V3D *v4));
01607     _soft_quad3d_f,             //AL_METHOD(void, quad3d_f, (struct BITMAP *bmp, int type, struct BITMAP *texture, V3D_f *v1, V3D_f *v2, V3D_f *v3, V3D_f *v4));
01608 };
01609 

Generated on Tue Aug 21 22:42:59 2007 for AllegroGL by  doxygen 1.5.2