diff --git a/stepmania/src/RageDisplay.cpp b/stepmania/src/RageDisplay.cpp index a7f3caedfa..8393ccdb39 100644 --- a/stepmania/src/RageDisplay.cpp +++ b/stepmania/src/RageDisplay.cpp @@ -17,6 +17,7 @@ #include "RageMath.h" #include "RageUtil.h" #include "GameConstantsAndTypes.h" +#include "SDL_utils.h" // // Statistics stuff @@ -566,3 +567,35 @@ RageMatrix RageDisplay::GetPerspectiveMatrix(float fovy, float aspect, float zNe return GetFrustrumMatrix(xmin, xmax, ymin, ymax, zNear, zFar); } + +SDL_Surface *RageDisplay::CreateSurfaceFromPixfmt( PixelFormat pixfmt, + void *pixels, int width, int height, int pitch ) +{ + const PixelFormatDesc *tpf = GetPixelFormatDesc(pixfmt); + + SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( + pixels, width, height, tpf->bpp, pitch, + tpf->masks[0], tpf->masks[1], tpf->masks[2], tpf->masks[3]); + + return surf; +} + +PixelFormat RageDisplay::FindPixelFormat( + int bpp, int Rmask, int Gmask, int Bmask, int Amask ) +{ + PixelFormatDesc tmp = { bpp, Rmask, Gmask, Bmask, Amask }; + + int pixfmt; + for(pixfmt = 0; pixfmt < NUM_PIX_FORMATS; ++pixfmt) + { + const PixelFormatDesc *pf = GetPixelFormatDesc(PixelFormat(pixfmt)); + if(!SupportsTextureFormat( PixelFormat(pixfmt) )) + continue; + + if(memcmp(pf, &tmp, sizeof(tmp))) + continue; + return PixelFormat(pixfmt); + } + + return NUM_PIX_FORMATS; +} diff --git a/stepmania/src/RageDisplay.h b/stepmania/src/RageDisplay.h index 114c3fde64..de807fdbfc 100644 --- a/stepmania/src/RageDisplay.h +++ b/stepmania/src/RageDisplay.h @@ -43,6 +43,8 @@ enum PixelFormat { FMT_RGB5A1, FMT_RGB5, FMT_RGB8, + /* This may not be as well-supported as RGBA; it's used to speed up DirectShow. */ + FMT_BGR8, FMT_PAL, NUM_PIX_FORMATS }; @@ -128,8 +130,7 @@ public: ) = 0; virtual void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) = 0; virtual void DeleteTexture( unsigned uTexHandle ) = 0; @@ -229,6 +230,9 @@ public: float zfar ); RageMatrix GetPerspectiveMatrix(float fovy, float aspect, float zNear, float zFar); + SDL_Surface *CreateSurfaceFromPixfmt( PixelFormat pixfmt, void *pixels, int width, int height, int pitch ); + PixelFormat FindPixelFormat( int bpp, int Rmask, int Gmask, int Bmask, int Amask ); + protected: const RageMatrix* GetProjection(); const RageMatrix* GetModelViewTop(); diff --git a/stepmania/src/RageDisplay_D3D.cpp b/stepmania/src/RageDisplay_D3D.cpp index bcedfc6f8b..5a2d50ec75 100644 --- a/stepmania/src/RageDisplay_D3D.cpp +++ b/stepmania/src/RageDisplay_D3D.cpp @@ -95,6 +95,7 @@ static void SetPalette( unsigned TexResource ) // Cards that don't support palettes with alpha will crash unless // all entires have full alpha. + // XXX: Since we disable FMT_PAL in SupportsTextureFormat, can we remove this? -glenn if( ! (g_DeviceCaps.TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) ) for(int j=0; j<256; j++) pal.p[j].peFlags = 255; @@ -165,6 +166,9 @@ static const PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { 0x00FF00, 0x0000FF, 0x000000 } + }, { + /* BGRA (N/A; OpenGL only) */ + 0, { 0,0,0,0 } }, { /* Paletted */ 8, @@ -183,6 +187,7 @@ static D3DFORMAT D3DFORMATS[NUM_PIX_FORMATS] = #else D3DFMT_A8R8G8B8, #endif + D3DFMT_UNKNOWN, /* no BGR */ D3DFMT_P8 }; @@ -555,6 +560,9 @@ bool RageDisplay_D3D::SupportsTextureFormat( PixelFormat pixfmt ) if( pixfmt == FMT_PAL && !(g_DeviceCaps.TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) ) return false; + if( D3DFORMATS[pixfmt] == D3DFMT_UNKNOWN ) + return false; + D3DFORMAT d3dfmt = D3DFORMATS[pixfmt]; HRESULT hr = g_pd3d->CheckDeviceFormat( D3DADAPTER_DEFAULT, @@ -563,6 +571,8 @@ bool RageDisplay_D3D::SupportsTextureFormat( PixelFormat pixfmt ) 0, D3DRTYPE_TEXTURE, d3dfmt); + if(FAILED(hr)) + LOG->Trace("format %i not supported", pixfmt); return SUCCEEDED( hr ); } @@ -910,20 +920,24 @@ unsigned RageDisplay_D3D::CreateTexture( g_TexResourceToTexturePalette[uTexHandle] = pal; } - UpdateTexture( uTexHandle, pixfmt, img, 0, 0, img->w, img->h ); + UpdateTexture( uTexHandle, img, 0, 0, img->w, img->h ); return uTexHandle; } void RageDisplay_D3D::UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) { IDirect3DTexture8* pTex = (IDirect3DTexture8*)uTexHandle; ASSERT( pTex != NULL ); + /* Make sure that the pixel format of the image is legit. We don't actually + * care, but the OpenGL renderer does, so make sure people coding in the D3D + * renderer don't accidentally break the OpenGL one. */ + FindPixelFormat( img->format->BitsPerPixel, img->format->Rmask, img->format->Gmask, img->format->Bmask, img->format->Amask ); + RECT rect; rect.left = xoffset; rect.top = yoffset; @@ -933,6 +947,29 @@ void RageDisplay_D3D::UpdateTexture( D3DLOCKED_RECT lr; pTex->LockRect( 0, &lr, &rect, 0 ); + D3DSURFACE_DESC desc; + pTex->GetLevelDesc(0, &desc); + ASSERT( xoffset+width <= int(desc.Width) ); + ASSERT( yoffset+height <= int(desc.Height) ); + + int texpixfmt; + for(texpixfmt = 0; texpixfmt < NUM_PIX_FORMATS; ++texpixfmt) + if(D3DFORMATS[texpixfmt] == desc.Format) break; + ASSERT( texpixfmt != NUM_PIX_FORMATS ); + + SDL_Surface *Texture = CreateSurfaceFromPixfmt(PixelFormat(texpixfmt), lr.pBits, width, height, lr.Pitch); + SDL_Rect area; + area.x = area.y = 0; + area.w = (Uint16) width; + area.h = (Uint16) height; + SDL_SetAlpha( img, 0, SDL_ALPHA_OPAQUE ); +// SDL_SetColorKey( img, 0, 0 ); +// SDL_BlitSurface( img, &area, Texture, &area ); + mySDL_BlitSurface( img, Texture, width, height, false ); + + SDL_FreeSurface( Texture ); + +#if 0 // copy each row int bytes_per_pixel = img->format->BytesPerPixel; for( int y=rect.top; yUnlockRect( 0 ); } diff --git a/stepmania/src/RageDisplay_D3D.h b/stepmania/src/RageDisplay_D3D.h index 5452c15238..a694f9188d 100644 --- a/stepmania/src/RageDisplay_D3D.h +++ b/stepmania/src/RageDisplay_D3D.h @@ -24,8 +24,7 @@ public: unsigned CreateTexture( PixelFormat pixfmt, SDL_Surface*& img ); void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ); void DeleteTexture( unsigned uTexHandle ); diff --git a/stepmania/src/RageDisplay_OGL.cpp b/stepmania/src/RageDisplay_OGL.cpp index 9479b6cfa0..ab3f93df22 100644 --- a/stepmania/src/RageDisplay_OGL.cpp +++ b/stepmania/src/RageDisplay_OGL.cpp @@ -73,7 +73,9 @@ namespace GLExt { PWSWAPINTERVALEXTPROC GLExt::wglSwapIntervalEXT = NULL; PFNGLCOLORTABLEPROC GLExt::glColorTableEXT = NULL; PFNGLCOLORTABLEPARAMETERIVPROC GLExt::glGetColorTableParameterivEXT = NULL; -bool g_bEXT_texture_env_combine = true; +bool g_bEXT_texture_env_combine = true; +bool g_bGL_EXT_bgra = true; + /* OpenGL system information that generally doesn't change at runtime. */ /* Range and granularity of points and lines: */ @@ -98,7 +100,7 @@ LowLevelWindow *wind; static PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { { - /* B8G8R8A8 */ + /* R8G8B8A8 */ 32, { 0xFF000000, 0x00FF0000, @@ -132,6 +134,13 @@ static PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = { 0x00FF00, 0x0000FF, 0x000000 } + }, { + /* B8G8R8A8 */ + 24, + { 0x0000FF, + 0x00FF00, + 0xFF0000, + 0x000000 } }, { /* Paletted */ 8, @@ -148,7 +157,7 @@ struct GLPixFmtInfo_t { * is not, but all SDL masks are affected by endianness, so GL_UNSIGNED_BYTE * is reversed. This isn't endian-safe. */ { - /* B8G8R8A8 */ + /* R8G8B8A8 */ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, @@ -172,6 +181,11 @@ struct GLPixFmtInfo_t { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, + }, { + /* B8G8R8 */ + GL_RGB8, + GL_BGR, + GL_UNSIGNED_BYTE, }, { /* Paletted */ GL_COLOR_INDEX8_EXT, @@ -367,6 +381,7 @@ void SetupExtensions() GLExt::glColorTableEXT = (PFNGLCOLORTABLEPROC) wind->GetProcAddress("glColorTableEXT"); GLExt::glGetColorTableParameterivEXT = (PFNGLCOLORTABLEPARAMETERIVPROC) wind->GetProcAddress("glGetColorTableParameterivEXT"); g_bEXT_texture_env_combine = HasExtension("GL_EXT_texture_env_combine"); + g_bGL_EXT_bgra = HasExtension("GL_EXT_bgra"); CheckPalettedTextures(); // Checks for known bad drivers @@ -515,6 +530,8 @@ bool RageDisplay_OGL::SupportsTextureFormat( PixelFormat pixfmt ) { case FMT_PAL: return GLExt::glColorTableEXT && GLExt::glGetColorTableParameterivEXT; + case FMT_BGR8: + return g_bGL_EXT_bgra; default: return true; // No way to query this in OGL. You pass it a format and hope it doesn't have to convert. } @@ -983,14 +1000,38 @@ unsigned RageDisplay_OGL::CreateTexture( void RageDisplay_OGL::UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ) { glBindTexture( GL_TEXTURE_2D, uTexHandle ); glPixelStorei(GL_UNPACK_ROW_LENGTH, img->pitch / img->format->BytesPerPixel); + PixelFormat pixfmt = FindPixelFormat( img->format->BitsPerPixel, img->format->Rmask, img->format->Gmask, img->format->Bmask, img->format->Amask ); + SDL_Surface *imgconv = NULL; + + if( pixfmt == NUM_PIX_FORMATS ) + { + LOG->Trace("guh"); + /* The source isn't in a supported, known pixel format. We need to convert + * it ourself. Just convert it to RGBA8, and let OpenGL convert it back + * down to whatever the actual pixel format is. This is a very slow code + * path, which should almost never be used. */ + pixfmt = FMT_RGBA8; + const PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt); + + SDL_SetAlpha( img, 0, SDL_ALPHA_OPAQUE ); + + SDL_Rect area; + area.x = area.y = 0; + area.w = short(width); + area.h = short(height); + imgconv = SDL_CreateRGBSurfaceSane(SDL_SWSURFACE, width, height, + pfd->bpp, pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3]); + SDL_BlitSurface(img, &area, imgconv, &area); + img = imgconv; + } + // GLenum glTexFormat = GL_PIXFMT_INFO[pixfmt].internalfmt; GLenum glImageFormat = GL_PIXFMT_INFO[pixfmt].format; GLenum glImageType = GL_PIXFMT_INFO[pixfmt].type; @@ -1003,6 +1044,9 @@ void RageDisplay_OGL::UpdateTexture( /* Must unset PixelStore when we're done! */ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glFlush(); + + if( imgconv ) + SDL_FreeSurface( imgconv ); } CString RageDisplay_OGL::GetTextureDiagnostics( unsigned id ) const diff --git a/stepmania/src/RageDisplay_OGL.h b/stepmania/src/RageDisplay_OGL.h index 4811643aec..30d8102f5e 100644 --- a/stepmania/src/RageDisplay_OGL.h +++ b/stepmania/src/RageDisplay_OGL.h @@ -20,8 +20,7 @@ public: unsigned CreateTexture( PixelFormat pixfmt, SDL_Surface*& img ); void UpdateTexture( unsigned uTexHandle, - PixelFormat pixfmt, // this must be the same as what was passed to CreateTexture - SDL_Surface*& img, + SDL_Surface* img, int xoffset, int yoffset, int width, int height ); void DeleteTexture( unsigned uTexHandle );