#include "jpeg.h"
#include "image_png.h"
-cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, note: this is automatically reduced to match video card capabilities (such as 256 on 3Dfx cards before Voodoo4/5)"};
+cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
+cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
-cvar_t r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1", "0 = never upload textures until used, 1 = upload most textures before use (exceptions: rarely used skin colormap layers), 2 = upload all textures before use (can increase texture memory usage significantly)"};
cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
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_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates"};
int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
int gl_filter_mag = GL_LINEAR;
static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_BGRA , 4, GL_UNSIGNED_BYTE};
static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_BGRA , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_BGRA , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
-static textypeinfo_t textype_shadowmap = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT32_ARB, GL_UNSIGNED_INT};
+static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP,2,2, 2.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16_ARB, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_ARB, GL_UNSIGNED_INT};
typedef enum gltexturetype_e
{
- GLTEXTURETYPE_1D,
GLTEXTURETYPE_2D,
GLTEXTURETYPE_3D,
GLTEXTURETYPE_CUBEMAP,
}
gltexturetype_t;
-static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
-static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB};
-static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {1, 2, 3, 2, 2};
+static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
+static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB};
+static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
static int cubemapside[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
void *updatacallback_data;
// --- [11/22/2007 Black]
+ // stores backup copy of texture for deferred texture updates (r_nopartialtextureupdates cvar)
+ unsigned char *bufferpixels;
+ qboolean buffermodified;
+
// pointer to texturepool (check this to see if the texture is allocated)
struct gltexturepool_s *pool;
// pointer to next texture in texturepool chain
// 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 gl_support_arb_texture_non_power_of_two is not supported)
+ // (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;
static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
{
- if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && gl_support_texture_compression)
+ if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression)
{
if (flags & TEXF_ALPHA)
{
case TEXTYPE_BGRA:
return &textype_bgra;
case TEXTYPE_SHADOWMAP:
- return &textype_shadowmap;
+ return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
default:
Host_Error("R_GetTexTypeInfo: unknown texture format");
return NULL;
}
}
-static void R_UploadTexture(gltexture_t *t);
-
-static void R_PrecacheTexture(gltexture_t *glt)
-{
- int precache;
- precache = false;
- if (glt->flags & TEXF_ALWAYSPRECACHE)
- precache = true;
- else if (r_precachetextures.integer >= 2)
- precache = true;
- else if (r_precachetextures.integer >= 1)
- if (glt->flags & TEXF_PRECACHE)
- precache = true;
-
- if (precache)
- R_UploadTexture(glt);
-}
-
-int R_RealGetTexture(rtexture_t *rt)
-{
- if (rt)
- {
- gltexture_t *glt;
- glt = (gltexture_t *)rt;
- if (glt->flags & GLTEXF_DYNAMIC)
- R_UpdateDynamicTexture(glt);
- if (glt->flags & GLTEXF_UPLOAD)
- R_UploadTexture(glt);
-
- return glt->texnum;
- }
- else
- return 0;
-}
-
void R_PurgeTexture(rtexture_t *rt)
{
if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
// 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)
{
for (glt = pool->gltchain;glt;glt = glt->chain)
// only update already uploaded images
if (!(glt->flags & (GLTEXF_UPLOAD | TEXF_FORCENEAREST | TEXF_FORCELINEAR)))
{
- qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
+ oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
if (glt->flags & TEXF_MIPMAP)
{
{
int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
- if (gl_max_size.integer > gl_max_texture_size)
- Cvar_SetValue("gl_max_size", gl_max_texture_size);
-
switch (texturetype)
{
default:
- case GLTEXTURETYPE_1D:
case GLTEXTURETYPE_2D:
- maxsize = gl_max_texture_size;
+ maxsize = vid.maxtexturesize_2d;
+ if (flags & TEXF_PICMIP)
+ {
+ maxsize = bound(1, gl_max_size.integer, maxsize);
+ picmip = gl_picmip.integer;
+ }
break;
case GLTEXTURETYPE_3D:
- maxsize = gl_max_3d_texture_size;
+ maxsize = vid.maxtexturesize_3d;
break;
case GLTEXTURETYPE_CUBEMAP:
- maxsize = gl_max_cube_map_texture_size;
+ maxsize = vid.maxtexturesize_cubemap;
break;
}
- if (flags & TEXF_PICMIP)
- {
- maxsize = min(maxsize, gl_max_size.integer);
- picmip = gl_picmip.integer;
- }
-
if (outwidth)
{
- if (gl_support_arb_texture_non_power_of_two)
+ if (vid.support.arb_texture_non_power_of_two)
width2 = min(inwidth >> picmip, maxsize);
else
{
}
if (outheight)
{
- if (gl_support_arb_texture_non_power_of_two)
+ if (vid.support.arb_texture_non_power_of_two)
height2 = min(inheight >> picmip, maxsize);
else
{
}
if (outdepth)
{
- if (gl_support_arb_texture_non_power_of_two)
+ if (vid.support.arb_texture_non_power_of_two)
depth2 = min(indepth >> picmip, maxsize);
else
{
Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
Cvar_RegisterVariable (&gl_max_size);
Cvar_RegisterVariable (&gl_picmip);
+ Cvar_RegisterVariable (&gl_max_lightmapsize);
Cvar_RegisterVariable (&r_lerpimages);
- Cvar_RegisterVariable (&r_precachetextures);
Cvar_RegisterVariable (&gl_texture_anisotropy);
Cvar_RegisterVariable (&gl_texturecompression);
Cvar_RegisterVariable (&gl_texturecompression_color);
Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps);
Cvar_RegisterVariable (&gl_texturecompression_sky);
Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
+ Cvar_RegisterVariable (&gl_nopartialtextureupdates);
R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
}
gltexturepool_t *pool;
GLint oldbindtexnum;
- old_aniso = bound(1, gl_texture_anisotropy.integer, gl_max_anisotropy);
+ old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso);
CHECKGLERROR
+ GL_ActiveTexture(0);
for (pool = gltexturepoolchain;pool;pool = pool->next)
{
for (glt = pool->gltchain;glt;glt = glt->chain)
// only update already uploaded images
if ((glt->flags & (GLTEXF_UPLOAD | TEXF_MIPMAP)) == TEXF_MIPMAP)
{
- qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
+ oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR
}
}
-static void GL_SetupTextureParameters(int flags, int texturetype)
+static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
{
int textureenum = gltexturetypeenums[texturetype];
- int wrapmode = ((flags & TEXF_CLAMP) && gl_support_clamptoedge) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
+ int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
CHECKGLERROR
- if (gl_support_anisotropy && (flags & TEXF_MIPMAP))
+ if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP))
{
- int aniso = bound(1, gl_texture_anisotropy.integer, gl_max_anisotropy);
+ int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy);
if (gl_texture_anisotropy.integer != aniso)
Cvar_SetValueQuick(&gl_texture_anisotropy, aniso);
qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
}
- if (texturetype == TEXTYPE_SHADOWMAP)
+ if (textype == TEXTYPE_SHADOWMAP)
{
-#if 1
- qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
- qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
- qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);CHECKGLERROR
-#else
- qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
- qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_ALWAYS);CHECKGLERROR
- qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);CHECKGLERROR
-#endif
+ 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
}
CHECKGLERROR
CHECKGLERROR
// we need to restore the texture binding after finishing the upload
- qglGetIntegerv(gltexturetypebindingenums[glt->texturetype], &oldbindtexnum);CHECKGLERROR
+ GL_ActiveTexture(0);
+ oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]);
qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
// these are rounded up versions of the size to do better resampling
- if (gl_support_arb_texture_non_power_of_two)
+ if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
{
width = glt->inputwidth;
height = glt->inputheight;
prevbuffer = colorconvertbuffer;
}
- if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth)
+ if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
{
// update a portion of the image
switch(glt->texturetype)
{
- case GLTEXTURETYPE_1D:
- qglTexSubImage1D(GL_TEXTURE_1D, 0, fragx, fragwidth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- break;
case GLTEXTURETYPE_2D:
qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
break;
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 1D, 2D, or 3D");
+ Host_Error("R_Upload: partial update of type other than 2D");
break;
}
}
}
}
mip = 0;
- if (gl_support_texture_compression)
+ if (qglGetCompressedTexImageARB)
{
if (gl_texturecompression.integer >= 2)
qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
}
switch(glt->texturetype)
{
- case GLTEXTURETYPE_1D:
- qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- if (glt->flags & TEXF_MIPMAP)
- {
- while (width > 1 || height > 1 || depth > 1)
- {
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
- prevbuffer = resizebuffer;
- qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- }
- }
- break;
case GLTEXTURETYPE_2D:
qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
if (glt->flags & TEXF_MIPMAP)
qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
break;
}
- GL_SetupTextureParameters(glt->flags, glt->texturetype);
+ GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
}
qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
}
-static void R_UploadTexture (gltexture_t *glt)
+int R_RealGetTexture(rtexture_t *rt)
{
- if (!(glt->flags & GLTEXF_UPLOAD))
- return;
-
- CHECKGLERROR
- qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
- R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
- if (glt->inputtexels)
+ if (rt)
{
- Mem_Free(glt->inputtexels);
- glt->inputtexels = NULL;
- glt->flags |= GLTEXF_DESTROYED;
+ gltexture_t *glt;
+ glt = (gltexture_t *)rt;
+ if (glt->flags & GLTEXF_DYNAMIC)
+ R_UpdateDynamicTexture(glt);
+ if (glt->flags & GLTEXF_UPLOAD)
+ {
+ CHECKGLERROR
+ qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+ R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+ if (glt->inputtexels)
+ {
+ Mem_Free(glt->inputtexels);
+ glt->inputtexels = NULL;
+ glt->flags |= GLTEXF_DESTROYED;
+ }
+ else if (glt->flags & GLTEXF_DESTROYED)
+ Con_Printf("R_GetTexture: Texture %s already uploaded and destroyed. Can not upload original image again. Uploaded blank texture.\n", glt->identifier);
+ }
+
+ return glt->texnum;
}
- else if (glt->flags & GLTEXF_DESTROYED)
- Con_Printf("R_UploadTexture: Texture %s already uploaded and destroyed. Can not upload original image again. Uploaded blank texture.\n", glt->identifier);
+ else
+ return 0;
}
static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
if (cls.state == ca_dedicated)
return NULL;
- if (texturetype == GLTEXTURETYPE_RECTANGLE && !gl_texturerectangle)
+ 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 && !gl_texturecubemap)
+ 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 && !gl_texture3d)
+ if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d)
{
Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n");
return NULL;
glt->updatecallback = NULL;
glt->updatacallback_data = NULL;
- if (data)
- {
- glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
- memcpy(glt->inputtexels, data, size);
- }
- else
- glt->inputtexels = NULL;
-
GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
- R_PrecacheTexture(glt);
+
+ // 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);
+ if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
+ glt->bufferpixels = Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
// texture converting and uploading can take a while, so make sure we're sending keepalives
CL_KeepaliveMessage(false);
return (rtexture_t *)glt;
}
-rtexture_t *R_LoadTexture1D(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
-{
- return R_SetupTexture(rtexturepool, identifier, width, 1, 1, 1, flags, textype, GLTEXTURETYPE_1D, data, palette);
-}
-
rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
{
return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data, palette);
return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
}
-rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height)
+rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette)
{
- return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
+ return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
}
-rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width)
+static int R_ShadowMapTextureFlags(int precision, qboolean filter)
{
- return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+ int flags = TEXF_CLAMP;
+ if (filter)
+ flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
+ else
+ flags |= TEXF_FORCENEAREST;
+ if (precision <= 16)
+ flags |= TEXF_LOWPRECISION;
+ return flags;
}
-rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height)
+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, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+ return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
}
-rtexture_t *R_LoadTextureCubeProjection(rtexturepool_t *rtexturepool, const char *identifier)
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
{
- return R_SetupTexture(rtexturepool, identifier, 2, 2, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+ return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
}
-int R_TextureHasAlpha(rtexture_t *rt)
+rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
{
- return rt ? (((gltexture_t *)rt)->flags & TEXF_ALPHA) != 0 : false;
+ return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
}
int R_TextureWidth(rtexture_t *rt)
void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
{
- gltexture_t *glt;
- if (rt == NULL)
- Host_Error("R_UpdateTexture: no texture supplied");
+ gltexture_t *glt = (gltexture_t *)rt;
if (data == NULL)
Host_Error("R_UpdateTexture: no data supplied");
- glt = (gltexture_t *)rt;
+ if (glt == NULL)
+ Host_Error("R_UpdateTexture: no texture supplied");
+ if (!glt->texnum)
+ Host_Error("R_UpdateTexture: texture has not been uploaded yet");
+ // update part of the texture
+ if (glt->bufferpixels)
+ {
+ int j;
+ int bpp = glt->bytesperpixel;
+ int inputskip = width*bpp;
+ int outputskip = glt->tilewidth*bpp;
+ const unsigned char *input = data;
+ unsigned char *output = glt->bufferpixels;
+ if (x < 0)
+ {
+ width += x;
+ input -= x*bpp;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ height += y;
+ input -= y*inputskip;
+ y = 0;
+ }
+ if (width > glt->tilewidth - x)
+ width = glt->tilewidth - x;
+ if (height > glt->tileheight - y)
+ height = glt->tileheight - y;
+ if (width < 1 || height < 1)
+ return;
+ glt->buffermodified = true;
+ output += y*outputskip + x*bpp;
+ for (j = 0;j < height;j++, output += outputskip, input += inputskip)
+ memcpy(output, input, width*bpp);
+ if (!(glt->flags & TEXF_MANUALFLUSHUPDATES))
+ R_FlushTexture(rt);
+ }
+ else
+ R_Upload(glt, data, x, y, 0, width, height, 1);
+}
- // we need it to be uploaded before we can update a part of it
- if (glt->flags & GLTEXF_UPLOAD)
- R_UploadTexture(glt);
+void R_FlushTexture(rtexture_t *rt)
+{
+ gltexture_t *glt;
+ if (rt == NULL)
+ Host_Error("R_FlushTexture: no texture supplied");
// update part of the texture
- R_Upload(glt, data, x, y, 0, width, height, 1);
+ glt = (gltexture_t *)rt;
+
+ if (!glt->buffermodified || !glt->bufferpixels)
+ return;
+ glt->buffermodified = false;
+ R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
}
void R_ClearTexture (rtexture_t *rt)