AllegroGL: texture.c Source File

- Main Page
- Related Pages
- Modules
- Files

- File List
- Globals

# 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 /* int __allegro_gl_get_num_channels(GLenum format) */
    00111 int __allegro_gl_get_num_channels(GLenum format) {
    00112
    00113     switch (format) {
    00114     case 1:
    00115     case GL_ALPHA:
    00116     case GL_ALPHA4:
    00117     case GL_ALPHA8:
    00118     case GL_ALPHA12:
    00119     case GL_ALPHA16:
    00120     case GL_ALPHA16F_ARB:
    00121     case GL_ALPHA32F_ARB:
    00122     case GL_INTENSITY:
    00123     case GL_INTENSITY4:
    00124     case GL_INTENSITY8:
    00125     case GL_INTENSITY12:
    00126     case GL_INTENSITY16:
    00127     case GL_INTENSITY16F_ARB:
    00128     case GL_INTENSITY32F_ARB:
    00129     case GL_LUMINANCE:
    00130     case GL_LUMINANCE4:
    00131     case GL_LUMINANCE8:
    00132     case GL_LUMINANCE12:
    00133     case GL_LUMINANCE16:
    00134     case GL_LUMINANCE16F_ARB:
    00135     case GL_LUMINANCE32F_ARB:
    00136         return 1;
    00137     case 2:
    00138     case GL_LUMINANCE_ALPHA:
    00139     case GL_LUMINANCE4_ALPHA4:
    00140     case GL_LUMINANCE12_ALPHA4:
    00141     case GL_LUMINANCE8_ALPHA8:
    00142     case GL_LUMINANCE6_ALPHA2:
    00143     case GL_LUMINANCE12_ALPHA12:
    00144     case GL_LUMINANCE16_ALPHA16:
    00145     case GL_LUMINANCE_ALPHA16F_ARB:
    00146     case GL_LUMINANCE_ALPHA32F_ARB:
    00147         return 2;
    00148     case 3:
    00149     case GL_RGB:
    00150     case GL_R3_G3_B2:
    00151     case GL_RGB4:
    00152     case GL_RGB5:
    00153     case GL_RGB8:
    00154     case GL_RGB10:
    00155     case GL_RGB12:
    00156     case GL_RGB16:
    00157     case GL_RGB16F_ARB:
    00158     case GL_RGB32F_ARB:
    00159         return 3;
    00160     case 4:
    00161     case GL_RGBA:
    00162     case GL_RGBA2:
    00163     case GL_RGBA4:
    00164     case GL_RGB5_A1:
    00165     case GL_RGBA8:
    00166     case GL_RGB10_A2:
    00167     case GL_RGBA12:
    00168     case GL_RGBA16:
    00169     case GL_RGBA16F_ARB:
    00170     case GL_RGBA32F_ARB:
    00171         return 4;
    00172     default:
    00173         return 0;
    00174     }
    00175 }
    00176
    00177
    00178
    00179 /* GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) */
    00190 GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) {
    00191
    00192     if (!bmp) {
    00193         return -1;
    00194     }
    00195
    00196     switch (bitmap_color_depth(bmp)) {
    00197         case 32:
    00198             if (flags
    00199                  & (AGL_TEXTURE_HAS_ALPHA | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
    00200                 return GL_RGBA8;
    00201             }
    00202             else {
    00203                 return GL_RGB8;
    00204             }
    00205         case 8:
    00206             return GL_INTENSITY8;
    00207         case 15:
    00208             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
    00209                 return GL_RGB5_A1;
    00210             }
    00211             else {
    00212                 return GL_RGB5;
    00213             }
    00214         case 16:
    00215         case 24:
    00216             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
    00217                 return GL_RGBA8;
    00218             }
    00219             else {
    00220                 return GL_RGB8;
    00221             }
    00222         default:
    00223             return -1;
    00224     }
    00225
    00226     return -1;
    00227 }
    00228
    00229
    00230
    00231 /* GLint allegro_gl_get_texture_format(BITMAP *bmp) */
    00248 GLint allegro_gl_get_texture_format(BITMAP *bmp) {
    00249
    00250     if (bmp && allegro_gl_opengl_internal_texture_format == -1) {
    00251         return __allegro_gl_get_texture_format_ex(bmp,
    00252                 __allegro_gl_use_alpha ? AGL_TEXTURE_FORCE_ALPHA_INTERNAL : 0);
    00253     }
    00254
    00255     return allegro_gl_opengl_internal_texture_format;
    00256 }
    00257
    00258
    00259
    00260 /* GLint allegro_gl_set_texture_format(GLint format) */
    00282 GLint allegro_gl_set_texture_format(GLint format) {
    00283
    00284     GLint old = allegro_gl_opengl_internal_texture_format;
    00285     allegro_gl_opengl_internal_texture_format = format;
    00286     return old;
    00287 }
    00288
    00289
    00290
    00291 /* GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) */
    00311 GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) {
    00312
    00313     int c = bitmap_color_depth(bmp);
    00314
    00315     switch (c) {
    00316
    00317         case 8:
    00318             return __allegro_gl_texture_read_format[0];
    00319
    00320         case 15:
    00321             return __allegro_gl_texture_read_format[1];
    00322
    00323         case 16:
    00324             return __allegro_gl_texture_read_format[2];
    00325
    00326         case 24:
    00327             return __allegro_gl_texture_read_format[3];
    00328
    00329         case 32:
    00330             return __allegro_gl_texture_read_format[4];
    00331
    00332         default:
    00333             TRACE(PREFIX_E "get_bitmap_type: unhandled bitmap depth: %d\n",
    00334                   c);
    00335             return -1;
    00336     }
    00337 }
    00338
    00339
    00340
    00341 /* GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) */
    00355 GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) {
    00356
    00357     int c = bitmap_color_depth(bmp);
    00358
    00359     switch (c) {
    00360
    00361         case 8:
    00362             if (flags & AGL_TEXTURE_ALPHA_ONLY) {
    00363                 return GL_ALPHA;
    00364             }
    00365             else {
    00366                 return __allegro_gl_texture_components[0];
    00367             }
    00368
    00369         case 15:
    00370             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
    00371                 return GL_RGBA;
    00372             }
    00373             else {
    00374                 return __allegro_gl_texture_components[1];
    00375             }
    00376
    00377         case 16:
    00378             return __allegro_gl_texture_components[2];
    00379
    00380         case 24:
    00381             return __allegro_gl_texture_components[3];
    00382
    00383         case 32:
    00384             if (flags & (AGL_TEXTURE_HAS_ALPHA
    00385                        | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
    00386                 return GL_RGBA;
    00387             }
    00388             else {
    00389                 return __allegro_gl_texture_components[4];
    00390             }
    00391
    00392         default:
    00393             TRACE(PREFIX_E "get_bitmap_color_format: unhandled bitmap "
    00394                   "depth: %d\n", c);
    00395             return -1;
    00396     }
    00397 }
    00398
    00399
    00400
    00401 /* int allegro_gl_use_mipmapping(int enable) */
    00415 int allegro_gl_use_mipmapping(int enable) {
    00416
    00417     int old = allegro_gl_use_mipmapping_for_textures;
    00418     allegro_gl_use_mipmapping_for_textures = enable;
    00419     return old;
    00420 }
    00421
    00422
    00423
    00424 /* int allegro_gl_use_alpha_channel(int enable) */
    00439 int allegro_gl_use_alpha_channel(int enable) {
    00440
    00441     int old = __allegro_gl_use_alpha;
    00442     __allegro_gl_use_alpha = enable;
    00443     return old;
    00444 }
    00445
    00446
    00447
    00448 /* int allegro_gl_flip_texture(int enable) */
    00464 int allegro_gl_flip_texture(int enable) {
    00465
    00466     int old = __allegro_gl_flip_texture;
    00467     __allegro_gl_flip_texture = enable;
    00468     return old;
    00469 }
    00470
    00471
    00472
    00473 /* int allegro_gl_check_texture_ex(int flags, BITMAP *bmp, GLuint internal_format) */
    00495 int allegro_gl_check_texture_ex(int flags, BITMAP *bmp,
    00496                                    GLint internal_format) {
    00497
    00498     return (allegro_gl_make_texture_ex(flags | AGL_TEXTURE_CHECK_VALID_INTERNAL,
    00499                                        bmp, internal_format) ? TRUE : FALSE);
    00500 }
    00501
    00502
    00503
    00504 /* Convert flags from pre-0.2.0 to 0.2.0+ */
    00505 static int __allegro_gl_convert_flags(int flags) {
    00506
    00507     flags |= AGL_TEXTURE_RESCALE;
    00508
    00509     if (allegro_gl_use_mipmapping_for_textures) {
    00510         flags |= AGL_TEXTURE_MIPMAP;
    00511     }
    00512     if (__allegro_gl_use_alpha) {
    00513         flags |= AGL_TEXTURE_HAS_ALPHA;
    00514     }
    00515     if (__allegro_gl_flip_texture) {
    00516         flags |= AGL_TEXTURE_FLIP;
    00517     }
    00518
    00519     if (allegro_gl_opengl_internal_texture_format == GL_ALPHA4
    00520      || allegro_gl_opengl_internal_texture_format == GL_ALPHA8
    00521      || allegro_gl_opengl_internal_texture_format == GL_ALPHA12
    00522      || allegro_gl_opengl_internal_texture_format == GL_ALPHA16
    00523      || allegro_gl_opengl_internal_texture_format == GL_ALPHA
    00524      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY4
    00525      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY8
    00526      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY12
    00527      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY16
    00528      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY
    00529      || allegro_gl_opengl_internal_texture_format == 1) {
    00530         flags |= AGL_TEXTURE_ALPHA_ONLY;
    00531     }
    00532
    00533     return flags;
    00534 }
    00535
    00536
    00537
    00538 /* int allegro_gl_check_texture(BITMAP *bmp) */
    00557 int allegro_gl_check_texture(BITMAP *bmp) {
    00558
    00559     int flags = __allegro_gl_convert_flags(0);
    00560
    00561     return allegro_gl_check_texture_ex(flags, bmp,
    00562                                      allegro_gl_opengl_internal_texture_format);
    00563 }
    00564
    00565
    00566
    00567 /* Integer log2 function. Not optimized for speed. */
    00568 static int log2i(int n) {
    00569
    00570     int k;
    00571
    00572     if (n < 1) {
    00573         return -1;
    00574     }
    00575
    00576     k = 0;
    00577     while (n >>= 1) {
    00578         k++;
    00579     }
    00580
    00581     return k;
    00582 }
    00583
    00584
    00585
    00586 /* BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, GLint *type, GLint *format) */
    00596 BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, int x, int y,
    00597                                   int w, int h, GLint *type, GLint *format) {
    00598
    00599     BITMAP *ret = 0, *temp = 0;
    00600
    00601     int need_rescale = 0;
    00602     int need_alpha   = 0;
    00603     int need_flip    = 0;
    00604     int depth = bitmap_color_depth(bmp);
    00605     int force_copy   = 0;
    00606
    00607     const int old_w = w, old_h = h;
    00608
    00609     if (flags & AGL_TEXTURE_RESCALE) {
    00610
    00611         /* Check if rescaling is needed */
    00612
    00613         /* NP2 is not supported, and the texture isn't a power-of-two.
    00614          * Resize the next power of 2
    00615          */
    00616         if (!allegro_gl_extensions_GL.ARB_texture_non_power_of_two
    00617          && ((w & (w - 1)) || (h & (h - 1)))) {
    00618             w = __allegro_gl_make_power_of_2(w);
    00619             h = __allegro_gl_make_power_of_2(h);
    00620             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
    00621                   "%ix%i to %ix%i due to non-power-of-2 source size.\n",
    00622                   old_w, old_h, w, h);
    00623             need_rescale = 1;
    00624         }
    00625
    00626         /* Don't go over the max texture size */
    00627         if (w > allegro_gl_info.max_texture_size) {
    00628             w = allegro_gl_info.max_texture_size;
    00629             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
    00630                   "%ix%i to %ix%i due to max supported size exceed.\n",
    00631                   old_w, old_h, w, h);
    00632             need_rescale = 1;
    00633         }
    00634
    00635         if (h > allegro_gl_info.max_texture_size) {
    00636             h = allegro_gl_info.max_texture_size;
    00637             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
    00638                   "%ix%i to %ix%i due to max supported size exceed.\n",
    00639                   old_w, old_h, w, h);
    00640             need_rescale = 1;
    00641         }
    00642
    00643         /* Voodoos don't support mipmaps for textures greater than 32x32.
    00644          * If we're allowed to rescale, rescale the bitmap to 32x32.
    00645          * XXX <rohannessian> Apparently, this is a bug in one version
    00646          * of the Voodoo GL driver. Need to figure out a workaround
    00647          * for that.
    00648          */
    00649         if (allegro_gl_info.is_voodoo && (flags & AGL_TEXTURE_MIPMAP)
    00650           && (w > 32 || h > 32)) {
    00651
    00652             w = MIN(32, w);
    00653             h = MIN(32, h);
    00654
    00655             TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap from "
    00656                   "%ix%i to %ix%i due to Voodoo driver bug.\n",
    00657                   old_w, old_h, w, h);
    00658             need_rescale = 1;
    00659         }
    00660     }
    00661
    00662     /* Matrox G200 cards have a bug where rectangular textures can't have
    00663      * more than 4 levels of mipmaps (max_mip == 3). This doesn't seem
    00664      * to affect square textures.
    00665      *
    00666      * Note: Using GLU to build the mipmaps seems to work. Maybe AGL is
    00667      * doing something wrong?
    00668      *
    00669      * Workaround: Use GLU to build the mipmaps, and force depth to 24 or
    00670      * 32.
    00671      */
    00672     if ( allegro_gl_info.is_matrox_g200 && (flags & AGL_TEXTURE_MIPMAP)) {
    00673         int wl = log2i(w);
    00674         int hl = log2i(h);
    00675
    00676         if (w != h && MAX(wl, hl) > 3 && depth < 24
    00677          && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
    00678             TRACE(PREFIX_I "munge_bitmap: G200 path in use.\n");
    00679             depth = 24;
    00680         }
    00681     }
    00682
    00683     /* Do we need to flip the texture on the t axis? */
    00684     if (flags & AGL_TEXTURE_FLIP) {
    00685         need_flip = 1;
    00686     }
    00687
    00688
    00689     /* If not supported, blit to a 24 bpp bitmap and try again
    00690      */
    00691     if (*type == -1) {
    00692         TRACE(PREFIX_W "munge_bitmap: using temporary 24bpp bitmap\n");
    00693         depth = 24;
    00694     }
    00695
    00696     /* We need a texture that can be used for masked blits.
    00697      * Insert an alpha channel if one is not there.
    00698      * If it's already there, replace it by 0/1 as needed.
    00699      */
    00700     if ((flags & AGL_TEXTURE_MASKED) && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
    00701         need_alpha = 1;
    00702
    00703         switch (depth) {
    00704         case 15:
    00705             if (!allegro_gl_extensions_GL.EXT_packed_pixels) {
    00706                 depth = 32;
    00707             }
    00708             break;
    00709         case 8:
    00710         case 16:
    00711         case 24:
    00712         case 32:
    00713             depth = 32;
    00714             break;
    00715         }
    00716         force_copy = 1;
    00717     }
    00718
    00719     /* Allegro fills in 0 for the alpha channel. Matrox G200 seems to ignore
    00720      * the internal format; so we need to drop down to 24-bpp if no alpha
    00721      * will be needed.
    00722      */
    00723     if (allegro_gl_info.is_matrox_g200 && !(flags & AGL_TEXTURE_MASKED)
    00724        && !(flags & AGL_TEXTURE_HAS_ALPHA) && depth == 32) {
    00725         TRACE(PREFIX_I "munge_bitmap: G200 path in use.\n");
    00726         depth = 24;
    00727         force_copy = 1;
    00728     }
    00729
    00730
    00731     /* Do we need to do a color depth conversion or bitmap copy? */
    00732     if (depth != bitmap_color_depth(bmp) || force_copy) {
    00733
    00734         TRACE(PREFIX_I "munge_bitmap: Need to perform depth conversion from %i "
    00735               "to %i bpp.\n", bitmap_color_depth(bmp), depth);
    00736
    00737         temp = create_bitmap_ex(depth, bmp->w, bmp->h);
    00738
    00739         if (!temp) {
    00740             TRACE(PREFIX_E "munge_bitmap: Unable to create temporary bitmap "
    00741                   "%ix%ix%i\n", bmp->w, bmp->h, depth);
    00742             return NULL;
    00743         }
    00744
    00745         /* XXX <rohannessian> Use palette conversion?
    00746          */
    00747         if (bitmap_color_depth(bmp) == 8 && depth > 8) {
    00748             int i, j;
    00749             for (j = 0; j < bmp->h; j++) {
    00750                 for (i = 0; i < bmp->w; i++) {
    00751                     int c = _getpixel(bmp, i, j);
    00752                     putpixel(temp, i, j, makecol_depth(depth, c, c, c));
    00753                 }
    00754             }
    00755         }
    00756         else {
    00757             blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
    00758         }
    00759         bmp = temp;
    00760
    00761         *format = __allegro_gl_get_bitmap_color_format(bmp, flags);
    00762         *type = __allegro_gl_get_bitmap_type(bmp, flags);
    00763     }
    00764
    00765
    00766
    00767     /* Nothing to do? */
    00768     if (!need_rescale && !need_alpha && !need_flip) {
    00769
    00770         TRACE(PREFIX_I "munge_bitmap: No need for munging - returning %p\n",
    00771               temp);
    00772
    00773         /* Return depth-converte bitmap, if present */
    00774         if (temp) {
    00775             return temp;
    00776         }
    00777         return NULL;
    00778     }
    00779
    00780     ret = create_bitmap_ex(depth, w, h);
    00781
    00782     if (!ret) {
    00783         TRACE(PREFIX_E "munge_bitmap: Unable to create result bitmap "
    00784               "%ix%ix%i\n", w, h, depth);
    00785         goto error;
    00786     }
    00787
    00788
    00789     /* No need to fill in bitmap if we're just making a query */
    00790     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) {
    00791         if (temp) {
    00792             destroy_bitmap(temp);
    00793         }
    00794         return ret;
    00795     }
    00796
    00797
    00798     /* Perform flip
    00799      * I don't want to have to deal with *yet another* temporary bitmap
    00800      * so instead, I fugde the line pointers around.
    00801      * This will work because we require Allegro memory bitmaps anyway.
    00802      */
    00803     if (need_flip) {
    00804         int i;
    00805         TRACE(PREFIX_I "munge_bitmap: Flipping bitmap.\n");
    00806         for (i = 0; i < bmp->h/2; i++) {
    00807             unsigned char *l = bmp->line[i];
    00808             bmp->line[i] = bmp->line[bmp->h - i - 1];
    00809             bmp->line[bmp->h - i - 1] = l;
    00810         }
    00811     }
    00812
    00813     /* Rescale bitmap */
    00814     if (need_rescale) {
    00815         TRACE(PREFIX_I "munge_bitmap: Rescaling bitmap.\n");
    00816         stretch_blit(bmp, ret, x, y, old_w, old_h, 0, 0, ret->w, ret->h);
    00817     }
    00818     else {
    00819         TRACE(PREFIX_I "munge_bitmap: Copying bitmap.\n");
    00820         blit(bmp, ret, x, y, 0, 0, w, h);
    00821     }
    00822
    00823     /* Restore the original bitmap, if needed */
    00824     if (need_flip && !temp) {
    00825         int i;
    00826         TRACE(PREFIX_I "munge_bitmap: Unflipping bitmap.\n");
    00827         for (i = 0; i < bmp->h/2; i++) {
    00828             unsigned char *l = bmp->line[i];
    00829             bmp->line[i] = bmp->line[bmp->h - i - 1];
    00830             bmp->line[bmp->h - i - 1] = l;
    00831         }
    00832     }
    00833
    00834     /* Insert alpha channel */
    00835     if (need_alpha) {
    00836         int i, j;
    00837         int mask = bitmap_mask_color(ret);
    00838
    00839         /* alpha mask for 5.5.5.1 pixels */
    00840         int alpha = (-1) ^ makecol_depth(depth, 255, 255, 255);
    00841
    00842         TRACE(PREFIX_I "munge_bitmap: Inserting alpha channel.\n");
    00843
    00844         for (j = 0; j < h; j++) {
    00845             for (i = 0; i < w; i++) {
    00846                 int pix;
    00847
    00848                 switch (depth) {
    00849                 case 32:
    00850                     pix = _getpixel32(ret, i, j);
    00851
    00852                     if (pix == mask) {
    00853                         pix = 0;
    00854                     }
    00855                     else if ((flags & AGL_TEXTURE_HAS_ALPHA) == 0) {
    00856                         int r, g, b;
    00857                         r = getr32(pix);
    00858                         g = getg32(pix);
    00859                         b = getb32(pix);
    00860                         pix = makeacol32(r, g, b, 255);
    00861                     }
    00862                     _putpixel32(ret, i, j, pix);
    00863                     break;
    00864                 case 15:
    00865                     pix = _getpixel16(ret, i, j);
    00866
    00867                     if (pix == mask) {
    00868                         pix = 0;
    00869                     }
    00870                     else {
    00871                         pix |= alpha;
    00872                     }
    00873
    00874                     _putpixel16(temp, i, j, pix);
    00875                     break;
    00876                 default:
    00877                     /* Shouldn't actually come here */
    00878                     ASSERT(0);
    00879                 }
    00880             }
    00881         }
    00882     }
    00883
    00884
    00885 error:
    00886     if (temp) {
    00887         destroy_bitmap(temp);
    00888     }
    00889
    00890     return ret;
    00891 }
    00892
    00893
    00894
    00895 /* Perform the actual texture upload. Helper for agl_make_texture_ex().
    00896  */
    00897 static GLuint do_texture_upload(BITMAP *bmp, GLuint tex, GLint internal_format,
    00898                               GLint format, GLint type, int flags) {
    00899
    00900     int bytes_per_pixel = BYTES_PER_PIXEL(bitmap_color_depth(bmp));
    00901     GLint saved_row_length;
    00902     GLint saved_alignment;
    00903     GLenum target = GL_TEXTURE_2D;
    00904
    00905     glBindTexture(target, tex);
    00906
    00907
    00908     /* Handle proxy texture checks */
    00909     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) {
    00910         /* <bcoconni> allegro_gl_check_texture is broken with GL drivers based
    00911          *  on Mesa. It seems this is a Mesa bug...
    00912          */
    00913         if (allegro_gl_info.is_mesa_driver) {
    00914             AGL_LOG(1, "* Note * check_texture: Mesa driver detected: "
    00915                    "PROXY_TEXTURE_2D tests are skipped\n");
    00916             return tex;
    00917         }
    00918         else {
    00919             glTexImage2D(GL_PROXY_TEXTURE_2D, 0, internal_format,
    00920                          bmp->w, bmp->h, 0, format, type, NULL);
    00921
    00922             glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0,
    00923                                      GL_TEXTURE_COMPONENTS, &internal_format);
    00924
    00925             return (internal_format ? tex : 0);
    00926         }
    00927     }
    00928
    00929
    00930     /* Set up pixel transfer mode */
    00931     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &saved_row_length);
    00932     glGetIntegerv(GL_UNPACK_ALIGNMENT,  &saved_alignment);
    00933     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    00934
    00935     TRACE(PREFIX_I "do_texture_upload: Making texture: bpp: %i\n",
    00936           bitmap_color_depth(bmp));
    00937
    00938     /* Generate mipmaps, if needed */
    00939     if (flags & AGL_TEXTURE_MIPMAP) {
    00940
    00941         if (allegro_gl_extensions_GL.SGIS_generate_mipmap) {
    00942             /* Easy way out - let the driver do it ;)
    00943              * We do need to set high-qual mipmap generation though.
    00944              */
    00945             glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
    00946             glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
    00947             TRACE(PREFIX_I "do_texture_upload: Using SGIS_generate_mipmap for "
    00948                   "mipmap generation.\n");
    00949         }
    00950         else if (allegro_gl_info.is_matrox_g200
    00951              && (flags & AGL_TEXTURE_MIPMAP) && (bitmap_color_depth(bmp) >= 24
    00952                 || bitmap_color_depth(bmp) == 8)
    00953              && (bmp->w != bmp->h)) {
    00954
    00955             /* Matrox G200 has issues with our mipmapping code. Use GLU if we
    00956              * can.
    00957              */
    00958             TRACE(PREFIX_I "do_texture_upload: Using GLU for mipmaps.\n");
    00959             glPixelStorei(GL_UNPACK_ROW_LENGTH, bmp->h > 1
    00960                         ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
    00961                         : bmp->w);
    00962             glPixelStorei(GL_UNPACK_ROW_LENGTH,
    00963                                (bmp->line[1] - bmp->line[0]) / bytes_per_pixel);
    00964             gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format, bmp->w, bmp->h,
    00965                               format, type, bmp->line[0]);
    00966         }
    00967         else {
    00968             int w = bmp->w;
    00969             int h = bmp->h;
    00970             int depth = bitmap_color_depth(bmp);
    00971
    00972             /* The driver can't generate mipmaps for us. We can't rely on GLU
    00973              * since the Win32 version doesn't support any of the new pixel
    00974              * formats. Instead, we'll use our own downsampler (which only
    00975              * has to work on Allegro BITMAPs)
    00976              */
    00977             BITMAP *temp = create_bitmap_ex(depth, w / 2, h / 2);
    00978
    00979             /* We need to generate mipmaps up to 1x1 - compute the number
    00980              * of levels we need.
    00981              */
    00982             int num_levels = log2i(MAX(bmp->w, bmp->h));
    00983
    00984             int i, x, y;
    00985
    00986             BITMAP *src, *dest;
    00987
    00988             TRACE(PREFIX_I "do_texture_upload: Using Allegro for "
    00989                   "mipmap generation.\n");
    00990
    00991             if (!temp) {
    00992                 TRACE(PREFIX_E "do_texture_upload: Unable to create "
    00993                       "temporary bitmap sized %ix%ix%i for mipmap generation!",
    00994                       w / 2, h / 2, depth);
    00995                 tex = 0;
    00996                 goto end;
    00997             }
    00998
    00999             src = bmp;
    01000             dest = temp;
    01001
    01002             for (i = 1; i <= num_levels; i++) {
    01003
    01004                 for (y = 0; y < h; y += 2) {
    01005                     for (x = 0; x < w; x += 2) {
    01006
    01007                         int r, g, b, a;
    01008                         int pix[4];
    01009                         int avg;
    01010
    01011                         pix[0] = getpixel(src, x,     y);
    01012                         pix[1] = getpixel(src, x + 1, y);
    01013                         pix[2] = getpixel(src, x,     y + 1);
    01014                         pix[3] = getpixel(src, x + 1, y + 1);
    01015
    01016                         if (w == 1) {
    01017                             pix[1] = pix[0];
    01018                             pix[3] = pix[2];
    01019                         }
    01020                         if (h == 1) {
    01021                             pix[2] = pix[0];
    01022                             pix[3] = pix[1];
    01023                         }
    01024
    01025                         if (flags & AGL_TEXTURE_ALPHA_ONLY) {
    01026                             avg = (pix[0] + pix[1] + pix[2] + pix[3] + 2) / 4;
    01027                         }
    01028                         else {
    01029                             r = (getr_depth(depth, pix[0])
    01030                                + getr_depth(depth, pix[1])
    01031                                + getr_depth(depth, pix[2])
    01032                                + getr_depth(depth, pix[3]) + 2) / 4;
    01033                             g = (getg_depth(depth, pix[0])
    01034                                + getg_depth(depth, pix[1])
    01035                                + getg_depth(depth, pix[2])
    01036                                + getg_depth(depth, pix[3]) + 2) / 4;
    01037                             b = (getb_depth(depth, pix[0])
    01038                                + getb_depth(depth, pix[1])
    01039                                + getb_depth(depth, pix[2])
    01040                                + getb_depth(depth, pix[3]) + 2) / 4;
    01041                             a = (geta_depth(depth, pix[0])
    01042                                + geta_depth(depth, pix[1])
    01043                                + geta_depth(depth, pix[2])
    01044                                + geta_depth(depth, pix[3]) + 2) / 4;
    01045
    01046                             avg = makeacol_depth(depth, r, g, b, a);
    01047                         }
    01048
    01049                         putpixel(dest, x / 2, y / 2, avg);
    01050                     }
    01051                 }
    01052                 src = temp;
    01053
    01054                 /* Note - we round down; we're still compatible with
    01055                  * ARB_texture_non_power_of_two.
    01056                  */
    01057                 w = MAX(w / 2, 1);
    01058                 h = MAX(h / 2, 1);
    01059
    01060                 TRACE(PREFIX_I "do_texture_upload: Unpack row length: %li.\n",
    01061                       (temp->h > 1)
    01062                      ? (long int)((temp->line[1] - temp->line[0]) / bytes_per_pixel)
    01063                      : temp->w);
    01064
    01065                 glPixelStorei(GL_UNPACK_ROW_LENGTH, temp->h > 1
    01066                              ? (temp->line[1] - temp->line[0]) / bytes_per_pixel
    01067                              : temp->w);
    01068
    01069                 glTexImage2D(GL_TEXTURE_2D, i, internal_format,
    01070                              w, h, 0, format, type, temp->line[0]);
    01071
    01072                 TRACE(PREFIX_I "do_texture_upload: Mipmap level: %i, "
    01073                       "size: %i x %i\n", i, w, h);
    01074
    01075                 TRACE(PREFIX_I "do_texture_upload: Uploaded texture: level %i, "
    01076                       "internalformat: %s, %ix%i, format: 0x%x, type: 0x%x."
    01077                       "\n", i, __allegro_gl_get_format_description(internal_format),
    01078                       bmp->w, bmp->h, format, type);
    01079             }
    01080
    01081             destroy_bitmap(temp);
    01082         }
    01083     }
    01084
    01085     glPixelStorei(GL_UNPACK_ROW_LENGTH, (bmp->h > 1)
    01086                  ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
    01087                  : bmp->w);
    01088
    01089     TRACE(PREFIX_I "do_texture_upload: Unpack row length: %li.\n",
    01090       (bmp->h > 1) ? (long int)((bmp->line[1] - bmp->line[0]) / bytes_per_pixel)
    01091                    : bmp->w);
    01092
    01093     /* Upload the base texture */
    01094     glGetError();
    01095     glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
    01096                  bmp->w, bmp->h, 0, format, type, bmp->line[0]);
    01097
    01098     TRACE(PREFIX_I "do_texture_upload: Uploaded texture: level 0, "
    01099           "internalformat: %s, %ix%i, format: 0x%x, type: 0x%x.\n",
    01100           __allegro_gl_get_format_description(internal_format),
    01101           bmp->w, bmp->h, format, type);
    01102
    01103     TRACE(PREFIX_I "do_texture_upload: GL Error code: 0x%x\n", glGetError());
    01104
    01105     if (!(flags & AGL_TEXTURE_MIPMAP)) {
    01106         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    01107     }
    01108
    01109 end:
    01110     /* Restore state */
    01111     glPixelStorei(GL_UNPACK_ROW_LENGTH, saved_row_length);
    01112     glPixelStorei(GL_UNPACK_ALIGNMENT,  saved_alignment);
    01113
    01114     return tex;
    01115 }
    01116
    01117
    01118
    01119 /* GLuint allegro_gl_make_texture_ex(int flag, BITMAP *bmp, GLint internal_format) */
    01165 GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
    01166 {
    01167     GLuint tex = 0, ret = 0;
    01168     BITMAP *temp = NULL;
    01169     GLint type;
    01170     GLint format;
    01171     GLint old_tex;
    01172
    01173     /* Print the parameters */
    01174 #ifdef DEBUGMODE
    01175     char buf[1024] = "";
    01176 #   define PFLAG(name) if (flags & name) strcat(buf, #name "|");
    01177     PFLAG(AGL_TEXTURE_MIPMAP);
    01178     PFLAG(AGL_TEXTURE_HAS_ALPHA);
    01179     PFLAG(AGL_TEXTURE_FLIP);
    01180     PFLAG(AGL_TEXTURE_MASKED);
    01181     PFLAG(AGL_TEXTURE_RESCALE);
    01182     PFLAG(AGL_TEXTURE_ALPHA_ONLY);
    01183 #   undef PFLAG
    01184
    01185     TRACE(PREFIX_I "make_texture_ex: flags: %s, bitmap %ix%i, %i bpp.\n", buf,
    01186           bmp ? bmp->w : 0, bmp ? bmp->h : 0,
    01187           bmp ? bitmap_color_depth(bmp) : 0);
    01188     if (internal_format == -1) {
    01189         TRACE(PREFIX_I "internalformat: AUTO\n");
    01190     }
    01191     else {
    01192         TRACE(PREFIX_I "internalformat: %s\n",
    01193             __allegro_gl_get_format_description(internal_format));
    01194     }
    01195 #endif
    01196
    01197     /* Basic parameter checks */
    01198     if (!__allegro_gl_valid_context)
    01199         return 0;
    01200
    01201     if (!bmp) {
    01202         return 0;
    01203     }
    01204
    01205     glGetIntegerv(GL_TEXTURE_2D_BINDING, &old_tex);
    01206
    01207     /* Voodoo cards don't seem to support mipmaps for textures over 32x32...
    01208      */
    01209     if ((bmp->w > 32 || bmp->h > 32) && (allegro_gl_info.is_voodoo)) {
    01210         /* Disable mipmapping if the user didn't allow us to rescale */
    01211         if (!(flags & AGL_TEXTURE_RESCALE)) {
    01212             TRACE(PREFIX_I "make_texture_ex: Voodoo card detected && texture "
    01213                   "size > 32 texels && no rescaling. Disabling mipmaps.\n");
    01214             flags &= ~AGL_TEXTURE_MIPMAP;
    01215         }
    01216     }
    01217
    01218     /* Check the maximum texture size */
    01219     if (bmp->w > allegro_gl_info.max_texture_size
    01220      || bmp->h > allegro_gl_info.max_texture_size) {
    01221         if ((flags & AGL_TEXTURE_RESCALE) == 0) {
    01222             TRACE(PREFIX_I "make_texture_ex: Max texture size exceeded but no "
    01223                   "rescaling allowed. Returning 0 (unsupported).\n");
    01224             return 0;
    01225         }
    01226     }
    01227
    01228     /* Check power-of-2 */
    01229     if (((bmp->w & (bmp->w - 1)) || (bmp->h & (bmp->h - 1)))
    01230       && !(flags & AGL_TEXTURE_RESCALE)
    01231       && !allegro_gl_extensions_GL.ARB_texture_non_power_of_two) {
    01232         TRACE(PREFIX_I "make_texture_ex: Non-power-of-2 sized bitmap provided, "
    01233               "no rescaling allowed, and ARB_texture_non_power_of_two "
    01234               "unsupported. Returning 0 (unsupported).\n");
    01235         return 0;
    01236     }
    01237
    01238
    01239     /* Get OpenGL format and type for this pixel data */
    01240     format = __allegro_gl_get_bitmap_color_format(bmp, flags);
    01241     type = __allegro_gl_get_bitmap_type(bmp, flags);
    01242
    01243     if (flags & AGL_TEXTURE_ALPHA_ONLY) {
    01244         type   = GL_UNSIGNED_BYTE;
    01245         if (internal_format == GL_ALPHA || internal_format == GL_ALPHA4
    01246          || internal_format == GL_ALPHA8) {
    01247             format = GL_ALPHA;
    01248         }
    01249         else if (internal_format == GL_INTENSITY
    01250               || internal_format == GL_INTENSITY4
    01251               || internal_format == GL_INTENSITY8) {
    01252             format = GL_RED;
    01253         }
    01254         else if (internal_format == GL_LUMINANCE
    01255               || internal_format == GL_LUMINANCE4
    01256               || internal_format == GL_LUMINANCE8) {
    01257             format = GL_LUMINANCE;
    01258         }
    01259
    01260         /* Alpha bitmaps must be 8-bpp */
    01261         if (bitmap_color_depth(bmp) != 8) {
    01262             return 0;
    01263         }
    01264     }
    01265
    01266     if (flags & AGL_TEXTURE_MASKED) {
    01267         flags |= AGL_TEXTURE_FORCE_ALPHA_INTERNAL;
    01268     }
    01269
    01270     TRACE(PREFIX_I "make_texture_ex: Preselected texture format: %s, "
    01271           "type: 0x%x\n", __allegro_gl_get_format_description(format), type);
    01272
    01273     /* Munge the bitmap if needed (rescaling, alpha channel, etc) */
    01274     temp = __allegro_gl_munge_bitmap(flags, bmp, 0, 0, bmp->w, bmp->h,
    01275                                      &type, &format);
    01276     if (temp) {
    01277         bmp = temp;
    01278     }
    01279
    01280     if (internal_format == -1) {
    01281         internal_format = __allegro_gl_get_texture_format_ex(bmp, flags);
    01282         TRACE(PREFIX_I "make_texture_ex: Picked internalformat: %s\n",
    01283               __allegro_gl_get_format_description(internal_format));
    01284     }
    01285
    01286     if (internal_format == -1) {
    01287         TRACE(PREFIX_E "make_texture_ex: Invalid internal format!: "
    01288               "%s\n", __allegro_gl_get_format_description(internal_format));
    01289         goto end;
    01290     }
    01291
    01292     TRACE(PREFIX_I "make_texture_ex: dest format=%s, source format=%s, "
    01293           "type=0x%x\n", __allegro_gl_get_format_description(internal_format),
    01294               __allegro_gl_get_format_description(format), (int)type);
    01295
    01296
    01297     /* ATI Radeon 7000 inverts R and B components when generating mipmaps and
    01298      * the internal format is GL_RGB8, but only on mipmaps. Instead, we'll use
    01299      * GL_RGBA8. This works for bitmaps of depth <= 24. For 32-bpp bitmaps,
    01300      * some additional tricks are needed: We must fill in alpha with 255.
    01301      */
    01302     if (allegro_gl_info.is_ati_radeon_7000 && (flags & AGL_TEXTURE_MIPMAP)
    01303      && internal_format == GL_RGB8
    01304      && allegro_gl_extensions_GL.SGIS_generate_mipmap) {
    01305
    01306         int i, j;
    01307         int depth = bitmap_color_depth(bmp);
    01308
    01309         TRACE(PREFIX_I "make_texture_ex: ATI Radeon 7000 detected, mipmapping "
    01310               "used, SGIS_generate_mipmap available and selected "
    01311               "internalformat is GL_RGB8 but format is GL_RGBA. Working around "
    01312               "ATI driver bug by upgrading bitmap to 32-bpp and using GL_RGBA8 "
    01313               "instead.\n");
    01314
    01315         if (depth == 32) {
    01316
    01317             /* Create temp bitmap if not already there */
    01318             if (!temp) {
    01319                 temp = create_bitmap_ex(depth, bmp->w, bmp->h);
    01320                 if (!temp) {
    01321                     TRACE(PREFIX_E "make_texture_ex: Unable to allocate "
    01322                           "memory for temporary bitmap (Radeon 7000 path)!\n");
    01323                     goto end;
    01324                 }
    01325                 blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
    01326                 bmp = temp;
    01327             }
    01328
    01329             /* Slow path, until ATI finally gets around to fixing their
    01330              * drivers.
    01331              *
    01332              * Note: If destination internal format was GL_RGBx, then no masking
    01333              * code is needed.
    01334              */
    01335             for (j = 0; j < bmp->h; j++) {
    01336                 for (i = 0; i < bmp->w; i++) {
    01337                     int pix = _getpixel32(bmp, i, j);
    01338                     _putpixel32(bmp, i, j,
    01339                         makeacol32(getr32(pix), getg32(pix), getb32(pix), 255));
    01340                 }
    01341             }
    01342         }
    01343         internal_format = GL_RGBA8;
    01344     }
    01345
    01346
    01347     /* Generate the texture */
    01348     glGenTextures(1, &tex);
    01349     if (!tex) {
    01350         TRACE(PREFIX_E "make_texture_ex: Unable to create GL texture!\n");
    01351         goto end;
    01352     }
    01353
    01354     ret = do_texture_upload(bmp, tex, internal_format, format, type, flags);
    01355
    01356 end:
    01357     if (temp) {
    01358         destroy_bitmap(temp);
    01359     }
    01360
    01361     if (!ret && tex) {
    01362         glDeleteTextures(1, &tex);
    01363     }
    01364
    01365     glBindTexture(GL_TEXTURE_2D, old_tex);
    01366
    01367     return tex;
    01368 }
    01369
    01370
    01371
    01372
    01373
    01374 /* GLuint allegro_gl_make_texture(BITMAP *bmp) */
    01383 GLuint allegro_gl_make_texture(BITMAP *bmp) {
    01384
    01385     int flags = __allegro_gl_convert_flags(0);
    01386
    01387     return allegro_gl_make_texture_ex(flags, bmp,
    01388                                      allegro_gl_opengl_internal_texture_format);
    01389 }
    01390
    01391
    01392
    01393 /* GLuint allegro_gl_make_masked_texture(BITMAP *bmp) */
    01402 GLuint allegro_gl_make_masked_texture(BITMAP *bmp) {
    01403
    01404     int flags = __allegro_gl_convert_flags(AGL_TEXTURE_MASKED);
    01405
    01406     return allegro_gl_make_texture_ex(flags, bmp,
    01407                                      allegro_gl_opengl_internal_texture_format);
    01408 }
    01409
    01410
    01411
    01412 /* GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) */
    01433 GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) {
    01434
    01435     int flags = __allegro_gl_convert_flags(0);
    01436     return __allegro_gl_get_bitmap_type(bmp, flags);
    01437 }
    01438
    01439
    01440
    01441 /* GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) */
    01456 GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) {
    01457
    01458     int flags = __allegro_gl_convert_flags(0);
    01459     return __allegro_gl_get_bitmap_color_format(bmp, flags);
    01460 }
    01461