X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_textures.c;h=c970f8cae333407d7de4f764f25e20b664e6b6ad;hp=bf504d96f68f4f5ae6e54de29276c1c3bc56e774;hb=85a33377d64ae8438e6582a7b8472f5a4bd41942;hpb=cb9437e103e973ba5833636ba973833945a2a148 diff --git a/gl_textures.c b/gl_textures.c index bf504d96..c970f8ca 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -1,9 +1,5 @@ #include "quakedef.h" -#ifdef SUPPORTD3D -#include -extern LPDIRECT3DDEVICE9 vid_d3d9dev; -#endif #include "image.h" #include "jpeg.h" #include "image_png.h" @@ -30,22 +26,16 @@ cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompressio cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"}; cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"}; cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"}; -cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"}; +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, 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; int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; int gl_filter_mag = GL_LINEAR; -#ifdef SUPPORTD3D -int d3d_filter_flatmin = D3DTEXF_LINEAR; -int d3d_filter_flatmag = D3DTEXF_LINEAR; -int d3d_filter_flatmix = D3DTEXF_POINT; -int d3d_filter_mipmin = D3DTEXF_LINEAR; -int d3d_filter_mipmag = D3DTEXF_LINEAR; -int d3d_filter_mipmix = D3DTEXF_LINEAR; -int d3d_filter_nomip = false; -#endif - static mempool_t *texturemempool; static memexpandablearray_t texturearray; @@ -58,6 +48,7 @@ static memexpandablearray_t texturearray; typedef struct textypeinfo_s { + const char *name; textype_t textype; int inputbytesperpixel; int internalbytesperpixel; @@ -68,47 +59,102 @@ typedef struct textypeinfo_s } textypeinfo_t; - -static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, 3 , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, 4 , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, 3 , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; -static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; -static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; -static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 }; -static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 }; -static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 }; -static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, 4 , GL_BGRA , GL_UNSIGNED_BYTE }; - +#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_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}; +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 }; +static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; +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_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 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +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 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8}; +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 , GL_RGBA , GL_HALF_FLOAT }; +static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.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 }; +static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE }; +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_rgba_compress = {"rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha_compress = {"rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , 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 }; +static textypeinfo_t textype_bgra_compress = {"bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha_compress = {"bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_compress = {"sRGB_rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha_compress = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_compress = {"sRGB_bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha_compress = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 }; +#endif typedef enum gltexturetype_e { GLTEXTURETYPE_2D, GLTEXTURETYPE_3D, GLTEXTURETYPE_CUBEMAP, - GLTEXTURETYPE_RECTANGLE, GLTEXTURETYPE_TOTAL } gltexturetype_t; -static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB}; -static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2}; +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_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; typedef struct gltexture_s @@ -116,28 +162,14 @@ 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; -#ifdef SUPPORTD3D - int d3dformat; - int d3dusage; - int d3dpool; - int d3daddressu; - int d3daddressv; - int d3daddressw; - int d3dmagfilter; - int d3dminfilter; - int d3dmipfilter; - int d3dmaxmiplevelfilter; - int d3dmipmaplodbias; - int d3dmaxmiplevel; -#endif // 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) @@ -169,7 +201,6 @@ typedef struct gltexture_s // palette if the texture is TEXTYPE_PALETTE const unsigned int *palette; // actual stored texture size after gl_picmip and gl_max_size are applied - // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported) int tilewidth, tileheight, tiledepth; // 1 or 6 depending on texturetype int sides; @@ -206,32 +237,53 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) { switch(textype) { - case TEXTYPE_DXT1: - return &textype_dxt1; - case TEXTYPE_DXT1A: - return &textype_dxt1a; - case TEXTYPE_DXT3: - return &textype_dxt3; - case TEXTYPE_DXT5: - return &textype_dxt5; - case TEXTYPE_PALETTE: - return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; - case TEXTYPE_RGBA: - if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression) - return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress; - return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba; - case TEXTYPE_BGRA: - if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression) - return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress; - return (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; +#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_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; +#else + case TEXTYPE_DXT1: return &textype_dxt1; + case TEXTYPE_DXT1A: return &textype_dxt1a; + case TEXTYPE_DXT3: return &textype_dxt3; + case TEXTYPE_DXT5: return &textype_dxt5; + case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; + 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_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; + case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5; + 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"); + Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags); break; } return NULL; @@ -260,13 +312,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 ); } } @@ -291,10 +343,23 @@ void R_FreeTexture(rtexture_t *rt) else Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier); - if (glt->texnum) + R_Mesh_ClearBindingsForTexture(glt->texnum); + + switch(vid.renderpath) { - CHECKGLERROR - qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + case RENDERPATH_GL32: + case RENDERPATH_GLES2: + if (glt->texnum) + { + CHECKGLERROR + qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + } + if (glt->renderbuffernum) + { + CHECKGLERROR + qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR + } + break; } if (glt->inputtexels) @@ -340,7 +405,7 @@ void R_FreeTexturePool(rtexturepool_t **rtexturepool) typedef struct glmode_s { - char *name; + const char *name; int minification, magnification; } glmode_t; @@ -355,25 +420,6 @@ static glmode_t modes[6] = {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} }; -#ifdef SUPPORTD3D -typedef struct d3dmode_s -{ - char *name; - int m1, m2; -} -d3dmode_t; - -static d3dmode_t d3dmodes[6] = -{ - {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT}, - {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT}, - {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT}, - {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT}, - {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR}, - {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR} -}; -#endif - static void GL_TextureMode_f (void) { int i; @@ -411,10 +457,8 @@ static void GL_TextureMode_f (void) switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: // change all the existing mipmap texture objects // FIXME: force renderer(/client/something?) restart instead? CHECKGLERROR @@ -442,43 +486,6 @@ static void GL_TextureMode_f (void) } } break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - d3d_filter_flatmin = d3dmodes[i].m1; - d3d_filter_flatmag = d3dmodes[i].m1; - d3d_filter_flatmix = D3DTEXF_POINT; - d3d_filter_mipmin = d3dmodes[i].m1; - d3d_filter_mipmag = d3dmodes[i].m1; - d3d_filter_mipmix = d3dmodes[i].m2; - d3d_filter_nomip = i < 2; - if (gl_texture_anisotropy.integer > 1 && i == 5) - d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC; - for (pool = gltexturepoolchain;pool;pool = pool->next) - { - for (glt = pool->gltchain;glt;glt = glt->chain) - { - // only update already uploaded images - if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) - { - if (glt->flags & TEXF_MIPMAP) - { - glt->d3dminfilter = d3d_filter_mipmin; - glt->d3dmagfilter = d3d_filter_mipmag; - glt->d3dmipfilter = d3d_filter_mipmix; - glt->d3dmaxmiplevelfilter = 0; - } - else - { - glt->d3dminfilter = d3d_filter_flatmin; - glt->d3dmagfilter = d3d_filter_flatmag; - glt->d3dmipfilter = d3d_filter_flatmix; - glt->d3dmaxmiplevelfilter = 0; - } - } - } - } -#endif - break; } } @@ -505,39 +512,9 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i break; } - if (outwidth) - { - if (vid.support.arb_texture_non_power_of_two) - width2 = min(inwidth >> picmip, maxsize); - else - { - for (width2 = 1;width2 < inwidth;width2 <<= 1); - for (width2 >>= picmip;width2 > maxsize;width2 >>= 1); - } - *outwidth = max(1, width2); - } - if (outheight) - { - if (vid.support.arb_texture_non_power_of_two) - height2 = min(inheight >> picmip, maxsize); - else - { - for (height2 = 1;height2 < inheight;height2 <<= 1); - for (height2 >>= picmip;height2 > maxsize;height2 >>= 1); - } - *outheight = max(1, height2); - } - if (outdepth) - { - if (vid.support.arb_texture_non_power_of_two) - depth2 = min(indepth >> picmip, maxsize); - else - { - for (depth2 = 1;depth2 < indepth;depth2 <<= 1); - for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1); - } - *outdepth = max(1, depth2); - } + width2 = min(inwidth >> picmip, maxsize); + height2 = min(inheight >> picmip, maxsize); + depth2 = min(indepth >> picmip, maxsize); miplevels = 1; if (flags & TEXF_MIPMAP) @@ -546,6 +523,13 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i while(extent >>= 1) miplevels++; } + + if (outwidth) + *outwidth = max(1, width2); + if (outheight) + *outheight = max(1, height2); + if (outdepth) + *outdepth = max(1, depth2); if (outmiplevels) *outmiplevels = miplevels; } @@ -597,7 +581,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; pooltotal++; pooltotalt += glsize; pooltotalp += glt->inputdatasize; @@ -608,7 +592,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print poolloadedp += glt->inputdatasize; } if (printeach) - Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier); + Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier); } if (printpool) Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0); @@ -632,23 +616,13 @@ static void r_textures_start(void) { switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: // LordHavoc: allow any alignment CHECKGLERROR qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR break; - case RENDERPATH_D3D9: - 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; } texturemempool = Mem_AllocPool("texture management", 0, NULL); @@ -689,7 +663,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); @@ -697,27 +671,8 @@ static void r_textures_devicelost(void) continue; switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - if (glt->tiledepth > 1) - IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture); - else if (glt->sides == 6) - IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture); - else - IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture); - glt->d3dtexture = NULL; -#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__); + case RENDERPATH_GL32: + case RENDERPATH_GLES2: break; } } @@ -727,7 +682,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); @@ -735,38 +690,8 @@ static void r_textures_devicerestored(void) continue; switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - { - HRESULT d3dresult; - 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!"); - } - else if (glt->sides == 6) - { - if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL))) - Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!"); - } - else - { - if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL))) - Sys_Error("IDirect3DDevice9_CreateTexture 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__); + case RENDERPATH_GL32: + case RENDERPATH_GLES2: break; } } @@ -798,14 +723,21 @@ void R_Textures_Init (void) Cvar_RegisterVariable (&gl_texturecompression_sky); Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps); Cvar_RegisterVariable (&gl_texturecompression_reflectmask); + Cvar_RegisterVariable (&gl_texturecompression_sprites); Cvar_RegisterVariable (&gl_nopartialtextureupdates); + Cvar_RegisterVariable (&r_texture_dds_load_alphamode); + Cvar_RegisterVariable (&r_texture_dds_load_logfailure); + Cvar_RegisterVariable (&r_texture_dds_swdecode); R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored); } void R_Textures_Frame (void) { +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT static int old_aniso = 0; + static qboolean first_time_aniso = true; +#endif // could do procedural texture animation here, if we keep track of which // textures were accessed this frame... @@ -823,6 +755,7 @@ void R_Textures_Frame (void) colorconvertbuffer = NULL; } +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT if (old_aniso != gl_texture_anisotropy.integer) { gltexture_t *glt; @@ -835,10 +768,14 @@ void R_Textures_Frame (void) switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: + // ignore the first difference, any textures loaded by now probably had the same aniso value + if (first_time_aniso) + { + first_time_aniso = false; + break; + } CHECKGLERROR GL_ActiveTexture(0); for (pool = gltexturepoolchain;pool;pool = pool->next) @@ -858,15 +795,12 @@ void R_Textures_Frame (void) } } break; - case RENDERPATH_D3D9: - case RENDERPATH_D3D10: - case RENDERPATH_D3D11: - break; } } +#endif } -void R_MakeResizeBufferBigger(int size) +static void R_MakeResizeBufferBigger(int size) { if (resizebuffersize < size) { @@ -889,6 +823,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); @@ -896,12 +831,15 @@ 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 if (gltexturetypedimensions[texturetype] >= 3) { qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR } +#endif CHECKGLERROR if (!gl_filter_force && flags & TEXF_FORCENEAREST) @@ -948,160 +886,152 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR } - if (textype == TEXTYPE_SHADOWMAP) +#ifndef USE_GLES2 + 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 - } - qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP24_COMP: + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR + break; + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_RAW: + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR + break; + default: + break; } +#endif CHECKGLERROR } -static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth) +static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth) { - int i, mip, width, height, depth; - GLint oldbindtexnum = 0; - const unsigned char *prevbuffer; - prevbuffer = data; + if (data == NULL) + Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier); + + if (glt->texturetype != GLTEXTURETYPE_2D) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier); + + if (glt->textype->textype == TEXTYPE_PALETTE) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier); + + if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) + Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier); + + if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1) + Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier); + + // update a portion of the image switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - 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 - break; - case RENDERPATH_D3D9: - case RENDERPATH_D3D10: - case RENDERPATH_D3D11: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: + { + int oldbindtexnum; + 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 + qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } break; } +} - // these are rounded up versions of the size to do better resampling - if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE) - { - width = glt->inputwidth; - height = glt->inputheight; - depth = glt->inputdepth; - } - else - { - for (width = 1;width < glt->inputwidth ;width <<= 1); - for (height = 1;height < glt->inputheight;height <<= 1); - for (depth = 1;depth < glt->inputdepth ;depth <<= 1); - } +static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) +{ + int i, mip = 0, width, height, depth; + GLint oldbindtexnum = 0; + const unsigned char *prevbuffer; + prevbuffer = data; + + // error out if a stretch is needed on special texture types + if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth)) + Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier); - R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); - R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel); + // when picmip or maxsize is applied, we scale up to a power of 2 multiple + // of the target size and then use the mipmap reduction function to get + // high quality supersampled results + 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); if (prevbuffer == NULL) { - memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel); - prevbuffer = resizebuffer; + 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; } - else if (glt->textype->textype == TEXTYPE_PALETTE) - { - // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code - Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette); - prevbuffer = colorconvertbuffer; - } - - // upload the image - preferring to do only complete uploads (drivers do not really like partial updates) - - if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight)) + else { - // update a portion of the image - if (glt->texturetype != GLTEXTURETYPE_2D) - Sys_Error("R_Upload: partial update of type other than 2D"); - switch(vid.renderpath) + if (glt->textype->textype == TEXTYPE_PALETTE) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR - break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - { - RECT d3drect; - D3DLOCKED_RECT d3dlockedrect; - int y; - memset(&d3drect, 0, sizeof(d3drect)); - d3drect.left = fragx; - d3drect.top = fragy; - d3drect.right = fragx+fragwidth; - d3drect.bottom = fragy+fragheight; - if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits) - { - for (y = 0;y < fragheight;y++) - memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel); - IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0); - } - } -#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; + // 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; } - } - else - { - if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth) - Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n"); - - // cubemaps contain multiple images and thus get processed a bit differently - if (glt->texturetype != GLTEXTURETYPE_CUBEMAP) + if (glt->flags & TEXF_RGBMULTIPLYBYALPHA) { - if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + // 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) { - 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) - { - Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); - prevbuffer = resizebuffer; + alpha = prevbuffer[i+3]; + colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8; + colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8; + colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8; + colorconvertbuffer[i+3] = alpha; } + prevbuffer = colorconvertbuffer; } - mip = 0; - switch(vid.renderpath) + // scale up to a power of 2 size (if appropriate) + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - if (qglGetCompressedTexImageARB) - { - if (gl_texturecompression.integer >= 2) - qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST); - else - qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST); - CHECKGLERROR - } + 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; + } + } + + // do the appropriate upload type... + switch(vid.renderpath) + { + case RENDERPATH_GL32: + case RENDERPATH_GLES2: + if (glt->texnum) // not renderbuffers + { + 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 + +#ifndef USE_GLES2 + if (gl_texturecompression.integer >= 2) + qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); + else + qglHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST); + CHECKGLERROR +#endif switch(glt->texturetype) { case GLTEXTURETYPE_2D: @@ -1110,6 +1040,7 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int { 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 @@ -1117,16 +1048,19 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int } 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; 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, @@ -1138,12 +1072,14 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int 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; } @@ -1153,6 +1089,7 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int { 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 @@ -1160,197 +1097,96 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int } } break; - case GLTEXTURETYPE_RECTANGLE: - qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR - break; } GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } + break; + } +} + +static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette) +{ + int i, size; + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo, *texinfo2; + unsigned char *temppixels = NULL; + qboolean swaprb; + + if (cls.state == ca_dedicated) + return NULL; + + // see if we need to swap red and blue (BGRA <-> RGBA conversion) + if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA) + { + int numpixels = width * height * depth * sides; + size = numpixels * 4; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + if (data) + { + const unsigned char *p; + unsigned char *o = temppixels; + for (i = 0;i < numpixels;i++, o += 4) + { + p = (const unsigned char *)palette + 4*data[i]; + o[0] = p[2]; + o[1] = p[1]; + o[2] = p[0]; + o[3] = p[3]; + } + } + data = temppixels; + textype = TEXTYPE_RGBA; + } + swaprb = false; + switch(textype) + { + case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break; + case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break; + case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break; + case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break; + default: break; + } + if (swaprb) + { + // swap bytes + static int rgbaswapindices[4] = {2, 1, 0, 3}; + size = width * height * depth * sides * 4; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + if (data) + Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices); + data = temppixels; + } + + // if sRGB texture formats are not supported, convert input to linear and upload as normal types + if (!vid.support.ext_texture_srgb) + { + qboolean convertsRGB = false; + switch(textype) + { + case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break; + 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_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break; + case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break; + default: break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - if (!(glt->flags & TEXF_RENDERTARGET)) + } + if (convertsRGB && data) + { + size = width * height * depth * sides * 4; + if (!temppixels) { - D3DLOCKED_RECT d3dlockedrect; - D3DLOCKED_BOX d3dlockedbox; - switch(glt->texturetype) - { - case GLTEXTURETYPE_2D: - if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) - { - if (prevbuffer) - memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); - else - memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel); - IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); - } - mip++; - if ((glt->flags & TEXF_MIPMAP) && prevbuffer) - { - while (width > 1 || height > 1 || depth > 1) - { - 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) - { - memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); - IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); - } - mip++; - } - } - break; - case GLTEXTURETYPE_3D: - if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits) - { - // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes - memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel); - IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip); - } - mip++; - if (glt->flags & TEXF_MIPMAP) - { - while (width > 1 || height > 1 || depth > 1) - { - 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) - { - // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes - memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel); - IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip); - } - mip++; - } - } - 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) - { - 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) - { - Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); - prevbuffer = resizebuffer; - } - mip = 0; - if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) - { - memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); - IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip); - } - mip++; - if (glt->flags & TEXF_MIPMAP) - { - while (width > 1 || height > 1 || depth > 1) - { - 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) - { - memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); - IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip); - } - mip++; - } - } - } - break; - case GLTEXTURETYPE_RECTANGLE: - Sys_Error("Direct3D does not have RECTANGLE textures\n"); - break; - } - } - glt->d3daddressw = 0; - if (glt->flags & TEXF_CLAMP) - { - glt->d3daddressu = D3DTADDRESS_CLAMP; - glt->d3daddressv = D3DTADDRESS_CLAMP; - if (glt->tiledepth > 1) - glt->d3daddressw = D3DTADDRESS_CLAMP; - } - else - { - glt->d3daddressu = D3DTADDRESS_WRAP; - glt->d3daddressv = D3DTADDRESS_WRAP; - if (glt->tiledepth > 1) - glt->d3daddressw = D3DTADDRESS_WRAP; - } - glt->d3dmipmaplodbias = 0; - glt->d3dmaxmiplevel = 0; - glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel; - if (glt->flags & TEXF_FORCELINEAR) - { - glt->d3dminfilter = D3DTEXF_LINEAR; - glt->d3dmagfilter = D3DTEXF_LINEAR; - glt->d3dmipfilter = D3DTEXF_POINT; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + memcpy(temppixels, data, size); + data = temppixels; } - else if (glt->flags & TEXF_FORCENEAREST) - { - glt->d3dminfilter = D3DTEXF_POINT; - glt->d3dmagfilter = D3DTEXF_POINT; - glt->d3dmipfilter = D3DTEXF_POINT; - } - else if (glt->flags & TEXF_MIPMAP) - { - glt->d3dminfilter = d3d_filter_mipmin; - glt->d3dmagfilter = d3d_filter_mipmag; - glt->d3dmipfilter = d3d_filter_mipmix; - } - else - { - glt->d3dminfilter = d3d_filter_flatmin; - glt->d3dmagfilter = d3d_filter_flatmag; - glt->d3dmipfilter = d3d_filter_flatmix; - } -#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; + Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides); } } -} - -static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette) -{ - int i, size; - gltexture_t *glt; - gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; - textypeinfo_t *texinfo, *texinfo2; - unsigned char *temppixels = NULL; - - if (cls.state == ca_dedicated) - return NULL; - - if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle) - { - Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n"); - return NULL; - } - if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map) - { - Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n"); - return NULL; - } - if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d) - { - Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n"); - return NULL; - } texinfo = R_GetTexTypeInfo(textype, flags); size = width * height * depth * sides * texinfo->inputbytesperpixel; @@ -1360,21 +1196,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden return NULL; } - if (textype == TEXTYPE_RGBA) - { - // swap bytes - static int rgbaswapindices[4] = {2, 1, 0, 3}; - textype = TEXTYPE_BGRA; - texinfo = R_GetTexTypeInfo(textype, flags); - temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4); - Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices); - data = temppixels; - } - // clear the alpha flag if the texture has no transparent pixels switch(textype) { case TEXTYPE_PALETTE: + case TEXTYPE_SRGB_PALETTE: if (flags & TEXF_ALPHA) { flags &= ~TEXF_ALPHA; @@ -1393,6 +1219,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden break; case TEXTYPE_RGBA: case TEXTYPE_BGRA: + case TEXTYPE_SRGB_RGBA: + case TEXTYPE_SRGB_BGRA: if (flags & TEXF_ALPHA) { flags &= ~TEXF_ALPHA; @@ -1409,19 +1237,28 @@ 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: break; case TEXTYPE_DXT1A: + case TEXTYPE_SRGB_DXT1A: case TEXTYPE_DXT3: + case TEXTYPE_SRGB_DXT3: case TEXTYPE_DXT5: + case TEXTYPE_SRGB_DXT5: flags |= TEXF_ALPHA; break; case TEXTYPE_ALPHA: flags |= TEXF_ALPHA; break; case TEXTYPE_COLORBUFFER: + case TEXTYPE_COLORBUFFER16F: + case TEXTYPE_COLORBUFFER32F: flags |= TEXF_ALPHA; break; default: @@ -1456,10 +1293,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); @@ -1467,67 +1305,14 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden // data may be NULL (blank texture for dynamic rendering) switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: CHECKGLERROR qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - { - D3DFORMAT d3dformat; - D3DPOOL d3dpool; - DWORD d3dusage; - HRESULT d3dresult; - d3dusage = 0; - d3dpool = D3DPOOL_MANAGED; - if (flags & TEXF_RENDERTARGET) - { - d3dusage |= D3DUSAGE_RENDERTARGET; - d3dpool = D3DPOOL_DEFAULT; - } - switch(textype) - { - case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; - case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break; - case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; - case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;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; - 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!"); - } - else if (glt->sides == 6) - { - if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL))) - Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!"); - } - else - { - if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL))) - Sys_Error("IDirect3DDevice9_CreateTexture 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; } - R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth); + R_UploadFullTexture(glt, data); if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer) glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel); @@ -1557,40 +1342,75 @@ 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); } -rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette) +rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter) { - return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette); + return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL); } -static int R_ShadowMapTextureFlags(int precision, qboolean filter) +rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype) { - 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; -} + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo; -rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter) -{ - return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL); -} + if (cls.state == ca_dedicated) + return NULL; -rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter) -{ - return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL); -} + texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP); -rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter) -{ - return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL); + 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_GL32: + 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; + } + + return (rtexture_t *)glt; } -int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed) +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha) { +#ifdef USE_GLES2 + return -1; // unsupported on this platform +#else gltexture_t *glt = (gltexture_t *)rt; unsigned char *dds; int oldbindtexnum; @@ -1625,13 +1445,22 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break; } + // if premultiplied alpha, say so in the DDS file + if(glt->flags & TEXF_RGBMULTIPLYBYALPHA) + { + switch(internalformat) + { + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break; + } + } if (!bytesperblock && skipuncompressed) return -3; // skipped memset(mipinfo, 0, sizeof(mipinfo)); mipinfo[0][0] = glt->tilewidth; mipinfo[0][1] = glt->tileheight; mipmaps = 1; - if (glt->flags & TEXF_MIPMAP) + if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1)) { for (mip = 1;mip < 16;mip++) { @@ -1664,19 +1493,21 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco else { dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH - dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS + dds_format_flags = 0x40; // DDPF_RGB } if (mipmaps) { dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX } + if(hasalpha) + dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS memcpy(dds, "DDS ", 4); - StoreLittleLong(dds+4, ddssize); + StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so StoreLittleLong(dds+8, dds_flags); StoreLittleLong(dds+12, mipinfo[0][1]); // height StoreLittleLong(dds+16, mipinfo[0][0]); // width - StoreLittleLong(dds+24, 1); // depth + StoreLittleLong(dds+24, 0); // depth StoreLittleLong(dds+28, mipmaps); // mipmaps StoreLittleLong(dds+76, 32); // format size StoreLittleLong(dds+80, dds_format_flags); @@ -1688,7 +1519,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco memcpy(dds+84, ddsfourcc, 4); for (mip = 0;mip < mipmaps;mip++) { - qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR + qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR } } else @@ -1705,9 +1536,15 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco ret = FS_WriteFile(filename, dds, ddssize); Mem_Free(dds); return ret ? ddssize : -5; +#endif } -rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, 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; @@ -1717,23 +1554,171 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen gltexture_t *glt; gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; textypeinfo_t *texinfo; - int mip, mipwidth, mipheight, mipsize; - unsigned int c; + int mip, mipwidth, mipheight, mipsize, mipsize_total; + unsigned int c, r, g, b; GLint oldbindtexnum = 0; - const unsigned char *mippixels, *ddspixels; + unsigned char *mippixels; + unsigned char *mippixels_start; + unsigned char *ddspixels; unsigned char *dds; fs_offset_t ddsfilesize; unsigned int ddssize; + qboolean force_swdecode; +#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) { - Log_Printf("ddstexturefailures.log", "%s\n", filename); + 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 } @@ -1751,11 +1736,16 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen dds_height = BuffLittleLong(dds+12); ddspixels = dds + 128; - flags &= ~TEXF_ALPHA; + if(r_texture_dds_load_alphamode.integer == 0) + if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS + flags &= ~TEXF_ALPHA; + + //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it! if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32) { // very sloppy BGRA 32bit identification textype = TEXTYPE_BGRA; + flags &= ~TEXF_COMPRESS; // don't let the textype be wrong bytesperblock = 0; bytesperpixel = 4; size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel); @@ -1765,12 +1755,15 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Con_Printf("^1%s: invalid BGRA DDS image\n", filename); return NULL; } - // check alpha - for (i = 3;i < size;i += 4) - if (ddspixels[i] < 255) - break; - if (i >= size) - flags &= ~TEXF_ALPHA; + if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA)) + { + // check alpha + for (i = 3;i < size;i += 4) + if (ddspixels[i] < 255) + break; + if (i >= size) + flags &= ~TEXF_ALPHA; + } } else if (!memcmp(dds+84, "DXT1", 4)) { @@ -1788,16 +1781,49 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Con_Printf("^1%s: invalid DXT1 DDS image\n", filename); return NULL; } - for (i = 0;i < size;i += bytesperblock) - if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256) - break; - if (i < size) - textype = TEXTYPE_DXT1A; - else - flags &= ~TEXF_ALPHA; + if (flags & TEXF_ALPHA) + { + if (r_texture_dds_load_alphamode.integer == 1) + { + // check alpha + for (i = 0;i < size;i += bytesperblock) + if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256) + { + // NOTE: this assumes sizeof(unsigned int) == 4 + unsigned int data = * (unsigned int *) &(ddspixels[i+4]); + // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel) + if(data & (data<<1) & 0xAAAAAAAA)//rgh + break; + } + if (i < size) + textype = TEXTYPE_DXT1A; + else + flags &= ~TEXF_ALPHA; + } + else if (r_texture_dds_load_alphamode.integer == 0) + textype = TEXTYPE_DXT1A; + else + { + flags &= ~TEXF_ALPHA; + } + } } - else if (!memcmp(dds+84, "DXT3", 4)) + else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4)) { + if(!memcmp(dds+84, "DXT2", 4)) + { + if(!(flags & TEXF_RGBMULTIPLYBYALPHA)) + { + Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename); + } + } + else + { + if(flags & TEXF_RGBMULTIPLYBYALPHA) + { + Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename); + } + } textype = TEXTYPE_DXT3; bytesperblock = 16; bytesperpixel = 0; @@ -1808,9 +1834,24 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Con_Printf("^1%s: invalid DXT3 DDS image\n", filename); return NULL; } + // we currently always assume alpha } - else if (!memcmp(dds+84, "DXT5", 4)) + else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4)) { + if(!memcmp(dds+84, "DXT4", 4)) + { + if(!(flags & TEXF_RGBMULTIPLYBYALPHA)) + { + Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename); + } + } + else + { + if(flags & TEXF_RGBMULTIPLYBYALPHA) + { + Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename); + } + } textype = TEXTYPE_DXT5; bytesperblock = 16; bytesperpixel = 0; @@ -1821,6 +1862,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Con_Printf("^1%s: invalid DXT5 DDS image\n", filename); return NULL; } + // we currently always assume alpha } else { @@ -1829,10 +1871,118 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen return NULL; } + // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1 + if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5)) + { + textype = TEXTYPE_DXT1; + bytesperblock = 8; + ddssize -= 128; + ddssize /= 2; + for (i = 0;i < (int)ddssize;i += bytesperblock) + memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8); + ddssize += 128; + } + + force_swdecode = false; + if(bytesperblock) + { + if(vid.support.ext_texture_compression_s3tc) + { + if(r_texture_dds_swdecode.integer > 1) + force_swdecode = true; + } + else + { + if(r_texture_dds_swdecode.integer < 1) + { + // unsupported + Mem_Free(dds); + return NULL; + } + force_swdecode = true; + } + } + // return whether this texture is transparent if (hasalphaflag) *hasalphaflag = (flags & TEXF_ALPHA) != 0; + // if we SW decode, choose 2 sizes bigger + if(force_swdecode) + { + // this is quarter res, so do not scale down more than we have to + miplevel -= 2; + + if(miplevel < 0) + Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename); + } + + // this is where we apply gl_picmip + mippixels_start = ddspixels; + mipwidth = dds_width; + mipheight = dds_height; + while(miplevel >= 1 && dds_miplevels >= 1) + { + if (mipwidth <= 1 && mipheight <= 1) + break; + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + mippixels_start += mipsize; // just skip + --dds_miplevels; + --miplevel; + if (mipwidth > 1) + mipwidth >>= 1; + if (mipheight > 1) + mipheight >>= 1; + } + mipsize_total = ddssize - 128 - (mippixels_start - ddspixels); + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + + // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt) + + // fake decode S3TC if needed + if(force_swdecode) + { + int mipsize_new = mipsize_total / bytesperblock * 4; + unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new); + unsigned char *p = mipnewpixels; + for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4) + { + c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3]; + p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f); + p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f); + p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f); + if(textype == TEXTYPE_DXT5) + p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]); + else if(textype == TEXTYPE_DXT3) + p[3] = ( + (mippixels_start[i-8] & 0x0F) + + (mippixels_start[i-8] >> 4) + + (mippixels_start[i-7] & 0x0F) + + (mippixels_start[i-7] >> 4) + + (mippixels_start[i-6] & 0x0F) + + (mippixels_start[i-6] >> 4) + + (mippixels_start[i-5] & 0x0F) + + (mippixels_start[i-5] >> 4) + ) * (0.125f / 15.0f * 255.0f); + else + p[3] = 255; + } + + textype = TEXTYPE_BGRA; + bytesperblock = 0; + bytesperpixel = 4; + + // as each block becomes a pixel, we must use pixel count for this + mipwidth = (mipwidth + 3) / 4; + mipheight = (mipheight + 3) / 4; + mipsize = bytesperpixel * mipwidth * mipheight; + mippixels_start = mipnewpixels; + mipsize_total = mipsize_new; + } + + // start mip counting + mippixels = mippixels_start; + // calculate average color if requested if (avgcolor) { @@ -1840,29 +1990,44 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen Vector4Clear(avgcolor); if (bytesperblock) { - for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock) + for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock) { - c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3]; + c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3]; avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F); avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F); avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F); + if(textype == TEXTYPE_DXT5) + 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) + + (mippixels_start[i-8] >> 4) + + (mippixels_start[i-7] & 0x0F) + + (mippixels_start[i-7] >> 4) + + (mippixels_start[i-6] & 0x0F) + + (mippixels_start[i-6] >> 4) + + (mippixels_start[i-5] & 0x0F) + + (mippixels_start[i-5] >> 4) + ) * (0.125f / 15.0f); + else + 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; - avgcolor[3] = 1; // too hard to calculate + avgcolor[3] *= f; } else { - for (i = 0;i < size;i += 4) + for (i = 0;i < mipsize;i += 4) { - avgcolor[0] += ddspixels[i+2]; - avgcolor[1] += ddspixels[i+1]; - avgcolor[2] += ddspixels[i]; - avgcolor[3] += ddspixels[i+3]; + avgcolor[0] += mippixels[i+2]; + avgcolor[1] += mippixels[i+1]; + 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; @@ -1870,37 +2035,110 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen } } - // this is where we apply gl_picmip - mippixels = ddspixels; - mipwidth = dds_width; - mipheight = dds_height; - while(miplevel >= 1 && dds_miplevels >= 1) + // if we want sRGB, convert now + if(srgb) { - if (mipwidth <= 1 && mipheight <= 1) - break; - mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; - mippixels += mipsize; // just skip - --dds_miplevels; - --miplevel; - if (mipwidth > 1) - mipwidth >>= 1; - if (mipheight > 1) - mipheight >>= 1; + if (vid.support.ext_texture_srgb) + { + switch(textype) + { + case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break; + case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break; + case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break; + case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break; + case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break; + default: + break; + } + } + else + { + switch(textype) + { + case TEXTYPE_DXT1: + case TEXTYPE_DXT1A: + case TEXTYPE_DXT3: + case TEXTYPE_DXT5: + { + for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock) + { + int c0, c1, c0new, c1new; + c0 = mippixels_start[i] + 256*mippixels_start[i+1]; + r = ((c0 >> 11) & 0x1F); + g = ((c0 >> 5) & 0x3F); + b = ((c0 ) & 0x1F); + r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + c0new = (r << 11) | (g << 5) | b; + c1 = mippixels_start[i+2] + 256*mippixels_start[i+3]; + r = ((c1 >> 11) & 0x1F); + g = ((c1 >> 5) & 0x3F); + b = ((c1 ) & 0x1F); + r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + c1new = (r << 11) | (g << 5) | b; + // swap the colors if needed to fix order + if(c0 > c1) // thirds + { + if(c0new < c1new) + { + c = c0new; + c0new = c1new; + c1new = c; + if(c0new == c1new) + mippixels_start[i+4] ^= 0x55; + mippixels_start[i+5] ^= 0x55; + mippixels_start[i+6] ^= 0x55; + mippixels_start[i+7] ^= 0x55; + } + else if(c0new == c1new) + { + mippixels_start[i+4] = 0x00; + mippixels_start[i+5] = 0x00; + mippixels_start[i+6] = 0x00; + mippixels_start[i+7] = 0x00; + } + } + else // half + transparent + { + if(c0new > c1new) + { + c = c0new; + c0new = c1new; + c1new = c; + mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55; + mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55; + mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55; + mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55; + } + } + mippixels_start[i] = c0new & 255; + mippixels_start[i+1] = c0new >> 8; + mippixels_start[i+2] = c1new & 255; + mippixels_start[i+3] = c1new >> 8; + } + } + break; + case TEXTYPE_RGBA: + Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock); + break; + default: + break; + } + } } - if (dds_miplevels > 1) + // when not requesting mipmaps, do not load them + if(!(flags & TEXF_MIPMAP)) + dds_miplevels = 0; + + if (dds_miplevels >= 1) flags |= TEXF_MIPMAP; else flags &= ~TEXF_MIPMAP; - // if S3TC is not supported, there's very little we can do about it - if (bytesperblock && !vid.support.ext_texture_compression_s3tc) - { - Mem_Free(dds); - Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename); - return NULL; - } - texinfo = R_GetTexTypeInfo(textype, flags); glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); @@ -1932,42 +2170,14 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen // create the texture object switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: CHECKGLERROR GL_ActiveTexture(0); oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - { - D3DFORMAT d3dformat; - D3DPOOL d3dpool; - DWORD d3dusage; - switch(textype) - { - case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; - case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break; - case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break; - case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break; - default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break; - } - d3dusage = 0; - d3dpool = D3DPOOL_MANAGED; - IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL); - } -#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; } // upload the texture @@ -1976,44 +2186,28 @@ 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 > dds + ddssize) + if (mippixels + mipsize > mippixels_start + mipsize_total) break; switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: if (bytesperblock) { - qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR + qglCompressedTexImage2D(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: -#ifdef SUPPORTD3D - { - D3DLOCKED_RECT d3dlockedrect; - if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) - { - memcpy(d3dlockedrect.pBits, mippixels, mipsize); - IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); - } - break; - } -#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; } + if(upload_mippixels != mippixels) + Mem_Free(upload_mippixels); mippixels += mipsize; if (mipwidth <= 1 && mipheight <= 1) { @@ -2029,61 +2223,23 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen // after upload we have to set some parameters... switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: + case RENDERPATH_GL32: + case RENDERPATH_GLES2: +#ifdef GL_TEXTURE_MAX_LEVEL 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 break; - case RENDERPATH_D3D9: -#ifdef SUPPORTD3D - glt->d3daddressw = 0; - if (glt->flags & TEXF_CLAMP) - { - glt->d3daddressu = D3DTADDRESS_CLAMP; - glt->d3daddressv = D3DTADDRESS_CLAMP; - if (glt->tiledepth > 1) - glt->d3daddressw = D3DTADDRESS_CLAMP; - } - else - { - glt->d3daddressu = D3DTADDRESS_WRAP; - glt->d3daddressv = D3DTADDRESS_WRAP; - if (glt->tiledepth > 1) - glt->d3daddressw = D3DTADDRESS_WRAP; - } - glt->d3dmipmaplodbias = 0; - glt->d3dmaxmiplevel = 0; - glt->d3dmaxmiplevelfilter = 0; - if (glt->flags & TEXF_MIPMAP) - { - glt->d3dminfilter = d3d_filter_mipmin; - glt->d3dmagfilter = d3d_filter_mipmag; - glt->d3dmipfilter = d3d_filter_mipmix; - } - else - { - glt->d3dminfilter = d3d_filter_flatmin; - glt->d3dmagfilter = d3d_filter_flatmag; - glt->d3dmipfilter = d3d_filter_flatmix; - } -#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; } Mem_Free(dds); + if(force_swdecode) + Mem_Free((unsigned char *) mippixels_start); return (rtexture_t *)glt; } @@ -2097,16 +2253,21 @@ int R_TextureHeight(rtexture_t *rt) return rt ? ((gltexture_t *)rt)->inputheight : 0; } -void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height) +int R_TextureFlags(rtexture_t *rt) +{ + return rt ? ((gltexture_t *)rt)->flags : 0; +} + +void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth) { gltexture_t *glt = (gltexture_t *)rt; if (data == NULL) Host_Error("R_UpdateTexture: no data supplied"); if (glt == NULL) Host_Error("R_UpdateTexture: no texture supplied"); - if (!glt->texnum && !glt->d3dtexture) + if (!glt->texnum) { - Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool); + Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool); return; } // update part of the texture @@ -2118,6 +2279,8 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in int outputskip = glt->tilewidth*bpp; const unsigned char *input = data; unsigned char *output = glt->bufferpixels; + if (glt->inputdepth != 1 || glt->sides != 1) + Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n"); if (x < 0) { width += x; @@ -2142,8 +2305,10 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in for (j = 0;j < height;j++, output += outputskip, input += inputskip) memcpy(output, input, width*bpp); } + else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth) + R_UploadPartialTexture(glt, data, x, y, z, width, height, depth); else - R_Upload(glt, data, x, y, 0, width, height, 1); + R_UploadFullTexture(glt, data); } int R_RealGetTexture(rtexture_t *rt) @@ -2157,20 +2322,20 @@ int R_RealGetTexture(rtexture_t *rt) if (glt->buffermodified && glt->bufferpixels) { glt->buffermodified = false; - R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth); + R_UploadFullTexture(glt, glt->bufferpixels); } glt->dirty = false; return glt->texnum; } else - return 0; + return r_texture_white->texnum; } void R_ClearTexture (rtexture_t *rt) { gltexture_t *glt = (gltexture_t *)rt; - R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth ); + R_UploadFullTexture(glt, NULL); } int R_PicmipForFlags(int flags) @@ -2196,5 +2361,5 @@ int R_PicmipForFlags(int flags) else miplevel += gl_picmip_other.integer; } - return miplevel; + return max(0, miplevel); }