Skip to content

Commit

Permalink
OpenGL2: DDS (compressed textures) support.
Browse files Browse the repository at this point in the history
  • Loading branch information
SmileTheory committed Dec 18, 2015
1 parent 3364192 commit f965f3c
Show file tree
Hide file tree
Showing 3 changed files with 564 additions and 15 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -1664,6 +1664,7 @@ Q3R2OBJ = \
$(B)/renderergl2/tr_image_pcx.o \
$(B)/renderergl2/tr_image_png.o \
$(B)/renderergl2/tr_image_tga.o \
$(B)/renderergl2/tr_image_dds.o \
$(B)/renderergl2/tr_init.o \
$(B)/renderergl2/tr_light.o \
$(B)/renderergl2/tr_main.o \
Expand Down
130 changes: 115 additions & 15 deletions code/renderergl2/tr_image.c
Expand Up @@ -1615,13 +1615,16 @@ 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 ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels))
Expand Down Expand Up @@ -1860,11 +1863,67 @@ static void RawImage_UploadToRgtc2Texture(byte *data, int width, int height, int
}


static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
{
int dataFormat, dataType;
qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2);

if (picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
{
int bytesPer4x4Block = 0;
int miplevel = 0;

switch (picFormat)
{
case GL_COMPRESSED_RGB_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:
bytesPer4x4Block = 8;
break;
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:
bytesPer4x4Block = 16;
break;
default:
ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat);
return;
break;

This comment has been minimized.

Copy link
@Mateos81

Mateos81 Dec 18, 2015

A break after a return?

}

for (miplevel = 0; miplevel < numMips; miplevel++)
{
int size;

size = ((width + 3) / 4) * ((height + 3) / 4) * bytesPer4x4Block;

if (subtexture)
qglCompressedTexSubImage2DARB(GL_TEXTURE_2D, miplevel, x, y, width, height, internalFormat, size, data);
else
qglCompressedTexImage2DARB(GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, size, data);

x >>= 1;
y >>= 1;
x -= x % 4;
y -= y % 4;

width = MAX(1, width >> 1);
height = MAX(1, height >> 1);
data += size;
}

return;
}

switch(internalFormat)
{
case GL_DEPTH_COMPONENT:
Expand Down Expand Up @@ -1948,7 +2007,7 @@ Upload32
===============
*/
static void Upload32(byte *data, int x, int y, int width, int height, image_t *image)
static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image)
{
byte *resampledBuffer = NULL;
int i, c;
Expand All @@ -1964,11 +2023,16 @@ static void Upload32(byte *data, int x, int y, int width, int height, image_t *i
if (!data)
{
RawImage_ScaleToPower2(NULL, &width, &height, type, flags, NULL);
RawImage_UploadTexture(NULL, 0, 0, width, height, internalFormat, type, flags, qfalse);
RawImage_UploadTexture(NULL, 0, 0, width, height, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
goto done;
}
else if (!subtexture)
{
if (picFormat != GL_RGBA8)
{
RawImage_UploadTexture(data, 0, 0, width, height, picFormat, numMips, internalFormat, type, flags, qfalse);
goto done;
}
notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer);
}

Expand Down Expand Up @@ -2006,12 +2070,12 @@ static void Upload32(byte *data, int x, int y, int width, int height, image_t *i
if (subtexture)
{
// FIXME: Incorrect if original texture was not a power of 2 texture or picmipped
RawImage_UploadTexture(data, x, y, width, height, internalFormat, type, flags, qtrue);
RawImage_UploadTexture(data, x, y, width, height, GL_RGBA8, 0, internalFormat, type, flags, qtrue);
GL_CheckErrors();
return;
}

RawImage_UploadTexture(data, 0, 0, width, height, internalFormat, type, flags, qfalse);
RawImage_UploadTexture(data, 0, 0, width, height, GL_RGBA8, 0, internalFormat, type, flags, qfalse);

done:

Expand Down Expand Up @@ -2061,12 +2125,12 @@ static void Upload32(byte *data, int x, int y, int width, int height, image_t *i

/*
================
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 ) {

This comment has been minimized.

Copy link
@ensiform

ensiform Dec 18, 2015

I think Ex or Ext sounds better than "2" as in extended version. :/

image_t *image;
qboolean isLightmap = qfalse;
long hash;
Expand Down Expand Up @@ -2104,7 +2168,7 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
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;
Expand Down Expand Up @@ -2155,7 +2219,7 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
}
else
{
Upload32( pic, 0, 0, image->width, image->height, image );
Upload32( pic, 0, 0, image->width, image->height, picFormat, numMips, image );

qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
Expand All @@ -2170,6 +2234,20 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
return image;
}


/*
================
R_CreateImage
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);
}


void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
{
if (qglActiveTextureARB) {
Expand All @@ -2178,13 +2256,16 @@ void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int h

GL_Bind(image);

Upload32(pic, x, y, width, height, image);
Upload32(pic, x, y, width, height, GL_RGBA8, 0, image);

GL_SelectTexture(0);
}

//===================================================================

// 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;
Expand Down Expand Up @@ -2213,7 +2294,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;
Expand All @@ -2225,11 +2306,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
Expand Down Expand Up @@ -2301,6 +2399,8 @@ 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;

if (!name) {
Expand All @@ -2327,12 +2427,12 @@ 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))
if (r_normalMapping->integer && (picFormat == GL_RGBA8) && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP))
{
char normalName[MAX_QPATH];
image_t *normalImage;
Expand Down Expand Up @@ -2435,7 +2535,7 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
}
}

image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 );
image = R_CreateImage2( ( char * ) name, pic, width, height, picFormat, picNumMips, type, flags, 0 );
ri.Free( pic );
return image;
}
Expand Down

6 comments on commit f965f3c

@leilei-
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only for gl2?

@ensiform
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not really a benefit to DDS support for gl1 imo.

@leilei-
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supporting the original releases of the dmmq3 maps would be one.

@ensiform
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, considering there is no dds support in any other standard Q3 engine which makes the maps invalid?

@leilei-
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's what made those particular maps exclusive to a vendor-locked DDS-supporting old q3 build (S3Quake3) way back in Jan 2000

@ensiform
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was unaware.

Please sign in to comment.