2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2001-11-04 19:34:28 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
2002-08-13 23:26:46 +00:00
|
|
|
Class: RageBitmapTexture
|
2001-11-04 19:34:28 +00:00
|
|
|
|
|
|
|
|
Desc: Holder for a static texture with metadata. Can load just about any image format.
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
2002-10-24 04:16:15 +00:00
|
|
|
Glenn Maynard
|
2002-11-14 01:26:19 +00:00
|
|
|
Chris Danford
|
2001-11-04 19:34:28 +00:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
#include "RageBitmapTexture.h"
|
|
|
|
|
#include "RageUtil.h"
|
2002-05-01 19:14:55 +00:00
|
|
|
#include "RageLog.h"
|
2002-07-27 19:29:51 +00:00
|
|
|
#include "RageException.h"
|
2002-11-14 01:26:19 +00:00
|
|
|
#include "RageDisplay.h"
|
2003-05-22 05:28:37 +00:00
|
|
|
#include "RageTypes.h"
|
2002-06-14 22:25:22 +00:00
|
|
|
|
2002-10-24 04:16:15 +00:00
|
|
|
#include "SDL.h"
|
|
|
|
|
#include "SDL_image.h"
|
|
|
|
|
#include "SDL_endian.h"
|
|
|
|
|
#include "SDL_rotozoom.h"
|
|
|
|
|
#include "SDL_utils.h"
|
|
|
|
|
#include "SDL_dither.h"
|
|
|
|
|
|
2002-11-14 01:26:19 +00:00
|
|
|
#include "RageTimer.h"
|
|
|
|
|
|
2003-05-05 03:14:47 +00:00
|
|
|
static void GetResolutionFromFileName( CString sPath, int &Width, int &Height )
|
|
|
|
|
{
|
|
|
|
|
/* Match:
|
2003-05-05 06:21:01 +00:00
|
|
|
* Foo (res 512x128).png
|
|
|
|
|
* Also allow, eg:
|
|
|
|
|
* Foo (dither, res 512x128).png
|
|
|
|
|
*
|
2003-05-05 03:14:47 +00:00
|
|
|
* Be careful that this doesn't get mixed up with frame dimensions. */
|
2003-05-05 06:21:01 +00:00
|
|
|
Regex re("\\([^\\)]*res ([0-9]+)x([0-9]+).*\\)");
|
2003-05-05 03:14:47 +00:00
|
|
|
|
|
|
|
|
vector<CString> matches;
|
|
|
|
|
if(!re.Compare(sPath, matches))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Width = atoi(matches[0].c_str());
|
|
|
|
|
Height = atoi(matches[1].c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RageBitmapTexture constructor
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2002-12-30 02:43:52 +00:00
|
|
|
RageBitmapTexture::RageBitmapTexture( RageTextureID name ) :
|
|
|
|
|
RageTexture( name )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-07-31 19:40:40 +00:00
|
|
|
// LOG->Trace( "RageBitmapTexture::RageBitmapTexture()" );
|
2003-05-22 05:28:37 +00:00
|
|
|
Create();
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RageBitmapTexture::~RageBitmapTexture()
|
|
|
|
|
{
|
2003-05-22 05:28:37 +00:00
|
|
|
Destroy();
|
2002-04-28 20:42:32 +00:00
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2003-01-26 00:56:13 +00:00
|
|
|
void RageBitmapTexture::Reload()
|
2002-11-14 01:26:19 +00:00
|
|
|
{
|
2003-05-22 05:28:37 +00:00
|
|
|
Destroy();
|
2002-11-14 01:26:19 +00:00
|
|
|
Create();
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/*
|
|
|
|
|
* Each dwMaxSize, dwTextureColorDepth and iAlphaBits are maximums; we may
|
|
|
|
|
* use less. iAlphaBits must be 0, 1 or 4.
|
|
|
|
|
*
|
|
|
|
|
* XXX: change iAlphaBits == 4 to iAlphaBits == 8 to indicate "as much alpha
|
|
|
|
|
* as needed", since that's what it really is; still only use 4 in 16-bit textures.
|
|
|
|
|
*
|
|
|
|
|
* Dither forces dithering when loading 16-bit textures.
|
|
|
|
|
* Stretch forces the loaded image to fill the texture completely.
|
2002-11-14 01:26:19 +00:00
|
|
|
*/
|
2003-05-22 05:28:37 +00:00
|
|
|
void RageBitmapTexture::Create()
|
2002-11-14 01:26:19 +00:00
|
|
|
{
|
2003-05-22 06:32:23 +00:00
|
|
|
RageTextureID actualID = GetID();
|
|
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/* Create (and return) a surface ready to be loaded to OpenGL */
|
2002-10-24 04:16:15 +00:00
|
|
|
/* Load the image into an SDL surface. */
|
2002-12-30 02:43:52 +00:00
|
|
|
SDL_Surface *img = IMG_Load(GetFilePath());
|
2003-01-23 04:45:45 +00:00
|
|
|
|
2002-11-21 00:54:28 +00:00
|
|
|
/* XXX: Wait, we don't want to throw for all images; in particular, we
|
|
|
|
|
* want to tolerate corrupt/unknown background images. */
|
|
|
|
|
if(img == NULL)
|
2003-04-25 00:01:35 +00:00
|
|
|
RageException::Throw( "RageBitmapTexture: Couldn't load %s: %s", GetFilePath().c_str(), SDL_GetError() );
|
2002-11-14 01:26:19 +00:00
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
if(actualID.bHotPinkColorKey)
|
2003-01-22 04:18:02 +00:00
|
|
|
{
|
|
|
|
|
/* Annoying: SDL will do a nearest-match on paletted images if
|
|
|
|
|
* they don't have the color we ask for, so images without HOT PINK
|
|
|
|
|
* will get some other random color transparent. We have to make
|
|
|
|
|
* sure the value returned for paletted images is exactly #FF00FF. */
|
|
|
|
|
int color = SDL_MapRGB(img->format, 0xFF, 0, 0xFF);
|
|
|
|
|
if( img->format->BitsPerPixel == 8 ) {
|
|
|
|
|
if(img->format->palette->colors[color].r != 0xFF ||
|
|
|
|
|
img->format->palette->colors[color].g != 0x00 ||
|
|
|
|
|
img->format->palette->colors[color].b != 0xFF )
|
|
|
|
|
color = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( color != -1 )
|
|
|
|
|
SDL_SetColorKey( img, SDL_SRCCOLORKEY, color);
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-27 06:01:43 +00:00
|
|
|
{
|
|
|
|
|
/* This should eventually obsolete 8alphaonly, 0alpha and 1alpha,
|
|
|
|
|
* and remove the need to special case background loads. Do this
|
|
|
|
|
* after setting the color key for paletted images; it'll also return
|
|
|
|
|
* TRAIT_NO_TRANSPARENCY if the color key is never used. */
|
|
|
|
|
int traits = FindSurfaceTraits(img);
|
2003-04-01 07:47:19 +00:00
|
|
|
if(traits & TRAIT_NO_TRANSPARENCY)
|
2003-05-22 06:32:23 +00:00
|
|
|
actualID.iAlphaBits = 0;
|
2003-04-01 07:47:19 +00:00
|
|
|
else if(traits & TRAIT_BOOL_TRANSPARENCY)
|
2003-05-22 06:32:23 +00:00
|
|
|
actualID.iAlphaBits = 1;
|
2003-04-01 07:47:19 +00:00
|
|
|
if(traits & TRAIT_WHITE_ONLY)
|
2003-05-22 06:32:23 +00:00
|
|
|
actualID.iTransparencyOnly = 8;
|
2003-03-27 06:01:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// look in the file name for a format hints
|
|
|
|
|
CString HintString = GetFilePath();
|
|
|
|
|
HintString.MakeLower();
|
|
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
if( HintString.Find("4alphaonly") != -1 ) actualID.iTransparencyOnly = 4;
|
|
|
|
|
else if( HintString.Find("8alphaonly") != -1 ) actualID.iTransparencyOnly = 8;
|
|
|
|
|
if( HintString.Find("dither") != -1 ) actualID.bDither = true;
|
2003-03-27 06:01:43 +00:00
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
if( actualID.iTransparencyOnly )
|
|
|
|
|
actualID.iColorDepth = 32; /* Treat the image as 32-bit, so we don't lose any alpha precision. */
|
2002-11-14 01:26:19 +00:00
|
|
|
|
|
|
|
|
/* Cap the max texture size to the hardware max. */
|
2003-05-22 06:32:23 +00:00
|
|
|
actualID.iMaxSize = min( actualID.iMaxSize, DISPLAY->GetMaxTextureSize() );
|
2002-11-14 01:26:19 +00:00
|
|
|
|
|
|
|
|
/* Save information about the source. */
|
|
|
|
|
m_iSourceWidth = img->w;
|
|
|
|
|
m_iSourceHeight = img->h;
|
|
|
|
|
|
|
|
|
|
/* image size cannot exceed max size */
|
2003-05-22 06:32:23 +00:00
|
|
|
m_iImageWidth = min( m_iSourceWidth, actualID.iMaxSize );
|
|
|
|
|
m_iImageHeight = min( m_iSourceHeight, actualID.iMaxSize );
|
2002-10-24 04:16:15 +00:00
|
|
|
|
|
|
|
|
/* Texture dimensions need to be a power of two; jump to the next. */
|
2002-11-14 01:26:19 +00:00
|
|
|
m_iTextureWidth = power_of_two(m_iImageWidth);
|
|
|
|
|
m_iTextureHeight = power_of_two(m_iImageHeight);
|
|
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
ASSERT( m_iTextureWidth <= actualID.iMaxSize );
|
|
|
|
|
ASSERT( m_iTextureHeight <= actualID.iMaxSize );
|
2002-11-14 01:26:19 +00:00
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
if(actualID.bStretch)
|
2002-11-21 22:34:37 +00:00
|
|
|
{
|
|
|
|
|
/* The hints asked for the image to be stretched to the texture size,
|
|
|
|
|
* probably for tiling. */
|
|
|
|
|
m_iImageWidth = m_iTextureWidth;
|
|
|
|
|
m_iImageHeight = m_iTextureHeight;
|
|
|
|
|
}
|
2002-11-14 01:26:19 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
if( img->w != m_iImageWidth || img->h != m_iImageHeight )
|
2002-11-14 01:26:19 +00:00
|
|
|
{
|
|
|
|
|
/* resize currently only does RGBA8888 */
|
2003-05-22 05:28:37 +00:00
|
|
|
ConvertSDLSurface(img, img->w, img->h, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
2002-11-21 22:34:37 +00:00
|
|
|
zoomSurface(img, m_iImageWidth, m_iImageHeight );
|
2002-11-14 01:26:19 +00:00
|
|
|
}
|
|
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
// Format of the image that we will pass to OpenGL and that we want OpenGL to use
|
|
|
|
|
PixelFormat pixfmt;
|
2003-01-01 09:07:34 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/* Figure out which texture format to use. */
|
|
|
|
|
// if the source is palleted, load palleted no matter what the prefs
|
|
|
|
|
if(img->format->BitsPerPixel == 8 && DISPLAY->SupportsTextureFormat(FMT_PAL))
|
|
|
|
|
{
|
2003-01-26 02:35:55 +00:00
|
|
|
pixfmt = FMT_PAL;
|
2003-05-22 05:28:37 +00:00
|
|
|
}
|
|
|
|
|
else
|
2003-01-26 02:35:55 +00:00
|
|
|
{
|
2003-05-22 05:28:37 +00:00
|
|
|
// not paletted
|
2003-05-22 06:32:23 +00:00
|
|
|
switch( actualID.iColorDepth )
|
2003-05-22 05:28:37 +00:00
|
|
|
{
|
|
|
|
|
case 16:
|
|
|
|
|
{
|
|
|
|
|
/* Bits of alpha in the source: */
|
|
|
|
|
int src_alpha_bits = 8 - img->format->Aloss;
|
|
|
|
|
|
|
|
|
|
/* No real alpha in paletted input. */
|
|
|
|
|
if( img->format->BytesPerPixel == 1 )
|
|
|
|
|
src_alpha_bits = 0;
|
|
|
|
|
|
|
|
|
|
/* Colorkeyed input effectively has at least one bit of alpha: */
|
|
|
|
|
if( img->flags & SDL_SRCCOLORKEY )
|
|
|
|
|
src_alpha_bits = max( 1, src_alpha_bits );
|
|
|
|
|
|
|
|
|
|
/* Don't use more than we were hinted to. */
|
2003-05-22 06:32:23 +00:00
|
|
|
src_alpha_bits = min( actualID.iAlphaBits, src_alpha_bits );
|
2003-05-22 05:28:37 +00:00
|
|
|
|
|
|
|
|
switch( src_alpha_bits ) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
pixfmt = FMT_RGB5A1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pixfmt = FMT_RGBA4;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 32:
|
|
|
|
|
pixfmt = FMT_RGBA8;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2003-05-22 06:32:23 +00:00
|
|
|
RageException::Throw( "Invalid color depth: %d bits", actualID.iColorDepth );
|
2003-05-22 05:28:37 +00:00
|
|
|
}
|
2003-01-26 02:35:55 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/* Override the internalformat with an alpha format if it was requested.
|
|
|
|
|
* Don't use iTransparencyOnly with paletted images; there's no point--paletted
|
|
|
|
|
* images are as small or smaller (and the load will fail). */
|
|
|
|
|
/* SDL surfaces don't allow for 8 bpp surfaces that aren't paletted. Arg!
|
|
|
|
|
* fix this later. -Chris */
|
2003-05-22 06:32:23 +00:00
|
|
|
// if(actualID.iTransparencyOnly > 0)
|
2003-05-22 05:28:37 +00:00
|
|
|
// {
|
|
|
|
|
// imagePixfmt = FMT_ALPHA8;
|
|
|
|
|
// texturePixfmt = FMT_ALPHA8;
|
|
|
|
|
// }
|
2003-01-26 02:35:55 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/* It's either not a paletted image, or we can't handle paletted textures.
|
|
|
|
|
* Convert to the desired RGBA format, dithering if appropriate. */
|
2003-05-22 06:32:23 +00:00
|
|
|
if( actualID.bDither &&
|
2003-05-22 05:28:37 +00:00
|
|
|
(pixfmt==FMT_RGBA4 || pixfmt==FMT_RGB5A1) ) /* Don't dither if format is 32bpp; there's no point. */
|
2003-01-26 02:35:55 +00:00
|
|
|
{
|
|
|
|
|
/* Dither down to the destination format. */
|
2003-05-26 03:12:12 +00:00
|
|
|
const PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
|
|
|
|
|
SDL_Surface *dst = SDL_CreateRGBSurfaceSane(SDL_SWSURFACE, img->w, img->h,
|
|
|
|
|
pfd->bpp, pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3]);
|
2003-01-26 02:35:55 +00:00
|
|
|
|
2003-04-26 10:57:40 +00:00
|
|
|
SM_SDL_ErrorDiffusionDither(img, dst);
|
2003-01-26 02:35:55 +00:00
|
|
|
SDL_FreeSurface(img);
|
|
|
|
|
img = dst;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This needs to be done *after* the final resize, since that resize
|
|
|
|
|
* may introduce new alpha bits that need to be set. It needs to be
|
|
|
|
|
* done *before* we set up the palette, since it might change it. */
|
2003-01-23 05:35:21 +00:00
|
|
|
FixHiddenAlpha(img);
|
2003-01-23 04:45:45 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
/* Convert the data to the destination format and dimensions
|
|
|
|
|
* required by OpenGL if it's not in it already. */
|
2003-05-26 03:12:12 +00:00
|
|
|
|
|
|
|
|
const PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
|
|
|
|
|
ConvertSDLSurface(img, m_iTextureWidth, m_iTextureHeight,
|
|
|
|
|
pfd->bpp, pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3]);
|
2003-05-22 05:28:37 +00:00
|
|
|
|
|
|
|
|
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, img );
|
2002-11-11 04:53:31 +00:00
|
|
|
|
2003-05-22 05:28:37 +00:00
|
|
|
SDL_FreeSurface( img );
|
2002-10-24 04:16:15 +00:00
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
CreateFrameRects();
|
2003-05-22 05:28:37 +00:00
|
|
|
|
2003-05-22 06:32:23 +00:00
|
|
|
/* See if the apparent "size" is being overridden. */
|
|
|
|
|
GetResolutionFromFileName(actualID.filename, m_iSourceWidth, m_iSourceHeight);
|
|
|
|
|
|
|
|
|
|
|
2003-05-26 01:06:01 +00:00
|
|
|
CString props;
|
|
|
|
|
props += PixelFormatToString( pixfmt ) + " ";
|
2003-05-22 06:32:23 +00:00
|
|
|
if(actualID.iAlphaBits == 0) props += "opaque ";
|
|
|
|
|
if(actualID.iAlphaBits == 1) props += "matte ";
|
|
|
|
|
if(actualID.iTransparencyOnly) props += "mask ";
|
|
|
|
|
if(actualID.bStretch) props += "stretch ";
|
|
|
|
|
if(actualID.bDither) props += "dither ";
|
2003-03-27 06:01:43 +00:00
|
|
|
props.erase(props.size()-1);
|
|
|
|
|
LOG->Trace( "RageBitmapTexture: Loaded '%s' (%ux%u); %s, source %d,%d; image %d,%d.",
|
2003-05-22 06:32:23 +00:00
|
|
|
actualID.filename.c_str(), GetTextureWidth(), GetTextureHeight(),
|
2003-04-25 00:01:35 +00:00
|
|
|
props.c_str(), m_iSourceWidth, m_iSourceHeight,
|
2003-03-27 06:01:43 +00:00
|
|
|
m_iImageWidth, m_iImageHeight);
|
2003-05-22 05:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageBitmapTexture::Destroy()
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->DeleteTexture( m_uTexHandle );
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
2002-11-14 01:26:19 +00:00
|
|
|
|