X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=gl_textures.c;h=14685e7949e1fe87a5b4fec166c3749f26bf6812;hb=6fb644eee19956bee121e1f2430d2b84067dc056;hp=aa1d2f12960466b96b4b36d66c28d5fddc9c70f8;hpb=9c3a68b2217df842dad217a52fd74cee522ddb05;p=xonotic%2Fdarkplaces.git diff --git a/gl_textures.c b/gl_textures.c index aa1d2f12..14685e79 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -38,7 +38,7 @@ cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_re cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"}; cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"}; cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"}; -cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log"}; +cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"}; cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"}; qboolean gl_filter_force = false; @@ -81,13 +81,23 @@ typedef struct textypeinfo_s textypeinfo_t; #ifdef USE_GLES2 + +// we use these internally even if we never deliver such data to the driver +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 + // framebuffer texture formats // GLES2 devices rarely support depth textures, so we actually use a renderbuffer there -static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; -static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; -static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA , GL_RGBA , GL_FLOAT }; -static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA , GL_RGBA , GL_FLOAT }; +static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5}; +static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT_ARB}; +static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT}; // image formats: static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; @@ -97,13 +107,21 @@ static textypeinfo_t textype_rgba = {"rgba", static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +#ifdef __ANDROID__ +static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 }; +#endif #else // framebuffer texture formats -static textypeinfo_t textype_shadowmap16 = {"shadowmap16", TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; -static textypeinfo_t textype_shadowmap24 = {"shadowmap24", TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; -static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT }; -static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT }; +static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT}; +static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_HALF_FLOAT_ARB}; +static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT }; // image formats: static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; @@ -147,7 +165,9 @@ typedef enum gltexturetype_e gltexturetype_t; static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP}; +#ifdef GL_TEXTURE_WRAP_R static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2}; +#endif static int cubemapside[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, @@ -163,12 +183,16 @@ typedef struct gltexture_s // this portion of the struct is exposed to the R_GetTexture macro for // speed reasons, must be identical in rtexture_t! int texnum; // GL texture slot number + int renderbuffernum; // GL renderbuffer slot number qboolean dirty; // indicates that R_RealGetTexture should be called + qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT int gltexturetypeenum; // used by R_Mesh_TexBind // d3d stuff the backend needs void *d3dtexture; + void *d3dsurface; #ifdef SUPPORTD3D - qboolean d3disdepthsurface; // for depth/stencil surfaces + qboolean d3disrendertargetsurface; + qboolean d3disdepthstencilsurface; int d3dformat; int d3dusage; int d3dpool; @@ -185,7 +209,7 @@ typedef struct gltexture_s // dynamic texture stuff [11/22/2007 Black] updatecallback_t updatecallback; - void *updatacallback_data; + void *updatecallback_data; // --- [11/22/2007 Black] // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar) @@ -252,24 +276,27 @@ static const unsigned char *texturebuffer; static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) { -#ifdef USE_GLES2 switch(textype) { +#ifdef USE_GLES2 case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba); case TEXTYPE_BGRA: return ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra); +#ifdef __ANDROID__ + case TEXTYPE_ETC1: return &textype_etc1; +#endif case TEXTYPE_ALPHA: return &textype_alpha; - case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; case TEXTYPE_COLORBUFFER: return &textype_colorbuffer; case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f; case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f; - default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); - break; - } + case TEXTYPE_DEPTHBUFFER16: return &textype_depth16; + case TEXTYPE_DEPTHBUFFER24: return &textype_depth24; + case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8; + case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp; + case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw; + case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp; + case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw; #else - switch(textype) - { case TEXTYPE_DXT1: return &textype_dxt1; case TEXTYPE_DXT1A: return &textype_dxt1a; case TEXTYPE_DXT3: return &textype_dxt3; @@ -278,10 +305,16 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba); case TEXTYPE_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra); case TEXTYPE_ALPHA: return &textype_alpha; - case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; case TEXTYPE_COLORBUFFER: return &textype_colorbuffer; case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f; case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f; + case TEXTYPE_DEPTHBUFFER16: return &textype_depth16; + case TEXTYPE_DEPTHBUFFER24: return &textype_depth24; + case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8; + case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp; + case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw; + case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp; + case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw; case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1; case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a; case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3; @@ -289,11 +322,11 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette; case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba); case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra); +#endif default: Host_Error("R_GetTexTypeInfo: unknown texture format"); break; } -#endif return NULL; } @@ -320,13 +353,13 @@ void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void glt->flags |= GLTEXF_DYNAMIC; glt->updatecallback = updatecallback; - glt->updatacallback_data = data; + glt->updatecallback_data = data; } static void R_UpdateDynamicTexture(gltexture_t *glt) { glt->dirty = false; if( glt->updatecallback ) { - glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data ); + glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data ); } } @@ -365,11 +398,16 @@ void R_FreeTexture(rtexture_t *rt) CHECKGLERROR qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR } + if (glt->renderbuffernum) + { + CHECKGLERROR + qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR + } break; case RENDERPATH_D3D9: #ifdef SUPPORTD3D - if (glt->d3disdepthsurface) - IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture); + if (glt->d3dsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface); else if (glt->tiledepth > 1) IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture); else if (glt->sides == 6) @@ -377,6 +415,7 @@ void R_FreeTexture(rtexture_t *rt) else IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture); glt->d3dtexture = NULL; + glt->d3dsurface = NULL; #endif break; case RENDERPATH_D3D10: @@ -557,7 +596,7 @@ static void GL_TextureMode_f (void) for (glt = pool->gltchain;glt;glt = glt->chain) { // only update already uploaded images - if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) + if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) { if (glt->flags & TEXF_MIPMAP) { @@ -721,7 +760,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print for (glt = pool->gltchain;glt;glt = glt->chain) { glsize = R_CalcTexelDataSize(glt); - isloaded = glt->texnum != 0; + isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface; pooltotal++; pooltotalt += glsize; pooltotalp += glt->inputdatasize; @@ -816,7 +855,7 @@ static void r_textures_devicelost(void) { int i, endindex; gltexture_t *glt; - endindex = Mem_ExpandableArray_IndexRange(&texturearray); + endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray); for (i = 0;i < endindex;i++) { glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); @@ -832,8 +871,8 @@ static void r_textures_devicelost(void) break; case RENDERPATH_D3D9: #ifdef SUPPORTD3D - if (glt->d3disdepthsurface) - IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture); + if (glt->d3dsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface); else if (glt->tiledepth > 1) IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture); else if (glt->sides == 6) @@ -841,6 +880,7 @@ static void r_textures_devicelost(void) else IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture); glt->d3dtexture = NULL; + glt->d3dsurface = NULL; #endif break; case RENDERPATH_D3D10: @@ -859,7 +899,7 @@ static void r_textures_devicerestored(void) { int i, endindex; gltexture_t *glt; - endindex = Mem_ExpandableArray_IndexRange(&texturearray); + endindex = (int)Mem_ExpandableArray_IndexRange(&texturearray); for (i = 0;i < endindex;i++) { glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); @@ -877,9 +917,14 @@ static void r_textures_devicerestored(void) #ifdef SUPPORTD3D { HRESULT d3dresult; - if (glt->d3disdepthsurface) + if (glt->d3disrendertargetsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!"); + } + else if (glt->d3disdepthstencilsurface) { - if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL))) + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); } else if (glt->tiledepth > 1) @@ -949,7 +994,9 @@ void R_Textures_Init (void) void R_Textures_Frame (void) { +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT static int old_aniso = 0; +#endif // could do procedural texture animation here, if we keep track of which // textures were accessed this frame... @@ -967,6 +1014,7 @@ void R_Textures_Frame (void) colorconvertbuffer = NULL; } +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT if (old_aniso != gl_texture_anisotropy.integer) { gltexture_t *glt; @@ -1010,9 +1058,10 @@ void R_Textures_Frame (void) break; } } +#endif } -void R_MakeResizeBufferBigger(int size) +static void R_MakeResizeBufferBigger(int size) { if (resizebuffersize < size) { @@ -1035,6 +1084,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet CHECKGLERROR +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP)) { int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy); @@ -1042,6 +1092,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet Cvar_SetValueQuick(&gl_texture_anisotropy, aniso); qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR } +#endif qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR #ifdef GL_TEXTURE_WRAP_R @@ -1096,22 +1147,23 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR } -#ifndef USE_GLES2 - if (textype == TEXTYPE_SHADOWMAP) +#ifdef GL_TEXTURE_COMPARE_MODE_ARB + switch(textype) { - if (vid.support.arb_shadow) - { - if (flags & TEXF_COMPARE) - { - qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR - } - else - { - qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR - } - qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR - } + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP24_COMP: + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR + break; + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_RAW: + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR + qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR + break; + default: + break; } #endif @@ -1204,13 +1256,13 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1); for (height = glt->tileheight;height < glt->inputheight;height <<= 1); for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1); - R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); if (prevbuffer == NULL) { width = glt->tilewidth; height = glt->tileheight; depth = glt->tiledepth; +// R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); // memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel); // prevbuffer = resizebuffer; } @@ -1219,6 +1271,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) if (glt->textype->textype == TEXTYPE_PALETTE) { // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette); prevbuffer = colorconvertbuffer; } @@ -1226,6 +1279,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) { // multiply RGB channels by A channel before uploading int alpha; + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4) { alpha = prevbuffer[i+3]; @@ -1239,12 +1293,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) // scale up to a power of 2 size (if appropriate) if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); prevbuffer = resizebuffer; } // apply mipmap reduction algorithm to get down to picmip/max_size while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); prevbuffer = resizebuffer; } @@ -1258,90 +1314,100 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) case RENDERPATH_GL20: case RENDERPATH_GLES1: case RENDERPATH_GLES2: - CHECKGLERROR - - // we need to restore the texture binding after finishing the upload - GL_ActiveTexture(0); - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); - qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR - -#ifdef GL_TEXTURE_COMPRESSION_HINT_ARB - if (qglGetCompressedTexImageARB) + if (glt->texnum) // not renderbuffers { - if (gl_texturecompression.integer >= 2) - qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST); - else - qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST); CHECKGLERROR - } -#endif - switch(glt->texturetype) - { - case GLTEXTURETYPE_2D: - qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - if (glt->flags & TEXF_MIPMAP) - { - while (width > 1 || height > 1 || depth > 1) - { - Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); - prevbuffer = resizebuffer; - qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - } - } - break; - case GLTEXTURETYPE_3D: + + // we need to restore the texture binding after finishing the upload + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + #ifndef USE_GLES2 - qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - if (glt->flags & TEXF_MIPMAP) +#ifdef GL_TEXTURE_COMPRESSION_HINT_ARB + if (qglGetCompressedTexImageARB) { - while (width > 1 || height > 1 || depth > 1) - { - Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); - prevbuffer = resizebuffer; - qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - } + if (gl_texturecompression.integer >= 2) + qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST); + else + qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST); + CHECKGLERROR } #endif - break; - case GLTEXTURETYPE_CUBEMAP: - // convert and upload each side in turn, - // from a continuous block of input texels - texturebuffer = (unsigned char *)prevbuffer; - for (i = 0;i < 6;i++) +#endif + switch(glt->texturetype) { - prevbuffer = texturebuffer; - texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; - if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) - { - Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); - prevbuffer = resizebuffer; - } - // picmip/max_size - while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + case GLTEXTURETYPE_2D: + qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) { - Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); - prevbuffer = resizebuffer; + while (width > 1 || height > 1 || depth > 1) + { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } } - mip = 0; - qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + break; + case GLTEXTURETYPE_3D: +#ifndef USE_GLES2 + qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR if (glt->flags & TEXF_MIPMAP) { while (width > 1 || height > 1 || depth > 1) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); prevbuffer = resizebuffer; - qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } + } +#endif + break; + case GLTEXTURETYPE_CUBEMAP: + // convert and upload each side in turn, + // from a continuous block of input texels + texturebuffer = (unsigned char *)prevbuffer; + for (i = 0;i < 6;i++) + { + prevbuffer = texturebuffer; + texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; + } + // picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); + prevbuffer = resizebuffer; + } + mip = 0; + qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } } } + break; } - break; + GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR } - GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR break; case RENDERPATH_D3D9: #ifdef SUPPORTD3D - if (!(glt->flags & TEXF_RENDERTARGET)) + if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface) { D3DLOCKED_RECT d3dlockedrect; D3DLOCKED_BOX d3dlockedbox; @@ -1361,6 +1427,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) { while (width > 1 || height > 1 || depth > 1) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); prevbuffer = resizebuffer; if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) @@ -1384,6 +1451,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) { while (width > 1 || height > 1 || depth > 1) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); prevbuffer = resizebuffer; if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits) @@ -1406,12 +1474,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); prevbuffer = resizebuffer; } // picmip/max_size while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); prevbuffer = resizebuffer; } @@ -1426,6 +1496,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) { while (width > 1 || height > 1 || depth > 1) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); prevbuffer = resizebuffer; if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) @@ -1513,12 +1584,14 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); prevbuffer = resizebuffer; } // picmip/max_size while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) { + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); prevbuffer = resizebuffer; } @@ -1607,7 +1680,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break; case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break; case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break; - case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break; + case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break; case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break; case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break; default: @@ -1620,6 +1693,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden { temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); memcpy(temppixels, data, size); + data = temppixels; } Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides); } @@ -1685,7 +1759,10 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden } } break; - case TEXTYPE_SHADOWMAP: + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_COMP: + case TEXTYPE_SHADOWMAP24_RAW: break; case TEXTYPE_DXT1: case TEXTYPE_SRGB_DXT1: @@ -1738,10 +1815,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1; glt->texnum = 0; glt->dirty = false; + glt->glisdepthstencil = false; glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; // init the dynamic texture attributes, too [11/22/2007 Black] glt->updatecallback = NULL; - glt->updatacallback_data = NULL; + glt->updatecallback_data = NULL; GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels); @@ -1779,20 +1857,15 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break; case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break; case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break; - case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break; default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break; } glt->d3dformat = d3dformat; glt->d3dusage = d3dusage; glt->d3dpool = d3dpool; - glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP; - if (glt->d3disdepthsurface) - { - if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL))) - Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); - } - else if (glt->tiledepth > 1) + glt->d3disrendertargetsurface = false; + glt->d3disdepthstencilsurface = false; + if (glt->tiledepth > 1) { if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL))) Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!"); @@ -1827,7 +1900,13 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break; case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break; case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break; - case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break; + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_COMP: + case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break; + case TEXTYPE_DEPTHBUFFER16: + case TEXTYPE_DEPTHBUFFER24: + case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break; case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break; default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype); } @@ -1870,21 +1949,126 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette); } -static int R_ShadowMapTextureFlags(int precision, qboolean filter) +rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter) { - int flags = TEXF_RENDERTARGET | TEXF_CLAMP; - if (filter) - flags |= TEXF_FORCELINEAR | TEXF_COMPARE; - else - flags |= TEXF_FORCENEAREST; - if (precision <= 16) - flags |= TEXF_LOWPRECISION; - return flags; + return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL); } -rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter) +rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype) { - return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL); + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo; + + if (cls.state == ca_dedicated) + return NULL; + + texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP); + + glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); + if (identifier) + strlcpy (glt->identifier, identifier, sizeof(glt->identifier)); + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = width; + glt->inputheight = height; + glt->inputdepth = 1; + glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST; + glt->miplevel = 0; + glt->textype = texinfo; + glt->texturetype = textype; + glt->inputdatasize = width*height*texinfo->internalbytesperpixel; + glt->palette = NULL; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1; + glt->texnum = 0; + glt->dirty = false; + glt->glisdepthstencil = textype == TEXTYPE_DEPTHBUFFER24STENCIL8; + glt->gltexturetypeenum = GL_TEXTURE_2D; + // init the dynamic texture attributes, too [11/22/2007 Black] + glt->updatecallback = NULL; + glt->updatecallback_data = NULL; + + GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels); + + // upload the texture + // data may be NULL (blank texture for dynamic rendering) + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR + qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR + qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR + // note we can query the renderbuffer for info with glGetRenderbufferParameteriv for GL_WIDTH, GL_HEIGHt, GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_INTERNAL_FORMAT + qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DFORMAT d3dformat; + HRESULT d3dresult; + glt->d3disrendertargetsurface = false; + glt->d3disdepthstencilsurface = false; + switch(textype) + { + case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break; + case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break; + case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break; + default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break; + } + glt->d3dformat = d3dformat; + glt->d3dusage = 0; + glt->d3dpool = 0; + if (glt->d3disrendertargetsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!"); + } + else if (glt->d3disdepthstencilsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + { + int tflags = 0; + switch(textype) + { + case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_DEPTHBUFFER16: + case TEXTYPE_DEPTHBUFFER24: + case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype); + } + glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth); + } + break; + } + + return (rtexture_t *)glt; } int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha) @@ -1941,7 +2125,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco mipinfo[0][0] = glt->tilewidth; mipinfo[0][1] = glt->tileheight; mipmaps = 1; - if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1)) + if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1)) { for (mip = 1;mip < 16;mip++) { @@ -2020,7 +2204,12 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco #endif } -rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint +#ifdef __ANDROID__ +// ELUAN: FIXME: separate this code +#include "ktx10/include/ktx.h" +#endif + +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint { int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height; //int dds_flags; @@ -2039,17 +2228,161 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen unsigned char *dds; fs_offset_t ddsfilesize; unsigned int ddssize; - qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1); + qboolean force_swdecode, npothack; +#ifdef __ANDROID__ + // ELUAN: FIXME: separate this code + char vabuf[1024]; + char vabuf2[1024]; + int strsize; + KTX_dimensions sizes; +#endif if (cls.state == ca_dedicated) return NULL; +#ifdef __ANDROID__ + // ELUAN: FIXME: separate this code + if (vid.renderpath != RENDERPATH_GLES2) + { + Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n"); + return NULL; + } + + // some textures are specified with extensions, so it becomes .tga.dds + FS_StripExtension (filename, vabuf2, sizeof(vabuf2)); + FS_StripExtension (vabuf2, vabuf, sizeof(vabuf)); + FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf)); + strsize = strlen(vabuf); + if (strsize > 5) + for (i = 0; i <= strsize - 4; i++) // copy null termination + vabuf[i] = vabuf[i + 4]; + + Con_DPrintf("Loading %s...\n", vabuf); + dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize); + ddssize = ddsfilesize; + + if (!dds) + { + Con_DPrintf("Not found!\n"); + return NULL; // not found + } + Con_DPrintf("Found!\n"); + + if (flags & TEXF_ALPHA) + { + Con_DPrintf("KTX texture with alpha not supported yet, disabling\n"); + flags &= ~TEXF_ALPHA; + } + + { + GLenum target; + GLenum glerror; + GLboolean isMipmapped; + KTX_error_code ktxerror; + + glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); + + // texture uploading can take a while, so make sure we're sending keepalives + CL_KeepaliveMessage(false); + + // create the texture object + CHECKGLERROR + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[GLTEXTURETYPE_2D]); + qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + qglBindTexture(gltexturetypeenums[GLTEXTURETYPE_2D], glt->texnum);CHECKGLERROR + + // upload the texture + // we need to restore the texture binding after finishing the upload + + // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later. + ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror, + 0, NULL);// can't CHECKGLERROR, the lib catches it + + // FIXME: delete texture if we fail here + if (target != GL_TEXTURE_2D) + { + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + Mem_Free(dds); + Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target); + return NULL; // FIXME: delete the texture from memory + } + + if (KTX_SUCCESS == ktxerror) + { + textype = TEXTYPE_ETC1; + flags &= ~TEXF_COMPRESS; // don't let the textype be wrong + + // return whether this texture is transparent + if (hasalphaflag) + *hasalphaflag = (flags & TEXF_ALPHA) != 0; + + // TODO: apply gl_picmip + // TODO: avgcolor + // TODO: srgb + // TODO: only load mipmaps if requested + + if (isMipmapped) + flags |= TEXF_MIPMAP; + else + flags &= ~TEXF_MIPMAP; + + texinfo = R_GetTexTypeInfo(textype, flags); + + strlcpy (glt->identifier, vabuf, sizeof(glt->identifier)); + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = sizes.width; + glt->inputheight = sizes.height; + glt->inputdepth = 1; + glt->flags = flags; + glt->textype = texinfo; + glt->texturetype = GLTEXTURETYPE_2D; + glt->inputdatasize = ddssize; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = 1; + glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; + glt->tilewidth = sizes.width; + glt->tileheight = sizes.height; + glt->tiledepth = 1; + glt->miplevels = isMipmapped ? 1 : 0; // FIXME + + // after upload we have to set some parameters... +#ifdef GL_TEXTURE_MAX_LEVEL + /* FIXME + if (dds_miplevels >= 1 && !mipcomplete) + { + // need to set GL_TEXTURE_MAX_LEVEL + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR + } + */ +#endif + GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); + + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + Mem_Free(dds); + return (rtexture_t *)glt; + } + else + { + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + Mem_Free(dds); + Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror); + return NULL; + } + } +#endif // __ANDROID__ + dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize); ddssize = ddsfilesize; if (!dds) { - if(r_texture_dds_load_logfailure.integer) + if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture)) Log_Printf("ddstexturefailures.log", "%s\n", filename); return NULL; // not found } @@ -2113,9 +2446,9 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Con_Printf("^1%s: invalid DXT1 DDS image\n", filename); return NULL; } - if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA)) + if (flags & TEXF_ALPHA) { - if(r_texture_dds_load_alphamode.integer == 1) + if (r_texture_dds_load_alphamode.integer == 1) { // check alpha for (i = 0;i < size;i += bytesperblock) @@ -2132,6 +2465,8 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen else flags &= ~TEXF_ALPHA; } + else if (r_texture_dds_load_alphamode.integer == 0) + textype = TEXTYPE_DXT1A; else { flags &= ~TEXF_ALPHA; @@ -2214,9 +2549,17 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen } force_swdecode = false; + npothack = + (!vid.support.arb_texture_non_power_of_two && + ( + (dds_width & (dds_width - 1)) + || + (dds_height & (dds_height - 1)) + ) + ); if(bytesperblock) { - if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc) + if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack) { if(r_texture_dds_swdecode.integer > 1) force_swdecode = true; @@ -2327,7 +2670,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F); avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F); if(textype == TEXTYPE_DXT5) - avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]); + avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f); else if(textype == TEXTYPE_DXT3) avgcolor[3] += ( (mippixels_start[i-8] & 0x0F) @@ -2338,11 +2681,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen + (mippixels_start[i-6] >> 4) + (mippixels_start[i-5] & 0x0F) + (mippixels_start[i-5] >> 4) - ) * (0.125f / 15.0f * 255.0f); + ) * (0.125f / 15.0f); else - avgcolor[3] += 255; + avgcolor[3] += 1.0f; } - f = (float)bytesperblock / size; + f = (float)bytesperblock / mipsize; avgcolor[0] *= (0.5f / 31.0f) * f; avgcolor[1] *= (0.5f / 63.0f) * f; avgcolor[2] *= (0.5f / 31.0f) * f; @@ -2357,7 +2700,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen avgcolor[2] += mippixels[i]; avgcolor[3] += mippixels[i+3]; } - f = (1.0f / 255.0f) * bytesperpixel / size; + f = (1.0f / 255.0f) * bytesperpixel / mipsize; avgcolor[0] *= f; avgcolor[1] *= f; avgcolor[2] *= f; @@ -2494,6 +2837,12 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen glt->tiledepth = 1; glt->miplevels = dds_miplevels; + if(npothack) + { + for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1); + for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1); + } + // texture uploading can take a while, so make sure we're sending keepalives CL_KeepaliveMessage(false); @@ -2548,9 +2897,25 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel { + unsigned char *upload_mippixels = mippixels; + int upload_mipwidth = mipwidth; + int upload_mipheight = mipheight; mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; if (mippixels + mipsize > mippixels_start + mipsize_total) break; + if(npothack) + { + upload_mipwidth = (glt->tilewidth >> mip); + upload_mipheight = (glt->tileheight >> mip); + if(upload_mipwidth != mipwidth || upload_mipheight != mipheight) + // I _think_ they always mismatch, but I was too lazy + // to properly check, and this test here is really + // harmless + { + upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight); + Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer); + } + } switch(vid.renderpath) { case RENDERPATH_GL11: @@ -2560,11 +2925,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen case RENDERPATH_GLES2: if (bytesperblock) { - qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR + qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR } else { - qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR + qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR } break; case RENDERPATH_D3D9: @@ -2573,7 +2938,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen D3DLOCKED_RECT d3dlockedrect; if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) { - memcpy(d3dlockedrect.pBits, mippixels, mipsize); + memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize); IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); } break; @@ -2590,11 +2955,13 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen if (bytesperblock) Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); else - DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels); + DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels); // DPSOFTRAST calculates its own mipmaps mip = dds_miplevels; break; } + if(upload_mippixels != mippixels) + Mem_Free(upload_mippixels); mippixels += mipsize; if (mipwidth <= 1 && mipheight <= 1) {