📄 tr_image.c
字号:
Upload32
===============
*/
extern qboolean charSet;
static void Upload32( unsigned *data,
int width, int height,
qboolean mipmap,
qboolean picmip,
qboolean lightMap,
int *format,
int *pUploadWidth, int *pUploadHeight )
{
int samples;
unsigned *scaledBuffer = NULL;
unsigned *resampledBuffer = NULL;
int scaled_width, scaled_height;
int i, c;
byte *scan;
GLenum internalFormat = GL_RGB;
float rMax = 0, gMax = 0, bMax = 0;
//
// convert to exact power of 2 sizes
//
for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
;
for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
;
if ( r_roundImagesDown->integer && scaled_width > width )
scaled_width >>= 1;
if ( r_roundImagesDown->integer && scaled_height > height )
scaled_height >>= 1;
if ( scaled_width != width || scaled_height != height ) {
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;
}
//
// perform optional picmip operation
//
if ( picmip ) {
scaled_width >>= r_picmip->integer;
scaled_height >>= r_picmip->integer;
}
//
// 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
//
while ( scaled_width > glConfig.maxTextureSize
|| scaled_height > glConfig.maxTextureSize ) {
scaled_width >>= 1;
scaled_height >>= 1;
}
scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
//
// scan the texture for each channel's max values
// and verify if the alpha channel is being used or not
//
c = width*height;
scan = ((byte *)data);
samples = 3;
if (!lightMap) {
for ( i = 0; i < c; i++ )
{
if ( scan[i*4+0] > rMax )
{
rMax = scan[i*4+0];
}
if ( scan[i*4+1] > gMax )
{
gMax = scan[i*4+1];
}
if ( scan[i*4+2] > bMax )
{
bMax = scan[i*4+2];
}
if ( scan[i*4 + 3] != 255 )
{
samples = 4;
break;
}
}
// select proper internal format
if ( samples == 3 )
{
if ( glConfig.textureCompression == TC_S3TC )
{
internalFormat = GL_RGB4_S3TC;
}
else if ( r_texturebits->integer == 16 )
{
internalFormat = GL_RGB5;
}
else if ( r_texturebits->integer == 32 )
{
internalFormat = GL_RGB8;
}
else
{
internalFormat = 3;
}
}
else if ( samples == 4 )
{
if ( r_texturebits->integer == 16 )
{
internalFormat = GL_RGBA4;
}
else if ( r_texturebits->integer == 32 )
{
internalFormat = GL_RGBA8;
}
else
{
internalFormat = 4;
}
}
} else {
internalFormat = 3;
}
// copy or resample data as appropriate for first MIP level
if ( ( scaled_width == width ) &&
( scaled_height == height ) ) {
if (!mipmap)
{
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
*pUploadWidth = scaled_width;
*pUploadHeight = scaled_height;
*format = internalFormat;
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 ) {
R_MipMap( (byte *)data, width, height );
width >>= 1;
height >>= 1;
if ( width < 1 ) {
width = 1;
}
if ( height < 1 ) {
height = 1;
}
}
Com_Memcpy( scaledBuffer, data, width * height * 4 );
}
R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap );
*pUploadWidth = scaled_width;
*pUploadHeight = scaled_height;
*format = internalFormat;
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
if (mipmap)
{
int miplevel;
miplevel = 0;
while (scaled_width > 1 || scaled_height > 1)
{
R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height );
scaled_width >>= 1;
scaled_height >>= 1;
if (scaled_width < 1)
scaled_width = 1;
if (scaled_height < 1)
scaled_height = 1;
miplevel++;
if ( r_colorMipLevels->integer ) {
R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
}
qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
}
}
done:
if (mipmap)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
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 );
}
/*
================
R_CreateImage
This is the only way any image_t are created
================
*/
image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
image_t *image;
qboolean isLightmap = qfalse;
long hash;
if (strlen(name) >= MAX_QPATH ) {
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
}
if ( !strncmp( name, "*lightmap", 9 ) ) {
isLightmap = qtrue;
}
if ( tr.numImages == MAX_DRAWIMAGES ) {
ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
}
image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
image->texnum = 1024 + tr.numImages;
tr.numImages++;
image->mipmap = mipmap;
image->allowPicmip = allowPicmip;
strcpy (image->imgName, name);
image->width = width;
image->height = height;
image->wrapClampMode = glWrapClampMode;
// lightmaps are always allocated on TMU 1
if ( qglActiveTextureARB && isLightmap ) {
image->TMU = 1;
} else {
image->TMU = 0;
}
if ( qglActiveTextureARB ) {
GL_SelectTexture( image->TMU );
}
GL_Bind(image);
Upload32( (unsigned *)pic, image->width, image->height,
image->mipmap,
allowPicmip,
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 );
qglBindTexture( GL_TEXTURE_2D, 0 );
if ( image->TMU == 1 ) {
GL_SelectTexture( 0 );
}
hash = generateHashValue(name);
image->next = hashTable[hash];
hashTable[hash] = image;
return image;
}
/*
=========================================================
BMP LOADING
=========================================================
*/
typedef struct
{
char id[2];
unsigned long fileSize;
unsigned long reserved0;
unsigned long bitmapDataOffset;
unsigned long bitmapHeaderSize;
unsigned long width;
unsigned long height;
unsigned short planes;
unsigned short bitsPerPixel;
unsigned long compression;
unsigned long bitmapDataSize;
unsigned long hRes;
unsigned long vRes;
unsigned long colors;
unsigned long importantColors;
unsigned char palette[256][4];
} BMPHeader_t;
static void LoadBMP( const char *name, byte **pic, int *width, int *height )
{
int columns, rows, numPixels;
byte *pixbuf;
int row, column;
byte *buf_p;
byte *buffer;
int length;
BMPHeader_t bmpHeader;
byte *bmpRGBA;
*pic = NULL;
//
// load the file
//
length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
if (!buffer) {
return;
}
buf_p = buffer;
bmpHeader.id[0] = *buf_p++;
bmpHeader.id[1] = *buf_p++;
bmpHeader.fileSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.width = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.height = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.planes = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.compression = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.hRes = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.vRes = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.colors = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.importantColors = LittleLong( * ( long * ) buf_p );
buf_p += 4;
Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
if ( bmpHeader.bitsPerPixel == 8 )
buf_p += 1024;
if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
{
ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
}
if ( bmpHeader.fileSize != length )
{
ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
}
if ( bmpHeader.compression != 0 )
{
ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
}
if ( bmpHeader.bitsPerPixel < 8 )
{
ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
}
columns = bmpHeader.width;
rows = bmpHeader.height;
if ( rows < 0 )
rows = -rows;
numPixels = columns * rows;
if ( width )
*width = columns;
if ( height )
*height = rows;
bmpRGBA = ri.Malloc( numPixels * 4 );
*pic = bmpRGBA;
for ( row = rows-1; row >= 0; row-- )
{
pixbuf = bmpRGBA + row*columns*4;
for ( column = 0; column < columns; column++ )
{
unsigned char red, green, blue, alpha;
int palIndex;
unsigned short shortPixel;
switch ( bmpHeader.bitsPerPixel )
{
case 8:
palIndex = *buf_p++;
*pixbuf++ = bmpHeader.palette[palIndex][2];
*pixbuf++ = bmpHeader.palette[palIndex][1];
*pixbuf++ = bmpHeader.palette[palIndex][0];
*pixbuf++ = 0xff;
break;
case 16:
shortPixel = * ( unsigned short * ) pixbuf;
pixbuf += 2;
*pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
*pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
*pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
*pixbuf++ = 0xff;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alpha = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alpha;
break;
default:
ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
break;
}
}
}
ri.FS_FreeFile( buffer );
}
/*
=================================================================
PCX LOADING
=================================================================
*/
/*
==============
LoadPCX
==============
*/
static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height)
{
byte *raw;
pcx_t *pcx;
int x, y;
int len;
int dataByte, runLength;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -