X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=gl_textures.c;h=455924b68c985359be67ae5ca398a4c5d12853a8;hb=179be6fd1f715bac570e73aa9cadb0e08d0f7979;hp=d20a0ecde3a13030582883ab6bbe42b06ba2c5ed;hpb=2db250bb0c08162bf6bd0913441b7f11f81475c0;p=xonotic%2Fdarkplaces.git diff --git a/gl_textures.c b/gl_textures.c index d20a0ecd..455924b6 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -1,5 +1,9 @@ #include "quakedef.h" +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +#endif #include "image.h" #include "jpeg.h" #include "image_png.h" @@ -27,11 +31,22 @@ cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", 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 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 ambigous, 2: texture format only"}; 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; @@ -80,13 +95,12 @@ 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_ARB}; +static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2}; static int cubemapside[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, @@ -104,6 +118,23 @@ typedef struct gltexture_s int texnum; // GL texture slot number qboolean dirty; // indicates that R_RealGetTexture should be called int gltexturetypeenum; // used by R_Mesh_TexBind + // d3d stuff the backend needs + void *d3dtexture; +#ifdef SUPPORTD3D + qboolean d3disdepthsurface; // for depth/stencil surfaces + 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; @@ -143,6 +174,8 @@ typedef struct gltexture_s int tilewidth, tileheight, tiledepth; // 1 or 6 depending on texturetype int sides; + // how many mipmap levels in this texture + int miplevels; // bytes per pixel int bytesperpixel; // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT @@ -185,11 +218,11 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) 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) + if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) 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) + if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress; return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra; case TEXTYPE_ALPHA: @@ -259,10 +292,37 @@ void R_FreeTexture(rtexture_t *rt) else Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier); - if (glt->texnum) + switch(vid.renderpath) { - CHECKGLERROR - qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (glt->texnum) + { + CHECKGLERROR + qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (glt->d3disdepthsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture); + else 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__); + break; } if (glt->inputtexels) @@ -308,7 +368,7 @@ void R_FreeTexturePool(rtexturepool_t **rtexturepool) typedef struct glmode_s { - char *name; + const char *name; int minification, magnification; } glmode_t; @@ -323,6 +383,25 @@ static glmode_t modes[6] = {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} }; +#ifdef SUPPORTD3D +typedef struct d3dmode_s +{ + const 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; @@ -358,37 +437,88 @@ static void GL_TextureMode_f (void) gl_filter_mag = modes[i].magnification; gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force")); - // change all the existing mipmap texture objects - // FIXME: force renderer(/client/something?) restart instead? - CHECKGLERROR - GL_ActiveTexture(0); - for (pool = gltexturepoolchain;pool;pool = pool->next) + switch(vid.renderpath) { - for (glt = pool->gltchain;glt;glt = glt->chain) + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + // change all the existing mipmap texture objects + // FIXME: force renderer(/client/something?) restart instead? + CHECKGLERROR + GL_ActiveTexture(0); + for (pool = gltexturepoolchain;pool;pool = pool->next) { - // only update already uploaded images - if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) + for (glt = pool->gltchain;glt;glt = glt->chain) { - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); - qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR - if (glt->flags & TEXF_MIPMAP) + // only update already uploaded images + if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) { - qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR + } + else + { + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR + } + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR } - else + } + } + 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 && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) { - qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR + 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; + } } - qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR } } +#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; } } -static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth) +static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels) { - int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1; + int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1; switch (texturetype) { @@ -409,39 +539,59 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i break; } - if (outwidth) + if (vid.support.arb_texture_non_power_of_two) { - 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); + width2 = min(inwidth >> picmip, maxsize); + height2 = min(inheight >> picmip, maxsize); + depth2 = min(indepth >> picmip, maxsize); } - if (outheight) + else { - 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); + for (width2 = 1;width2 < inwidth;width2 <<= 1); + for (width2 >>= picmip;width2 > maxsize;width2 >>= 1); + for (height2 = 1;height2 < inheight;height2 <<= 1); + for (height2 >>= picmip;height2 > maxsize;height2 >>= 1); + for (depth2 = 1;depth2 < indepth;depth2 <<= 1); + for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1); } - if (outdepth) + + switch(vid.renderpath) { - if (vid.support.arb_texture_non_power_of_two) - depth2 = min(indepth >> picmip, maxsize); - else + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_D3D9: +#if 0 + // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures... + if (texturetype == GLTEXTURETYPE_2D) { - for (depth2 = 1;depth2 < indepth;depth2 <<= 1); - for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1); + width2 = max(width2, 2); + height2 = max(height2, 2); } - *outdepth = max(1, depth2); +#endif + break; } + + miplevels = 1; + if (flags & TEXF_MIPMAP) + { + int extent = max(width2, max(height2, depth2)); + 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; } @@ -449,7 +599,7 @@ static int R_CalcTexelDataSize (gltexture_t *glt) { int width2, height2, depth2, size; - GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2); + GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL); size = width2 * height2 * depth2; @@ -524,10 +674,26 @@ static void R_TextureStats_f(void) static void r_textures_start(void) { - // LordHavoc: allow any alignment - CHECKGLERROR - qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR - qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + // 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); Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512); @@ -563,6 +729,101 @@ static void r_textures_newmap(void) { } +static void r_textures_devicelost(void) +{ + int i, endindex; + gltexture_t *glt; + endindex = Mem_ExpandableArray_IndexRange(&texturearray); + for (i = 0;i < endindex;i++) + { + glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); + if (!glt || !(glt->flags & TEXF_RENDERTARGET)) + continue; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (glt->d3disdepthsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture); + else 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__); + break; + } + } +} + +static void r_textures_devicerestored(void) +{ + int i, endindex; + gltexture_t *glt; + endindex = Mem_ExpandableArray_IndexRange(&texturearray); + for (i = 0;i < endindex;i++) + { + glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); + if (!glt || !(glt->flags & TEXF_RENDERTARGET)) + 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->d3disdepthsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); + } + else if (glt->tiledepth > 1) + { + 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; + } + } +} + + void R_Textures_Init (void) { Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate"); @@ -589,8 +850,9 @@ void R_Textures_Init (void) Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps); Cvar_RegisterVariable (&gl_texturecompression_reflectmask); Cvar_RegisterVariable (&gl_nopartialtextureupdates); + Cvar_RegisterVariable (&r_texture_dds_load_alphamode); - R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap); + R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored); } void R_Textures_Frame (void) @@ -623,23 +885,35 @@ void R_Textures_Frame (void) Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso); - CHECKGLERROR - GL_ActiveTexture(0); - for (pool = gltexturepoolchain;pool;pool = pool->next) + switch(vid.renderpath) { - for (glt = pool->gltchain;glt;glt = glt->chain) + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + CHECKGLERROR + GL_ActiveTexture(0); + for (pool = gltexturepoolchain;pool;pool = pool->next) { - // only update already uploaded images - if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP) + for (glt = pool->gltchain;glt;glt = glt->chain) { - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + // only update already uploaded images + if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP) + { + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); - qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR - qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } } } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; } } } @@ -746,88 +1020,132 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet 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; - const unsigned char *prevbuffer; - prevbuffer = data; + if (data == NULL) + Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier); - CHECKGLERROR + if (glt->texturetype != GLTEXTURETYPE_2D) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier); - // 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 + if (glt->textype->textype == TEXTYPE_PALETTE) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier); - // 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 + 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) { - for (width = 1;width < glt->inputwidth ;width <<= 1); - for (height = 1;height < glt->inputheight;height <<= 1); - for (depth = 1;depth < glt->inputdepth ;depth <<= 1); + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + { + 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; + 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, data + 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; } +} + +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); + + // 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); R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); - R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel); if (prevbuffer == NULL) { - memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel); + width = glt->tilewidth; + height = glt->tileheight; + depth = glt->tiledepth; + 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); + Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * 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)) + // scale up to a power of 2 size (if appropriate) + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) { - // update a portion of the image - switch(glt->texturetype) - { - case GLTEXTURETYPE_2D: - qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - break; - case GLTEXTURETYPE_3D: - qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR - break; - default: - Host_Error("R_Upload: partial update of type other than 2D"); - break; - } + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; } - else + // apply mipmap reduction algorithm to get down to picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) { - 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"); + 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_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 - // cubemaps contain multiple images and thus get processed a bit differently - if (glt->texturetype != GLTEXTURETYPE_CUBEMAP) - { - 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 (qglGetCompressedTexImageARB) { if (gl_texturecompression.integer >= 2) @@ -894,13 +1212,162 @@ 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; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (!(glt->flags & TEXF_RENDERTARGET)) + { + 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; + } + } + 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; + } + 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; } - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR } 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) @@ -909,15 +1376,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden 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"); @@ -937,6 +1400,17 @@ 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) { @@ -991,7 +1465,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden flags |= TEXF_ALPHA; break; default: - Host_Error("R_LoadTexture: unknown texture type"); + Sys_Error("R_LoadTexture: unknown texture type"); } texinfo2 = R_GetTexTypeInfo(textype, flags); @@ -1027,18 +1501,89 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden glt->updatecallback = NULL; glt->updatacallback_data = NULL; - GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth); + 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) - CHECKGLERROR - qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR - R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + 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; + glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP; + if (glt->d3disdepthsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); + } + else if (glt->tiledepth > 1) + { + 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_UploadFullTexture(glt, data); if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer) - glt->bufferpixels = Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel); + glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel); + + // free any temporary processing buffer we allocated... + if (temppixels) + Mem_Free(temppixels); // texture converting and uploading can take a while, so make sure we're sending keepalives - CL_KeepaliveMessage(false); + // FIXME: this causes rendering during R_Shadow_DrawLights +// CL_KeepaliveMessage(false); return (rtexture_t *)glt; } @@ -1058,14 +1603,9 @@ 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) -{ - return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette); -} - static int R_ShadowMapTextureFlags(int precision, qboolean filter) { - int flags = TEXF_CLAMP; + int flags = TEXF_RENDERTARGET | TEXF_CLAMP; if (filter) flags |= TEXF_FORCELINEAR | TEXF_COMPARE; else @@ -1075,22 +1615,12 @@ static int R_ShadowMapTextureFlags(int precision, qboolean filter) return flags; } -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); -} - 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); } -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); -} - -int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed) +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha) { gltexture_t *glt = (gltexture_t *)rt; unsigned char *dds; @@ -1152,7 +1682,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco mipinfo[mip][3] = ddssize; ddssize += mipinfo[mip][2]; } - dds = Mem_Alloc(tempmempool, ddssize); + dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize); if (!dds) return -4; dds_caps1 = 0x1000; // DDSCAPS_TEXTURE @@ -1165,13 +1695,15 @@ 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+8, dds_flags); @@ -1220,7 +1752,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen textypeinfo_t *texinfo; int mip, mipwidth, mipheight, mipsize; unsigned int c; - GLint oldbindtexnum; + GLint oldbindtexnum = 0; const unsigned char *mippixels, *ddspixels; unsigned char *dds; fs_offset_t ddsfilesize; @@ -1252,7 +1784,11 @@ 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 @@ -1266,15 +1802,23 @@ 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)) { + if(!vid.support.ext_texture_compression_s3tc) + { + Mem_Free(dds); + return NULL; + } // we need to find out if this is DXT1 (opaque) or DXT1A (transparent) // LordHavoc: it is my belief that this does not infringe on the // patent because it is not decoding pixels... @@ -1289,16 +1833,38 @@ 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(r_texture_dds_load_alphamode.integer && (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 + { + flags &= ~TEXF_ALPHA; + } + } } else if (!memcmp(dds+84, "DXT3", 4)) { + if(!vid.support.ext_texture_compression_s3tc) + { + Mem_Free(dds); + return NULL; + } textype = TEXTYPE_DXT3; bytesperblock = 16; bytesperpixel = 0; @@ -1309,9 +1875,15 @@ 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)) { + if(!vid.support.ext_texture_compression_s3tc) + { + Mem_Free(dds); + return NULL; + } textype = TEXTYPE_DXT5; bytesperblock = 16; bytesperpixel = 0; @@ -1322,6 +1894,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 { @@ -1389,7 +1962,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen mipheight >>= 1; } - 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; @@ -1425,17 +2002,54 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen glt->tilewidth = mipwidth; glt->tileheight = mipheight; glt->tiledepth = 1; + glt->miplevels = dds_miplevels; // texture uploading can take a while, so make sure we're sending keepalives CL_KeepaliveMessage(false); + // create the texture object + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + 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 // we need to restore the texture binding after finishing the upload - 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 mipcomplete = false; for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel @@ -1443,13 +2057,40 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; if (mippixels + mipsize > dds + ddssize) break; - if (bytesperblock) - { - qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR - } - else + switch(vid.renderpath) { - qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (bytesperblock) + { + qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR + } + else + { + qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, 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; } mippixels += mipsize; if (mipwidth <= 1 && mipheight <= 1) @@ -1462,13 +2103,63 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen if (mipheight > 1) mipheight >>= 1; } - if (dds_miplevels >= 1 && !mipcomplete) + + // after upload we have to set some parameters... + switch(vid.renderpath) { - // need to set GL_TEXTURE_MAX_LEVEL - qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (dds_miplevels >= 1 && !mipcomplete) + { + // need to set GL_TEXTURE_MAX_LEVEL + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR + } + 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; } - GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); - qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR Mem_Free(dds); return (rtexture_t *)glt; @@ -1491,8 +2182,11 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in Host_Error("R_UpdateTexture: no data supplied"); if (glt == NULL) Host_Error("R_UpdateTexture: no texture supplied"); - if (!glt->texnum) - Host_Error("R_UpdateTexture: texture has not been uploaded yet"); + if (!glt->texnum && !glt->d3dtexture) + { + Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool); + return; + } // update part of the texture if (glt->bufferpixels) { @@ -1526,8 +2220,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 || width != glt->inputwidth || height != glt->inputheight) + R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1); else - R_Upload(glt, data, x, y, 0, width, height, 1); + R_UploadFullTexture(glt, data); } int R_RealGetTexture(rtexture_t *rt) @@ -1541,7 +2237,7 @@ 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; @@ -1554,7 +2250,7 @@ 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) @@ -1580,5 +2276,5 @@ int R_PicmipForFlags(int flags) else miplevel += gl_picmip_other.integer; } - return miplevel; + return max(0, miplevel); }