texture.c

Go to the documentation of this file.
00001 
00005 #include <string.h>
00006 
00007 #include "alleggl.h"
00008 #include "allglint.h"
00009 
00010 #include <allegro/internal/aintern.h>
00011 
00012 #ifdef ALLEGRO_MACOSX
00013 #include <OpenGL/glu.h>
00014 #else
00015 #include <GL/glu.h>
00016 #endif
00017 
00018 static GLint allegro_gl_opengl_internal_texture_format = -1;
00019 static int allegro_gl_use_mipmapping_for_textures = 0;
00020 int __allegro_gl_use_alpha = FALSE;
00021 int __allegro_gl_flip_texture = TRUE;
00022 GLint __allegro_gl_texture_read_format[5];
00023 GLint __allegro_gl_texture_components[5];
00024 
00025 
00026 
00027 /* GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) */
00038 GLint __allegro_gl_get_texture_format_ex(BITMAP *bmp, int flags) {
00039 
00040     if (!bmp) {
00041         return -1;
00042     }
00043 
00044     switch (bitmap_color_depth(bmp)) {
00045         case 32:
00046             if (flags
00047                  & (AGL_TEXTURE_HAS_ALPHA | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
00048                 return GL_RGBA8;
00049             }
00050             else {
00051                 return GL_RGB8;
00052             }
00053         case 8:
00054             return GL_INTENSITY8;
00055         case 15:
00056             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00057                 return GL_RGB5_A1;
00058             }
00059             else {
00060                 return GL_RGB5;
00061             }
00062         case 16:
00063         case 24:
00064             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00065                 return GL_RGBA8;
00066             }
00067             else {
00068                 return GL_RGB8;
00069             }
00070         default:
00071             return -1;
00072     }
00073 
00074     return -1;
00075 }
00076 
00077 
00078 
00079 /* GLint allegro_gl_get_texture_format(BITMAP *bmp) */
00096 GLint allegro_gl_get_texture_format(BITMAP *bmp) {
00097 
00098     if (bmp && allegro_gl_opengl_internal_texture_format == -1) {
00099         return __allegro_gl_get_texture_format_ex(bmp,
00100                 __allegro_gl_use_alpha ? AGL_TEXTURE_FORCE_ALPHA_INTERNAL : 0);
00101     }
00102     
00103     return allegro_gl_opengl_internal_texture_format;
00104 }
00105 
00106 
00107 
00108 /* GLint allegro_gl_set_texture_format(GLint format) */
00130 GLint allegro_gl_set_texture_format(GLint format) {
00131 
00132     GLint old = allegro_gl_opengl_internal_texture_format;
00133     allegro_gl_opengl_internal_texture_format = format;
00134     return old;
00135 }
00136 
00137 
00138 
00139 /* GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) */
00159 GLenum __allegro_gl_get_bitmap_type(BITMAP *bmp, int flags) {
00160 
00161     int c = bitmap_color_depth(bmp);
00162 
00163     switch (c) {
00164 
00165         case 8:
00166             return __allegro_gl_texture_read_format[0];
00167 
00168         case 15:
00169             return __allegro_gl_texture_read_format[1];
00170 
00171         case 16:
00172             return __allegro_gl_texture_read_format[2];
00173 
00174         case 24:
00175             return __allegro_gl_texture_read_format[3];
00176 
00177         case 32:
00178             return __allegro_gl_texture_read_format[4];
00179     
00180         default:
00181             TRACE("** ERROR ** get_bitmap_type: unhandled bitmap depth: %d\n",
00182                   c);
00183             return -1;
00184     }
00185 }
00186 
00187 
00188 
00189 /* GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) */
00203 GLenum __allegro_gl_get_bitmap_color_format(BITMAP *bmp, int flags) {
00204 
00205     int c = bitmap_color_depth(bmp);
00206 
00207     switch (c) {
00208 
00209         case 8:
00210             if (flags & AGL_TEXTURE_ALPHA_ONLY) {
00211                 return GL_ALPHA;
00212             }
00213             else {
00214                 return __allegro_gl_texture_components[0];
00215             }
00216 
00217         case 15:
00218             if (flags & AGL_TEXTURE_FORCE_ALPHA_INTERNAL) {
00219                 return GL_RGBA;
00220             }
00221             else {
00222                 return __allegro_gl_texture_components[1];
00223             }
00224 
00225         case 16:
00226             return __allegro_gl_texture_components[2];
00227 
00228         case 24:
00229             return __allegro_gl_texture_components[3];
00230 
00231         case 32:
00232             if (flags & (AGL_TEXTURE_HAS_ALPHA
00233                        | AGL_TEXTURE_FORCE_ALPHA_INTERNAL)) {
00234                 return GL_RGBA;
00235             }
00236             else {
00237                 return __allegro_gl_texture_components[4];
00238             }
00239     
00240         default:
00241             TRACE("** ERROR ** get_bitmap_color_format: unhandled bitmap "
00242                   "depth: %d\n", c);
00243             return -1;
00244     }
00245 }
00246 
00247 
00248 
00249 /* int allegro_gl_use_mipmapping(int enable) */
00263 int allegro_gl_use_mipmapping(int enable) {
00264 
00265     int old = allegro_gl_use_mipmapping_for_textures;
00266     allegro_gl_use_mipmapping_for_textures = enable;
00267     return old;
00268 }
00269     
00270 
00271 
00272 /* int allegro_gl_use_alpha_channel(int enable) */
00287 int allegro_gl_use_alpha_channel(int enable) {
00288 
00289     int old = __allegro_gl_use_alpha;
00290     __allegro_gl_use_alpha = enable;
00291     return old;
00292 }
00293     
00294 
00295 
00296 /* int allegro_gl_flip_texture(int enable) */
00312 int allegro_gl_flip_texture(int enable) {
00313 
00314     int old = __allegro_gl_flip_texture;
00315     __allegro_gl_flip_texture = enable;
00316     return old;
00317 }
00318     
00319 
00320 
00321 /* int allegro_gl_check_texture_ex(int flags, BITMAP *bmp, GLuint internal_format) */
00343 int allegro_gl_check_texture_ex(int flags, BITMAP *bmp,
00344                                    GLint internal_format) {
00345 
00346     return (allegro_gl_make_texture_ex(flags | AGL_TEXTURE_CHECK_VALID_INTERNAL,
00347                                        bmp, internal_format) ? TRUE : FALSE);
00348 }
00349 
00350 
00351 
00352 /* Convert flags from pre-0.2.0 to 0.2.0+ */
00353 static int __allegro_gl_convert_flags(int flags) {
00354 
00355     flags |= AGL_TEXTURE_RESCALE;
00356 
00357     if (allegro_gl_use_mipmapping_for_textures) {
00358         flags |= AGL_TEXTURE_MIPMAP;
00359     }
00360     if (__allegro_gl_use_alpha) {
00361         flags |= AGL_TEXTURE_HAS_ALPHA;
00362     }
00363     if (__allegro_gl_flip_texture) {
00364         flags |= AGL_TEXTURE_FLIP;
00365     }
00366 
00367     if (allegro_gl_opengl_internal_texture_format == GL_ALPHA4
00368      || allegro_gl_opengl_internal_texture_format == GL_ALPHA8
00369      || allegro_gl_opengl_internal_texture_format == GL_ALPHA12
00370      || allegro_gl_opengl_internal_texture_format == GL_ALPHA16
00371      || allegro_gl_opengl_internal_texture_format == GL_ALPHA
00372      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY4
00373      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY8
00374      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY12
00375      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY16
00376      || allegro_gl_opengl_internal_texture_format == GL_INTENSITY
00377      || allegro_gl_opengl_internal_texture_format == 1) {
00378         flags |= AGL_TEXTURE_ALPHA_ONLY;
00379     }
00380 
00381     return flags;
00382 }
00383 
00384 
00385 
00386 /* int allegro_gl_check_texture(BITMAP *bmp) */
00405 int allegro_gl_check_texture(BITMAP *bmp) {
00406 
00407     int flags = __allegro_gl_convert_flags(0);
00408     
00409     return allegro_gl_check_texture_ex(flags, bmp,
00410                                      allegro_gl_opengl_internal_texture_format);
00411 }
00412 
00413 
00414 
00415 /* Integer log2 function. Not optimized for speed. */
00416 static int log2i(int n) {
00417     
00418     int k;
00419     
00420     if (n < 1) {
00421         return -1;
00422     }
00423 
00424     k = 0;
00425     while (n >>= 1) {
00426         k++;
00427     }
00428 
00429     return k;
00430 }
00431 
00432 
00433 
00434 /* BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, GLint *type, GLint *format) */
00444 BITMAP *__allegro_gl_munge_bitmap(int flags, BITMAP *bmp, int x, int y,
00445                                   int w, int h, GLint *type, GLint *format) {
00446     
00447     BITMAP *ret = 0, *temp = 0;
00448 
00449     int need_rescale = 0;
00450     int need_alpha   = 0;
00451     int need_flip    = 0;
00452     int depth = bitmap_color_depth(bmp);
00453     int force_copy   = 0;
00454 
00455     const int old_w = w, old_h = h;
00456 
00457     if (flags & AGL_TEXTURE_RESCALE) {
00458         
00459         /* Check if rescaling is needed */
00460 
00461         /* NP2 is not supported, and the texture isn't a power-of-two.
00462          * Resize the next power of 2
00463          */     
00464         if (!allegro_gl_extensions_GL.ARB_texture_non_power_of_two
00465          && ((w & (w - 1)) || (h & (h - 1)))) {
00466             w = __allegro_gl_make_power_of_2(w);
00467             h = __allegro_gl_make_power_of_2(h);
00468             TRACE("* Note * munge_bitmap: Rescaling bitmap from "
00469                   "%ix%i to %ix%i due to non-power-of-2 source size.\n",
00470                   old_w, old_h, w, h);
00471             need_rescale = 1;
00472         }
00473 
00474         /* Don't go over the max texture size */
00475         if (w > allegro_gl_info.max_texture_size) {
00476             w = allegro_gl_info.max_texture_size;
00477             TRACE("* Note * munge_bitmap: Rescaling bitmap from "
00478                   "%ix%i to %ix%i due to max supported size exceed.\n",
00479                   old_w, old_h, w, h);
00480             need_rescale = 1;
00481         }
00482         
00483         if (h > allegro_gl_info.max_texture_size) {
00484             h = allegro_gl_info.max_texture_size;
00485             TRACE("* Note * munge_bitmap: Rescaling bitmap from "
00486                   "%ix%i to %ix%i due to max supported size exceed.\n",
00487                   old_w, old_h, w, h);
00488             need_rescale = 1;
00489         }
00490 
00491         /* Voodoos don't support mipmaps for textures greater than 32x32.
00492          * If we're allowed to rescale, rescale the bitmap to 32x32.
00493          * XXX <rohannessian> Apparently, this is a bug in one version
00494          * of the Voodoo GL driver. Need to figure out a workaround
00495          * for that.
00496          */
00497         if (allegro_gl_info.is_voodoo && (flags & AGL_TEXTURE_MIPMAP)
00498           && (w > 32 || h > 32)) {
00499 
00500             w = MIN(32, w);
00501             h = MIN(32, h);
00502             
00503             TRACE("* Note * munge_bitmap: Rescaling bitmap from "
00504                   "%ix%i to %ix%i due to Voodoo driver bug.\n",
00505                   old_w, old_h, w, h);
00506             need_rescale = 1;
00507         }
00508     }
00509 
00510     /* Matrox G200 cards have a bug where rectangular textures can't have
00511      * more than 4 levels of mipmaps (max_mip == 3). This doesn't seem
00512      * to affect square textures.
00513      *
00514      * Note: Using GLU to build the mipmaps seems to work. Maybe AGL is
00515      * doing something wrong?
00516      *
00517      * Workaround: Use GLU to build the mipmaps, and force depth to 24 or
00518      * 32.
00519      */
00520     if ( allegro_gl_info.is_matrox_g200 && (flags & AGL_TEXTURE_MIPMAP)) {
00521         int wl = log2i(w);
00522         int hl = log2i(h);
00523 
00524         if (w != h && MAX(wl, hl) > 3 && depth < 24
00525          && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
00526             TRACE("* Note * munge_bitmap: G200 path in use.\n");
00527             depth = 24;
00528         }
00529     }
00530     
00531     /* Do we need to flip the texture on the t axis? */
00532     if (flags & AGL_TEXTURE_FLIP) {
00533         need_flip = 1;
00534     }
00535 
00536 
00537     /* If not supported, blit to a 24 bpp bitmap and try again
00538      */
00539     if (*type == -1) {
00540         TRACE("** Warning ** munge_bitmap: using temporary 24bpp bitmap\n");
00541         depth = 24;
00542     }
00543 
00544     /* We need a texture that can be used for masked blits.
00545      * Insert an alpha channel if one is not there.
00546      * If it's already there, replace it by 0/1 as needed.
00547      */
00548     if ((flags & AGL_TEXTURE_MASKED) && !(flags & AGL_TEXTURE_ALPHA_ONLY)) {
00549         need_alpha = 1;
00550 
00551         switch (depth) {
00552         case 15:
00553             if (!allegro_gl_extensions_GL.EXT_packed_pixels) {
00554                 depth = 32;
00555             }
00556             break;
00557         case 8:
00558         case 16:
00559         case 24:
00560         case 32:
00561             depth = 32;
00562             break;
00563         }
00564         force_copy = 1;
00565     }
00566 
00567     /* Allegro fills in 0 for the alpha channel. Matrox G200 seems to ignore
00568      * the internal format; so we need to drop down to 24-bpp if no alpha
00569      * will be needed.
00570      */
00571     if (allegro_gl_info.is_matrox_g200 && !(flags & AGL_TEXTURE_MASKED)
00572        && !(flags & AGL_TEXTURE_HAS_ALPHA) && depth == 32) {
00573         TRACE("* Note * munge_bitmap: G200 path in use.\n");
00574         depth = 24;
00575         force_copy = 1;
00576     }
00577 
00578     
00579     /* Do we need to do a color depth conversion or bitmap copy? */
00580     if (depth != bitmap_color_depth(bmp) || force_copy) {
00581 
00582         TRACE("* Note * munge_bitmap: Need to perform depth conversion from %i "
00583               "to %i bpp.\n", bitmap_color_depth(bmp), depth);
00584 
00585         temp = create_bitmap_ex(depth, bmp->w, bmp->h);
00586 
00587         if (!temp) {
00588             TRACE("** ERROR ** munge_bitmap: Unable to create temporary bitmap "
00589                   "%ix%ix%i\n", bmp->w, bmp->h, depth);
00590             return NULL;
00591         }
00592 
00593         /* XXX <rohannessian> Use palette conversion?
00594          */
00595         if (bitmap_color_depth(bmp) == 8 && depth > 8) {
00596             int i, j;
00597             for (j = 0; j < bmp->h; j++) {
00598                 for (i = 0; i < bmp->w; i++) {
00599                     int c = _getpixel(bmp, i, j);
00600                     putpixel(temp, i, j, makecol_depth(depth, c, c, c));
00601                 }
00602             }
00603         }
00604         else {
00605             blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
00606         }
00607         bmp = temp;
00608 
00609         *format = __allegro_gl_get_bitmap_color_format(bmp, flags);
00610         *type = __allegro_gl_get_bitmap_type(bmp, flags);
00611     }
00612 
00613 
00614 
00615     /* Nothing to do? */
00616     if (!need_rescale && !need_alpha && !need_flip) {
00617 
00618         TRACE("* Note * munge_bitmap: No need for munging - returning %p\n",
00619               temp);
00620         
00621         /* Return depth-converte bitmap, if present */
00622         if (temp) {
00623             return temp;
00624         }
00625         return NULL;
00626     }
00627 
00628     ret = create_bitmap_ex(depth, w, h);
00629     
00630     if (!ret) {
00631         TRACE("** ERROR ** munge_bitmap: Unable to create result bitmap "
00632               "%ix%ix%i\n", w, h, depth);
00633         goto error;
00634     }
00635 
00636 
00637     /* No need to fill in bitmap if we're just making a query */
00638     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) {
00639         if (temp) {
00640             destroy_bitmap(temp);
00641         }
00642         return ret;
00643     }
00644 
00645 
00646     /* Perform flip
00647      * I don't want to have to deal with *yet another* temporary bitmap
00648      * so instead, I fugde the line pointers around.
00649      * This will work because we require Allegro memory bitmaps anyway.
00650      */
00651     if (need_flip) {
00652         int i;
00653         TRACE("* Note * munge_bitmap: Flipping bitmap.\n");
00654         for (i = 0; i < bmp->h/2; i++) {
00655             unsigned char *l = bmp->line[i];
00656             bmp->line[i] = bmp->line[bmp->h - i - 1];
00657             bmp->line[bmp->h - i - 1] = l;
00658         }
00659     }
00660     
00661     /* Rescale bitmap */
00662     if (need_rescale) {
00663         TRACE("* Note * munge_bitmap: Rescaling bitmap.\n");
00664         stretch_blit(bmp, ret, x, y, old_w, old_h, 0, 0, ret->w, ret->h);
00665     }
00666     else {
00667         TRACE("* Note * munge_bitmap: Copying bitmap.\n");
00668         blit(bmp, ret, x, y, 0, 0, w, h);
00669     }
00670 
00671     /* Restore the original bitmap, if needed */
00672     if (need_flip && !temp) {
00673         int i;
00674         TRACE("* Note * munge_bitmap: Unflipping bitmap.\n");
00675         for (i = 0; i < bmp->h/2; i++) {
00676             unsigned char *l = bmp->line[i];
00677             bmp->line[i] = bmp->line[bmp->h - i - 1];
00678             bmp->line[bmp->h - i - 1] = l;
00679         }
00680     }
00681     
00682     /* Insert alpha channel */
00683     if (need_alpha) {
00684         int i, j;
00685         int mask = bitmap_mask_color(ret);
00686 
00687         /* alpha mask for 5.5.5.1 pixels */
00688         int alpha = (-1) ^ makecol_depth(depth, 255, 255, 255);
00689 
00690         TRACE("* Note * munge_bitmap: Inserting alpha channel.\n");
00691 
00692         for (j = 0; j < h; j++) {
00693             for (i = 0; i < w; i++) {
00694                 int pix;
00695                 
00696                 switch (depth) {
00697                 case 32:
00698                     pix = _getpixel32(ret, i, j);
00699 
00700                     if (pix == mask) {
00701                         pix = 0;
00702                     }
00703                     else if ((flags & AGL_TEXTURE_HAS_ALPHA) == 0) {
00704                         int r, g, b;
00705                         r = getr32(pix);
00706                         g = getg32(pix);
00707                         b = getb32(pix);
00708                         pix = makeacol32(r, g, b, 255);
00709                     }
00710                     _putpixel32(ret, i, j, pix);
00711                     break;
00712                 case 15: 
00713                     pix = _getpixel16(ret, i, j);
00714 
00715                     if (pix == mask) {
00716                         pix = 0;
00717                     }
00718                     else {
00719                         pix |= alpha;
00720                     }
00721                     
00722                     _putpixel16(temp, i, j, pix);
00723                     break;
00724                 default:
00725                     /* Shouldn't actually come here */
00726                     ASSERT(0);
00727                 }
00728             }
00729         }
00730     }
00731 
00732 
00733 error:
00734     if (temp) {
00735         destroy_bitmap(temp);
00736     }
00737 
00738     return ret;
00739 }
00740 
00741 
00742 
00743 /* Perform the actual texture upload. Helper for agl_make_texture_ex().
00744  */
00745 static GLuint do_texture_upload(BITMAP *bmp, GLuint tex, GLint internal_format,
00746                               GLint format, GLint type, int flags) {
00747 
00748     int bytes_per_pixel = BYTES_PER_PIXEL(bitmap_color_depth(bmp));
00749     GLint saved_row_length;
00750     GLint saved_alignment;
00751     GLenum target = GL_TEXTURE_2D;
00752 
00753     glBindTexture(target, tex);
00754     
00755 
00756     /* Handle proxy texture checks */
00757     if (flags & AGL_TEXTURE_CHECK_VALID_INTERNAL) { 
00758         /* <bcoconni> allegro_gl_check_texture is broken with GL drivers based
00759          *  on Mesa. It seems this is a Mesa bug...
00760          */
00761         if (allegro_gl_info.is_mesa_driver) {
00762             AGL_LOG(1, "* Note * check_texture: Mesa driver detected: "
00763                    "PROXY_TEXTURE_2D tests are skipped\n");
00764             return tex;
00765         }
00766         else {
00767             glTexImage2D(GL_PROXY_TEXTURE_2D, 0, internal_format,
00768                          bmp->w, bmp->h, 0, format, type, NULL);
00769 
00770             glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0,
00771                                      GL_TEXTURE_COMPONENTS, &internal_format);
00772 
00773             return (internal_format ? tex : 0);
00774         }
00775     }
00776     
00777 
00778     /* Set up pixel transfer mode */
00779     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &saved_row_length);
00780     glGetIntegerv(GL_UNPACK_ALIGNMENT,  &saved_alignment);
00781     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00782 
00783     TRACE("* Note * do_texture_upload: Making texture: bpp: %i\n",
00784           bitmap_color_depth(bmp));
00785 
00786     /* Generate mipmaps, if needed */
00787     if (flags & AGL_TEXTURE_MIPMAP) {
00788         
00789         if (allegro_gl_extensions_GL.SGIS_generate_mipmap) {
00790             /* Easy way out - let the driver do it ;) 
00791              * We do need to set high-qual mipmap generation though.
00792              */
00793             glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
00794             glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
00795             TRACE("* Note * do_texture_upload: Using SGIS_generate_mipmap for "
00796                   "mipmap generation.\n");
00797         }
00798         else if (allegro_gl_info.is_matrox_g200
00799              && (flags & AGL_TEXTURE_MIPMAP) && (bitmap_color_depth(bmp) >= 24
00800                 || bitmap_color_depth(bmp) == 8)
00801              && (bmp->w != bmp->h)) {
00802                 
00803             /* Matrox G200 has issues with our mipmapping code. Use GLU if we
00804              * can.
00805              */
00806             TRACE("* Note * do_texture_upload: Using GLU for mipmaps.\n");
00807             glPixelStorei(GL_UNPACK_ROW_LENGTH, bmp->h > 1
00808                         ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
00809                         : bmp->w);
00810             glPixelStorei(GL_UNPACK_ROW_LENGTH,
00811                                (bmp->line[1] - bmp->line[0]) / bytes_per_pixel);
00812             gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format, bmp->w, bmp->h,
00813                               format, type, bmp->line[0]);
00814         }
00815         else {
00816             int w = bmp->w;
00817             int h = bmp->h;
00818             int depth = bitmap_color_depth(bmp);
00819             
00820             /* The driver can't generate mipmaps for us. We can't rely on GLU
00821              * since the Win32 version doesn't support any of the new pixel
00822              * formats. Instead, we'll use our own downsampler (which only
00823              * has to work on Allegro BITMAPs)
00824              */
00825             BITMAP *temp = create_bitmap_ex(depth, w / 2, h / 2);
00826 
00827             /* We need to generate mipmaps up to 1x1 - compute the number
00828              * of levels we need.
00829              */
00830             int num_levels = log2i(MAX(bmp->w, bmp->h));
00831             
00832             int i, x, y;
00833 
00834             BITMAP *src, *dest;
00835 
00836             TRACE("* Note * do_texture_upload: Using Allegro for "
00837                   "mipmap generation.\n");
00838 
00839             if (!temp) {
00840                 TRACE("** ERROR ** do_texture_upload: Unable to create "
00841                       "temporary bitmap sized %ix%ix%i for mipmap generation!",
00842                       w / 2, h / 2, depth);
00843                 tex = 0;
00844                 goto end;
00845             }
00846 
00847             src = bmp;
00848             dest = temp;
00849             
00850             for (i = 1; i <= num_levels; i++) {
00851 
00852                 for (y = 0; y < h; y += 2) {
00853                     for (x = 0; x < w; x += 2) {
00854 
00855                         int r, g, b, a;
00856                         int pix[4];
00857                         int avg;
00858                         
00859                         pix[0] = getpixel(src, x,     y);
00860                         pix[1] = getpixel(src, x + 1, y);
00861                         pix[2] = getpixel(src, x,     y + 1);
00862                         pix[3] = getpixel(src, x + 1, y + 1);
00863 
00864                         if (w == 1) {
00865                             pix[1] = pix[0];
00866                             pix[3] = pix[2];
00867                         }
00868                         if (h == 1) {
00869                             pix[2] = pix[0];
00870                             pix[3] = pix[1];
00871                         }
00872 
00873                         if (flags & AGL_TEXTURE_ALPHA_ONLY) {
00874                             avg = (pix[0] + pix[1] + pix[2] + pix[3] + 2) / 4;
00875                         }
00876                         else {
00877                             r = (getr_depth(depth, pix[0])
00878                                + getr_depth(depth, pix[1])
00879                                + getr_depth(depth, pix[2])
00880                                + getr_depth(depth, pix[3]) + 2) / 4;
00881                             g = (getg_depth(depth, pix[0])
00882                                + getg_depth(depth, pix[1])
00883                                + getg_depth(depth, pix[2])
00884                                + getg_depth(depth, pix[3]) + 2) / 4;
00885                             b = (getb_depth(depth, pix[0])
00886                                + getb_depth(depth, pix[1])
00887                                + getb_depth(depth, pix[2])
00888                                + getb_depth(depth, pix[3]) + 2) / 4;
00889                             a = (geta_depth(depth, pix[0])
00890                                + geta_depth(depth, pix[1])
00891                                + geta_depth(depth, pix[2])
00892                                + geta_depth(depth, pix[3]) + 2) / 4;
00893 
00894                             avg = makeacol_depth(depth, r, g, b, a);
00895                         }
00896 
00897                         putpixel(dest, x / 2, y / 2, avg);
00898                     }
00899                 }
00900                 src = temp;
00901 
00902                 /* Note - we round down; we're still compatible with
00903                  * ARB_texture_non_power_of_two.
00904                  */
00905                 w = MAX(w / 2, 1);
00906                 h = MAX(h / 2, 1);
00907 
00908                 TRACE("* Note * do_texture_upload: Unpack row length: %i.\n",
00909                       (temp->h > 1)
00910                      ? (temp->line[1] - temp->line[0]) / bytes_per_pixel
00911                      : temp->w);
00912 
00913                 glPixelStorei(GL_UNPACK_ROW_LENGTH, temp->h > 1
00914                              ? (temp->line[1] - temp->line[0]) / bytes_per_pixel
00915                              : temp->w);    
00916 
00917                 glTexImage2D(GL_TEXTURE_2D, i, internal_format,
00918                              w, h, 0, format, type, temp->line[0]);
00919 
00920                 TRACE("* Note * do_texture_upload: Mipmap level: %i, "
00921                       "size: %i x %i\n", i, w, h);
00922 
00923                 TRACE("* Note * do_texture_upload: Uploaded texture: level %i, "
00924                       "internalformat: 0x%x, %ix%i, format: 0x%x, type: 0x%x."
00925                       "\n", i, internal_format, bmp->w, bmp->h, format, type);
00926             }
00927 
00928             destroy_bitmap(temp);
00929         }
00930     }
00931 
00932     glPixelStorei(GL_UNPACK_ROW_LENGTH, (bmp->h > 1)
00933                  ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
00934                  : bmp->w);
00935     
00936     TRACE("* Note * do_texture_upload: Unpack row length: %i.\n",
00937           (bmp->h > 1) ? (bmp->line[1] - bmp->line[0]) / bytes_per_pixel
00938                        : bmp->w);
00939 
00940     /* Upload the base texture */
00941     glGetError();
00942     glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
00943                  bmp->w, bmp->h, 0, format, type, bmp->line[0]);
00944 
00945     TRACE("* Note * do_texture_upload: Uploaded texture: level 0, "
00946           "internalformat: 0x%x, %ix%i, format: 0x%x, type: 0x%x.\n",
00947           internal_format, bmp->w, bmp->h, format, type);
00948     
00949     TRACE("* Note * do_texture_upload: GL Error code: 0x%x\n", glGetError());
00950 
00951     if (!(flags & AGL_TEXTURE_MIPMAP)) {
00952         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00953     }
00954     
00955 end:
00956     /* Restore state */
00957     glPixelStorei(GL_UNPACK_ROW_LENGTH, saved_row_length);
00958     glPixelStorei(GL_UNPACK_ALIGNMENT,  saved_alignment);
00959 
00960     return tex;
00961 }   
00962 
00963 
00964 
00965 /* GLuint allegro_gl_make_texture_ex(int flag, BITMAP *bmp, GLint internal_format) */
01011 GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
01012 {
01013     GLuint tex = 0, ret = 0;
01014     BITMAP *temp = NULL;
01015     GLint type;
01016     GLint format;
01017     GLint old_tex;
01018 
01019     /* Print the parameters */
01020 #ifdef DEBUGMODE
01021     char buf[1024] = "";
01022 #   define PFLAG(name) if (flags & name) strcat(buf, #name "|");
01023     PFLAG(AGL_TEXTURE_MIPMAP);
01024     PFLAG(AGL_TEXTURE_HAS_ALPHA);
01025     PFLAG(AGL_TEXTURE_FLIP);
01026     PFLAG(AGL_TEXTURE_MASKED);
01027     PFLAG(AGL_TEXTURE_RESCALE);
01028     PFLAG(AGL_TEXTURE_ALPHA_ONLY);
01029 #   undef PFLAG
01030 
01031     TRACE("* Note * make_texture_ex: flags: %s, bitmap %ix%i, %i bpp. ", buf,
01032           bmp ? bmp->w : 0, bmp ? bmp->h : 0,
01033           bmp ? bitmap_color_depth(bmp) : 0);
01034     if (internal_format == -1) {
01035         TRACE("internalformat: AUTO\n");
01036     }
01037     else {
01038         TRACE("internalformat: 0x%x\n", (int)internal_format);
01039     }
01040 #endif  
01041 
01042     /* Basic parameter checks */
01043     if (!__allegro_gl_valid_context)
01044         return 0;
01045 
01046     if (!bmp) {
01047         return 0;
01048     }
01049 
01050     glGetIntegerv(GL_TEXTURE_2D_BINDING, &old_tex);
01051 
01052     /* Voodoo cards don't seem to support mipmaps for textures over 32x32...
01053      */
01054     if ((bmp->w > 32 || bmp->h > 32) && (allegro_gl_info.is_voodoo)) {
01055         /* Disable mipmapping if the user didn't allow us to rescale */
01056         if (!(flags & AGL_TEXTURE_RESCALE)) {
01057             TRACE("* Note * make_texture_ex: Voodoo card detected && texture "
01058                   "size > 32 texels && no rescaling. Disabling mipmaps.\n");
01059             flags &= ~AGL_TEXTURE_MIPMAP;
01060         }
01061     }
01062 
01063     /* Check the maximum texture size */
01064     if (bmp->w > allegro_gl_info.max_texture_size
01065      || bmp->h > allegro_gl_info.max_texture_size) {
01066         if ((flags & AGL_TEXTURE_RESCALE) == 0) {
01067             TRACE("* Note * make_texture_ex: Max texture size exceeded but no "
01068                   "rescaling allowed. Returning 0 (unsupported).\n");
01069             return 0;
01070         }
01071     }
01072 
01073     /* Check power-of-2 */
01074     if (((bmp->w & (bmp->w - 1)) || (bmp->h & (bmp->h - 1)))
01075       && !(flags & AGL_TEXTURE_RESCALE)
01076       && !allegro_gl_extensions_GL.ARB_texture_non_power_of_two) {
01077         TRACE("* Note * make_texture_ex: Non-power-of-2 sized bitmap provided, "
01078               "no rescaling allowed, and ARB_texture_non_power_of_two "
01079               "unsupported. Returning 0 (unsupported).\n");
01080         return 0;
01081     }
01082     
01083     
01084     /* Get OpenGL format and type for this pixel data */
01085     format = __allegro_gl_get_bitmap_color_format(bmp, flags);
01086     type = __allegro_gl_get_bitmap_type(bmp, flags);
01087     
01088     if (flags & AGL_TEXTURE_ALPHA_ONLY) {
01089         type   = GL_UNSIGNED_BYTE;
01090         if (internal_format == GL_ALPHA || internal_format == GL_ALPHA4
01091          || internal_format == GL_ALPHA8) {
01092             format = GL_ALPHA;
01093         }
01094         else if (internal_format == GL_INTENSITY
01095               || internal_format == GL_INTENSITY4
01096               || internal_format == GL_INTENSITY8) {
01097             format = GL_RED;
01098         }
01099         else if (internal_format == GL_LUMINANCE
01100               || internal_format == GL_LUMINANCE4
01101               || internal_format == GL_LUMINANCE8) {
01102             format = GL_LUMINANCE;
01103         }
01104 
01105         /* Alpha bitmaps must be 8-bpp */
01106         if (bitmap_color_depth(bmp) != 8) {
01107             return 0;
01108         }
01109     }
01110 
01111     if (flags & AGL_TEXTURE_MASKED) {
01112         flags |= AGL_TEXTURE_FORCE_ALPHA_INTERNAL;
01113     }
01114 
01115     TRACE("* Note * make_texture_ex: Preselected texture format: 0x%x, "
01116           "type: 0x%x\n", format, type);
01117     
01118     /* Munge the bitmap if needed (rescaling, alpha channel, etc) */
01119     temp = __allegro_gl_munge_bitmap(flags, bmp, 0, 0, bmp->w, bmp->h,
01120                                      &type, &format);
01121     if (temp) {
01122         bmp = temp;
01123     }
01124     
01125     if (internal_format == -1) {
01126         internal_format = __allegro_gl_get_texture_format_ex(bmp, flags);
01127         TRACE("* Note * make_texture_ex: Picked internalformat: 0x%x\n",
01128               (int)internal_format);
01129     }
01130 
01131     if (internal_format == -1) {
01132         TRACE("** ERROR ** make_texture_ex: Invalid internal format!: "
01133               "0x%x\n", (int)internal_format);
01134         goto end;
01135     }
01136     
01137     TRACE("* Note * make_texture_ex: dest format=%04x, source format=0x%x, "
01138           "type=0x%x\n", (int)internal_format, (int)format, (int)type);
01139 
01140     
01141     /* ATI Radeon 7000 inverts R and B components when generating mipmaps and
01142      * the internal format is GL_RGB8, but only on mipmaps. Instead, we'll use
01143      * GL_RGBA8. This works for bitmaps of depth <= 24. For 32-bpp bitmaps,
01144      * some additional tricks are needed: We must fill in alpha with 255.
01145      */
01146     if (allegro_gl_info.is_ati_radeon_7000 && (flags & AGL_TEXTURE_MIPMAP)
01147      && internal_format == GL_RGB8
01148      && allegro_gl_extensions_GL.SGIS_generate_mipmap) {
01149 
01150         int i, j;
01151         int depth = bitmap_color_depth(bmp);
01152 
01153         TRACE("* Note * make_texture_ex: ATI Radeon 7000 detected, mipmapping "
01154               "used, SGIS_generate_mipmap available and selected "
01155               "internalformat is GL_RGB8 but format is GL_RGBA. Working around "
01156               "ATI driver bug by upgrading bitmap to 32-bpp and using GL_RGBA8 "
01157               "instead.\n");
01158 
01159         if (depth == 32) {
01160 
01161             /* Create temp bitmap if not already there */
01162             if (!temp) {
01163                 temp = create_bitmap_ex(depth, bmp->w, bmp->h);
01164                 if (!temp) {
01165                     TRACE("** ERROR ** make_texture_ex: Unable to allocate "
01166                           "memory for temporary bitmap (Radeon 7000 path)!\n");
01167                     goto end;
01168                 }
01169                 blit(bmp, temp, 0, 0, 0, 0, bmp->w, bmp->h);
01170                 bmp = temp;
01171             }
01172             
01173             /* Slow path, until ATI finally gets around to fixing their
01174              * drivers.
01175              *
01176              * Note: If destination internal format was GL_RGBx, then no masking
01177              * code is needed.
01178              */
01179             for (j = 0; j < bmp->h; j++) {
01180                 for (i = 0; i < bmp->w; i++) {
01181                     int pix = _getpixel32(bmp, i, j);
01182                     _putpixel32(bmp, i, j,
01183                         makeacol32(getr32(pix), getg32(pix), getb32(pix), 255));
01184                 }
01185             }
01186         }
01187         internal_format = GL_RGBA8;
01188     }
01189     
01190 
01191     /* Generate the texture */
01192     glGenTextures(1, &tex);
01193     if (!tex) {
01194         TRACE("** ERROR ** make_texture_ex: Unable to create GL texture!\n");
01195         goto end;
01196     }
01197 
01198     ret = do_texture_upload(bmp, tex, internal_format, format, type, flags);
01199 
01200 end:
01201     if (temp) {
01202         destroy_bitmap(temp);
01203     }
01204 
01205     if (!ret && tex) {
01206         glDeleteTextures(1, &tex);
01207     }
01208 
01209     glBindTexture(GL_TEXTURE_2D, old_tex);
01210 
01211     return tex;
01212 }
01213 
01214 
01215 
01216 
01217 
01218 /* GLuint allegro_gl_make_texture(BITMAP *bmp) */
01227 GLuint allegro_gl_make_texture(BITMAP *bmp) {
01228         
01229     int flags = __allegro_gl_convert_flags(0);
01230     
01231     return allegro_gl_make_texture_ex(flags, bmp,
01232                                      allegro_gl_opengl_internal_texture_format);
01233 }
01234 
01235 
01236 
01237 /* GLuint allegro_gl_make_masked_texture(BITMAP *bmp) */
01246 GLuint allegro_gl_make_masked_texture(BITMAP *bmp) {
01247         
01248     int flags = __allegro_gl_convert_flags(AGL_TEXTURE_MASKED);
01249 
01250     return allegro_gl_make_texture_ex(flags, bmp,
01251                                      allegro_gl_opengl_internal_texture_format);
01252 }
01253 
01254 
01255 
01256 
01257 /* GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) */
01278 GLenum allegro_gl_get_bitmap_type(BITMAP *bmp) {
01279 
01280     int flags = __allegro_gl_convert_flags(0);
01281     return __allegro_gl_get_bitmap_type(bmp, flags);
01282 }
01283 
01284 
01285 
01286 /* GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) */
01301 GLenum allegro_gl_get_bitmap_color_format(BITMAP *bmp) {
01302 
01303     int flags = __allegro_gl_convert_flags(0);
01304     return __allegro_gl_get_bitmap_color_format(bmp, flags);
01305 }
01306 

Generated on Mon Apr 3 18:20:13 2006 for AllegroGL by  doxygen 1.4.6