texture.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  */
00008 #include <string.h>
00009 
00010 #include "alleggl.h"
00011 #include "allglint.h"
00012 
00013 #include <allegro/internal/aintern.h>
00014 
00015 #ifdef ALLEGRO_MACOSX
00016 #include <OpenGL/glu.h>
00017 #else
00018 #include <GL/glu.h>
00019 #endif
00020 
00021 static GLint allegro_gl_opengl_internal_texture_format = -1;
00022 static int allegro_gl_use_mipmapping_for_textures = 0;
00023 int __allegro_gl_use_alpha = FALSE;
00024 int __allegro_gl_flip_texture = TRUE;
00025 GLint __allegro_gl_texture_read_format[5];
00026 GLint __allegro_gl_texture_components[5];
00027 
00028 #define PREFIX_I                "agl-tex INFO: "
00029 #define PREFIX_W                "agl-tex WARNING: "
00030 #define PREFIX_E                "agl-tex ERROR: "
00031 
00032 
00038 char const *__allegro_gl_get_format_description(GLint format)
00039 {
00040     static char str[256];
00041 #define F(s) case s: return #s
00042     switch (format) {
00043         F(GL_ALPHA);
00044         F(GL_ALPHA4);
00045         F(GL_ALPHA8);
00046         F(GL_ALPHA12);
00047         F(GL_ALPHA16);
00048         F(GL_ALPHA16F_ARB);
00049         F(GL_ALPHA32F_ARB);
00050         F(GL_INTENSITY);
00051         F(GL_INTENSITY4);
00052         F(GL_INTENSITY8);
00053         F(GL_INTENSITY12);
00054         F(GL_INTENSITY16);
00055         F(GL_INTENSITY16F_ARB);
00056         F(GL_INTENSITY32F_ARB);
00057         F(GL_LUMINANCE);
00058         F(GL_LUMINANCE4);
00059         F(GL_LUMINANCE8);
00060         F(GL_LUMINANCE12);
00061         F(GL_LUMINANCE16);
00062         F(GL_LUMINANCE16F_ARB);
00063         F(GL_LUMINANCE32F_ARB);
00064         F(GL_LUMINANCE_ALPHA);
00065         F(GL_LUMINANCE4_ALPHA4);
00066         F(GL_LUMINANCE12_ALPHA4);
00067         F(GL_LUMINANCE8_ALPHA8);
00068         F(GL_LUMINANCE6_ALPHA2);
00069         F(GL_LUMINANCE12_ALPHA12);
00070         F(GL_LUMINANCE16_ALPHA16);
00071         F(GL_LUMINANCE_ALPHA16F_ARB);
00072         F(GL_LUMINANCE_ALPHA32F_ARB);
00073         F(GL_RGB);
00074         F(GL_R3_G3_B2);
00075         F(GL_RGB4);
00076         F(GL_RGB5);
00077         F(GL_RGB8);
00078         F(GL_RGB10);
00079         F(GL_RGB12);
00080         F(GL_RGB16);
00081         F(GL_RGB16F_ARB);
00082         F(GL_RGB32F_ARB);
00083         F(GL_RGBA);
00084         F(GL_RGBA2);
00085         F(GL_RGBA4);
00086         F(GL_RGB5_A1);
00087         F(GL_RGBA8);
00088         F(GL_RGB10_A2);
00089         F(GL_RGBA12);
00090         F(GL_RGBA16);
00091         F(GL_RGBA16F_ARB);
00092         F(GL_RGBA32F_ARB);
00093     }
00094     uszprintf(str, sizeof str, "%x", format);
00095     return str;
00096 #undef F
00097 }
00098 
00099 
00100 
00101 /* GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) */
00112 GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) {
00113 
00114     if (!bmp) {
00115         return -1;
00116     }
00117 
00118     switch (bitmap_color_depth(bmp)) {
00119         case 32:
00120             if (flags
00121                  & (AGL_TEXTURE_HAS_ALPHA | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
00122                 return GL_RGBA8;
00123             }
00124             else {
00125                 return GL_RGB8;
00126             }
00127         case 8:
00128             return GL_INTENSITY8;
00129         case 15:
00130             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00131                 return GL_RGB5_A1;
00132             }
00133             else {
00134                 return GL_RGB5;
00135             }
00136         case 16:
00137         case 24:
00138             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00139                 return GL_RGBA8;
00140             }
00141             else {
00142                 return GL_RGB8;
00143             }
00144         default:
00145             return -1;
00146     }
00147 
00148     return -1;
00149 }
00150 
00151 
00152 
00153 /* GLint allegro_gl_get_texture_format(BITMAP *bmp) */
00170 GLint allegro_gl_get_texture_format(BITMAP *bmp) {
00171 
00172     if (bmp && allegro_gl_opengl_internal_texture_format == -1) {
00173         return __allegro_gl_get_texture_format_ex(bmp,
00174                 __allegro_gl_use_alpha ? AGL_TEXTURE_FORCE_ALPHA_INTERNAL : 0);
00175     }
00176     
00177     return allegro_gl_opengl_internal_texture_format;
00178 }
00179 
00180 
00181 
00182 /* GLint allegro_gl_set_texture_format(GLint format) */
00204 GLint allegro_gl_set_texture_format(GLint format) {
00205 
00206     GLint old = allegro_gl_opengl_internal_texture_format;
00207     allegro_gl_opengl_internal_texture_format = format;
00208     return old;
00209 }
00210 
00211 
00212 
00213 /* GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) */
00233 GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) {
00234 
00235     int c = bitmap_color_depth(bmp);
00236 
00237     switch (c) {
00238 
00239         case 8:
00240             return __allegro_gl_texture_read_format[0];
00241 
00242         case 15:
00243             return __allegro_gl_texture_read_format[1];
00244 
00245         case 16:
00246             return __allegro_gl_texture_read_format[2];
00247 
00248         case 24:
00249             return __allegro_gl_texture_read_format[3];
00250 
00251         case 32:
00252             return __allegro_gl_texture_read_format[4];
00253     
00254         default:
00255             TRACE(PREFIX_E "get_bitmap_type: unhandled bitmap depth: %d\n",
00256                   c);
00257             return -1;
00258     }
00259 }
00260 
00261 
00262 
00263 /* GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) */
00277 GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) {
00278 
00279     int c = bitmap_color_depth(bmp);
00280 
00281     switch (c) {
00282 
00283         case 8:
00284             if (flags & AGL_TEXTURE_ALPHA_ONLY) {
00285                 return GL_ALPHA;
00286             }
00287             else {
00288                 return __allegro_gl_texture_components[0];
00289             }
00290 
00291         case 15:
00292             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00293                 return GL_RGBA;
00294             }
00295             else {
00296                 return __allegro_gl_texture_components[1];
00297             }
00298 
00299         case 16:
00300             return __allegro_gl_texture_components[2];
00301 
00302         case 24:
00303             return __allegro_gl_texture_components[3];
00304 
00305         case 32:
00306             if (flags & (AGL_TEXTURE_HAS_ALPHA
00307                        | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
00308                 return GL_RGBA;
00309             }
00310             else {
00311                 return __allegro_gl_texture_components[4];
00312             }
00313     
00314         default:
00315             TRACE(PREFIX_E "get_bitmap_color_format: unhandled bitmap "
00316                   "depth: %d\n", c);
00317             return -1;
00318     }
00319 }
00320 
00321 
00322 
00323 /* int allegro_gl_use_mipmapping(int enable) */
00337 int allegro_gl_use_mipmapping(int enable) {
00338 
00339     int old = allegro_gl_use_mipmapping_for_textures;
00340     allegro_gl_use_mipmapping_for_textures = enable;
00341     return old;
00342 }
00343     
00344 
00345 
00346 /* int allegro_gl_use_alpha_channel(int enable) */
00361 int allegro_gl_use_alpha_channel(int enable) {
00362 
00363     int old = __allegro_gl_use_alpha;
00364     __allegro_gl_use_alpha = enable;
00365     return old;
00366 }
00367     
00368 
00369 
00370 /* int allegro_gl_flip_texture(int enable) */
00386 int allegro_gl_flip_texture(int enable) {
00387 
00388     int old = __allegro_gl_flip_texture;
00389     __allegro_gl_flip_texture = enable;
00390     return old;
00391 }
00392     
00393 
00394 
00395 /* int allegro_gl_check_texture_ex(int flags, BITMAP *bmp, GLuint internal_format) */
00417 int allegro_gl_check_texture_ex(int flags, BITMAP *bmp,
00418                                    GLint internal_format) {
00419 
00420     return (allegro_gl_make_texture_ex(flags | AGL_TEXTURE_CHECK_VALID_INTERNAL,
00421                                        bmp, internal_format) ? TRUE : FALSE);
00422 }
00423 
00424 
00425 
00426 /* Convert flags from pre-0.2.0 to 0.2.0+ */
00427 static int __allegro_gl_convert_flags(int flags) {
00428 
00429     flags |= AGL_TEXTURE_RESCALE;
00430 
00431     if (allegro_gl_use_mipmapping_for_textures) {
00432         flags |= AGL_TEXTURE_MIPMAP;
00433     }
00434     if (__allegro_gl_use_alpha) {
00435         flags |= AGL_TEXTURE_HAS_ALPHA;
00436     }
00437     if (__allegro_gl_flip_texture) {
00438         flags |= AGL_TEXTURE_FLIP;
00439     }
00440 
00441     if (allegro_gl_opengl_internal_texture_format == GL_ALPHA4
00442      || allegro_gl_opengl_internal_texture_format == GL_ALPHA8
00443      || allegro_gl_opengl_internal_texture_format == GL_ALPHA12
00444      || allegro_gl_opengl_internal_texture_format == GL_ALPHA16
00445      || allegro_gl_opengl_internal_texture_format == GL_ALPHA
00446      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY4
00447      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY8
00448      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY12
00449      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY16
00450      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY
00451      || allegro_gl_opengl_internal_texture_format == 1) {
00452         flags |= AGL_TEXTURE_ALPHA_ONLY;
00453     }
00454 
00455     return flags;
00456 }
00457 
00458 
00459 
00460 /* int allegro_gl_check_texture(BITMAP *bmp) */
00479 int allegro_gl_check_texture(BITMAP *bmp) {
00480 
00481     int flags = __allegro_gl_convert_flags(0);
00482     
00483     return allegro_gl_check_texture_ex(flags, bmp,
00484                                      allegro_gl_opengl_internal_texture_format);
00485 }
00486 
00487 
00488 
00489 /* Integer log2 function. Not optimized for speed. */
00490 static int log2i(int n) {
00491     
00492     int k;
00493     
00494     if (n < 1) {
00495         return -1;
00496     }
00497 
00498     k = 0;
00499     while (n >>= 1) {
00500         k++;
00501     }
00502 
00503     return k;
00504 }
00505 
00506 
00507 
00508 /* BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, GLint *type, GLint *format) */
00518 BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, int x, int y,
00519                                   int w, int h, GLint *type, GLint *format) {
00520     
00521     BITMAP *ret = 0, *temp = 0;
00522 
00523     int need_rescale = 0;
00524     int need_alpha   = 0;
00525     int need_flip    = 0;
00526     int depth = bitmap_color_depth(bmp);
00527     int force_copy   = 0;
00528 
00529     const int old_w = w, old_h = h;
00530 
00531     if (flags & AGL_TEXTURE_RESCALE) {
00532         
00533         /* Check if rescaling is needed */
00534 
00535         /* NP2 is not supported, and the texture isn't a power-of-two.
00536          * Resize the next power of 2
00537          */     
00538         if (!allegro_gl_extensions_GL.ARB_texture_non_power_of_two
00539          && ((w & (w - 1)) || (h & (h - 1)))) {
00540             w = __allegro_gl_make_power_of_2(w);
00541             h = __allegro_gl_make_power_of_2(h);
00542             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
00543                   "%ix%i to %ix%i due to non-power-of-2 source size.\n",
00544                   old_w, old_h, w, h);
00545             need_rescale = 1;
00546         }
00547 
00548         /* Don't go over the max texture size */
00549         if (w > allegro_gl_info.max_texture_size) {
00550             w = allegro_gl_info.max_texture_size;
00551             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
00552                   "%ix%i to %ix%i due to max supported size exceed.\n",
00553                   old_w, old_h, w, h);
00554             need_rescale = 1;
00555         }
00556         
00557         if (h > allegro_gl_info.max_texture_size) {
00558             h = allegro_gl_info.max_texture_size;
00559             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
00560                   "%ix%i to %ix%i due to max supported size exceed.\n",
00561                   old_w, old_h, w, h);
00562             need_rescale = 1;
00563         }
00564 
00565         /* Voodoos don't support mipmaps for textures greater than 32x32.
00566          * If we're allowed to rescale, rescale the bitmap to 32x32.
00567          * XXX <rohannessian> Apparently, this is a bug in one version
00568          * of the Voodoo GL driver. Need to figure out a workaround
00569          * for that.
00570          */
00571         if (allegro_gl_info.is_voodoo && (flags & AGL_TEXTURE_MIPMAP)
00572           && (w > 32 || h > 32)) {
00573 
00574             w = MIN(32, w);
00575             h = MIN(32, h);
00576             
00577             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
00578                   "%ix%i to %ix%i due to Voodoo driver bug.\n",
00579                   old_w, old_h, w, h);
00580             need_rescale = 1;
00581         }
00582     }
00583 
00584     /* Matrox G200 cards have a bug where rectangular textures can't have
00585      * more than 4 levels of mipmaps (max_mip == 3). This doesn't seem
00586      * to affect square textures.
00587      *
00588      * Note: Using GLU to build the mipmaps seems to work. Maybe AGL is
00589      * doing something wrong?
00590      *
00591      * Workaround: Use GLU to build the mipmaps, and force depth to 24 or
00592      * 32.
00593      */
00594     if ( allegro_gl_info.is_matrox_g200 && (flags & AGL_TEXTURE_MIPMAP)) {
00595         int wl = log2i(w);
00596         int hl = log2i(h);
00597 
00598         if (w != h && MAX(wl, hl) > 3 && depth < 24
00599          && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
00600             TRACE(PREFIX_I "munge_bitmap: G200 path in use.\n");
00601             depth = 24;
00602         }
00603     }
00604     
00605     /* Do we need to flip the texture on the t axis? */
00606     if (flags & AGL_TEXTURE_FLIP) {
00607         need_flip = 1;
00608     }
00609 
00610 
00611     /* If not supported, blit to a 24 bpp bitmap and try again
00612      */
00613     if (*type == -1) {
00614         TRACE(PREFIX_W "munge_bitmap: using temporary 24bpp bitmap\n");
00615         depth = 24;
00616     }
00617 
00618     /* We need a texture that can be used for masked blits.
00619      * Insert an alpha channel if one is not there.
00620      * If it's already there, replace it by 0/1 as needed.
00621      */
00622     if ((flags & AGL_TEXTURE_MASKED) && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
00623         need_alpha = 1;
00624 
00625         switch (depth) {
00626         case 15:
00627             if (!allegro_gl_extensions_GL.EXT_packed_pixels) {
00628                 depth = 32;
00629             }
00630             break;
00631         case 8:
00632         case 16:
00633         case 24:
00634         case 32:
00635             depth = 32;
00636             break;
00637         }
00638         force_copy = 1;
00639     }
00640 
00641     /* Allegro fills in 0 for the alpha channel. Matrox G200 seems to ignore
00642      * the internal format; so we need to drop down to 24-bpp if no alpha
00643      * will be needed.
00644      */
00645     if (allegro_gl_info.is_matrox_g200 && !(flags & AGL_TEXTURE_MASKED)
00646        && !(flags & AGL_TEXTURE_HAS_ALPHA) && depth == 32) {
00647         TRACE(PREFIX_I "munge_bitmap: G200 path in use.\n");
00648         depth = 24;
00649         force_copy = 1;
00650     }
00651 
00652     
00653     /* Do we need to do a color depth conversion or bitmap copy? */
00654     if (depth != bitmap_color_depth(bmp) || force_copy) {
00655 
00656         TRACE(PREFIX_I "munge_bitmap: Need to perform depth conversion from %i "
00657               "to %i bpp.\n", bitmap_color_depth(bmp), depth);
00658 
00659         temp = create_bitmap_ex(depth, bmp->w, bmp->h);
00660 
00661         if (!temp) {
00662             TRACE(PREFIX_E "munge_bitmap: Unable to create temporary bitmap "
00663                   "%ix%ix%i\n", bmp->w, bmp->h, depth);
00664             return NULL;
00665         }
00666 
00667         /* XXX <rohannessian> Use palette conversion?
00668          */
00669         if (bitmap_color_depth(bmp) == 8 && depth > 8) {
00670             int i, j;
00671             for (j = 0; j < bmp->h; j++) {
00672                 for (i = 0; i < bmp->w; i++) {
00673                     int c = _getpixel(bmp, i, j);
00674                     putpixel(temp, i, j, makecol_depth(depth, c, c, c));
00675                 }
00676             }
00677         }
00678         else {
00679             blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
00680         }
00681         bmp = temp;
00682 
00683         *format = __allegro_gl_get_bitmap_color_format(bmp, flags);
00684         *type = __allegro_gl_get_bitmap_type(bmp, flags);
00685     }
00686 
00687 
00688 
00689     /* Nothing to do? */
00690     if (!need_rescale && !need_alpha && !need_flip) {
00691 
00692         TRACE(PREFIX_I "munge_bitmap: No need for munging - returning %p\n",
00693               temp);
00694         
00695         /* Return depth-converte bitmap, if present */
00696         if (temp) {
00697             return temp;
00698         }
00699         return NULL;
00700     }
00701 
00702     ret = create_bitmap_ex(depth, w, h);
00703     
00704     if (!ret) {
00705         TRACE(PREFIX_E "munge_bitmap: Unable to create result bitmap "
00706               "%ix%ix%i\n", w, h, depth);
00707         goto error;
00708     }
00709 
00710 
00711     /* No need to fill in bitmap if we're just making a query */
00712     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) {
00713         if (temp) {
00714             destroy_bitmap(temp);
00715         }
00716         return ret;
00717     }
00718 
00719 
00720     /* Perform flip
00721      * I don't want to have to deal with *yet another* temporary bitmap
00722      * so instead, I fugde the line pointers around.
00723      * This will work because we require Allegro memory bitmaps anyway.
00724      */
00725     if (need_flip) {
00726         int i;
00727         TRACE(PREFIX_I "munge_bitmap: Flipping bitmap.\n");
00728         for (i = 0; i < bmp->h/2; i++) {
00729             unsigned char *l = bmp->line[i];
00730             bmp->line[i] = bmp->line[bmp->h - i - 1];
00731             bmp->line[bmp->h - i - 1] = l;
00732         }
00733     }
00734     
00735     /* Rescale bitmap */
00736     if (need_rescale) {
00737         TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap.\n");
00738         stretch_blit(bmp, ret, x, y, old_w, old_h, 0, 0, ret->w, ret->h);
00739     }
00740     else {
00741         TRACE(PREFIX_I "munge_bitmap: Copying bitmap.\n");
00742         blit(bmp, ret, x, y, 0, 0, w, h);
00743     }
00744 
00745     /* Restore the original bitmap, if needed */
00746     if (need_flip && !temp) {
00747         int i;
00748         TRACE(PREFIX_I "munge_bitmap: Unflipping bitmap.\n");
00749         for (i = 0; i < bmp->h/2; i++) {
00750             unsigned char *l = bmp->line[i];
00751             bmp->line[i] = bmp->line[bmp->h - i - 1];
00752             bmp->line[bmp->h - i - 1] = l;
00753         }
00754     }
00755     
00756     /* Insert alpha channel */
00757     if (need_alpha) {
00758         int i, j;
00759         int mask = bitmap_mask_color(ret);
00760 
00761         /* alpha mask for 5.5.5.1 pixels */
00762         int alpha = (-1) ^ makecol_depth(depth, 255, 255, 255);
00763 
00764         TRACE(PREFIX_I "munge_bitmap: Inserting alpha channel.\n");
00765 
00766         for (j = 0; j < h; j++) {
00767             for (i = 0; i < w; i++) {
00768                 int pix;
00769                 
00770                 switch (depth) {
00771                 case 32:
00772                     pix = _getpixel32(ret, i, j);
00773 
00774                     if (pix == mask) {
00775                         pix = 0;
00776                     }
00777                     else if ((flags & AGL_TEXTURE_HAS_ALPHA) == 0) {
00778                         int r, g, b;
00779                         r = getr32(pix);
00780                         g = getg32(pix);
00781                         b = getb32(pix);
00782                         pix = makeacol32(r, g, b, 255);
00783                     }
00784                     _putpixel32(ret, i, j, pix);
00785                     break;
00786                 case 15: 
00787                     pix = _getpixel16(ret, i, j);
00788 
00789                     if (pix == mask) {
00790                         pix = 0;
00791                     }
00792                     else {
00793                         pix |= alpha;
00794                     }
00795                     
00796                     _putpixel16(temp, i, j, pix);
00797                     break;
00798                 default:
00799                     /* Shouldn't actually come here */
00800                     ASSERT(0);
00801                 }
00802             }
00803         }
00804     }
00805 
00806 
00807 error:
00808     if (temp) {
00809         destroy_bitmap(temp);
00810     }
00811 
00812     return ret;
00813 }
00814 
00815 
00816 
00817 /* Perform the actual texture upload. Helper for agl_make_texture_ex().
00818  */
00819 static GLuint do_texture_upload(BITMAP *bmp, GLuint tex, GLint internal_format,
00820                               GLint format, GLint type, int flags) {
00821 
00822     int bytes_per_pixel = BYTES_PER_PIXEL(bitmap_color_depth(bmp));
00823     GLint saved_row_length;
00824     GLint saved_alignment;
00825     GLenum target = GL_TEXTURE_2D;
00826 
00827     glBindTexture(target, tex);
00828     
00829 
00830     /* Handle proxy texture checks */
00831     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) { 
00832         /* <bcoconni> allegro_gl_check_texture is broken with GL drivers based
00833          *  on Mesa. It seems this is a Mesa bug...
00834          */
00835         if (allegro_gl_info.is_mesa_driver) {
00836             AGL_LOG(1, "* Note * check_texture: Mesa driver detected: "
00837                    "PROXY_TEXTURE_2D tests are skipped\n");
00838             return tex;
00839         }
00840         else {
00841             glTexImage2D(GL_PROXY_TEXTURE_2D, 0, internal_format,
00842                          bmp->w, bmp->h, 0, format, type, NULL);
00843 
00844             glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0,
00845                                      GL_TEXTURE_COMPONENTS, &internal_format);
00846 
00847             return (internal_format ? tex : 0);
00848         }
00849     }
00850     
00851 
00852     /* Set up pixel transfer mode */
00853     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &saved_row_length);
00854     glGetIntegerv(GL_UNPACK_ALIGNMENT,  &saved_alignment);
00855     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00856 
00857     TRACE(PREFIX_I "do_texture_upload: Making texture: bpp: %i\n",
00858           bitmap_color_depth(bmp));
00859 
00860     /* Generate mipmaps, if needed */
00861     if (flags & AGL_TEXTURE_MIPMAP) {
00862         
00863         if (allegro_gl_extensions_GL.SGIS_generate_mipmap) {
00864             /* Easy way out - let the driver do it ;) 
00865              * We do need to set high-qual mipmap generation though.
00866              */
00867             glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
00868             glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
00869             TRACE(PREFIX_I "do_texture_upload: Using SGIS_generate_mipmap for "
00870                   "mipmap generation.\n");
00871         }
00872         else if (allegro_gl_info.is_matrox_g200
00873              && (flags & AGL_TEXTURE_MIPMAP) && (bitmap_color_depth(bmp) >= 24
00874                 || bitmap_color_depth(bmp) == 8)
00875              && (bmp->w != bmp->h)) {
00876                 
00877             /* Matrox G200 has issues with our mipmapping code. Use GLU if we
00878              * can.
00879              */
00880             TRACE(PREFIX_I "do_texture_upload: Using GLU for mipmaps.\n");
00881             glPixelStorei(GL_UNPACK_ROW_LENGTH, bmp->h > 1
00882                         ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
00883                         : bmp->w);
00884             glPixelStorei(GL_UNPACK_ROW_LENGTH,
00885                                (bmp->line[1] - bmp->line[0]) / bytes_per_pixel);
00886             gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format, bmp->w, bmp->h,
00887                               format, type, bmp->line[0]);
00888         }
00889         else {
00890             int w = bmp->w;
00891             int h = bmp->h;
00892             int depth = bitmap_color_depth(bmp);
00893             
00894             /* The driver can't generate mipmaps for us. We can't rely on GLU
00895              * since the Win32 version doesn't support any of the new pixel
00896              * formats. Instead, we'll use our own downsampler (which only
00897              * has to work on Allegro BITMAPs)
00898              */
00899             BITMAP *temp = create_bitmap_ex(depth, w / 2, h / 2);
00900 
00901             /* We need to generate mipmaps up to 1x1 - compute the number
00902              * of levels we need.
00903              */
00904             int num_levels = log2i(MAX(bmp->w, bmp->h));
00905             
00906             int i, x, y;
00907 
00908             BITMAP *src, *dest;
00909 
00910             TRACE(PREFIX_I "do_texture_upload: Using Allegro for "
00911                   "mipmap generation.\n");
00912 
00913             if (!temp) {
00914                 TRACE(PREFIX_E "do_texture_upload: Unable to create "
00915                       "temporary bitmap sized %ix%ix%i for mipmap generation!",
00916                       w / 2, h / 2, depth);
00917                 tex = 0;
00918                 goto end;
00919             }
00920 
00921             src = bmp;
00922             dest = temp;
00923             
00924             for (i = 1; i <= num_levels; i++) {
00925 
00926                 for (y = 0; y < h; y += 2) {
00927                     for (x = 0; x < w; x += 2) {
00928 
00929                         int r, g, b, a;
00930                         int pix[4];
00931                         int avg;
00932                         
00933                         pix[0] = getpixel(src, x,     y);
00934                         pix[1] = getpixel(src, x + 1, y);
00935                         pix[2] = getpixel(src, x,     y + 1);
00936                         pix[3] = getpixel(src, x + 1, y + 1);
00937 
00938                         if (w == 1) {
00939                             pix[1] = pix[0];
00940                             pix[3] = pix[2];
00941                         }
00942                         if (h == 1) {
00943                             pix[2] = pix[0];
00944                             pix[3] = pix[1];
00945                         }
00946 
00947                         if (flags & AGL_TEXTURE_ALPHA_ONLY) {
00948                             avg = (pix[0] + pix[1] + pix[2] + pix[3] + 2) / 4;
00949                         }
00950                         else {
00951                             r = (getr_depth(depth, pix[0])
00952                                + getr_depth(depth, pix[1])
00953                                + getr_depth(depth, pix[2])
00954                                + getr_depth(depth, pix[3]) + 2) / 4;
00955                             g = (getg_depth(depth, pix[0])
00956                                + getg_depth(depth, pix[1])
00957                                + getg_depth(depth, pix[2])
00958                                + getg_depth(depth, pix[3]) + 2) / 4;
00959                             b = (getb_depth(depth, pix[0])
00960                                + getb_depth(depth, pix[1])
00961                                + getb_depth(depth, pix[2])
00962                                + getb_depth(depth, pix[3]) + 2) / 4;
00963                             a = (geta_depth(depth, pix[0])
00964                                + geta_depth(depth, pix[1])
00965                                + geta_depth(depth, pix[2])
00966                                + geta_depth(depth, pix[3]) + 2) / 4;
00967 
00968                             avg = makeacol_depth(depth, r, g, b, a);
00969                         }
00970 
00971                         putpixel(dest, x / 2, y / 2, avg);
00972                     }
00973                 }
00974                 src = temp;
00975 
00976                 /* Note - we round down; we're still compatible with
00977                  * ARB_texture_non_power_of_two.
00978                  */
00979                 w = MAX(w / 2, 1);
00980                 h = MAX(h / 2, 1);
00981 
00982                 TRACE(PREFIX_I "do_texture_upload: Unpack row length: %i.\n",
00983                       (temp->h > 1)
00984                      ? (temp->line[1] - temp->line[0]) / bytes_per_pixel
00985                      : temp->w);
00986 
00987                 glPixelStorei(GL_UNPACK_ROW_LENGTH, temp->h > 1
00988                              ? (temp->line[1] - temp->line[0]) / bytes_per_pixel
00989                              : temp->w);    
00990 
00991                 glTexImage2D(GL_TEXTURE_2D, i, internal_format,
00992                              w, h, 0, format, type, temp->line[0]);
00993 
00994                 TRACE(PREFIX_I "do_texture_upload: Mipmap level: %i, "
00995                       "size: %i x %i\n", i, w, h);
00996 
00997                 TRACE(PREFIX_I "do_texture_upload: Uploaded texture: level %i, "
00998                       "internalformat: %s, %ix%i, format: 0x%x, type: 0x%x."
00999                       "\n", i, __allegro_gl_get_format_description(internal_format),
01000                       bmp->w, bmp->h, format, type);
01001             }
01002 
01003             destroy_bitmap(temp);
01004         }
01005     }
01006 
01007     glPixelStorei(GL_UNPACK_ROW_LENGTH, (bmp->h > 1)
01008                  ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
01009                  : bmp->w);
01010     
01011     TRACE(PREFIX_I "do_texture_upload: Unpack row length: %i.\n",
01012           (bmp->h > 1) ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
01013                        : bmp->w);
01014 
01015     /* Upload the base texture */
01016     glGetError();
01017     glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
01018                  bmp->w, bmp->h, 0, format, type, bmp->line[0]);
01019 
01020     TRACE(PREFIX_I "do_texture_upload: Uploaded texture: level 0, "
01021           "internalformat: %s, %ix%i, format: 0x%x, type: 0x%x.\n",
01022           __allegro_gl_get_format_description(internal_format),
01023           bmp->w, bmp->h, format, type);
01024     
01025     TRACE(PREFIX_I "do_texture_upload: GL Error code: 0x%x\n", glGetError());
01026 
01027     if (!(flags & AGL_TEXTURE_MIPMAP)) {
01028         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01029     }
01030     
01031 end:
01032     /* Restore state */
01033     glPixelStorei(GL_UNPACK_ROW_LENGTH, saved_row_length);
01034     glPixelStorei(GL_UNPACK_ALIGNMENT,  saved_alignment);
01035 
01036     return tex;
01037 }   
01038 
01039 
01040 
01041 /* GLuint allegro_gl_make_texture_ex(int flag, BITMAP *bmp, GLint internal_format) */
01087 GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
01088 {
01089     GLuint tex = 0, ret = 0;
01090     BITMAP *temp = NULL;
01091     GLint type;
01092     GLint format;
01093     GLint old_tex;
01094 
01095     /* Print the parameters */
01096 #ifdef DEBUGMODE
01097     char buf[1024] = "";
01098 #   define PFLAG(name) if (flags & name) strcat(buf, #name "|");
01099     PFLAG(AGL_TEXTURE_MIPMAP);
01100     PFLAG(AGL_TEXTURE_HAS_ALPHA);
01101     PFLAG(AGL_TEXTURE_FLIP);
01102     PFLAG(AGL_TEXTURE_MASKED);
01103     PFLAG(AGL_TEXTURE_RESCALE);
01104     PFLAG(AGL_TEXTURE_ALPHA_ONLY);
01105 #   undef PFLAG
01106 
01107     TRACE(PREFIX_I "make_texture_ex: flags: %s, bitmap %ix%i, %i bpp.\n", buf,
01108           bmp ? bmp->w : 0, bmp ? bmp->h : 0,
01109           bmp ? bitmap_color_depth(bmp) : 0);
01110     if (internal_format == -1) {
01111         TRACE(PREFIX_I "internalformat: AUTO\n");
01112     }
01113     else {
01114         TRACE(PREFIX_I "internalformat: %s\n",
01115             __allegro_gl_get_format_description(internal_format));
01116     }
01117 #endif  
01118 
01119     /* Basic parameter checks */
01120     if (!__allegro_gl_valid_context)
01121         return 0;
01122 
01123     if (!bmp) {
01124         return 0;
01125     }
01126 
01127     glGetIntegerv(GL_TEXTURE_2D_BINDING, &old_tex);
01128 
01129     /* Voodoo cards don't seem to support mipmaps for textures over 32x32...
01130      */
01131     if ((bmp->w > 32 || bmp->h > 32) && (allegro_gl_info.is_voodoo)) {
01132         /* Disable mipmapping if the user didn't allow us to rescale */
01133         if (!(flags & AGL_TEXTURE_RESCALE)) {
01134             TRACE(PREFIX_I "make_texture_ex: Voodoo card detected && texture "
01135                   "size > 32 texels && no rescaling. Disabling mipmaps.\n");
01136             flags &= ~AGL_TEXTURE_MIPMAP;
01137         }
01138     }
01139 
01140     /* Check the maximum texture size */
01141     if (bmp->w > allegro_gl_info.max_texture_size
01142      || bmp->h > allegro_gl_info.max_texture_size) {
01143         if ((flags & AGL_TEXTURE_RESCALE) == 0) {
01144             TRACE(PREFIX_I "make_texture_ex: Max texture size exceeded but no "
01145                   "rescaling allowed. Returning 0 (unsupported).\n");
01146             return 0;
01147         }
01148     }
01149 
01150     /* Check power-of-2 */
01151     if (((bmp->w & (bmp->w - 1)) || (bmp->h & (bmp->h - 1)))
01152       && !(flags & AGL_TEXTURE_RESCALE)
01153       && !allegro_gl_extensions_GL.ARB_texture_non_power_of_two) {
01154         TRACE(PREFIX_I "make_texture_ex: Non-power-of-2 sized bitmap provided, "
01155               "no rescaling allowed, and ARB_texture_non_power_of_two "
01156               "unsupported. Returning 0 (unsupported).\n");
01157         return 0;
01158     }
01159     
01160     
01161     /* Get OpenGL format and type for this pixel data */
01162     format = __allegro_gl_get_bitmap_color_format(bmp, flags);
01163     type = __allegro_gl_get_bitmap_type(bmp, flags);
01164     
01165     if (flags & AGL_TEXTURE_ALPHA_ONLY) {
01166         type   = GL_UNSIGNED_BYTE;
01167         if (internal_format == GL_ALPHA || internal_format == GL_ALPHA4
01168          || internal_format == GL_ALPHA8) {
01169             format = GL_ALPHA;
01170         }
01171         else if (internal_format == GL_INTENSITY
01172               || internal_format == GL_INTENSITY4
01173               || internal_format == GL_INTENSITY8) {
01174             format = GL_RED;
01175         }
01176         else if (internal_format == GL_LUMINANCE
01177               || internal_format == GL_LUMINANCE4
01178               || internal_format == GL_LUMINANCE8) {
01179             format = GL_LUMINANCE;
01180         }
01181 
01182         /* Alpha bitmaps must be 8-bpp */
01183         if (bitmap_color_depth(bmp) != 8) {
01184             return 0;
01185         }
01186     }
01187 
01188     if (flags & AGL_TEXTURE_MASKED) {
01189         flags |= AGL_TEXTURE_FORCE_ALPHA_INTERNAL;
01190     }
01191 
01192     TRACE(PREFIX_I "make_texture_ex: Preselected texture format: %s, "
01193           "type: 0x%x\n", __allegro_gl_get_format_description(format), type);
01194     
01195     /* Munge the bitmap if needed (rescaling, alpha channel, etc) */
01196     temp = __allegro_gl_munge_bitmap(flags, bmp, 0, 0, bmp->w, bmp->h,
01197                                      &type, &format);
01198     if (temp) {
01199         bmp = temp;
01200     }
01201     
01202     if (internal_format == -1) {
01203         internal_format = __allegro_gl_get_texture_format_ex(bmp, flags);
01204         TRACE(PREFIX_I "make_texture_ex: Picked internalformat: %s\n",
01205               __allegro_gl_get_format_description(internal_format));
01206     }
01207 
01208     if (internal_format == -1) {
01209         TRACE(PREFIX_E "make_texture_ex: Invalid internal format!: "
01210               "%s\n", __allegro_gl_get_format_description(internal_format));
01211         goto end;
01212     }
01213     
01214     TRACE(PREFIX_I "make_texture_ex: dest format=%s, source format=%s, "
01215           "type=0x%x\n", __allegro_gl_get_format_description(internal_format),
01216               __allegro_gl_get_format_description(format), (int)type);
01217 
01218     
01219     /* ATI Radeon 7000 inverts R and B components when generating mipmaps and
01220      * the internal format is GL_RGB8, but only on mipmaps. Instead, we'll use
01221      * GL_RGBA8. This works for bitmaps of depth <= 24. For 32-bpp bitmaps,
01222      * some additional tricks are needed: We must fill in alpha with 255.
01223      */
01224     if (allegro_gl_info.is_ati_radeon_7000 && (flags & AGL_TEXTURE_MIPMAP)
01225      && internal_format == GL_RGB8
01226      && allegro_gl_extensions_GL.SGIS_generate_mipmap) {
01227 
01228         int i, j;
01229         int depth = bitmap_color_depth(bmp);
01230 
01231         TRACE(PREFIX_I "make_texture_ex: ATI Radeon 7000 detected, mipmapping "
01232               "used, SGIS_generate_mipmap available and selected "
01233               "internalformat is GL_RGB8 but format is GL_RGBA. Working around "
01234               "ATI driver bug by upgrading bitmap to 32-bpp and using GL_RGBA8 "
01235               "instead.\n");
01236 
01237         if (depth == 32) {
01238 
01239             /* Create temp bitmap if not already there */
01240             if (!temp) {
01241                 temp = create_bitmap_ex(depth, bmp->w, bmp->h);
01242                 if (!temp) {
01243                     TRACE(PREFIX_E "make_texture_ex: Unable to allocate "
01244                           "memory for temporary bitmap (Radeon 7000 path)!\n");
01245                     goto end;
01246                 }
01247                 blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
01248                 bmp = temp;
01249             }
01250             
01251             /* Slow path, until ATI finally gets around to fixing their
01252              * drivers.
01253              *
01254              * Note: If destination internal format was GL_RGBx, then no masking
01255              * code is needed.
01256              */
01257             for (j = 0; j < bmp->h; j++) {
01258                 for (i = 0; i < bmp->w; i++) {
01259                     int pix = _getpixel32(bmp, i, j);
01260                     _putpixel32(bmp, i, j,
01261                         makeacol32(getr32(pix), getg32(pix), getb32(pix), 255));
01262                 }
01263             }
01264         }
01265         internal_format = GL_RGBA8;
01266     }
01267     
01268 
01269     /* Generate the texture */
01270     glGenTextures(1, &tex);
01271     if (!tex) {
01272         TRACE(PREFIX_E "make_texture_ex: Unable to create GL texture!\n");
01273         goto end;
01274     }
01275 
01276     ret = do_texture_upload(bmp, tex, internal_format, format, type, flags);
01277 
01278 end:
01279     if (temp) {
01280         destroy_bitmap(temp);
01281     }
01282 
01283     if (!ret && tex) {
01284         glDeleteTextures(1, &tex);
01285     }
01286 
01287     glBindTexture(GL_TEXTURE_2D, old_tex);
01288 
01289     return tex;
01290 }
01291 
01292 
01293 
01294 
01295 
01296 /* GLuint allegro_gl_make_texture(BITMAP *bmp) */
01305 GLuint allegro_gl_make_texture(BITMAP *bmp) {
01306         
01307     int flags = __allegro_gl_convert_flags(0);
01308     
01309     return allegro_gl_make_texture_ex(flags, bmp,
01310                                      allegro_gl_opengl_internal_texture_format);
01311 }
01312 
01313 
01314 
01315 /* GLuint allegro_gl_make_masked_texture(BITMAP *bmp) */
01324 GLuint allegro_gl_make_masked_texture(BITMAP *bmp) {
01325         
01326     int flags = __allegro_gl_convert_flags(AGL_TEXTURE_MASKED);
01327 
01328     return allegro_gl_make_texture_ex(flags, bmp,
01329                                      allegro_gl_opengl_internal_texture_format);
01330 }
01331 
01332 
01333 
01334 /* GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) */
01355 GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) {
01356 
01357     int flags = __allegro_gl_convert_flags(0);
01358     return __allegro_gl_get_bitmap_type(bmp, flags);
01359 }
01360 
01361 
01362 
01363 /* GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) */
01378 GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) {
01379 
01380     int flags = __allegro_gl_convert_flags(0);
01381     return __allegro_gl_get_bitmap_color_format(bmp, flags);
01382 }
01383 

Generated on Sun Dec 3 18:06:49 2006 for AllegroGL by  doxygen 1.5.1