You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1078 lines
28 KiB
1078 lines
28 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: texture.c
|
|
*
|
|
* Texture handling functions
|
|
*
|
|
* Copyright (c) 1994 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
#include <scrnsave.h>
|
|
#include <commdlg.h>
|
|
|
|
#include "mtk.h"
|
|
#include "texture.hxx"
|
|
#include "glutil.hxx"
|
|
|
|
//static int VerifyTextureFile( TEXFILE *pTexFile );
|
|
static int GetTexFileType( TEXFILE *pTexFile );
|
|
|
|
static PFNGLCOLORTABLEEXTPROC pfnColorTableEXT;
|
|
static PFNGLCOLORSUBTABLEEXTPROC pfnColorSubTableEXT;
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* TEXTURE
|
|
*
|
|
* Create a texture from a BMP or RGB file
|
|
*
|
|
\**************************************************************************/
|
|
|
|
TEXTURE::TEXTURE( TEXFILE *pTexFile )
|
|
{
|
|
TK_RGBImageRec *image = (TK_RGBImageRec *) NULL;
|
|
LPTSTR pszBmpfile = pTexFile->szPathName;
|
|
int type;
|
|
|
|
Init();
|
|
|
|
// Verify file / set type
|
|
|
|
if( !(type = mtk_VerifyTextureFileData( pTexFile )) )
|
|
return;
|
|
|
|
// While we're still calling into the tk routines, disable popups
|
|
// Eventually should pull tk code in here - all that's required is the
|
|
// file parsing code.
|
|
|
|
tkErrorPopups( FALSE );
|
|
|
|
//mf: I guess can't have TEX_A8 type file ?
|
|
|
|
if( type == TEX_BMP ) {
|
|
|
|
#ifdef UNICODE
|
|
image = tkDIBImageLoadAW( (char *) pszBmpfile, TRUE );
|
|
#else
|
|
image = tkDIBImageLoadAW( (char *) pszBmpfile, FALSE );
|
|
#endif
|
|
} else {
|
|
#ifdef UNICODE
|
|
image = tkRGBImageLoadAW( (char *) pszBmpfile, TRUE );
|
|
#else
|
|
image = tkRGBImageLoadAW( (char *) pszBmpfile, FALSE );
|
|
#endif
|
|
}
|
|
|
|
if( !image ) {
|
|
return;
|
|
}
|
|
ProcessTkTexture( image );
|
|
}
|
|
|
|
TEXTURE::TEXTURE( LPTSTR pszBmpFile )
|
|
{
|
|
TK_RGBImageRec *image = (TK_RGBImageRec *) NULL;
|
|
int type;
|
|
TEXFILE texFile; // path name, plus offset to file name
|
|
|
|
Init();
|
|
|
|
//mf: this VerifyFile stuff needs some work
|
|
|
|
// Look for file, and set nOffset if found
|
|
lstrcpy( texFile.szPathName, pszBmpFile );
|
|
if( ! mtk_VerifyTextureFilePath( &texFile ) )
|
|
return;
|
|
|
|
// Now determine the file type (this also aborts if size is too big)
|
|
if( !(type = mtk_VerifyTextureFileData( &texFile )) )
|
|
return;
|
|
|
|
// Now the bmp file should point to the full path for tk
|
|
pszBmpFile = texFile.szPathName;
|
|
|
|
//mf: I guess can't have TEX_A8 type file ?
|
|
if( type == TEX_BMP ) {
|
|
|
|
#ifdef UNICODE
|
|
image = tkDIBImageLoadAW( (char *) pszBmpFile, TRUE );
|
|
#else
|
|
image = tkDIBImageLoadAW( (char *) pszBmpFile, FALSE );
|
|
#endif
|
|
} else {
|
|
#ifdef UNICODE
|
|
image = tkRGBImageLoadAW( (char *) pszBmpFile, TRUE );
|
|
#else
|
|
image = tkRGBImageLoadAW( (char *) pszBmpFile, FALSE );
|
|
#endif
|
|
}
|
|
|
|
if( !image ) {
|
|
return;
|
|
}
|
|
ProcessTkTexture( image );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* TEXTURE
|
|
*
|
|
* Create a texture from a BMP or other resource (RGB , A8, etc. )
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
TEXTURE::TEXTURE( TEX_RES *pTexRes, HINSTANCE hInst )
|
|
{
|
|
HMODULE hModule;
|
|
|
|
Init();
|
|
|
|
if( hInst )
|
|
hModule = hInst;
|
|
else
|
|
hModule = GetModuleHandle(NULL);
|
|
|
|
if( pTexRes->type == TEX_BMP )
|
|
LoadBitmapResource( MAKEINTRESOURCE( pTexRes->name ), hModule );
|
|
else
|
|
LoadOtherResource( pTexRes, hModule );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* TEXTURE
|
|
*
|
|
* Create a texture from an HBITMAP
|
|
*
|
|
\**************************************************************************/
|
|
|
|
TEXTURE::TEXTURE( HBITMAP hBitmap )
|
|
{
|
|
if (hBitmap == NULL)
|
|
{
|
|
SS_ERROR( "TEXTURE::TEXTURE : hBitmap is NULL\n" );
|
|
return;
|
|
}
|
|
|
|
Init();
|
|
LoadFromBitmap( hBitmap );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Load a bitmap texture resource, creating the HBITMAP from the resource
|
|
* identifier
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::LoadBitmapResource( LPTSTR pRes, HINSTANCE hInst )
|
|
{
|
|
HBITMAP hBitmap = LoadBitmap( hInst, pRes );
|
|
if( hBitmap == NULL ) {
|
|
SS_ERROR( "TEXTURE::LoadBitmapResource : LoadBitmap failure\n" );
|
|
return FALSE;
|
|
}
|
|
LoadFromBitmap( hBitmap );
|
|
DeleteObject( hBitmap );
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Load a non-bmp texture resource
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::LoadOtherResource( TEX_RES *pTexRes, HINSTANCE hInst )
|
|
{
|
|
HRSRC hr;
|
|
HGLOBAL hg;
|
|
LPVOID pv;
|
|
LPCTSTR lpType;
|
|
BOOL fLoaded = FALSE;
|
|
|
|
switch(pTexRes->type)
|
|
{
|
|
case TEX_RGB:
|
|
lpType = MAKEINTRESOURCE(RT_RGB);
|
|
break;
|
|
case TEX_A8:
|
|
lpType = MAKEINTRESOURCE(RT_A8);
|
|
break;
|
|
default :
|
|
return FALSE;
|
|
}
|
|
|
|
hr = FindResource(hInst, MAKEINTRESOURCE(pTexRes->name), lpType);
|
|
if (hr == NULL)
|
|
{
|
|
SS_ERROR( "TEXTURE::LoadOtherResource() : Can't find texture resource\n" );
|
|
goto EH_NotFound;
|
|
}
|
|
hg = LoadResource(hInst, hr);
|
|
if (hg == NULL)
|
|
{
|
|
SS_ERROR( "TEXTURE::LoadOtherResource() : Error loading texture resource\n" );
|
|
goto EH_FreeResource;
|
|
}
|
|
pv = (PSZ)LockResource(hg);
|
|
if (pv == NULL)
|
|
{
|
|
SS_ERROR( "TEXTURE::LoadOtherResource() : Error locking texture resource\n" );
|
|
goto EH_FreeResource;
|
|
}
|
|
|
|
switch(pTexRes->type)
|
|
{
|
|
case TEX_RGB:
|
|
fLoaded = RGBImageLoad( pv );
|
|
break;
|
|
case TEX_A8:
|
|
fLoaded = A8ImageLoad( pv );
|
|
break;
|
|
}
|
|
|
|
EH_FreeResource:
|
|
FreeResource(hr);
|
|
EH_NotFound:
|
|
|
|
if( !fLoaded ) {
|
|
SS_ERROR( "TEXTURE::LoadOtherResource() : Texture resource did not load\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
Process();
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Load a bitmap texture resource from an HBITMAP
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL
|
|
TEXTURE::LoadFromBitmap( HBITMAP hBitmap )
|
|
{
|
|
BOOL fLoaded = DIBImageLoad( hBitmap );
|
|
|
|
if( !fLoaded ) {
|
|
SS_ERROR( "TEXTURE::LoadFromBitmap : bitmap texture did not load\n" );
|
|
return FALSE;
|
|
}
|
|
Process();
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Init
|
|
*
|
|
* Common constructor intialization
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
TEXTURE::Init()
|
|
{
|
|
width = 0;
|
|
height = 0;
|
|
data = NULL;
|
|
pal_size = 0;
|
|
pal = NULL;
|
|
texObj = 0;
|
|
iPalRot = 0;
|
|
bMipmap = FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ValidateTextureSize
|
|
*
|
|
* - Scales the texture to powers of 2
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::ValidateSize()
|
|
{
|
|
double xPow2, yPow2;
|
|
int ixPow2, iyPow2;
|
|
int xSize2, ySize2;
|
|
float fxFact, fyFact;
|
|
GLint glMaxTexDim;
|
|
|
|
if( (width <= 0) || (height <= 0) ) {
|
|
SS_WARNING( "ValidateTextureSize : invalid texture dimensions\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// origAspectRatio = (float) height / (float) width;
|
|
//mf: changed this to standard x/y
|
|
origAspectRatio = (float) width / (float) height;
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
|
|
if( glMaxTexDim <= 0 )
|
|
return FALSE;
|
|
|
|
if( format != GL_COLOR_INDEX ) {
|
|
|
|
// We limit the max dimension here for performance reasons
|
|
glMaxTexDim = min(256, glMaxTexDim);
|
|
|
|
if (width <= glMaxTexDim)
|
|
xPow2 = log((double)width) / log((double)2.0);
|
|
else
|
|
xPow2 = log((double)glMaxTexDim) / log((double)2.0);
|
|
|
|
if (height <= glMaxTexDim)
|
|
yPow2 = log((double)height) / log((double)2.0);
|
|
else
|
|
yPow2 = log((double)glMaxTexDim) / log((double)2.0);
|
|
|
|
ixPow2 = (int)xPow2;
|
|
iyPow2 = (int)yPow2;
|
|
|
|
// Always scale to higher nearest power
|
|
if (xPow2 != (double)ixPow2)
|
|
ixPow2++;
|
|
if (yPow2 != (double)iyPow2)
|
|
iyPow2++;
|
|
|
|
xSize2 = 1 << ixPow2;
|
|
ySize2 = 1 << iyPow2;
|
|
|
|
if (xSize2 != width ||
|
|
ySize2 != height)
|
|
{
|
|
BYTE *pData;
|
|
|
|
pData = (BYTE *) malloc(xSize2 * ySize2 * components * sizeof(BYTE));
|
|
if (!pData) {
|
|
SS_WARNING( "ValidateTextureSize : can't alloc pData\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
if( gluScaleImage(format, width, height,
|
|
GL_UNSIGNED_BYTE, data,
|
|
xSize2, ySize2, GL_UNSIGNED_BYTE,
|
|
pData) )
|
|
{
|
|
// glu failure
|
|
SS_WARNING( "ValidateTextureSize : gluScaleImage failure\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// set the new width,height,data
|
|
width = xSize2;
|
|
height = ySize2;
|
|
free(data);
|
|
data = pData;
|
|
}
|
|
} else { // paletted texture case
|
|
//mf
|
|
// paletted texture: must be power of 2 - but might need to enforce
|
|
// here if not done in a8 load. Also have to check against
|
|
// GL_MAX_TEXTURE_SIZE. Could then clip it to power of 2 size
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* SetDefaultTextureParams
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
TEXTURE::SetDefaultParams()
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
if( bMipmap )
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
GL_LINEAR_MIPMAP_LINEAR);
|
|
else
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ProcessTexture
|
|
*
|
|
* - Verifies texture size
|
|
* - Fills out TEXTURE structure with required data
|
|
* - Creates a texture object if extension exists
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int
|
|
TEXTURE::Process()
|
|
{
|
|
// Enforce proper texture size (power of 2, etc.)
|
|
|
|
if( !ValidateSize() )
|
|
return 0;
|
|
|
|
// if texturing objects available, init the object
|
|
if( gGLCaps.bTextureObjects ) {
|
|
glGenTextures( 1, &texObj );
|
|
glBindTexture( GL_TEXTURE_2D, texObj );
|
|
|
|
//mf: mipmap stuff
|
|
// Default attributes for texObj
|
|
SetDefaultParams();
|
|
|
|
if( bMipmap )
|
|
//mf: error return...
|
|
gluBuild2DMipmaps( GL_TEXTURE_2D, components,
|
|
width, height, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
else
|
|
glTexImage2D( GL_TEXTURE_2D, 0, components,
|
|
width, height, 0, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
|
|
if (gGLCaps.bPalettedTexture && pal != NULL)
|
|
{
|
|
pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pal_size,
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pal);
|
|
}
|
|
} else
|
|
texObj = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ProcessTkTexture
|
|
*
|
|
* Simple wrapper for ProcessTexture which fills out a TEXTURE
|
|
* from a TK_RGBImageRec
|
|
*
|
|
* Frees the ImageRec if ProcessTexture succeeds
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int
|
|
TEXTURE::ProcessTkTexture( TK_RGBImageRec *image )
|
|
{
|
|
width = image->sizeX;
|
|
height = image->sizeY;
|
|
format = GL_RGB;
|
|
components = 3;
|
|
data = image->data;
|
|
pal_size = 0;
|
|
pal = NULL;
|
|
|
|
if( Process() )
|
|
{
|
|
//mf: ?? don't understand this freeing stuff...
|
|
free(image);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* MakeCurrent
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
TEXTURE::MakeCurrent()
|
|
{
|
|
if( texObj ) {
|
|
glBindTexture( GL_TEXTURE_2D, texObj );
|
|
return;
|
|
}
|
|
|
|
if( bMipmap )
|
|
gluBuild2DMipmaps( GL_TEXTURE_2D, components,
|
|
width, height, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
else
|
|
glTexImage2D( GL_TEXTURE_2D, 0, components,
|
|
width, height, 0, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
|
|
//mf: ? no rotation if no tex objs ?
|
|
if( pal )
|
|
{
|
|
pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pal_size,
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pal);
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_CopyTexture
|
|
*
|
|
* Make a copy of a texture.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::ss_CopyTexture( TEXTURE *pTexDst, TEXTURE *pTexSrc )
|
|
{
|
|
int size;
|
|
|
|
if( (pTexDst == NULL) || (pTexSrc == NULL) )
|
|
return FALSE;
|
|
|
|
*pTexDst = *pTexSrc;
|
|
|
|
if( gGLCaps.bTextureObjects && pTexSrc->texObj ) {
|
|
glGenTextures( 1, &pTexDst->texObj );
|
|
}
|
|
|
|
// copy image data
|
|
|
|
size = pTexSrc->width * pTexSrc->height;
|
|
if( pTexSrc->components != GL_COLOR_INDEX8_EXT )
|
|
size *= pTexSrc->components; // since data format always UNSIGNED_BYTE
|
|
|
|
pTexDst->data = (unsigned char *) malloc( size );
|
|
if( pTexDst->pal == NULL )
|
|
return FALSE;
|
|
memcpy( pTexDst->data, pTexSrc->data, size );
|
|
|
|
// copy palette data
|
|
|
|
if( gGLCaps.bPalettedTexture && pTexSrc->pal != NULL )
|
|
{
|
|
size = pTexSrc->pal_size*sizeof(RGBQUAD);
|
|
pTexDst->pal = (RGBQUAD *) malloc(size);
|
|
if( pTexDst->pal == NULL )
|
|
{
|
|
free(pTexDst->data);
|
|
return FALSE;
|
|
}
|
|
memcpy( pTexDst->pal, pTexSrc->pal, size );
|
|
}
|
|
|
|
if( pTexDst->texObj ) {
|
|
glBindTexture( GL_TEXTURE_2D, pTexDst->texObj );
|
|
|
|
// Default attributes for texObj
|
|
SetDefaultTextureParams( pTexDst );
|
|
|
|
if( pTexDst->bMipmap )
|
|
gluBuild2DMipmaps( GL_TEXTURE_2D, pTexDst->components,
|
|
pTexDst->width, pTexDst->height, pTexDst->format,
|
|
GL_UNSIGNED_BYTE, pTexDst->data );
|
|
else
|
|
glTexImage2D( GL_TEXTURE_2D, 0, pTexDst->components,
|
|
pTexDst->width, pTexDst->height, 0, pTexDst->format,
|
|
GL_UNSIGNED_BYTE, pTexDst->data );
|
|
|
|
if( pTexDst->pal )
|
|
{
|
|
pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pTexDst->pal_size,
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pTexDst->pal);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_SetTexturePalette
|
|
*
|
|
* Set a texture's palette according to the supplied index. This index
|
|
* indicates the start of the palette, which then wraps around if necessary.
|
|
* Of course this only works on paletted textures.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
TEXTURE::SetPaletteRotation( int index )
|
|
{
|
|
if( index == iPalRot )
|
|
return;
|
|
|
|
if( pal && pal_size ) {
|
|
iPalRot = index & (pal_size - 1);
|
|
MakeCurrent();
|
|
SetPalette();
|
|
}
|
|
}
|
|
|
|
void
|
|
TEXTURE::IncrementPaletteRotation()
|
|
{
|
|
if( pal && pal_size ) {
|
|
iPalRot = ++iPalRot & (pal_size - 1);
|
|
MakeCurrent();
|
|
SetPalette();
|
|
}
|
|
}
|
|
|
|
void
|
|
TEXTURE::SetPalette()
|
|
{
|
|
int start, count;
|
|
|
|
start = iPalRot & (pal_size - 1);
|
|
count = pal_size - start;
|
|
pfnColorSubTableEXT(GL_TEXTURE_2D, 0, count, GL_BGRA_EXT,
|
|
GL_UNSIGNED_BYTE, pal + start);
|
|
if (start != 0)
|
|
{
|
|
pfnColorSubTableEXT(GL_TEXTURE_2D, count, start, GL_BGRA_EXT,
|
|
GL_UNSIGNED_BYTE, pal);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* SetTextureAlpha
|
|
*
|
|
* Set a constant alpha value for the texture
|
|
* Again, don't overwrite any existing 0 alpha values, as explained in
|
|
* ss_SetTextureTransparency
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
TEXTURE::SetAlpha( float fAlpha )
|
|
{
|
|
int i;
|
|
unsigned char *pData = data;
|
|
RGBA8 *pColor = (RGBA8 *) data;
|
|
BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
|
|
|
|
if( components != 4 )
|
|
return;
|
|
|
|
for( i = 0; i < width*height; i ++, pColor++ ) {
|
|
if( pColor->a != 0 )
|
|
pColor->a = bAlpha;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ConvertToRGBA
|
|
*
|
|
* Convert RGB texture to RGBA
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::ConvertToRGBA( float fAlpha )
|
|
{
|
|
unsigned char *pNewData;
|
|
int count = width * height;
|
|
unsigned char *src, *dst;
|
|
BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
|
|
int i;
|
|
|
|
if( components != 3 ) {
|
|
SS_ERROR( "TEXTURE::ConvertToRGBA : Can't convert, components != 3\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
pNewData = (unsigned char *) LocalAlloc(LMEM_FIXED, count * sizeof(RGBA8));
|
|
if( !pNewData ) {
|
|
SS_ERROR( "TEXTURE::ConvertToRGBA : memory failure\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
src = data;
|
|
dst = pNewData;
|
|
|
|
if( format == GL_RGB ) {
|
|
// R is lsb, A will be msb
|
|
for( i = 0; i < count; i ++ ) {
|
|
*((RGB8 *)dst) = *((RGB8 *)src);
|
|
dst += sizeof(RGB8);
|
|
src += sizeof(RGB8);
|
|
*dst++ = bAlpha;
|
|
}
|
|
format = GL_RGBA;
|
|
} else { // format == GL_BGR_EXT
|
|
// R is msb, A will be msb
|
|
for( i = 0; i < count; i ++ ) {
|
|
*dst++ = bAlpha;
|
|
*((RGB8 *)dst) = *((RGB8 *)src);
|
|
dst += sizeof(RGB8);
|
|
src += sizeof(RGB8);
|
|
}
|
|
format = GL_BGRA_EXT;
|
|
}
|
|
|
|
LocalFree( data );
|
|
data = pNewData;
|
|
components = 4;
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_SetTextureTransparency
|
|
*
|
|
* Set transparency for a texture by adding or modifying the alpha data.
|
|
* Transparency value must be between 0.0 (opaque) and 1.0 (fully transparent)
|
|
* If the texture data previously had no alpha, add it in.
|
|
* If bSet is TRUE, make this the current texture.
|
|
*
|
|
* Note: Currently fully transparent pixels (alpha=0) will not be altered, since
|
|
* it is assumed these should be permanently transparent (could make this an
|
|
* option? - bPreserveTransparentPixels )
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
TEXTURE::SetTransparency( float fTransp, BOOL bSet )
|
|
{
|
|
int i;
|
|
float fAlpha;
|
|
|
|
SS_CLAMP_TO_RANGE2( fTransp, 0.0f, 1.0f );
|
|
fAlpha = 1 - fTransp;
|
|
|
|
if( format == GL_COLOR_INDEX )
|
|
{
|
|
// just need to modify the palette
|
|
RGBQUAD *pPal = pal;
|
|
BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
|
|
|
|
if( !pPal )
|
|
return FALSE;
|
|
|
|
for( i = 0; i < pal_size; i ++, pPal++ ) {
|
|
if( pPal->rgbReserved != 0 )
|
|
pPal->rgbReserved = bAlpha;
|
|
}
|
|
|
|
// need to send down the new palette for texture objects
|
|
if( texObj && pal )
|
|
{
|
|
glBindTexture( GL_TEXTURE_2D, texObj );
|
|
pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pal_size,
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pal);
|
|
}
|
|
}
|
|
else {
|
|
// Need to setup new texture data
|
|
if( components != 4 ) {
|
|
// Make room for alpha component
|
|
//mf: ? change to byte Alpha ?
|
|
if( !ConvertToRGBA( fAlpha ) )
|
|
return FALSE;
|
|
} else {
|
|
// Set alpha component
|
|
SetAlpha( fAlpha );
|
|
}
|
|
// Send down new data if texture objects
|
|
if( texObj )
|
|
{
|
|
glBindTexture( GL_TEXTURE_2D, texObj );
|
|
if( bMipmap )
|
|
//mf: inefficient !!!
|
|
gluBuild2DMipmaps( GL_TEXTURE_2D, components,
|
|
width, height, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
else
|
|
glTexImage2D( GL_TEXTURE_2D, 0, components,
|
|
width, height, 0, format,
|
|
GL_UNSIGNED_BYTE, data );
|
|
}
|
|
}
|
|
|
|
if( bSet )
|
|
MakeCurrent();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_DeleteTexture
|
|
*
|
|
\**************************************************************************/
|
|
|
|
TEXTURE::~TEXTURE()
|
|
{
|
|
if( texObj ) {
|
|
glDeleteTextures( 1, &texObj );
|
|
}
|
|
if (pal != NULL)
|
|
{
|
|
free(pal);
|
|
}
|
|
if( data )
|
|
free( data );
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_TextureObjectsEnabled
|
|
*
|
|
* Returns BOOL set by ss_QueryGLVersion (Texture Objects only supported on
|
|
* GL v.1.1 or greater)
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
mtk_TextureObjectsEnabled( void )
|
|
{
|
|
return gGLCaps.bTextureObjects;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_PalettedTextureEnabled
|
|
*
|
|
* Returns result from ss_QueryPalettedTextureEXT
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
mtk_PalettedTextureEnabled( void )
|
|
{
|
|
return gGLCaps.bPalettedTexture;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_QueryPalettedTextureEXT
|
|
*
|
|
* Queries the OpenGL implementation to see if paletted texture is supported
|
|
* Typically called once at app startup.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
mtk_QueryPalettedTextureEXT( void )
|
|
{
|
|
PFNGLGETCOLORTABLEPARAMETERIVEXTPROC pfnGetColorTableParameterivEXT;
|
|
int size;
|
|
|
|
pfnColorTableEXT = (PFNGLCOLORTABLEEXTPROC)
|
|
wglGetProcAddress("glColorTableEXT");
|
|
if (pfnColorTableEXT == NULL)
|
|
return FALSE;
|
|
pfnColorSubTableEXT = (PFNGLCOLORSUBTABLEEXTPROC)
|
|
wglGetProcAddress("glColorSubTableEXT");
|
|
if (pfnColorSubTableEXT == NULL)
|
|
return FALSE;
|
|
|
|
// Check color table size
|
|
pfnGetColorTableParameterivEXT = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)
|
|
wglGetProcAddress("glGetColorTableParameterivEXT");
|
|
if (pfnGetColorTableParameterivEXT == NULL)
|
|
return FALSE;
|
|
// For now, the only paletted textures supported in this lib are TEX_A8,
|
|
// with 256 color table entries. Make sure the device supports this.
|
|
pfnColorTableEXT(GL_PROXY_TEXTURE_2D, GL_RGBA, 256,
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL );
|
|
pfnGetColorTableParameterivEXT( GL_PROXY_TEXTURE_2D,
|
|
GL_COLOR_TABLE_WIDTH_EXT, &size );
|
|
if( size != 256 )
|
|
// The device does not support a color table size of 256, so we don't
|
|
// enable paletted textures in general.
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_VerifyTextureFile
|
|
*
|
|
* Validates texture bmp or rgb file, by checking for valid pathname and
|
|
* correct format.
|
|
*
|
|
* History
|
|
* Apr. 28, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
* Jul. 25, 95 : [marcfo]
|
|
* - Suppress warning dialog box in child preview mode, as it will
|
|
* be continuously brought up.
|
|
*
|
|
* Dec. 12, 95 : [marcfo]
|
|
* - Support .rgb files as well
|
|
*
|
|
* Dec. 14, 95 : [marcfo]
|
|
* - Change to have it only check the file path
|
|
*
|
|
\**************************************************************************/
|
|
|
|
//mf: this can become a standard file function
|
|
|
|
BOOL
|
|
mtk_VerifyTextureFilePath( TEXFILE *ptf )
|
|
{
|
|
// Make sure the selected texture file is OK.
|
|
|
|
ISIZE size;
|
|
TCHAR szFileName[MAX_PATH];
|
|
PTSTR pszString;
|
|
TCHAR szString[MAX_PATH];
|
|
|
|
lstrcpy(szFileName, ptf->szPathName);
|
|
|
|
if ( SearchPath(NULL, szFileName, NULL, MAX_PATH,
|
|
ptf->szPathName, &pszString)
|
|
)
|
|
{
|
|
ptf->nOffset = pszString - ptf->szPathName;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(ptf->szPathName, szFileName); // restore
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VerifyTextureFile
|
|
*
|
|
* Verify that a bitmap or rgb file is valid
|
|
*
|
|
* Returns:
|
|
* File type (RGB or BMP) if valid file; otherwise, 0.
|
|
*
|
|
* History
|
|
* Dec. 12, 95 : [marcfo]
|
|
* - Creation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int
|
|
mtk_VerifyTextureFileData( TEXFILE *pTexFile )
|
|
{
|
|
int type;
|
|
ISIZE size;
|
|
BOOL bValid;
|
|
TCHAR szString[2 * MAX_PATH]; // May contain a pathname
|
|
|
|
// check for 0 offset and null strings
|
|
if( (pTexFile->nOffset == 0) || (*pTexFile->szPathName == 0) )
|
|
return 0;
|
|
|
|
type = GetTexFileType( pTexFile );
|
|
|
|
switch( type ) {
|
|
case TEX_BMP:
|
|
bValid = bVerifyDIB( pTexFile->szPathName, &size );
|
|
break;
|
|
case TEX_RGB:
|
|
bValid = bVerifyRGB( pTexFile->szPathName, &size );
|
|
break;
|
|
case TEX_UNKNOWN:
|
|
default:
|
|
bValid = FALSE;
|
|
}
|
|
|
|
if( !bValid ) {
|
|
return 0;
|
|
}
|
|
|
|
// Check size ?
|
|
|
|
if ( (size.width > TEX_WIDTH_MAX) ||
|
|
(size.height > TEX_HEIGHT_MAX) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ss_InitAutoTexture
|
|
*
|
|
* Generate texture coordinates automatically.
|
|
* If pTexRep is not NULL, use it to set the repetition of the generated
|
|
* texture.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
mtk_InitAutoTexture( TEX_POINT2D *pTexRep )
|
|
{
|
|
GLfloat sgenparams[] = {1.0f, 0.0f, 0.0f, 0.0f};
|
|
GLfloat tgenparams[] = {0.0f, 1.0f, 0.0f, 0.0f};
|
|
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
|
|
if( pTexRep )
|
|
sgenparams[0] = pTexRep->s;
|
|
glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams );
|
|
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
|
|
if( pTexRep )
|
|
tgenparams[0] = pTexRep->t;
|
|
glTexGenfv(GL_T, GL_OBJECT_PLANE, tgenparams );
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable( GL_TEXTURE_2D );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetTexFileType
|
|
*
|
|
* Determine if a texture file is rgb or bmp, based on extension. This is
|
|
* good enough, as the open texture dialog only shows files with these
|
|
* extensions.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static int
|
|
GetTexFileType( TEXFILE *pTexFile )
|
|
{
|
|
LPTSTR pszStr;
|
|
|
|
#ifdef UNICODE
|
|
pszStr = wcsrchr( pTexFile->szPathName + pTexFile->nOffset,
|
|
(USHORT) L'.' );
|
|
#else
|
|
pszStr = strrchr( pTexFile->szPathName + pTexFile->nOffset,
|
|
(USHORT) L'.' );
|
|
#endif
|
|
if( !pszStr || (lstrlen(++pszStr) == 0) )
|
|
return TEX_UNKNOWN;
|
|
|
|
if( !lstrcmpi( pszStr, TEXT("bmp") ) )
|
|
return TEX_BMP;
|
|
else if( !lstrcmpi( pszStr, TEXT("rgb") ) )
|
|
return TEX_RGB;
|
|
else
|
|
return TEX_UNKNOWN;
|
|
}
|