diff options
Diffstat (limited to 'src/renderergl2/tr_image.c')
-rw-r--r-- | src/renderergl2/tr_image.c | 894 |
1 files changed, 444 insertions, 450 deletions
diff --git a/src/renderergl2/tr_image.c b/src/renderergl2/tr_image.c index 08894a4a..331e7f61 100644 --- a/src/renderergl2/tr_image.c +++ b/src/renderergl2/tr_image.c @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_image.c #include "tr_local.h" +#include "tr_dsa.h" + static byte s_intensitytable[256]; static unsigned char s_gammatable[256]; @@ -114,10 +116,9 @@ void GL_TextureMode( const char *string ) { // change all the existing mipmap texture objects for ( i = 0 ; i < tr.numImages ; i++ ) { glt = tr.images[ i ]; - if ( glt->flags & IMGFLAG_MIPMAP ) { - GL_Bind (glt); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + if ( glt->flags & IMGFLAG_MIPMAP && !(glt->flags & IMGFLAG_CUBEMAP)) { + qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } } } @@ -177,15 +178,20 @@ void R_ImageList_f( void ) { format = "sBPTC"; // 128 bits per 16 pixels, so 1 byte per pixel break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - format = "LATC "; + case GL_COMPRESSED_RG_RGTC2: + format = "RGTC2"; // 128 bits per 16 pixels, so 1 byte per pixel break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: format = "DXT1 "; // 64 bits per 16 pixels, so 4 bits per pixel estSize /= 2; break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + format = "DXT1a"; + // 64 bits per 16 pixels, so 4 bits per pixel + estSize /= 2; + break; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: format = "DXT5 "; // 128 bits per 16 pixels, so 1 byte per pixel @@ -1332,41 +1338,6 @@ static void R_MipMapsRGB( byte *in, int inWidth, int inHeight) } -static void R_MipMapLuminanceAlpha (const byte *in, byte *out, int width, int height) -{ - int i, j, row; - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i<width ; i++, out+=4, in+=8 ) { - out[0] = - out[1] = - out[2] = (in[0] + in[4]) >> 1; - out[3] = (in[3] + in[7]) >> 1; - } - return; - } - - for (i=0 ; i<height ; i++, in+=row) { - for (j=0 ; j<width ; j++, out+=4, in+=8) { - out[0] = - out[1] = - out[2] = (in[0] + in[4] + in[row ] + in[row+4]) >> 2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7]) >> 2; - } - } - -} - - static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int height, qboolean swizzle) { int i, j; @@ -1482,7 +1453,7 @@ RawImage_ScaleToPower2 =============== */ -static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_height, int *inout_scaled_width, int *inout_scaled_height, imgType_t type, imgFlags_t flags, byte **resampledBuffer) +static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_height, imgType_t type, imgFlags_t flags, byte **resampledBuffer) { int width = *inout_width; int height = *inout_height; @@ -1491,6 +1462,7 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he qboolean picmip = flags & IMGFLAG_PICMIP; qboolean mipmap = flags & IMGFLAG_MIPMAP; qboolean clampToEdge = flags & IMGFLAG_CLAMPTOEDGE; + qboolean notScaled; // // convert to exact power of 2 sizes @@ -1537,22 +1509,9 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he *resampledBuffer = ri.Hunk_AllocateTempMemory( finalwidth * finalheight * 4 ); if (scaled_width != width || scaled_height != height) - { ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); - } else - { - byte *inbyte, *outbyte; - int i; - - inbyte = *data; - outbyte = *resampledBuffer; - - for (i = width * height * 4; i > 0; i--) - { - *outbyte++ = *inbyte++; - } - } + Com_Memcpy(*resampledBuffer, *data, width * height * 4); if (type == IMGTYPE_COLORALPHA) RGBAtoYCoCgA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); @@ -1566,34 +1525,29 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he } if (type == IMGTYPE_COLORALPHA) - { YCoCgAtoRGBA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } - //endTime = ri.Milliseconds(); //ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime); *data = *resampledBuffer; - width = scaled_width; - height = scaled_height; } - else if ( scaled_width != width || scaled_height != height ) { + else if ( scaled_width != width || scaled_height != height ) + { if (data && resampledBuffer) { *resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); *data = *resampledBuffer; } - width = scaled_width; - height = scaled_height; } + width = scaled_width; + height = scaled_height; + // // perform optional picmip operation // @@ -1603,16 +1557,6 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he } // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; - } - - // // clamp to the current upper OpenGL limit // scale both axis down equally so we don't have to // deal with a half mip resampling @@ -1623,10 +1567,35 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he scaled_height >>= 1; } - *inout_width = width; - *inout_height = height; - *inout_scaled_width = scaled_width; - *inout_scaled_height = scaled_height; + // + // clamp to minimum size + // + scaled_width = MAX(1, scaled_width); + scaled_height = MAX(1, scaled_height); + + notScaled = (width == scaled_width) && (height == scaled_height); + + // + // rescale texture to new size using existing mipmap functions + // + if (data) + { + while (width > scaled_width || height > scaled_height) + { + if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) + R_MipMapNormalHeight(*data, *data, width, height, qfalse); + else + R_MipMapsRGB(*data, width, height); + + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + } + } + + *inout_width = width; + *inout_height = height; + + return notScaled; } @@ -1648,22 +1617,25 @@ static qboolean RawImage_HasAlpha(const byte *scan, int numPixels) return qfalse; } -static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean lightMap, imgType_t type, imgFlags_t flags) +static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picFormat, qboolean lightMap, imgType_t type, imgFlags_t flags) { int samples = 3; GLenum internalFormat = GL_RGB; qboolean forceNoCompression = (flags & IMGFLAG_NO_COMPRESSION); qboolean normalmap = (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT); + if (picFormat != GL_RGBA8) + return picFormat; + if(normalmap) { - if ((!RawImage_HasAlpha(data, numPixels) || (type == IMGTYPE_NORMAL)) && !forceNoCompression && (glRefConfig.textureCompression & TCR_LATC)) + if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels)) { - internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; - } - else - { - if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) + if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC) + { + internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + } + else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB) { internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } @@ -1680,6 +1652,33 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean light internalFormat = GL_RGBA; } } + else + { + if (!forceNoCompression && glRefConfig.textureCompression & TCR_RGTC) + { + internalFormat = GL_COMPRESSED_RG_RGTC2; + } + else if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC) + { + internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + } + else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB) + { + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + else if (r_texturebits->integer == 16) + { + internalFormat = GL_RGB5; + } + else if (r_texturebits->integer == 32) + { + internalFormat = GL_RGB8; + } + else + { + internalFormat = GL_RGB; + } + } } else if(lightMap) { @@ -1775,12 +1774,147 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean light return internalFormat; } +static void CompressMonoBlock(byte outdata[8], const byte indata[16]) +{ + int hi, lo, diff, bias, outbyte, shift, i; + byte *p = outdata; + + hi = lo = indata[0]; + for (i = 1; i < 16; i++) + { + hi = MAX(indata[i], hi); + lo = MIN(indata[i], lo); + } + + *p++ = hi; + *p++ = lo; + + diff = hi - lo; + + if (diff == 0) + { + outbyte = (hi == 255) ? 255 : 0; + + for (i = 0; i < 6; i++) + *p++ = outbyte; + + return; + } + + bias = diff / 2 - lo * 7; + outbyte = shift = 0; + for (i = 0; i < 16; i++) + { + const byte fixIndex[8] = { 1, 7, 6, 5, 4, 3, 2, 0 }; + byte index = fixIndex[(indata[i] * 7 + bias) / diff]; -static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) + outbyte |= index << shift; + shift += 3; + if (shift >= 8) + { + *p++ = outbyte & 0xff; + shift -= 8; + outbyte >>= 8; + } + } +} + +static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip) { - int dataFormat, dataType; + int wBlocks, hBlocks, y, x, size; + byte *compressedData, *p; - switch(internalFormat) + wBlocks = (width + 3) / 4; + hBlocks = (height + 3) / 4; + size = wBlocks * hBlocks * 16; + + p = compressedData = ri.Hunk_AllocateTempMemory(size); + for (y = 0; y < height; y += 4) + { + int oh = MIN(4, height - y); + + for (x = 0; x < width; x += 4) + { + byte workingData[16]; + int component; + + int ow = MIN(4, width - x); + + for (component = 0; component < 2; component++) + { + int ox, oy; + + for (oy = 0; oy < oh; oy++) + for (ox = 0; ox < ow; ox++) + workingData[oy * 4 + ox] = data[((y + oy) * width + x + ox) * 4 + component]; + + // dupe data to fill + for (oy = 0; oy < 4; oy++) + for (ox = (oy < oh) ? ow : 0; ox < 4; ox++) + workingData[oy * 4 + ox] = workingData[(oy % oh) * 4 + ox % ow]; + + CompressMonoBlock(p, workingData); + p += 8; + } + } + } + + qglCompressedTextureImage2D(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData); + + ri.Hunk_FreeTempMemory(compressedData); +} + +static int CalculateMipSize(int width, int height, GLenum picFormat) +{ + int numBlocks = ((width + 3) / 4) * ((height + 3) / 4); + int numPixels = width * height; + + switch (picFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + return numBlocks * 8; + + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB: + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB: + case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: + return numBlocks * 16; + + case GL_RGBA8: + case GL_SRGB8_ALPHA8_EXT: + return numPixels * 4; + + default: + ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat); + return 0; + } + + return 0; +} + + +static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) +{ + int dataFormat, dataType; + qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2); + qboolean compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT)); + qboolean mipmap = !!(flags & IMGFLAG_MIPMAP); + qboolean picmip = !!(flags & IMGFLAG_PICMIP); + int size, miplevel; + qboolean lastMip = qfalse; + + switch (internalFormat) { case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16_ARB: @@ -1799,60 +1933,83 @@ static void RawImage_UploadTexture( byte *data, int x, int y, int width, int hei break; } - if ( subtexture ) - qglTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, dataFormat, dataType, data ); - else - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, dataType, data ); + if (!data) + { + miplevel = 0; + do + { + lastMip = (width == 1 && height == 1) || !mipmap; + qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL); + + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + miplevel++; + } + while (!lastMip); + + return; + } - if (flags & IMGFLAG_MIPMAP) + if (compressed && picmip) { - int miplevel; + for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--) + { + size = CalculateMipSize(width, height, picFormat); + x >>= 1; + y >>= 1; + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + data += size; + } + } - miplevel = 0; - while (width > 1 || height > 1) + miplevel = 0; + do + { + lastMip = (width == 1 && height == 1) || !mipmap; + size = CalculateMipSize(width, height, picFormat); + + if (compressed) { - if (data) + if (subtexture) + qglCompressedTextureSubImage2D(texture, target, miplevel, x, y, width, height, picFormat, size, data); + else + qglCompressedTextureImage2D(texture, target, miplevel, picFormat, width, height, 0, size, data); + } + else + { + if (miplevel != 0 && r_colorMipLevels->integer) + R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]); + + if (rgtc) + RawImage_UploadToRgtc2Texture(texture, data, width, height, miplevel); + else if (subtexture) + qglTextureSubImage2D(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data); + else + qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data); + + if (!lastMip && numMips < 2) { if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - R_MipMapLuminanceAlpha( data, data, width, height ); - } - else - { - R_MipMapNormalHeight( data, data, width, height, qtrue); - } - } + R_MipMapNormalHeight(data, data, width, height, glRefConfig.swizzleNormalmap); else - { - R_MipMapsRGB( data, width, height ); - } + R_MipMapsRGB(data, width, height); } - - width >>= 1; - height >>= 1; - if (width < 1) - width = 1; - if (height < 1) - height = 1; - miplevel++; + } - if ( data && r_colorMipLevels->integer ) - R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] ); + x >>= 1; + y >>= 1; + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + miplevel++; - if ( subtexture ) - { - x >>= 1; - y >>= 1; - qglTexSubImage2D( GL_TEXTURE_2D, miplevel, x, y, width, height, dataFormat, dataType, data ); - } - else - { - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data ); - } + if (numMips > 1) + { + data += size; + numMips--; } } + while (!lastMip); } @@ -1862,23 +2019,51 @@ Upload32 =============== */ -static void Upload32( byte *data, int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight) +static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image) { - byte *scaledBuffer = NULL; byte *resampledBuffer = NULL; - int scaled_width, scaled_height; int i, c; byte *scan; - RawImage_ScaleToPower2(&data, &width, &height, &scaled_width, &scaled_height, type, flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); + imgType_t type = image->type; + imgFlags_t flags = image->flags; + GLenum internalFormat = image->internalFormat; + qboolean subtexture = (x != 0) || (y != 0) || (width != image->width) || (height != image->height); + qboolean notScaled = qtrue; + qboolean compressed = (picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT); + qboolean mipmap = !!(flags & IMGFLAG_MIPMAP) && (!compressed || numMips > 1); + qboolean cubemap = !!(flags & IMGFLAG_CUBEMAP); + GLenum uploadTarget = cubemap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : GL_TEXTURE_2D; + GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + int depth = cubemap ? 6 : 1; + + if (!data) + { + RawImage_ScaleToPower2(NULL, &width, &height, type, flags, NULL); + for (i = 0; i < depth; i++) + RawImage_UploadTexture(image->texnum, NULL, 0, 0, width, height, uploadTarget + i, GL_RGBA8, 0, internalFormat, type, flags, qfalse); + goto done; + } + else if (!subtexture) + { + if (compressed || cubemap) + { + for (i = 0; i < depth; i++) + { + int w2 = width, h2 = height; + RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget + i, picFormat, numMips, internalFormat, type, flags, qfalse); + for (c = numMips; c; c--) + { + data += CalculateMipSize(w2, h2, picFormat); + w2 = MAX(1, w2 >> 1); + h2 = MAX(1, h2 >> 1); + } + } + goto done; + } + notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer); + } - // - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not - // c = width*height; scan = data; @@ -1903,137 +2088,44 @@ static void Upload32( byte *data, int width, int height, imgType_t type, imgFlag } } - // normals are always swizzled - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { + if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)) RawImage_SwizzleRA(data, width, height); - } - // LATC2 is only used for normals - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(flags & IMGFLAG_MIPMAP)) - { - RawImage_UploadTexture( data, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse ); - //qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; + // This corresponds to what the OpenGL1 renderer does + if (!(flags & IMGFLAG_NOLIGHTSCALE) && (!notScaled || mipmap)) + R_LightScaleTexture(data, width, height, !mipmap); - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else + if (subtexture) { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - R_MipMapLuminanceAlpha( data, data, width, height ); - } - else - { - R_MipMapNormalHeight( data, data, width, height, qtrue); - } - } - else - { - R_MipMapsRGB( data, width, height ); - } - - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); + // FIXME: Incorrect if original texture was not a power of 2 texture or picmipped + RawImage_UploadTexture(image->texnum, data, x, y, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qtrue); + GL_CheckErrors(); + return; } - if (!(flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(flags & IMGFLAG_MIPMAP) ); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(scaledBuffer, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); + RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse); done: - if (flags & IMGFLAG_MIPMAP) - { - if ( glConfig.textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( glConfig.textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - - -static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight ) -{ - int scaled_width, scaled_height; - - RawImage_ScaleToPower2(NULL, &width, &height, &scaled_width, &scaled_height, type, flags, NULL); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(NULL, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); + image->uploadWidth = width; + image->uploadHeight = height; - if (flags & IMGFLAG_MIPMAP) + if (mipmap) { - if ( glConfig.textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer ) ); + if (glConfig.textureFilterAnisotropic && !cubemap) + qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, + (GLint)Com_Clamp(1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer)); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max); } else { - if ( glConfig.textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); + if (glConfig.textureFilterAnisotropic && !cubemap) + qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } // Fix for sampling depth buffer on old nVidia cards @@ -2044,26 +2136,29 @@ static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flag case GL_DEPTH_COMPONENT16_ARB: case GL_DEPTH_COMPONENT24_ARB: case GL_DEPTH_COMPONENT32_ARB: - qglTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + qglTextureParameterf(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; default: break; } GL_CheckErrors(); + + if ( resampledBuffer != NULL ) + ri.Hunk_FreeTempMemory( resampledBuffer ); } /* ================ -R_CreateImage +R_CreateImage2 This is the only way any image_t are created ================ */ -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ) { +image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLenum picFormat, int numMips, imgType_t type, imgFlags_t flags, int internalFormat ) { image_t *image; qboolean isLightmap = qfalse; long hash; @@ -2097,81 +2192,24 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT glWrapClampMode = GL_REPEAT; if (!internalFormat) - { - if (image->flags & IMGFLAG_CUBEMAP) - internalFormat = GL_RGBA8; - else - internalFormat = RawImage_GetFormat(pic, width * height, isLightmap, image->type, image->flags); - } + internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags); image->internalFormat = internalFormat; - - // lightmaps are always allocated on TMU 1 - if ( qglActiveTextureARB && isLightmap ) { - image->TMU = 1; - } else { - image->TMU = 0; - } - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } + Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image); if (image->flags & IMGFLAG_CUBEMAP) { - GL_Bind(image); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - if (image->flags & IMGFLAG_MIPMAP) - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - else - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - - if (image->flags & IMGFLAG_MIPMAP) - qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); - - image->uploadWidth = width; - image->uploadHeight = height; + qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, glWrapClampMode); + qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, glWrapClampMode); + qglTextureParameteri(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, glWrapClampMode); } else { - GL_Bind(image); - - if (pic) - { - Upload32( pic, image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - else - { - EmptyTexture(image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); + qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode); + qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode); } - GL_SelectTexture( 0 ); - hash = generateHashValue(name); image->next = hashTable[hash]; hashTable[hash] = image; @@ -2179,114 +2217,30 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT return image; } -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ) -{ - byte *scaledBuffer = NULL; - byte *resampledBuffer = NULL; - int scaled_width, scaled_height, scaled_x, scaled_y; - byte *data = pic; - - // normals are always swizzled - if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT) - { - RawImage_SwizzleRA(pic, width, height); - } - - // LATC2 is only used for normals - if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - - RawImage_ScaleToPower2(&pic, &width, &height, &scaled_width, &scaled_height, image->type, image->flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - GL_Bind(image); - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(image->flags & IMGFLAG_MIPMAP)) - { - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); - //qglTexSubImage2D( GL_TEXTURE_2D, 0, scaled_x, scaled_y, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, data ); - - GL_CheckErrors(); - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT) - { - if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - R_MipMapLuminanceAlpha( data, data, width, height ); - } - else - { - R_MipMapNormalHeight( data, data, width, height, qtrue); - } - } - else - { - R_MipMapsRGB( data, width, height ); - } - - width >>= 1; - height >>= 1; - x >>= 1; - y >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - if (!(image->flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(image->flags & IMGFLAG_MIPMAP) ); - - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( (byte *)data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); +/* +================ +R_CreateImage -done: - - GL_SelectTexture( 0 ); +Wrapper for R_CreateImage2(), for the old parameters. +================ +*/ +image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat) +{ + return R_CreateImage2(name, pic, width, height, GL_RGBA8, 0, type, flags, internalFormat); +} - GL_CheckErrors(); - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); +void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ) +{ + Upload32(pic, x, y, width, height, GL_RGBA8, 0, image); } //=================================================================== +// Prototype for dds loader function which isn't common to both renderers +void R_LoadDDS(const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips); + typedef struct { char *ext; @@ -2315,7 +2269,7 @@ Loads any of the supported image types into a cannonical 32 bit format. ================= */ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) +void R_LoadImage( const char *name, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips ) { qboolean orgNameFailed = qfalse; int orgLoader = -1; @@ -2327,11 +2281,28 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height ) *pic = NULL; *width = 0; *height = 0; + *picFormat = GL_RGBA8; + *numMips = 0; Q_strncpyz( localName, name, MAX_QPATH ); ext = COM_GetExtension( localName ); + // If compressed textures are enabled, try loading a DDS first, it'll load fastest + if (r_ext_compressed_textures->integer) + { + char ddsName[MAX_QPATH]; + + COM_StripExtension(name, ddsName, MAX_QPATH); + Q_strcat(ddsName, MAX_QPATH, ".dds"); + + R_LoadDDS(ddsName, pic, width, height, picFormat, numMips); + + // If loaded, we're done. + if (*pic) + return; + } + if( *ext ) { // Look for the correct loader and use it @@ -2403,7 +2374,10 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) image_t *image; int width, height; byte *pic; + GLenum picFormat; + int picNumMips; long hash; + imgFlags_t checkFlagsTrue, checkFlagsFalse; if (!name) { return NULL; @@ -2429,12 +2403,15 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) // // load the pic from disk // - R_LoadImage( name, &pic, &width, &height ); + R_LoadImage( name, &pic, &width, &height, &picFormat, &picNumMips ); if ( pic == NULL ) { return NULL; } - if (r_normalMapping->integer && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP)) + checkFlagsTrue = IMGFLAG_PICMIP | IMGFLAG_MIPMAP | IMGFLAG_GENNORMALMAP; + checkFlagsFalse = IMGFLAG_CUBEMAP; + if (r_normalMapping->integer && (picFormat == GL_RGBA8) && (type == IMGTYPE_COLORALPHA) && + ((flags & checkFlagsTrue) == checkFlagsTrue) && !(flags & checkFlagsFalse)) { char normalName[MAX_QPATH]; image_t *normalImage; @@ -2537,7 +2514,21 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) } } - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); + // force mipmaps off if image is compressed but doesn't have enough mips + if ((flags & IMGFLAG_MIPMAP) && picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT) + { + int wh = MAX(width, height); + int neededMips = 0; + while (wh) + { + neededMips++; + wh >>= 1; + } + if (neededMips > picNumMips) + flags &= ~IMGFLAG_MIPMAP; + } + + image = R_CreateImage2( ( char * ) name, pic, width, height, picFormat, picNumMips, type, flags, 0 ); ri.Free( pic ); return image; } @@ -2764,6 +2755,12 @@ void R_CreateBuiltinImages( void ) { tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); + if (r_shadowBlur->integer) + tr.screenScratchImage = R_CreateImage("screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); + + if (r_shadowBlur->integer || r_ssao->integer) + tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); + if (r_drawSunRays->integer) tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); @@ -2811,7 +2808,6 @@ void R_CreateBuiltinImages( void ) { if (r_ssao->integer) { tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); } if (r_shadows->integer == 4) @@ -2827,11 +2823,8 @@ void R_CreateBuiltinImages( void ) { for ( x = 0; x < 4; x++) { tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - GL_Bind(tr.sunShadowDepthImage[x]); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); @@ -2839,7 +2832,7 @@ void R_CreateBuiltinImages( void ) { if (r_cubeMapping->integer) { - tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); + tr.renderCubeImage = R_CreateImage("*renderCube", NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); } } } @@ -2856,7 +2849,11 @@ void R_SetColorMappings( void ) { int inf; // setup the overbright lighting +#if defined(USE_OVERBRIGHT) tr.overbrightBits = r_overBrightBits->integer; +#else + tr.overbrightBits = 0; +#endif // allow 2 overbright bits if ( tr.overbrightBits > 2 ) { @@ -2865,6 +2862,11 @@ void R_SetColorMappings( void ) { tr.overbrightBits = 0; } + // don't allow more overbright bits than map overbright bits + if ( tr.overbrightBits > r_mapOverBrightBits->integer ) { + tr.overbrightBits = r_mapOverBrightBits->integer; + } + tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); tr.identityLightByte = 255 * tr.identityLight; @@ -2940,15 +2942,7 @@ void R_DeleteTextures( void ) { tr.numImages = 0; - Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - GL_SelectTexture( 0 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - } else { - qglBindTexture( GL_TEXTURE_2D, 0 ); - } + GL_BindNullTextures(); } /* @@ -3121,7 +3115,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { // If not a .skin file, load as a single shader if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); + skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); return hSkin; } @@ -3192,7 +3186,7 @@ void R_InitSkins( void ) { skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) ); skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); + skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); skin->surfaces[0]->shader = tr.defaultShader; } |