2011-03-17 01:47:30 -04:00
# include "global.h"
# include "RageDisplay_OGL.h"
# include "RageDisplay_OGL_Helpers.h"
2011-05-02 20:11:26 -05:00
using namespace RageDisplay_Legacy_Helpers ;
2011-03-17 01:47:30 -04:00
# include "RageFile.h"
# include "RageSurface.h"
# include "RageSurfaceUtils.h"
# include "RageUtil.h"
# include "RageLog.h"
# include "RageTextureManager.h"
# include "RageMath.h"
# include "RageTypes.h"
# include "RageUtil.h"
# include "EnumHelper.h"
# include "Foreach.h"
# include "DisplayResolutions.h"
# include "LocalizedString.h"
# include "arch/LowLevelWindow/LowLevelWindow.h"
# include <set>
2011-05-04 00:33:32 -05:00
# if defined(WINDOWS)
2011-05-04 00:31:42 -05:00
# include <GL/wglew.h>
2011-05-04 00:33:32 -05:00
# endif
2011-05-04 00:31:42 -05:00
2011-03-17 01:47:30 -04:00
# if defined(_MSC_VER)
# pragma comment(lib, "opengl32.lib")
# pragma comment(lib, "glu32.lib")
# endif
# ifdef NO_GL_FLUSH
# define glFlush()
# endif
//
// Globals
//
static bool g_bReversePackedPixelsWorks = true ;
static bool g_bColorIndexTableWorks = true ;
/* OpenGL system information that generally doesn't change at runtime. */
/* Range and granularity of points and lines: */
static float g_line_range [ 2 ] ;
static float g_point_range [ 2 ] ;
/* OpenGL version * 10: */
static int g_glVersion ;
/* GLU version * 10: */
static int g_gluVersion ;
static int g_iMaxTextureUnits = 0 ;
/* We don't actually use normals (we don't turn on lighting), there's just
* no GL_T2F_C4F_V3F. */
static const GLenum RageSpriteVertexFormat = GL_T2F_C4F_N3F_V3F ;
/* If we support texture matrix scaling, a handle to the vertex program: */
static GLhandleARB g_bTextureMatrixShader = 0 ;
static map < unsigned , RenderTarget * > g_mapRenderTargets ;
static RenderTarget * g_pCurrentRenderTarget = NULL ;
static LowLevelWindow * g_pWind ;
static bool g_bInvertY = false ;
static void InvalidateObjects ( ) ;
static RageDisplay : : PixelFormatDesc PIXEL_FORMAT_DESC [ NUM_PixelFormat ] = {
{
/* R8G8B8A8 */
32 ,
{ 0xFF000000 ,
0x00FF0000 ,
0x0000FF00 ,
0x000000FF }
} , {
/* B8G8R8A8 */
32 ,
{ 0x0000FF00 ,
0x00FF0000 ,
0xFF000000 ,
0x000000FF }
} , {
/* R4G4B4A4 */
16 ,
{ 0xF000 ,
0x0F00 ,
0x00F0 ,
0x000F } ,
} , {
/* R5G5B5A1 */
16 ,
{ 0xF800 ,
0x07C0 ,
0x003E ,
0x0001 } ,
} , {
/* R5G5B5X1 */
16 ,
{ 0xF800 ,
0x07C0 ,
0x003E ,
0x0000 } ,
} , {
/* R8G8B8 */
24 ,
{ 0xFF0000 ,
0x00FF00 ,
0x0000FF ,
0x000000 }
} , {
/* Paletted */
8 ,
{ 0 , 0 , 0 , 0 } /* N/A */
} , {
/* B8G8R8 */
24 ,
{ 0x0000FF ,
0x00FF00 ,
0xFF0000 ,
0x000000 }
} , {
/* A1R5G5B5 */
16 ,
{ 0x7C00 ,
0x03E0 ,
0x001F ,
0x8000 } ,
} , {
/* X1R5G5B5 */
16 ,
{ 0x7C00 ,
0x03E0 ,
0x001F ,
0x0000 } ,
}
} ;
/* g_GLPixFmtInfo is used for both texture formats and surface formats. For example,
* it's fine to ask for a PixelFormat_RGB5 texture, but to supply a surface matching
* PixelFormat_RGB8. OpenGL will simply discard the extra bits.
*
* It's possible for a format to be supported as a texture format but not as a
* surface format. For example, if packed pixels aren't supported, we can still
* use GL_RGB5_A1, but we'll have to convert to a supported surface pixel format
* first. It's not ideal, since we'll convert to RGBA8 and OGL will convert back,
* but it works fine.
*/
struct GLPixFmtInfo_t {
GLenum internalfmt ; /* target format */
GLenum format ; /* target format */
GLenum type ; /* data format */
} const g_GLPixFmtInfo [ NUM_PixelFormat ] = {
{
/* R8G8B8A8 */
GL_RGBA8 ,
GL_RGBA ,
GL_UNSIGNED_BYTE ,
} , {
/* R8G8B8A8 */
GL_RGBA8 ,
GL_BGRA ,
GL_UNSIGNED_BYTE ,
} , {
/* B4G4R4A4 */
GL_RGBA4 ,
GL_RGBA ,
GL_UNSIGNED_SHORT_4_4_4_4 ,
} , {
/* B5G5R5A1 */
GL_RGB5_A1 ,
GL_RGBA ,
GL_UNSIGNED_SHORT_5_5_5_1 ,
} , {
/* B5G5R5 */
GL_RGB5 ,
GL_RGBA ,
GL_UNSIGNED_SHORT_5_5_5_1 ,
} , {
/* B8G8R8 */
GL_RGB8 ,
GL_RGB ,
GL_UNSIGNED_BYTE ,
} , {
/* Paletted */
GL_COLOR_INDEX8_EXT ,
GL_COLOR_INDEX ,
GL_UNSIGNED_BYTE ,
} , {
/* B8G8R8 */
GL_RGB8 ,
GL_BGR ,
GL_UNSIGNED_BYTE ,
} , {
/* A1R5G5B5 (matches D3DFMT_A1R5G5B5) */
GL_RGB5_A1 ,
GL_BGRA ,
GL_UNSIGNED_SHORT_1_5_5_5_REV ,
} , {
/* X1R5G5B5 */
GL_RGB5 ,
GL_BGRA ,
GL_UNSIGNED_SHORT_1_5_5_5_REV ,
}
} ;
static void FixLittleEndian ( )
{
# if defined(ENDIAN_LITTLE)
static bool bInitialized = false ;
2011-05-02 20:11:26 -05:00
if ( bInitialized )
2011-03-17 01:47:30 -04:00
return ;
bInitialized = true ;
for ( int i = 0 ; i < NUM_PixelFormat ; + + i )
{
RageDisplay : : PixelFormatDesc & pf = PIXEL_FORMAT_DESC [ i ] ;
/* OpenGL and RageSurface handle byte formats differently; we need
* to flip non-paletted masks to make them line up. */
2011-05-02 20:11:26 -05:00
if ( g_GLPixFmtInfo [ i ] . type ! = GL_UNSIGNED_BYTE | | pf . bpp = = 8 )
2011-03-17 01:47:30 -04:00
continue ;
for ( int mask = 0 ; mask < 4 ; + + mask )
{
int m = pf . masks [ mask ] ;
switch ( pf . bpp )
{
case 24 : m = Swap24 ( m ) ; break ;
case 32 : m = Swap32 ( m ) ; break ;
2012-12-27 16:59:35 -05:00
default :
FAIL_M ( ssprintf ( " Unsupported BPP value: %i " , pf . bpp ) ) ;
2011-03-17 01:47:30 -04:00
}
pf . masks [ mask ] = m ;
}
}
# endif
}
static void TurnOffHardwareVBO ( )
{
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_vertex_buffer_object )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , 0 ) ;
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , 0 ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
RageDisplay_Legacy : : RageDisplay_Legacy ( )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
LOG - > Trace ( " RageDisplay_Legacy::RageDisplay_Legacy() " ) ;
2011-03-17 01:47:30 -04:00
LOG - > MapLog ( " renderer " , " Current renderer: OpenGL " ) ;
FixLittleEndian ( ) ;
2011-05-02 20:11:26 -05:00
RageDisplay_Legacy_Helpers : : Init ( ) ;
2011-03-17 01:47:30 -04:00
g_pWind = NULL ;
g_bTextureMatrixShader = 0 ;
}
RString GetInfoLog ( GLhandleARB h )
{
GLint iLength ;
2011-05-02 20:11:26 -05:00
glGetObjectParameterivARB ( h , GL_OBJECT_INFO_LOG_LENGTH_ARB , & iLength ) ;
if ( ! iLength )
2011-03-17 01:47:30 -04:00
return RString ( ) ;
GLcharARB * pInfoLog = new GLcharARB [ iLength ] ;
2011-05-02 20:11:26 -05:00
glGetInfoLogARB ( h , iLength , & iLength , pInfoLog ) ;
2011-03-17 01:47:30 -04:00
RString sRet = pInfoLog ;
delete [ ] pInfoLog ;
TrimRight ( sRet ) ;
return sRet ;
}
GLhandleARB CompileShader ( GLenum ShaderType , RString sFile , vector < RString > asDefines )
{
2012-11-13 15:01:32 -08:00
/* XXX: This would not be necessary if it wasn't for the special case for Cel. */
if ( ShaderType = = GL_FRAGMENT_SHADER_ARB & & ! glewIsSupported ( " GL_VERSION_2_0 " ) )
{
LOG - > Warn ( " Fragment shaders not supported by driver. Some effects will not be available. " ) ;
2011-12-29 16:06:15 -07:00
return 0 ;
2012-11-13 15:01:32 -08:00
}
2011-03-17 01:47:30 -04:00
RString sBuffer ;
{
RageFile file ;
2011-05-02 20:11:26 -05:00
if ( ! file . Open ( sFile ) )
2011-03-17 01:47:30 -04:00
{
LOG - > Warn ( " Error compiling shader %s: %s " , sFile . c_str ( ) , file . GetError ( ) . c_str ( ) ) ;
return 0 ;
}
2011-05-02 20:11:26 -05:00
if ( file . Read ( sBuffer , file . GetFileSize ( ) ) = = - 1 )
2011-03-17 01:47:30 -04:00
{
LOG - > Warn ( " Error compiling shader %s: %s " , sFile . c_str ( ) , file . GetError ( ) . c_str ( ) ) ;
return 0 ;
}
}
LOG - > Trace ( " Compiling shader %s " , sFile . c_str ( ) ) ;
2011-05-02 20:11:26 -05:00
GLhandleARB hShader = glCreateShaderObjectARB ( ShaderType ) ;
2011-03-17 01:47:30 -04:00
vector < const GLcharARB * > apData ;
vector < GLint > aiLength ;
FOREACH ( RString , asDefines , s )
{
* s = ssprintf ( " #define %s \n " , s - > c_str ( ) ) ;
apData . push_back ( s - > data ( ) ) ;
aiLength . push_back ( s - > size ( ) ) ;
}
apData . push_back ( " #line 1 \n " ) ;
aiLength . push_back ( 8 ) ;
apData . push_back ( sBuffer . data ( ) ) ;
aiLength . push_back ( sBuffer . size ( ) ) ;
2011-05-02 20:11:26 -05:00
glShaderSourceARB ( hShader , apData . size ( ) , & apData [ 0 ] , & aiLength [ 0 ] ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
glCompileShaderARB ( hShader ) ;
2011-03-17 01:47:30 -04:00
RString sInfo = GetInfoLog ( hShader ) ;
GLint bCompileStatus = GL_FALSE ;
2011-05-02 20:11:26 -05:00
glGetObjectParameterivARB ( hShader , GL_OBJECT_COMPILE_STATUS_ARB , & bCompileStatus ) ;
if ( ! bCompileStatus )
2011-03-17 01:47:30 -04:00
{
LOG - > Warn ( " Error compiling shader %s: \n %s " , sFile . c_str ( ) , sInfo . c_str ( ) ) ;
2011-05-02 20:11:26 -05:00
glDeleteObjectARB ( hShader ) ;
2011-03-17 01:47:30 -04:00
return 0 ;
}
2011-05-02 20:11:26 -05:00
if ( ! sInfo . empty ( ) )
2011-03-17 01:47:30 -04:00
LOG - > Trace ( " Messages compiling shader %s: \n %s " , sFile . c_str ( ) , sInfo . c_str ( ) ) ;
return hShader ;
}
GLhandleARB LoadShader ( GLenum ShaderType , RString sFile , vector < RString > asDefines )
{
2012-11-13 15:01:32 -08:00
/* Vertex shaders are supported by more hardware than fragment shaders.
* If this causes any trouble I will have to up the requirement for both
* of them to at least GL 2.0. Regardless we need basic GLSL support.
* -Colby */
if ( ! glewIsSupported ( " GL_ARB_shading_language_100 GL_ARB_shader_objects " ) | |
( ShaderType = = GL_FRAGMENT_SHADER_ARB & & ! glewIsSupported ( " GL_VERSION_2_0 " ) ) | |
( ShaderType = = GL_VERTEX_SHADER_ARB & & ! glewIsSupported ( " GL_ARB_vertex_shader " ) ) )
{
LOG - > Warn ( " %s shaders not supported by driver. Some effects will not be available. " ,
( ShaderType = = GL_FRAGMENT_SHADER_ARB ) ? " Fragment " : " Vertex " ) ;
2011-03-17 01:47:30 -04:00
return 0 ;
2012-11-13 15:01:32 -08:00
}
2011-03-17 01:47:30 -04:00
// XXX: dumb, but I don't feel like refactoring ragedisplay for this. -Colby
GLhandleARB secondaryShader = 0 ;
2011-05-02 20:11:26 -05:00
if ( sFile = = " Data/Shaders/GLSL/Cel.vert " )
2011-03-17 01:47:30 -04:00
secondaryShader = CompileShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Cel.frag " , asDefines ) ;
2011-05-02 20:11:26 -05:00
else if ( sFile = = " Data/Shaders/GLSL/Shell.vert " )
2011-03-17 01:47:30 -04:00
secondaryShader = CompileShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Shell.frag " , asDefines ) ;
GLhandleARB hShader = CompileShader ( ShaderType , sFile , asDefines ) ;
2011-05-02 20:11:26 -05:00
if ( hShader = = 0 )
2011-03-17 01:47:30 -04:00
return 0 ;
2011-05-02 20:11:26 -05:00
GLhandleARB hProgram = glCreateProgramObjectARB ( ) ;
glAttachObjectARB ( hProgram , hShader ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
if ( secondaryShader )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glAttachObjectARB ( hProgram , secondaryShader ) ;
glDeleteObjectARB ( secondaryShader ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
glDeleteObjectARB ( hShader ) ;
2011-03-17 01:47:30 -04:00
// Link the program.
2011-05-02 20:11:26 -05:00
glLinkProgramARB ( hProgram ) ;
2011-03-17 01:47:30 -04:00
GLint bLinkStatus = false ;
2011-05-02 20:11:26 -05:00
glGetObjectParameterivARB ( hProgram , GL_OBJECT_LINK_STATUS_ARB , & bLinkStatus ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
if ( ! bLinkStatus )
2011-03-17 01:47:30 -04:00
{
LOG - > Warn ( " Error linking shader %s: %s " , sFile . c_str ( ) , GetInfoLog ( hProgram ) . c_str ( ) ) ;
2011-05-02 20:11:26 -05:00
glDeleteObjectARB ( hProgram ) ;
2011-03-17 01:47:30 -04:00
return 0 ;
}
return hProgram ;
}
static int g_iAttribTextureMatrixScale ;
static GLhandleARB g_bUnpremultiplyShader = 0 ;
static GLhandleARB g_bColorBurnShader = 0 ;
static GLhandleARB g_bColorDodgeShader = 0 ;
static GLhandleARB g_bVividLightShader = 0 ;
static GLhandleARB g_hHardMixShader = 0 ;
static GLhandleARB g_hOverlayShader = 0 ;
static GLhandleARB g_hScreenShader = 0 ;
static GLhandleARB g_hYUYV422Shader = 0 ;
static GLhandleARB g_gShellShader = 0 ;
static GLhandleARB g_gCelShader = 0 ;
void InitShaders ( )
{
// xxx: replace this with a ShaderManager or something that reads in
// the shaders and determines shader type by file extension. -aj
// argh shaders in stepmania are painful -colby
vector < RString > asDefines ;
// used for scrolling textures (I think)
g_bTextureMatrixShader = LoadShader ( GL_VERTEX_SHADER_ARB , " Data/Shaders/GLSL/Texture matrix scaling.vert " , asDefines ) ;
// these two are for dancing characters and are both actually shader pairs
g_gShellShader = LoadShader ( GL_VERTEX_SHADER_ARB , " Data/Shaders/GLSL/Shell.vert " , asDefines ) ;
g_gCelShader = LoadShader ( GL_VERTEX_SHADER_ARB , " Data/Shaders/GLSL/Cel.vert " , asDefines ) ;
// effects
g_bUnpremultiplyShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Unpremultiply.frag " , asDefines ) ;
g_bColorBurnShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Color burn.frag " , asDefines ) ;
g_bColorDodgeShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Color dodge.frag " , asDefines ) ;
g_bVividLightShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Vivid light.frag " , asDefines ) ;
g_hHardMixShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Hard mix.frag " , asDefines ) ;
g_hOverlayShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Overlay.frag " , asDefines ) ;
g_hScreenShader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/Screen.frag " , asDefines ) ;
g_hYUYV422Shader = LoadShader ( GL_FRAGMENT_SHADER_ARB , " Data/Shaders/GLSL/YUYV422.frag " , asDefines ) ;
// Bind attributes.
2011-05-02 20:11:26 -05:00
if ( g_bTextureMatrixShader )
2011-03-17 01:47:30 -04:00
{
FlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
g_iAttribTextureMatrixScale = glGetAttribLocationARB ( g_bTextureMatrixShader , " TextureMatrixScale " ) ;
if ( g_iAttribTextureMatrixScale = = - 1 )
2011-03-17 01:47:30 -04:00
{
LOG - > Trace ( " Scaling shader link failed: couldn't bind attribute \" TextureMatrixScale \" " ) ;
2011-05-02 20:11:26 -05:00
glDeleteObjectARB ( g_bTextureMatrixShader ) ;
2011-03-17 01:47:30 -04:00
g_bTextureMatrixShader = 0 ;
}
else
{
AssertNoGLError ( ) ;
/* Older Catalyst drivers seem to throw GL_INVALID_OPERATION here. */
2011-05-02 20:11:26 -05:00
glVertexAttrib2fARB ( g_iAttribTextureMatrixScale , 1 , 1 ) ;
2011-03-17 01:47:30 -04:00
GLenum iError = glGetError ( ) ;
2011-05-02 20:11:26 -05:00
if ( iError = = GL_INVALID_OPERATION )
2011-03-17 01:47:30 -04:00
{
LOG - > Trace ( " Scaling shader failed: glVertexAttrib2fARB returned GL_INVALID_OPERATION " ) ;
2011-05-02 20:11:26 -05:00
glDeleteObjectARB ( g_bTextureMatrixShader ) ;
2011-03-17 01:47:30 -04:00
g_bTextureMatrixShader = 0 ;
}
else
{
ASSERT_M ( iError = = GL_NO_ERROR , GLToString ( iError ) ) ;
}
}
}
}
2011-05-02 20:11:26 -05:00
static LocalizedString OBTAIN_AN_UPDATED_VIDEO_DRIVER ( " RageDisplay_Legacy " , " Obtain an updated driver from your video card manufacturer. " ) ;
static LocalizedString GLDIRECT_IS_NOT_COMPATIBLE ( " RageDisplay_Legacy " , " GLDirect was detected. GLDirect is not compatible with this game and should be disabled. " ) ;
RString RageDisplay_Legacy : : Init ( const VideoModeParams & p , bool bAllowUnacceleratedRenderer )
2011-03-17 01:47:30 -04:00
{
g_pWind = LowLevelWindow : : Create ( ) ;
bool bIgnore = false ;
RString sError = SetVideoMode ( p , bIgnore ) ;
2011-05-02 20:11:26 -05:00
if ( sError ! = " " )
2011-03-17 01:47:30 -04:00
return sError ;
// Log driver details
g_pWind - > LogDebugInformation ( ) ;
LOG - > Info ( " OGL Vendor: %s " , glGetString ( GL_VENDOR ) ) ;
LOG - > Info ( " OGL Renderer: %s " , glGetString ( GL_RENDERER ) ) ;
LOG - > Info ( " OGL Version: %s " , glGetString ( GL_VERSION ) ) ;
LOG - > Info ( " OGL Max texture size: %i " , GetMaxTextureSize ( ) ) ;
LOG - > Info ( " OGL Texture units: %i " , g_iMaxTextureUnits ) ;
LOG - > Info ( " GLU Version: %s " , gluGetString ( GLU_VERSION ) ) ;
/* Pretty-print the extension string: */
LOG - > Info ( " OGL Extensions: " ) ;
{
const char * szExtensionString = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
vector < RString > asExtensions ;
split ( szExtensionString , " " , asExtensions ) ;
sort ( asExtensions . begin ( ) , asExtensions . end ( ) ) ;
size_t iNextToPrint = 0 ;
while ( iNextToPrint < asExtensions . size ( ) )
{
size_t iLastToPrint = iNextToPrint ;
RString sType ;
for ( size_t i = iNextToPrint ; i < asExtensions . size ( ) ; + + i )
{
vector < RString > asBits ;
split ( asExtensions [ i ] , " _ " , asBits ) ;
RString sThisType ;
2011-05-02 20:11:26 -05:00
if ( asBits . size ( ) > 2 )
2011-03-17 01:47:30 -04:00
sThisType = join ( " _ " , asBits . begin ( ) , asBits . begin ( ) + 2 ) ;
2011-05-02 20:11:26 -05:00
if ( i > iNextToPrint & & sThisType ! = sType )
2011-03-17 01:47:30 -04:00
break ;
sType = sThisType ;
iLastToPrint = i ;
}
2011-05-02 20:11:26 -05:00
if ( iNextToPrint = = iLastToPrint )
2011-03-17 01:47:30 -04:00
{
LOG - > Info ( " %s " , asExtensions [ iNextToPrint ] . c_str ( ) ) ;
+ + iNextToPrint ;
continue ;
}
RString sList = ssprintf ( " %s: " , sType . c_str ( ) ) ;
while ( iNextToPrint < = iLastToPrint )
{
vector < RString > asBits ;
split ( asExtensions [ iNextToPrint ] , " _ " , asBits ) ;
RString sShortExt = join ( " _ " , asBits . begin ( ) + 2 , asBits . end ( ) ) ;
sList + = sShortExt ;
2011-05-02 20:11:26 -05:00
if ( iNextToPrint < iLastToPrint )
2011-03-17 01:47:30 -04:00
sList + = " , " ;
2011-05-02 20:11:26 -05:00
if ( iNextToPrint = = iLastToPrint | | sList . size ( ) + asExtensions [ iNextToPrint + 1 ] . size ( ) > 120 )
2011-03-17 01:47:30 -04:00
{
LOG - > Info ( " %s " , sList . c_str ( ) ) ;
sList = " " ;
}
+ + iNextToPrint ;
}
}
}
2011-05-02 20:11:26 -05:00
if ( g_pWind - > IsSoftwareRenderer ( sError ) )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! bAllowUnacceleratedRenderer )
2011-03-17 01:47:30 -04:00
return sError + " " + OBTAIN_AN_UPDATED_VIDEO_DRIVER . GetValue ( ) + " \n \n " ;
LOG - > Warn ( " Low-performance OpenGL renderer: %s " , sError . c_str ( ) ) ;
}
# if defined(_WINDOWS)
/* GLDirect is a Direct3D wrapper for OpenGL. It's rather buggy; and if in
* any case GLDirect can successfully render us, we should be able to do so
* too using Direct3D directly. (If we can't, it's a bug that we can work
* around--if GLDirect can do it, so can we!) */
2011-05-02 20:11:26 -05:00
if ( ! strncmp ( ( const char * ) glGetString ( GL_RENDERER ) , " GLDirect " , 8 ) )
2011-03-17 01:47:30 -04:00
return GLDIRECT_IS_NOT_COMPATIBLE . GetValue ( ) + " \n " ;
# endif
/* Log this, so if people complain that the radar looks bad on their
* system we can compare them: */
glGetFloatv ( GL_LINE_WIDTH_RANGE , g_line_range ) ;
glGetFloatv ( GL_POINT_SIZE_RANGE , g_point_range ) ;
return RString ( ) ;
}
2011-05-02 20:11:26 -05:00
RageDisplay_Legacy : : ~ RageDisplay_Legacy ( )
2011-03-17 01:47:30 -04:00
{
delete g_pWind ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : GetDisplayResolutions ( DisplayResolutions & out ) const
2011-03-17 01:47:30 -04:00
{
out . clear ( ) ;
g_pWind - > GetDisplayResolutions ( out ) ;
}
static void CheckPalettedTextures ( )
{
RString sError ;
do
{
2011-05-02 20:11:26 -05:00
if ( ! GLEW_EXT_paletted_texture )
2011-03-17 01:47:30 -04:00
{
sError = " GL_EXT_paletted_texture missing " ;
break ;
}
/* Check to see if paletted textures really work. */
GLenum glTexFormat = g_GLPixFmtInfo [ PixelFormat_PAL ] . internalfmt ;
GLenum glImageFormat = g_GLPixFmtInfo [ PixelFormat_PAL ] . format ;
GLenum glImageType = g_GLPixFmtInfo [ PixelFormat_PAL ] . type ;
int iBits = 8 ;
FlushGLErrors ( ) ;
# define GL_CHECK_ERROR(f) \
{ \
GLenum glError = glGetError(); \
2011-05-02 20:11:26 -05:00
if (glError != GL_NO_ERROR) { \
2011-03-17 01:47:30 -04:00
sError = ssprintf(f " failed (%s)", GLToString(glError).c_str() ); \
break; \
} \
}
glTexImage2D ( GL_PROXY_TEXTURE_2D ,
0 , glTexFormat ,
16 , 16 , 0 ,
glImageFormat , glImageType , NULL ) ;
GL_CHECK_ERROR ( " glTexImage2D " ) ;
GLuint iFormat = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INTERNAL_FORMAT ) , ( GLint * ) & iFormat ) ;
GL_CHECK_ERROR ( " glGetTexLevelParameteriv(GL_TEXTURE_INTERNAL_FORMAT) " ) ;
2011-05-02 20:11:26 -05:00
if ( iFormat ! = glTexFormat )
2011-03-17 01:47:30 -04:00
{
sError = ssprintf ( " Expected format %s, got %s instead " ,
GLToString ( glTexFormat ) . c_str ( ) , GLToString ( iFormat ) . c_str ( ) ) ;
break ;
}
GLubyte palette [ 256 * 4 ] ;
memset ( palette , 0 , sizeof ( palette ) ) ;
2011-05-02 20:11:26 -05:00
glColorTableEXT ( GL_PROXY_TEXTURE_2D , GL_RGBA8 , 256 , GL_RGBA , GL_UNSIGNED_BYTE , palette ) ;
2011-03-17 01:47:30 -04:00
GL_CHECK_ERROR ( " glColorTableEXT " ) ;
GLint iSize = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INDEX_SIZE_EXT ) , & iSize ) ;
GL_CHECK_ERROR ( " glGetTexLevelParameteriv(GL_TEXTURE_INDEX_SIZE_EXT) " ) ;
2011-05-02 20:11:26 -05:00
if ( iBits > iSize | | iSize > 8 )
2011-03-17 01:47:30 -04:00
{
sError = ssprintf ( " Expected %i-bit palette, got a %i-bit one instead " , iBits , int ( iSize ) ) ;
break ;
}
GLint iRealWidth = 0 ;
2011-05-02 20:11:26 -05:00
glGetColorTableParameterivEXT ( GL_PROXY_TEXTURE_2D , GL_COLOR_TABLE_WIDTH , & iRealWidth ) ;
2011-03-17 01:47:30 -04:00
GL_CHECK_ERROR ( " glGetColorTableParameterivEXT(GL_COLOR_TABLE_WIDTH) " ) ;
2011-05-02 20:11:26 -05:00
if ( iRealWidth ! = 1 < < iBits )
2011-03-17 01:47:30 -04:00
{
sError = ssprintf ( " GL_COLOR_TABLE_WIDTH returned %i instead of %i " , int ( iRealWidth ) , 1 < < iBits ) ;
break ;
}
GLint iRealFormat = 0 ;
2011-05-02 20:11:26 -05:00
glGetColorTableParameterivEXT ( GL_PROXY_TEXTURE_2D , GL_COLOR_TABLE_FORMAT , & iRealFormat ) ;
2011-03-17 01:47:30 -04:00
GL_CHECK_ERROR ( " glGetColorTableParameterivEXT(GL_COLOR_TABLE_FORMAT) " ) ;
2011-05-02 20:11:26 -05:00
if ( iRealFormat ! = GL_RGBA8 )
2011-03-17 01:47:30 -04:00
{
sError = ssprintf ( " GL_COLOR_TABLE_FORMAT returned %s instead of GL_RGBA8 " , GLToString ( iRealFormat ) . c_str ( ) ) ;
break ;
}
} while ( 0 ) ;
# undef GL_CHECK_ERROR
2011-05-02 20:11:26 -05:00
if ( sError = = " " )
2011-03-17 01:47:30 -04:00
return ;
/* If 8-bit palettes don't work, disable them entirely--don't trust 4-bit
* palettes if it can't even get 8-bit ones right. */
2011-05-02 20:11:26 -05:00
glColorTableEXT = NULL ;
glGetColorTableParameterivEXT = NULL ;
2011-03-17 01:47:30 -04:00
LOG - > Info ( " Paletted textures disabled: %s. " , sError . c_str ( ) ) ;
}
static void CheckReversePackedPixels ( )
{
/* Try to create a texture. */
FlushGLErrors ( ) ;
glTexImage2D ( GL_PROXY_TEXTURE_2D ,
0 , GL_RGBA ,
16 , 16 , 0 ,
GL_BGRA , GL_UNSIGNED_SHORT_1_5_5_5_REV , NULL ) ;
const GLenum glError = glGetError ( ) ;
2011-05-02 20:11:26 -05:00
if ( glError = = GL_NO_ERROR )
2011-03-17 01:47:30 -04:00
{
g_bReversePackedPixelsWorks = true ;
}
else
{
g_bReversePackedPixelsWorks = false ;
LOG - > Info ( " GL_UNSIGNED_SHORT_1_5_5_5_REV failed (%s), disabled " ,
GLToString ( glError ) . c_str ( ) ) ;
}
}
void SetupExtensions ( )
{
const float fGLVersion = StringToFloat ( ( const char * ) glGetString ( GL_VERSION ) ) ;
g_glVersion = lrintf ( fGLVersion * 10 ) ;
const float fGLUVersion = StringToFloat ( ( const char * ) gluGetString ( GLU_VERSION ) ) ;
g_gluVersion = lrintf ( fGLUVersion * 10 ) ;
2011-05-02 20:11:26 -05:00
glewInit ( ) ;
2011-03-17 01:47:30 -04:00
g_iMaxTextureUnits = 1 ;
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_multitexture )
2011-03-17 01:47:30 -04:00
glGetIntegerv ( GL_MAX_TEXTURE_UNITS_ARB , ( GLint * ) & g_iMaxTextureUnits ) ;
CheckPalettedTextures ( ) ;
CheckReversePackedPixels ( ) ;
{
GLint iMaxTableSize = 0 ;
glGetIntegerv ( GL_MAX_PIXEL_MAP_TABLE , & iMaxTableSize ) ;
2011-05-02 20:11:26 -05:00
if ( iMaxTableSize < 256 )
2011-03-17 01:47:30 -04:00
{
/* The minimum GL_MAX_PIXEL_MAP_TABLE is 32; if it's not at least 256,
* we can't fit a palette in it, so we can't send paletted data as input
* for a non-paletted texture. */
LOG - > Info ( " GL_MAX_PIXEL_MAP_TABLE is only %d " , int ( iMaxTableSize ) ) ;
g_bColorIndexTableWorks = false ;
}
else
{
g_bColorIndexTableWorks = true ;
}
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : ResolutionChanged ( )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
//LOG->Warn( "RageDisplay_Legacy::ResolutionChanged" );
2011-03-17 01:47:30 -04:00
/* Clear any junk that's in the framebuffer. */
2011-05-02 20:11:26 -05:00
if ( BeginFrame ( ) )
2011-03-17 01:47:30 -04:00
EndFrame ( ) ;
RageDisplay : : ResolutionChanged ( ) ;
}
// Return true if mode change was successful.
// bNewDeviceOut is set true if a new device was created and textures
// need to be reloaded.
2011-05-02 20:11:26 -05:00
RString RageDisplay_Legacy : : TryVideoMode ( const VideoModeParams & p , bool & bNewDeviceOut )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
//LOG->Warn( "RageDisplay_Legacy::TryVideoMode( %d, %d, %d, %d, %d, %d )", p.windowed, p.width, p.height, p.bpp, p.rate, p.vsync );
2011-03-17 01:47:30 -04:00
RString err ;
err = g_pWind - > TryVideoMode ( p , bNewDeviceOut ) ;
2011-05-02 20:11:26 -05:00
if ( err ! = " " )
2011-03-17 01:47:30 -04:00
return err ; // failed to set video mode
/* Now that we've initialized, we can search for extensions. Do this before InvalidateObjects,
* since AllocateBuffers needs it. */
SetupExtensions ( ) ;
2011-05-02 20:11:26 -05:00
if ( bNewDeviceOut )
2011-03-17 01:47:30 -04:00
{
/* We have a new OpenGL context, so we have to tell our textures that
* their OpenGL texture number is invalid. */
2011-05-02 20:11:26 -05:00
if ( TEXTUREMAN )
2011-03-17 01:47:30 -04:00
TEXTUREMAN - > InvalidateTextures ( ) ;
/* Delete all render targets. They may have associated resources other than
* the texture itself. */
FOREACHM ( unsigned , RenderTarget * , g_mapRenderTargets , rt )
delete rt - > second ;
g_mapRenderTargets . clear ( ) ;
/* Recreate all vertex buffers. */
InvalidateObjects ( ) ;
InitShaders ( ) ;
}
2011-05-02 20:11:26 -05:00
// I'm not sure this is correct -Colby
# if defined(WINDOWS)
2011-03-17 01:47:30 -04:00
/* Set vsync the Windows way, if we can. (What other extensions are there
* to do this, for other archs?) */
2011-05-04 00:31:42 -05:00
if ( wglewIsSupported ( " WGL_EXT_swap_control " ) )
2011-05-02 20:11:26 -05:00
wglSwapIntervalEXT ( p . vsync ) ;
2011-05-04 00:31:42 -05:00
else
return RString ( " The WGL_EXT_swap_control extension is not supported on your computer. " ) ;
2011-05-02 20:11:26 -05:00
# endif
2011-03-17 01:47:30 -04:00
ResolutionChanged ( ) ;
return RString ( ) ; // successfully set mode
}
2011-05-02 20:11:26 -05:00
int RageDisplay_Legacy : : GetMaxTextureSize ( ) const
2011-03-17 01:47:30 -04:00
{
GLint size ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & size ) ;
return size ;
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : BeginFrame ( )
2011-03-17 01:47:30 -04:00
{
/* We do this in here, rather than ResolutionChanged, or we won't update the
* viewport for the concurrent rendering context. */
int fWidth = g_pWind - > GetActualVideoModeParams ( ) . width ;
int fHeight = g_pWind - > GetActualVideoModeParams ( ) . height ;
glViewport ( 0 , 0 , fWidth , fHeight ) ;
glClearColor ( 0 , 0 , 0 , 0 ) ;
SetZWrite ( true ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
return RageDisplay : : BeginFrame ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : EndFrame ( )
2011-03-17 01:47:30 -04:00
{
glFlush ( ) ;
FrameLimitBeforeVsync ( g_pWind - > GetActualVideoModeParams ( ) . rate ) ;
g_pWind - > SwapBuffers ( ) ;
FrameLimitAfterVsync ( ) ;
g_pWind - > Update ( ) ;
RageDisplay : : EndFrame ( ) ;
}
2011-05-02 20:11:26 -05:00
RageSurface * RageDisplay_Legacy : : CreateScreenshot ( )
2011-03-17 01:47:30 -04:00
{
int width = g_pWind - > GetActualVideoModeParams ( ) . width ;
int height = g_pWind - > GetActualVideoModeParams ( ) . height ;
const PixelFormatDesc & desc = PIXEL_FORMAT_DESC [ PixelFormat_RGBA8 ] ;
RageSurface * image = CreateSurface ( width , height , desc . bpp ,
desc . masks [ 0 ] , desc . masks [ 1 ] , desc . masks [ 2 ] , 0 ) ;
DebugFlushGLErrors ( ) ;
glReadBuffer ( GL_FRONT ) ;
DebugAssertNoGLError ( ) ;
glReadPixels ( 0 , 0 , g_pWind - > GetActualVideoModeParams ( ) . width , g_pWind - > GetActualVideoModeParams ( ) . height , GL_RGBA ,
GL_UNSIGNED_BYTE , image - > pixels ) ;
DebugAssertNoGLError ( ) ;
RageSurfaceUtils : : FlipVertically ( image ) ;
return image ;
}
2011-05-02 20:11:26 -05:00
RageSurface * RageDisplay_Legacy : : GetTexture ( unsigned iTexture )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( iTexture = = 0 )
2011-03-17 01:47:30 -04:00
return NULL ; // XXX
FlushGLErrors ( ) ;
glBindTexture ( GL_TEXTURE_2D , iTexture ) ;
GLint iHeight , iWidth , iAlphaBits ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_HEIGHT , & iHeight ) ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & iWidth ) ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_ALPHA_SIZE , & iAlphaBits ) ;
int iFormat = iAlphaBits ? PixelFormat_RGBA8 : PixelFormat_RGB8 ;
const PixelFormatDesc & desc = PIXEL_FORMAT_DESC [ iFormat ] ;
RageSurface * pImage = CreateSurface ( iWidth , iHeight , desc . bpp ,
desc . masks [ 0 ] , desc . masks [ 1 ] , desc . masks [ 2 ] , desc . masks [ 3 ] ) ;
glGetTexImage ( GL_TEXTURE_2D , 0 , g_GLPixFmtInfo [ iFormat ] . format , GL_UNSIGNED_BYTE , pImage - > pixels ) ;
AssertNoGLError ( ) ;
return pImage ;
}
2011-05-02 20:11:26 -05:00
VideoModeParams RageDisplay_Legacy : : GetActualVideoModeParams ( ) const
2011-03-17 01:47:30 -04:00
{
return g_pWind - > GetActualVideoModeParams ( ) ;
}
static void SetupVertices ( const RageSpriteVertex v [ ] , int iNumVerts )
{
static float * Vertex , * Texture , * Normal ;
static GLubyte * Color ;
static int Size = 0 ;
2011-05-02 20:11:26 -05:00
if ( iNumVerts > Size )
2011-03-17 01:47:30 -04:00
{
Size = iNumVerts ;
delete [ ] Vertex ;
delete [ ] Color ;
delete [ ] Texture ;
delete [ ] Normal ;
Vertex = new float [ Size * 3 ] ;
Color = new GLubyte [ Size * 4 ] ;
Texture = new float [ Size * 2 ] ;
Normal = new float [ Size * 3 ] ;
}
for ( unsigned i = 0 ; i < unsigned ( iNumVerts ) ; + + i )
{
Vertex [ i * 3 + 0 ] = v [ i ] . p [ 0 ] ;
Vertex [ i * 3 + 1 ] = v [ i ] . p [ 1 ] ;
Vertex [ i * 3 + 2 ] = v [ i ] . p [ 2 ] ;
Color [ i * 4 + 0 ] = v [ i ] . c . r ;
Color [ i * 4 + 1 ] = v [ i ] . c . g ;
Color [ i * 4 + 2 ] = v [ i ] . c . b ;
Color [ i * 4 + 3 ] = v [ i ] . c . a ;
Texture [ i * 2 + 0 ] = v [ i ] . t [ 0 ] ;
Texture [ i * 2 + 1 ] = v [ i ] . t [ 1 ] ;
Normal [ i * 3 + 0 ] = v [ i ] . n [ 0 ] ;
Normal [ i * 3 + 1 ] = v [ i ] . n [ 1 ] ;
Normal [ i * 3 + 2 ] = v [ i ] . n [ 2 ] ;
}
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glVertexPointer ( 3 , GL_FLOAT , 0 , Vertex ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
glColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , Color ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , 0 , Texture ) ;
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_multitexture )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glClientActiveTextureARB ( GL_TEXTURE1_ARB ) ;
2011-03-17 01:47:30 -04:00
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , 0 , Texture ) ;
2011-05-02 20:11:26 -05:00
glClientActiveTextureARB ( GL_TEXTURE0_ARB ) ;
2011-03-17 01:47:30 -04:00
}
glEnableClientState ( GL_NORMAL_ARRAY ) ;
glNormalPointer ( GL_FLOAT , 0 , Normal ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SendCurrentMatrices ( )
2011-03-17 01:47:30 -04:00
{
RageMatrix projection ;
RageMatrixMultiply ( & projection , GetCentering ( ) , GetProjectionTop ( ) ) ;
2011-05-02 20:11:26 -05:00
if ( g_bInvertY )
2011-03-17 01:47:30 -04:00
{
RageMatrix flip ;
RageMatrixScale ( & flip , + 1 , - 1 , + 1 ) ;
RageMatrixMultiply ( & projection , & flip , & projection ) ;
}
glMatrixMode ( GL_PROJECTION ) ;
glLoadMatrixf ( ( const float * ) & projection ) ;
// OpenGL has just "modelView", whereas D3D has "world" and "view"
RageMatrix modelView ;
RageMatrixMultiply ( & modelView , GetViewTop ( ) , GetWorldTop ( ) ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadMatrixf ( ( const float * ) & modelView ) ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( ( const float * ) GetTextureTop ( ) ) ;
}
class RageCompiledGeometrySWOGL : public RageCompiledGeometry
{
public :
void Allocate ( const vector < msMesh > & vMeshes )
{
/* Always allocate at least 1 entry, so &x[0] is valid. */
m_vPosition . resize ( max ( 1u , GetTotalVertices ( ) ) ) ;
m_vTexture . resize ( max ( 1u , GetTotalVertices ( ) ) ) ;
m_vNormal . resize ( max ( 1u , GetTotalVertices ( ) ) ) ;
m_vTexMatrixScale . resize ( max ( 1u , GetTotalVertices ( ) ) ) ;
m_vTriangles . resize ( max ( 1u , GetTotalTriangles ( ) ) ) ;
}
void Change ( const vector < msMesh > & vMeshes )
{
for ( unsigned i = 0 ; i < vMeshes . size ( ) ; i + + )
{
const MeshInfo & meshInfo = m_vMeshInfo [ i ] ;
const msMesh & mesh = vMeshes [ i ] ;
const vector < RageModelVertex > & Vertices = mesh . Vertices ;
const vector < msTriangle > & Triangles = mesh . Triangles ;
for ( unsigned j = 0 ; j < Vertices . size ( ) ; j + + )
{
m_vPosition [ meshInfo . iVertexStart + j ] = Vertices [ j ] . p ;
m_vTexture [ meshInfo . iVertexStart + j ] = Vertices [ j ] . t ;
m_vNormal [ meshInfo . iVertexStart + j ] = Vertices [ j ] . n ;
m_vTexMatrixScale [ meshInfo . iVertexStart + j ] = Vertices [ j ] . TextureMatrixScale ;
}
for ( unsigned j = 0 ; j < Triangles . size ( ) ; j + + )
for ( unsigned k = 0 ; k < 3 ; k + + )
{
int iVertexIndexInVBO = meshInfo . iVertexStart + Triangles [ j ] . nVertexIndices [ k ] ;
m_vTriangles [ meshInfo . iTriangleStart + j ] . nVertexIndices [ k ] = ( uint16_t ) iVertexIndexInVBO ;
}
}
}
void Draw ( int iMeshIndex ) const
{
TurnOffHardwareVBO ( ) ;
const MeshInfo & meshInfo = m_vMeshInfo [ iMeshIndex ] ;
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glVertexPointer ( 3 , GL_FLOAT , 0 , & m_vPosition [ 0 ] ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , 0 , & m_vTexture [ 0 ] ) ;
glEnableClientState ( GL_NORMAL_ARRAY ) ;
glNormalPointer ( GL_FLOAT , 0 , & m_vNormal [ 0 ] ) ;
2011-05-02 20:11:26 -05:00
if ( meshInfo . m_bNeedsTextureMatrixScale )
2011-03-17 01:47:30 -04:00
{
// Kill the texture translation.
// XXX: Change me to scale the translation by the TextureTranslationScale of the first vertex.
RageMatrix mat ;
glGetFloatv ( GL_TEXTURE_MATRIX , ( float * ) mat ) ;
/*
for( int i=0; i<4; i++ )
{
RString s;
for( int j=0; j<4; j++ )
s += ssprintf( "%f ", mat.m[i][j] );
LOG->Trace( s );
}
*/
mat . m [ 3 ] [ 0 ] = 0 ;
mat . m [ 3 ] [ 1 ] = 0 ;
mat . m [ 3 ] [ 2 ] = 0 ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( ( const float * ) mat ) ;
}
glDrawElements (
GL_TRIANGLES ,
meshInfo . iTriangleCount * 3 ,
GL_UNSIGNED_SHORT ,
& m_vTriangles [ 0 ] + meshInfo . iTriangleStart ) ;
}
protected :
vector < RageVector3 > m_vPosition ;
vector < RageVector2 > m_vTexture ;
vector < RageVector3 > m_vNormal ;
vector < msTriangle > m_vTriangles ;
vector < RageVector2 > m_vTexMatrixScale ;
} ;
class InvalidateObject ;
static set < InvalidateObject * > g_InvalidateList ;
class InvalidateObject
{
public :
InvalidateObject ( ) { g_InvalidateList . insert ( this ) ; }
virtual ~ InvalidateObject ( ) { g_InvalidateList . erase ( this ) ; }
virtual void Invalidate ( ) = 0 ;
} ;
static void InvalidateObjects ( )
{
FOREACHS ( InvalidateObject * , g_InvalidateList , it )
( * it ) - > Invalidate ( ) ;
}
class RageCompiledGeometryHWOGL : public RageCompiledGeometrySWOGL , public InvalidateObject
{
protected :
// vertex buffer object names
GLuint m_nPositions ;
GLuint m_nTextureCoords ;
GLuint m_nNormals ;
GLuint m_nTriangles ;
GLuint m_nTextureMatrixScale ;
void AllocateBuffers ( ) ;
void UploadData ( ) ;
public :
RageCompiledGeometryHWOGL ( ) ;
~ RageCompiledGeometryHWOGL ( ) ;
/* This is called when our OpenGL context is invalidated. */
void Invalidate ( ) ;
void Allocate ( const vector < msMesh > & vMeshes ) ;
void Change ( const vector < msMesh > & vMeshes ) ;
void Draw ( int iMeshIndex ) const ;
} ;
RageCompiledGeometryHWOGL : : RageCompiledGeometryHWOGL ( )
{
m_nPositions = 0 ;
m_nTextureCoords = 0 ;
m_nNormals = 0 ;
m_nTriangles = 0 ;
m_nTextureMatrixScale = 0 ;
AllocateBuffers ( ) ;
}
RageCompiledGeometryHWOGL : : ~ RageCompiledGeometryHWOGL ( )
{
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_nPositions ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_nTextureCoords ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_nNormals ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_nTriangles ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_nTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
void RageCompiledGeometryHWOGL : : AllocateBuffers ( )
{
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
if ( ! m_nPositions )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_nPositions ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
if ( ! m_nTextureCoords )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_nTextureCoords ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
if ( ! m_nNormals )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_nNormals ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
if ( ! m_nTriangles )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_nTriangles ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
if ( ! m_nTextureMatrixScale )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_nTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
}
void RageCompiledGeometryHWOGL : : UploadData ( )
{
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector3 ) ,
& m_vPosition [ 0 ] ,
GL_STATIC_DRAW_ARB ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector2 ) ,
& m_vTexture [ 0 ] ,
GL_STATIC_DRAW_ARB ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector3 ) ,
& m_vNormal [ 0 ] ,
GL_STATIC_DRAW_ARB ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
GL_ELEMENT_ARRAY_BUFFER_ARB ,
GetTotalTriangles ( ) * sizeof ( msTriangle ) ,
& m_vTriangles [ 0 ] ,
GL_STATIC_DRAW_ARB ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
if ( m_bAnyNeedsTextureMatrixScale )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
2011-03-17 01:47:30 -04:00
GetTotalVertices ( ) * sizeof ( RageVector2 ) ,
& m_vTexMatrixScale [ 0 ] ,
2011-05-02 20:11:26 -05:00
GL_STATIC_DRAW_ARB ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
}
void RageCompiledGeometryHWOGL : : Invalidate ( )
{
/* Our vertex buffers no longer exist. Reallocate and reupload. */
m_nPositions = 0 ;
m_nTextureCoords = 0 ;
m_nNormals = 0 ;
m_nTriangles = 0 ;
m_nTextureMatrixScale = 0 ;
AllocateBuffers ( ) ;
UploadData ( ) ;
}
void RageCompiledGeometryHWOGL : : Allocate ( const vector < msMesh > & vMeshes )
{
DebugFlushGLErrors ( ) ;
RageCompiledGeometrySWOGL : : Allocate ( vMeshes ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
2011-03-17 01:47:30 -04:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector3 ) ,
NULL ,
GL_STATIC_DRAW_ARB ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
2011-03-17 01:47:30 -04:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector2 ) ,
NULL ,
GL_STATIC_DRAW_ARB ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
2011-03-17 01:47:30 -04:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector3 ) ,
NULL ,
GL_STATIC_DRAW_ARB ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
2011-03-17 01:47:30 -04:00
GL_ELEMENT_ARRAY_BUFFER_ARB ,
GetTotalTriangles ( ) * sizeof ( msTriangle ) ,
NULL ,
GL_STATIC_DRAW_ARB ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBufferDataARB (
2011-03-17 01:47:30 -04:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices ( ) * sizeof ( RageVector2 ) ,
NULL ,
GL_STATIC_DRAW_ARB ) ;
}
void RageCompiledGeometryHWOGL : : Change ( const vector < msMesh > & vMeshes )
{
RageCompiledGeometrySWOGL : : Change ( vMeshes ) ;
UploadData ( ) ;
}
void RageCompiledGeometryHWOGL : : Draw ( int iMeshIndex ) const
{
DebugFlushGLErrors ( ) ;
const MeshInfo & meshInfo = m_vMeshInfo [ iMeshIndex ] ;
2011-05-02 20:11:26 -05:00
if ( ! meshInfo . iVertexCount | | ! meshInfo . iTriangleCount )
2011-03-17 01:47:30 -04:00
return ;
glEnableClientState ( GL_VERTEX_ARRAY ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
glVertexPointer ( 3 , GL_FLOAT , 0 , NULL ) ;
DebugAssertNoGLError ( ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
DebugAssertNoGLError ( ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
glTexCoordPointer ( 2 , GL_FLOAT , 0 , NULL ) ;
DebugAssertNoGLError ( ) ;
// TRICKY: Don't bind and send normals if lighting is disabled. This
// will save some effort transforming these values.
// XXX: We should keep track of these ourself and avoid glGet*()
GLboolean bLighting ;
glGetBooleanv ( GL_LIGHTING , & bLighting ) ;
GLboolean bTextureGenS ;
glGetBooleanv ( GL_TEXTURE_GEN_S , & bTextureGenS ) ;
GLboolean bTextureGenT ;
glGetBooleanv ( GL_TEXTURE_GEN_T , & bTextureGenT ) ;
2011-05-02 20:11:26 -05:00
if ( bLighting | | bTextureGenS | | bTextureGenT )
2011-03-17 01:47:30 -04:00
{
glEnableClientState ( GL_NORMAL_ARRAY ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
glNormalPointer ( GL_FLOAT , 0 , NULL ) ;
DebugAssertNoGLError ( ) ;
}
else
{
glDisableClientState ( GL_NORMAL_ARRAY ) ;
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
if ( meshInfo . m_bNeedsTextureMatrixScale )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( g_bTextureMatrixShader ! = 0 )
2011-03-17 01:47:30 -04:00
{
/* If we're using texture matrix scales, set up that buffer, too, and enable the
* vertex shader. This shader doesn't support all OpenGL state, so only enable it
* if we're using it. */
2011-05-02 20:11:26 -05:00
glEnableVertexAttribArrayARB ( g_iAttribTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glVertexAttribPointerARB ( g_iAttribTextureMatrixScale , 2 , GL_FLOAT , false , 0 , NULL ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
glUseProgramObjectARB ( g_bTextureMatrixShader ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
else
{
// Kill the texture translation.
// XXX: Change me to scale the translation by the TextureTranslationScale of the first vertex.
RageMatrix mat ;
glGetFloatv ( GL_TEXTURE_MATRIX , ( float * ) mat ) ;
/*
for( int i=0; i<4; i++ )
{
RString s;
for( int j=0; j<4; j++ )
s += ssprintf( "%f ", mat.m[i][j] );
LOG->Trace( s );
}
*/
mat . m [ 3 ] [ 0 ] = 0 ;
mat . m [ 3 ] [ 1 ] = 0 ;
mat . m [ 3 ] [ 2 ] = 0 ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( ( const float * ) mat ) ;
DebugAssertNoGLError ( ) ;
}
}
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
# define BUFFER_OFFSET(o) ((char*)(o))
2012-12-27 12:45:04 -05:00
ASSERT ( glDrawRangeElements ! = NULL ) ;
2011-05-02 20:11:26 -05:00
glDrawRangeElements (
2011-03-17 01:47:30 -04:00
GL_TRIANGLES ,
meshInfo . iVertexStart , // minimum array index contained in indices
meshInfo . iVertexStart + meshInfo . iVertexCount - 1 ,
// maximum array index contained in indices
meshInfo . iTriangleCount * 3 , // number of elements to be rendered
GL_UNSIGNED_SHORT ,
BUFFER_OFFSET ( meshInfo . iTriangleStart * sizeof ( msTriangle ) ) ) ;
DebugAssertNoGLError ( ) ;
2011-05-02 20:11:26 -05:00
if ( meshInfo . m_bNeedsTextureMatrixScale & & g_bTextureMatrixShader ! = 0 )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glDisableVertexAttribArrayARB ( g_iAttribTextureMatrixScale ) ;
glUseProgramObjectARB ( 0 ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
RageCompiledGeometry * RageDisplay_Legacy : : CreateCompiledGeometry ( )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_vertex_buffer_object )
2011-03-17 01:47:30 -04:00
return new RageCompiledGeometryHWOGL ;
else
return new RageCompiledGeometrySWOGL ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DeleteCompiledGeometry ( RageCompiledGeometry * p )
2011-03-17 01:47:30 -04:00
{
delete p ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawQuadsInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_QUADS , 0 , iNumVerts ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawQuadStripInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_QUAD_STRIP , 0 , iNumVerts ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawSymmetricQuadStripInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
int iNumPieces = ( iNumVerts - 3 ) / 3 ;
int iNumTriangles = iNumPieces * 4 ;
int iNumIndices = iNumTriangles * 3 ;
// make a temporary index buffer
static vector < uint16_t > vIndices ;
unsigned uOldSize = vIndices . size ( ) ;
unsigned uNewSize = max ( uOldSize , ( unsigned ) iNumIndices ) ;
vIndices . resize ( uNewSize ) ;
for ( uint16_t i = ( uint16_t ) uOldSize / 12 ; i < ( uint16_t ) iNumPieces ; i + + )
{
// { 1, 3, 0 } { 1, 4, 3 } { 1, 5, 4 } { 1, 2, 5 }
vIndices [ i * 12 + 0 ] = i * 3 + 1 ;
vIndices [ i * 12 + 1 ] = i * 3 + 3 ;
vIndices [ i * 12 + 2 ] = i * 3 + 0 ;
vIndices [ i * 12 + 3 ] = i * 3 + 1 ;
vIndices [ i * 12 + 4 ] = i * 3 + 4 ;
vIndices [ i * 12 + 5 ] = i * 3 + 3 ;
vIndices [ i * 12 + 6 ] = i * 3 + 1 ;
vIndices [ i * 12 + 7 ] = i * 3 + 5 ;
vIndices [ i * 12 + 8 ] = i * 3 + 4 ;
vIndices [ i * 12 + 9 ] = i * 3 + 1 ;
vIndices [ i * 12 + 10 ] = i * 3 + 2 ;
vIndices [ i * 12 + 11 ] = i * 3 + 5 ;
}
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawElements (
GL_TRIANGLES ,
iNumIndices ,
GL_UNSIGNED_SHORT ,
& vIndices [ 0 ] ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawFanInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , iNumVerts ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawStripInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , iNumVerts ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawTrianglesInternal ( const RageSpriteVertex v [ ] , int iNumVerts )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_TRIANGLES , 0 , iNumVerts ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawCompiledGeometryInternal ( const RageCompiledGeometry * p , int iMeshIndex )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
SendCurrentMatrices ( ) ;
p - > Draw ( iMeshIndex ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DrawLineStripInternal ( const RageSpriteVertex v [ ] , int iNumVerts , float fLineWidth )
2011-03-17 01:47:30 -04:00
{
TurnOffHardwareVBO ( ) ;
2011-05-02 20:11:26 -05:00
if ( ! GetActualVideoModeParams ( ) . bSmoothLines )
2011-03-17 01:47:30 -04:00
{
/* Fall back on the generic polygon-based line strip. */
RageDisplay : : DrawLineStripInternal ( v , iNumVerts , fLineWidth ) ;
return ;
}
SendCurrentMatrices ( ) ;
/* Draw a nice AA'd line loop. One problem with this is that point and line
* sizes don't always precisely match, which doesn't look quite right.
* It's worth it for the AA, though. */
glEnable ( GL_LINE_SMOOTH ) ;
/* fLineWidth is in units relative to object space, but OpenGL line and point sizes
* are in raster units (actual pixels). Scale the line width by the average ratio;
* if object space is 640x480, and we have a 1280x960 window, we'll double the
* width. */
{
const RageMatrix * pMat = GetProjectionTop ( ) ;
float fW = 2 / pMat - > m [ 0 ] [ 0 ] ;
float fH = - 2 / pMat - > m [ 1 ] [ 1 ] ;
float fWidthVal = float ( g_pWind - > GetActualVideoModeParams ( ) . width ) / fW ;
float fHeightVal = float ( g_pWind - > GetActualVideoModeParams ( ) . height ) / fH ;
fLineWidth * = ( fWidthVal + fHeightVal ) / 2 ;
}
/* Clamp the width to the hardware max for both lines and points (whichever
* is more restrictive). */
fLineWidth = clamp ( fLineWidth , g_line_range [ 0 ] , g_line_range [ 1 ] ) ;
fLineWidth = clamp ( fLineWidth , g_point_range [ 0 ] , g_point_range [ 1 ] ) ;
/* Hmm. The granularity of lines and points might be different; for example,
* if lines are .5 and points are .25, we might want to snap the width to the
* nearest .5, so the hardware doesn't snap them to different sizes. Does it
* matter? */
glLineWidth ( fLineWidth ) ;
/* Draw the line loop: */
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_LINE_STRIP , 0 , iNumVerts ) ;
glDisable ( GL_LINE_SMOOTH ) ;
/* Round off the corners. This isn't perfect; the point is sometimes a little
* larger than the line, causing a small bump on the edge. Not sure how to fix
* that. */
glPointSize ( fLineWidth ) ;
/* Hack: if the points will all be the same, we don't want to draw
* any points at all, since there's nothing to connect. That'll happen
* if both scale factors in the matrix are ~0. (Actually, I think
* it's true if two of the three scale factors are ~0, but we don't
* use this for anything 3d at the moment anyway ...) This is needed
* because points aren't scaled like regular polys--a zero-size point
* will still be drawn. */
RageMatrix mat ;
glGetFloatv ( GL_MODELVIEW_MATRIX , ( float * ) mat ) ;
2011-05-02 20:11:26 -05:00
if ( mat . m [ 0 ] [ 0 ] < 1e-5 & & mat . m [ 1 ] [ 1 ] < 1e-5 )
2011-03-17 01:47:30 -04:00
return ;
glEnable ( GL_POINT_SMOOTH ) ;
SetupVertices ( v , iNumVerts ) ;
glDrawArrays ( GL_POINTS , 0 , iNumVerts ) ;
glDisable ( GL_POINT_SMOOTH ) ;
}
static bool SetTextureUnit ( TextureUnit tu )
{
// If multitexture isn't supported, ignore all textures except for 0.
2011-05-02 20:11:26 -05:00
if ( ! GLEW_ARB_multitexture & & tu ! = TextureUnit_1 )
2011-03-17 01:47:30 -04:00
return false ;
2011-05-02 20:11:26 -05:00
if ( ( int ) tu > g_iMaxTextureUnits )
2011-03-17 01:47:30 -04:00
return false ;
2011-05-02 20:11:26 -05:00
glActiveTextureARB ( enum_add2 ( GL_TEXTURE0_ARB , tu ) ) ;
2011-03-17 01:47:30 -04:00
return true ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : ClearAllTextures ( )
2011-03-17 01:47:30 -04:00
{
FOREACH_ENUM ( TextureUnit , i )
SetTexture ( i , 0 ) ;
// HACK: Reset the active texture to 0.
// TODO: Change all texture functions to take a stage number.
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_multitexture )
glActiveTextureARB ( GL_TEXTURE0_ARB ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
int RageDisplay_Legacy : : GetNumTextureUnits ( )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( GLEW_ARB_multitexture )
2011-03-17 01:47:30 -04:00
return 1 ;
else
return g_iMaxTextureUnits ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetTexture ( TextureUnit tu , unsigned iTexture )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! SetTextureUnit ( tu ) )
2011-03-17 01:47:30 -04:00
return ;
2011-05-02 20:11:26 -05:00
if ( iTexture )
2011-03-17 01:47:30 -04:00
{
glEnable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , iTexture ) ;
}
else
{
glDisable ( GL_TEXTURE_2D ) ;
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetTextureMode ( TextureUnit tu , TextureMode tm )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! SetTextureUnit ( tu ) )
2011-03-17 01:47:30 -04:00
return ;
switch ( tm )
{
case TextureMode_Modulate :
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
break ;
case TextureMode_Add :
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_ADD ) ;
break ;
case TextureMode_Glow :
// the below function is glowmode,brighten:
2011-05-02 20:11:26 -05:00
if ( ! GLEW_ARB_texture_env_combine & & ! GLEW_EXT_texture_env_combine )
2011-03-17 01:47:30 -04:00
{
/* This is changing blend state, instead of texture state, which
* isn't great, but it's better than doing nothing. */
glBlendFunc ( GL_SRC_ALPHA , GL_ONE ) ;
return ;
}
// and this is glowmode,whiten:
// Source color is the diffuse color only:
2011-05-02 20:11:26 -05:00
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_COMBINE_EXT ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_COMBINE_RGB_EXT ) , GL_REPLACE ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_SOURCE0_RGB_EXT ) , GL_PRIMARY_COLOR_EXT ) ;
2011-03-17 01:47:30 -04:00
// Source alpha is texture alpha * diffuse alpha:
2011-05-02 20:11:26 -05:00
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_COMBINE_ALPHA_EXT ) , GL_MODULATE ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_OPERAND0_ALPHA_EXT ) , GL_SRC_ALPHA ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_SOURCE0_ALPHA_EXT ) , GL_PRIMARY_COLOR_EXT ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_OPERAND1_ALPHA_EXT ) , GL_SRC_ALPHA ) ;
glTexEnvi ( GL_TEXTURE_ENV , GLenum ( GL_SOURCE1_ALPHA_EXT ) , GL_TEXTURE ) ;
2011-03-17 01:47:30 -04:00
break ;
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetTextureFiltering ( TextureUnit tu , bool b )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , b ? GL_LINEAR : GL_NEAREST ) ;
2011-03-17 01:47:30 -04:00
GLint iMinFilter ;
2011-05-02 20:11:26 -05:00
if ( b )
2011-03-17 01:47:30 -04:00
{
GLint iWidth1 = - 1 ;
GLint iWidth2 = - 1 ;
2011-05-02 20:11:26 -05:00
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & iWidth1 ) ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 1 , GL_TEXTURE_WIDTH , & iWidth2 ) ;
if ( iWidth1 > 1 & & iWidth2 ! = 0 )
2011-03-17 01:47:30 -04:00
{
/* Mipmaps are enabled. */
2011-05-02 20:11:26 -05:00
if ( g_pWind - > GetActualVideoModeParams ( ) . bTrilinearFiltering )
2011-03-17 01:47:30 -04:00
iMinFilter = GL_LINEAR_MIPMAP_LINEAR ;
else
iMinFilter = GL_LINEAR_MIPMAP_NEAREST ;
}
else
{
iMinFilter = GL_LINEAR ;
}
}
else
{
iMinFilter = GL_NEAREST ;
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , iMinFilter ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetEffectMode ( EffectMode effect )
2011-03-17 01:47:30 -04:00
{
2011-12-29 16:47:03 -07:00
if ( ! GLEW_ARB_fragment_program | | ! GLEW_ARB_shading_language_100 | | ! GLEW_ARB_shader_objects )
2011-03-17 01:47:30 -04:00
return ;
GLhandleARB hShader = 0 ;
2011-05-02 20:11:26 -05:00
switch ( effect )
2011-03-17 01:47:30 -04:00
{
case EffectMode_Normal : hShader = 0 ; break ;
case EffectMode_Unpremultiply : hShader = g_bUnpremultiplyShader ; break ;
case EffectMode_ColorBurn : hShader = g_bColorBurnShader ; break ;
case EffectMode_ColorDodge : hShader = g_bColorDodgeShader ; break ;
case EffectMode_VividLight : hShader = g_bVividLightShader ; break ;
case EffectMode_HardMix : hShader = g_hHardMixShader ; break ;
case EffectMode_Overlay : hShader = g_hOverlayShader ; break ;
case EffectMode_Screen : hShader = g_hScreenShader ; break ;
case EffectMode_YUYV422 : hShader = g_hYUYV422Shader ; break ;
}
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
glUseProgramObjectARB ( hShader ) ;
if ( hShader = = 0 )
2011-03-17 01:47:30 -04:00
return ;
2011-05-02 20:11:26 -05:00
GLint iTexture1 = glGetUniformLocationARB ( hShader , " Texture1 " ) ;
GLint iTexture2 = glGetUniformLocationARB ( hShader , " Texture2 " ) ;
glUniform1iARB ( iTexture1 , 0 ) ;
glUniform1iARB ( iTexture2 , 1 ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
if ( effect = = EffectMode_YUYV422 )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
GLint iTextureWidthUniform = glGetUniformLocationARB ( hShader , " TextureWidth " ) ;
2011-03-17 01:47:30 -04:00
GLint iWidth ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & iWidth ) ;
2011-05-02 20:11:26 -05:00
glUniform1iARB ( iTextureWidthUniform , iWidth ) ;
2011-03-17 01:47:30 -04:00
}
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : IsEffectModeSupported ( EffectMode effect )
2011-03-17 01:47:30 -04:00
{
switch ( effect )
{
case EffectMode_Normal : return true ;
case EffectMode_Unpremultiply : return g_bUnpremultiplyShader ! = 0 ;
case EffectMode_ColorBurn : return g_bColorBurnShader ! = 0 ;
case EffectMode_ColorDodge : return g_bColorDodgeShader ! = 0 ;
case EffectMode_VividLight : return g_bVividLightShader ! = 0 ;
case EffectMode_HardMix : return g_hHardMixShader ! = 0 ;
case EffectMode_Overlay : return g_hOverlayShader ! = 0 ;
case EffectMode_Screen : return g_hScreenShader ! = 0 ;
case EffectMode_YUYV422 : return g_hYUYV422Shader ! = 0 ;
}
return false ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetBlendMode ( BlendMode mode )
2011-03-17 01:47:30 -04:00
{
glEnable ( GL_BLEND ) ;
2011-05-02 20:11:26 -05:00
if ( glBlendEquation ! = NULL )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( mode = = BLEND_INVERT_DEST )
glBlendEquation ( GL_FUNC_SUBTRACT ) ;
else if ( mode = = BLEND_SUBTRACT )
glBlendEquation ( GL_FUNC_REVERSE_SUBTRACT ) ;
2011-03-17 01:47:30 -04:00
else
2011-05-02 20:11:26 -05:00
glBlendEquation ( GL_FUNC_ADD ) ;
2011-03-17 01:47:30 -04:00
}
int iSourceRGB , iDestRGB ;
int iSourceAlpha = GL_ONE , iDestAlpha = GL_ONE_MINUS_SRC_ALPHA ;
switch ( mode )
{
case BLEND_NORMAL :
iSourceRGB = GL_SRC_ALPHA ; iDestRGB = GL_ONE_MINUS_SRC_ALPHA ;
break ;
case BLEND_ADD :
iSourceRGB = GL_SRC_ALPHA ; iDestRGB = GL_ONE ;
break ;
case BLEND_SUBTRACT :
iSourceRGB = GL_SRC_ALPHA ; iDestRGB = GL_ONE_MINUS_SRC_ALPHA ;
break ;
case BLEND_MODULATE :
iSourceRGB = GL_ZERO ; iDestRGB = GL_SRC_COLOR ;
break ;
case BLEND_COPY_SRC :
iSourceRGB = GL_ONE ; iDestRGB = GL_ZERO ;
iSourceAlpha = GL_ONE ; iDestAlpha = GL_ZERO ;
break ;
case BLEND_ALPHA_MASK :
iSourceRGB = GL_ZERO ; iDestRGB = GL_ONE ;
iSourceAlpha = GL_ZERO ; iDestAlpha = GL_SRC_ALPHA ;
break ;
case BLEND_ALPHA_KNOCK_OUT :
iSourceRGB = GL_ZERO ; iDestRGB = GL_ONE ;
iSourceAlpha = GL_ZERO ; iDestAlpha = GL_ONE_MINUS_SRC_ALPHA ;
break ;
case BLEND_ALPHA_MULTIPLY :
iSourceRGB = GL_SRC_ALPHA ; iDestRGB = GL_ZERO ;
break ;
case BLEND_WEIGHTED_MULTIPLY :
/* output = 2*(dst*src). 0.5,0.5,0.5 is identity; darker colors darken the image,
* and brighter colors lighten the image. */
iSourceRGB = GL_DST_COLOR ; iDestRGB = GL_SRC_COLOR ;
break ;
case BLEND_INVERT_DEST :
/* out = src - dst. The source color should almost always be #FFFFFF, to make it "1 - dst". */
iSourceRGB = GL_ONE ; iDestRGB = GL_ONE ;
break ;
case BLEND_NO_EFFECT :
iSourceRGB = GL_ZERO ; iDestRGB = GL_ONE ;
2012-07-31 23:26:50 -04:00
iSourceAlpha = GL_ZERO ; iDestAlpha = GL_ONE ;
2011-03-17 01:47:30 -04:00
break ;
DEFAULT_FAIL ( mode ) ;
}
2011-05-02 20:11:26 -05:00
if ( GLEW_EXT_blend_equation_separate )
glBlendFuncSeparateEXT ( iSourceRGB , iDestRGB , iSourceAlpha , iDestAlpha ) ;
2011-03-17 01:47:30 -04:00
else
glBlendFunc ( iSourceRGB , iDestRGB ) ;
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : IsZWriteEnabled ( ) const
2011-03-17 01:47:30 -04:00
{
bool a ;
glGetBooleanv ( GL_DEPTH_WRITEMASK , ( unsigned char * ) & a ) ;
return a ;
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : IsZTestEnabled ( ) const
2011-03-17 01:47:30 -04:00
{
GLenum a ;
glGetIntegerv ( GL_DEPTH_FUNC , ( GLint * ) & a ) ;
return a ! = GL_ALWAYS ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : ClearZBuffer ( )
2011-03-17 01:47:30 -04:00
{
bool write = IsZWriteEnabled ( ) ;
SetZWrite ( true ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
SetZWrite ( write ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetZWrite ( bool b )
2011-03-17 01:47:30 -04:00
{
glDepthMask ( b ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetZBias ( float f )
2011-03-17 01:47:30 -04:00
{
float fNear = SCALE ( f , 0.0f , 1.0f , 0.05f , 0.0f ) ;
float fFar = SCALE ( f , 0.0f , 1.0f , 1.0f , 0.95f ) ;
glDepthRange ( fNear , fFar ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetZTestMode ( ZTestMode mode )
2011-03-17 01:47:30 -04:00
{
glEnable ( GL_DEPTH_TEST ) ;
switch ( mode )
{
case ZTEST_OFF : glDepthFunc ( GL_ALWAYS ) ; break ;
case ZTEST_WRITE_ON_PASS : glDepthFunc ( GL_LEQUAL ) ; break ;
case ZTEST_WRITE_ON_FAIL : glDepthFunc ( GL_GREATER ) ; break ;
2012-12-27 16:59:35 -05:00
default :
FAIL_M ( ssprintf ( " Invalid ZTestMode: %i " , mode ) ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetTextureWrapping ( TextureUnit tu , bool b )
2011-03-17 01:47:30 -04:00
{
/* This should be per-texture-unit state, but it's per-texture state in OpenGl,
* so we'll behave incorrectly if the same texture is used in more than one texture
* unit simultaneously with different wrapping. */
SetTextureUnit ( tu ) ;
GLenum mode = b ? GL_REPEAT : GL_CLAMP_TO_EDGE ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , mode ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , mode ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetMaterial (
2011-03-17 01:47:30 -04:00
const RageColor & emissive ,
const RageColor & ambient ,
const RageColor & diffuse ,
const RageColor & specular ,
float shininess
)
{
// TRICKY: If lighting is off, then setting the material
// will have no effect. Even if lighting is off, we still
// want Models to have basic color and transparency.
// We can do this fake lighting by setting the vertex color.
// XXX: unintended: SetLighting must be called before SetMaterial
GLboolean bLighting ;
glGetBooleanv ( GL_LIGHTING , & bLighting ) ;
2011-05-02 20:11:26 -05:00
if ( bLighting )
2011-03-17 01:47:30 -04:00
{
glMaterialfv ( GL_FRONT , GL_EMISSION , emissive ) ;
glMaterialfv ( GL_FRONT , GL_AMBIENT , ambient ) ;
glMaterialfv ( GL_FRONT , GL_DIFFUSE , diffuse ) ;
glMaterialfv ( GL_FRONT , GL_SPECULAR , specular ) ;
glMaterialf ( GL_FRONT , GL_SHININESS , shininess ) ;
}
else
{
RageColor c = diffuse ;
c . r + = emissive . r + ambient . r ;
c . g + = emissive . g + ambient . g ;
c . b + = emissive . b + ambient . b ;
glColor4fv ( c ) ;
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetLighting ( bool b )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( b )
glEnable ( GL_LIGHTING ) ;
else
glDisable ( GL_LIGHTING ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetLightOff ( int index )
2011-03-17 01:47:30 -04:00
{
glDisable ( GL_LIGHT0 + index ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetLightDirectional (
2011-03-17 01:47:30 -04:00
int index ,
const RageColor & ambient ,
const RageColor & diffuse ,
const RageColor & specular ,
const RageVector3 & dir )
{
// Light coordinates are transformed by the modelview matrix, but
// we are being passed in world-space coords.
glPushMatrix ( ) ;
glLoadIdentity ( ) ;
glEnable ( GL_LIGHT0 + index ) ;
glLightfv ( GL_LIGHT0 + index , GL_AMBIENT , ambient ) ;
glLightfv ( GL_LIGHT0 + index , GL_DIFFUSE , diffuse ) ;
glLightfv ( GL_LIGHT0 + index , GL_SPECULAR , specular ) ;
float position [ 4 ] = { dir . x , dir . y , dir . z , 0 } ;
glLightfv ( GL_LIGHT0 + index , GL_POSITION , position ) ;
glPopMatrix ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetCullMode ( CullMode mode )
2011-03-17 01:47:30 -04:00
{
if ( mode ! = CULL_NONE )
glEnable ( GL_CULL_FACE ) ;
switch ( mode )
{
case CULL_BACK :
glCullFace ( GL_BACK ) ;
break ;
case CULL_FRONT :
glCullFace ( GL_FRONT ) ;
break ;
case CULL_NONE :
glDisable ( GL_CULL_FACE ) ;
break ;
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( " Invalid CullMode: %i " , mode ) ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
const RageDisplay : : PixelFormatDesc * RageDisplay_Legacy : : GetPixelFormatDesc ( PixelFormat pf ) const
2011-03-17 01:47:30 -04:00
{
ASSERT ( pf < NUM_PixelFormat ) ;
return & PIXEL_FORMAT_DESC [ pf ] ;
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : SupportsThreadedRendering ( )
2011-03-17 01:47:30 -04:00
{
return g_pWind - > SupportsThreadedRendering ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : BeginConcurrentRenderingMainThread ( )
2011-03-17 01:47:30 -04:00
{
g_pWind - > BeginConcurrentRenderingMainThread ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : EndConcurrentRenderingMainThread ( )
2011-03-17 01:47:30 -04:00
{
g_pWind - > EndConcurrentRenderingMainThread ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : BeginConcurrentRendering ( )
2011-03-17 01:47:30 -04:00
{
g_pWind - > BeginConcurrentRendering ( ) ;
RageDisplay : : BeginConcurrentRendering ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : EndConcurrentRendering ( )
2011-03-17 01:47:30 -04:00
{
g_pWind - > EndConcurrentRendering ( ) ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : DeleteTexture ( unsigned iTexture )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( iTexture = = 0 )
2011-03-17 01:47:30 -04:00
return ;
2011-05-02 20:11:26 -05:00
if ( g_mapRenderTargets . find ( iTexture ) ! = g_mapRenderTargets . end ( ) )
2011-03-17 01:47:30 -04:00
{
delete g_mapRenderTargets [ iTexture ] ;
g_mapRenderTargets . erase ( iTexture ) ;
return ;
}
DebugFlushGLErrors ( ) ;
glDeleteTextures ( 1 , reinterpret_cast < GLuint * > ( & iTexture ) ) ;
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
PixelFormat RageDisplay_Legacy : : GetImgPixelFormat ( RageSurface * & img , bool & bFreeImg , int width , int height , bool bPalettedTexture )
2011-03-17 01:47:30 -04:00
{
PixelFormat pixfmt = FindPixelFormat ( img - > format - > BitsPerPixel , img - > format - > Rmask , img - > format - > Gmask , img - > format - > Bmask , img - > format - > Amask ) ;
/* If img is paletted, we're setting up a non-paletted texture, and color indexes
* are too small, depalettize. */
bool bSupported = true ;
2011-05-02 20:11:26 -05:00
if ( ! bPalettedTexture & & img - > fmt . BytesPerPixel = = 1 & & ! g_bColorIndexTableWorks )
2011-03-17 01:47:30 -04:00
bSupported = false ;
2011-05-02 20:11:26 -05:00
if ( pixfmt = = PixelFormat_Invalid | | ! SupportsSurfaceFormat ( pixfmt ) )
2011-03-17 01:47:30 -04:00
bSupported = false ;
2011-05-02 20:11:26 -05:00
if ( ! bSupported )
2011-03-17 01:47:30 -04:00
{
/* 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 = PixelFormat_RGBA8 ;
ASSERT ( SupportsSurfaceFormat ( pixfmt ) ) ;
const PixelFormatDesc * pfd = DISPLAY - > GetPixelFormatDesc ( pixfmt ) ;
RageSurface * imgconv = CreateSurface ( img - > w , img - > h ,
pfd - > bpp , pfd - > masks [ 0 ] , pfd - > masks [ 1 ] , pfd - > masks [ 2 ] , pfd - > masks [ 3 ] ) ;
RageSurfaceUtils : : Blit ( img , imgconv , width , height ) ;
img = imgconv ;
bFreeImg = true ;
}
else
{
bFreeImg = false ;
}
return pixfmt ;
}
/* If we're sending a paletted surface to a non-paletted texture, set the palette. */
void SetPixelMapForSurface ( int glImageFormat , int glTexFormat , const RageSurfacePalette * palette )
{
2011-05-02 20:11:26 -05:00
if ( glImageFormat ! = GL_COLOR_INDEX | | glTexFormat = = GL_COLOR_INDEX8_EXT )
2011-03-17 01:47:30 -04:00
{
glPixelTransferi ( GL_MAP_COLOR , false ) ;
return ;
}
GLushort buf [ 4 ] [ 256 ] ;
memset ( buf , 0 , sizeof ( buf ) ) ;
for ( int i = 0 ; i < palette - > ncolors ; + + i )
{
buf [ 0 ] [ i ] = SCALE ( palette - > colors [ i ] . r , 0 , 255 , 0 , 65535 ) ;
buf [ 1 ] [ i ] = SCALE ( palette - > colors [ i ] . g , 0 , 255 , 0 , 65535 ) ;
buf [ 2 ] [ i ] = SCALE ( palette - > colors [ i ] . b , 0 , 255 , 0 , 65535 ) ;
buf [ 3 ] [ i ] = SCALE ( palette - > colors [ i ] . a , 0 , 255 , 0 , 65535 ) ;
}
DebugFlushGLErrors ( ) ;
glPixelMapusv ( GL_PIXEL_MAP_I_TO_R , 256 , buf [ 0 ] ) ;
glPixelMapusv ( GL_PIXEL_MAP_I_TO_G , 256 , buf [ 1 ] ) ;
glPixelMapusv ( GL_PIXEL_MAP_I_TO_B , 256 , buf [ 2 ] ) ;
glPixelMapusv ( GL_PIXEL_MAP_I_TO_A , 256 , buf [ 3 ] ) ;
glPixelTransferi ( GL_MAP_COLOR , true ) ;
DebugAssertNoGLError ( ) ;
}
2011-05-02 20:11:26 -05:00
unsigned RageDisplay_Legacy : : CreateTexture (
2011-03-17 01:47:30 -04:00
PixelFormat pixfmt ,
RageSurface * pImg ,
bool bGenerateMipMaps )
{
ASSERT ( pixfmt < NUM_PixelFormat ) ;
/* Find the pixel format of the surface we've been given. */
bool bFreeImg ;
PixelFormat SurfacePixFmt = GetImgPixelFormat ( pImg , bFreeImg , pImg - > w , pImg - > h , pixfmt = = PixelFormat_PAL ) ;
ASSERT ( SurfacePixFmt ! = PixelFormat_Invalid ) ;
GLenum glTexFormat = g_GLPixFmtInfo [ pixfmt ] . internalfmt ;
GLenum glImageFormat = g_GLPixFmtInfo [ SurfacePixFmt ] . format ;
GLenum glImageType = g_GLPixFmtInfo [ SurfacePixFmt ] . type ;
/* If the image is paletted, but we're not sending it to a paletted image,
* set up glPixelMap. */
SetPixelMapForSurface ( glImageFormat , glTexFormat , pImg - > format - > palette ) ;
// HACK: OpenGL 1.2 types aren't available in GLU 1.3. Don't call GLU for mip
// mapping if we're using an OGL 1.2 type and don't have >= GLU 1.3.
// http://pyopengl.sourceforge.net/documentation/manual/gluBuild2DMipmaps.3G.html
2011-05-02 20:11:26 -05:00
if ( bGenerateMipMaps & & g_gluVersion < 13 )
2011-03-17 01:47:30 -04:00
{
switch ( pixfmt )
{
// OpenGL 1.1 types
case PixelFormat_RGBA8 :
case PixelFormat_RGB8 :
case PixelFormat_PAL :
case PixelFormat_BGR8 :
break ;
// OpenGL 1.2 types
default :
LOG - > Trace ( " Can't generate mipmaps for type %s because GLU version %.1f is too old. " , GLToString ( glImageType ) . c_str ( ) , g_gluVersion / 10.f ) ;
bGenerateMipMaps = false ;
break ;
}
}
SetTextureUnit ( TextureUnit_1 ) ;
// allocate OpenGL texture resource
unsigned int iTexHandle ;
glGenTextures ( 1 , reinterpret_cast < GLuint * > ( & iTexHandle ) ) ;
2012-12-27 12:45:04 -05:00
ASSERT ( iTexHandle ! = 0 ) ;
2011-03-17 01:47:30 -04:00
glBindTexture ( GL_TEXTURE_2D , iTexHandle ) ;
2011-05-02 20:11:26 -05:00
if ( g_pWind - > GetActualVideoModeParams ( ) . bAnisotropicFiltering & &
GLEW_EXT_texture_filter_anisotropic )
2011-03-17 01:47:30 -04:00
{
GLfloat fLargestSupportedAnisotropy ;
glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & fLargestSupportedAnisotropy ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , fLargestSupportedAnisotropy ) ;
}
SetTextureFiltering ( TextureUnit_1 , true ) ;
SetTextureWrapping ( TextureUnit_1 , false ) ;
glPixelStorei ( GL_UNPACK_ROW_LENGTH , pImg - > pitch / pImg - > format - > BytesPerPixel ) ;
2011-05-02 20:11:26 -05:00
if ( pixfmt = = PixelFormat_PAL )
2011-03-17 01:47:30 -04:00
{
/* The texture is paletted; set the texture palette. */
GLubyte palette [ 256 * 4 ] ;
memset ( palette , 0 , sizeof ( palette ) ) ;
int p = 0 ;
/* Copy the palette to the format OpenGL expects. */
for ( int i = 0 ; i < pImg - > format - > palette - > ncolors ; + + i )
{
palette [ p + + ] = pImg - > format - > palette - > colors [ i ] . r ;
palette [ p + + ] = pImg - > format - > palette - > colors [ i ] . g ;
palette [ p + + ] = pImg - > format - > palette - > colors [ i ] . b ;
palette [ p + + ] = pImg - > format - > palette - > colors [ i ] . a ;
}
/* Set the palette. */
2011-05-02 20:11:26 -05:00
glColorTableEXT ( GL_TEXTURE_2D , GL_RGBA8 , 256 , GL_RGBA , GL_UNSIGNED_BYTE , palette ) ;
2011-03-17 01:47:30 -04:00
GLint iRealFormat = 0 ;
2011-05-02 20:11:26 -05:00
glGetColorTableParameterivEXT ( GL_TEXTURE_2D , GL_COLOR_TABLE_FORMAT , & iRealFormat ) ;
2011-03-17 01:47:30 -04:00
ASSERT ( iRealFormat = = GL_RGBA8 ) ;
}
LOG - > Trace ( " %s (format %s, %ix%i, format %s, type %s, pixfmt %i, imgpixfmt %i) " ,
bGenerateMipMaps ? " gluBuild2DMipmaps " : " glTexImage2D " ,
GLToString ( glTexFormat ) . c_str ( ) ,
pImg - > w , pImg - > h ,
GLToString ( glImageFormat ) . c_str ( ) ,
GLToString ( glImageType ) . c_str ( ) , pixfmt , SurfacePixFmt ) ;
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
if ( bGenerateMipMaps )
2011-03-17 01:47:30 -04:00
{
GLenum error = gluBuild2DMipmaps (
GL_TEXTURE_2D , glTexFormat ,
pImg - > w , pImg - > h ,
glImageFormat , glImageType , pImg - > pixels ) ;
ASSERT_M ( error = = 0 , ( char * ) gluErrorString ( error ) ) ;
}
else
{
glTexImage2D (
GL_TEXTURE_2D , 0 , glTexFormat ,
power_of_two ( pImg - > w ) , power_of_two ( pImg - > h ) , 0 ,
glImageFormat , glImageType , NULL ) ;
2011-05-02 20:11:26 -05:00
if ( pImg - > pixels )
2011-03-17 01:47:30 -04:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 ,
0 , 0 ,
pImg - > w , pImg - > h ,
glImageFormat , glImageType , pImg - > pixels ) ;
DebugAssertNoGLError ( ) ;
}
/* Sanity check: */
2011-05-02 20:11:26 -05:00
if ( pixfmt = = PixelFormat_PAL )
2011-03-17 01:47:30 -04:00
{
GLint iSize = 0 ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INDEX_SIZE_EXT ) , & iSize ) ;
2011-05-02 20:11:26 -05:00
if ( iSize ! = 8 )
2011-03-17 01:47:30 -04:00
RageException : : Throw ( " Thought paletted textures worked, but they don't. " ) ;
}
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ;
glFlush ( ) ;
2011-05-02 20:11:26 -05:00
if ( bFreeImg )
2011-03-17 01:47:30 -04:00
delete pImg ;
return iTexHandle ;
}
struct RageTextureLock_OGL : public RageTextureLock , public InvalidateObject
{
public :
RageTextureLock_OGL ( )
{
m_iTexHandle = 0 ;
m_iBuffer = 0 ;
CreateObject ( ) ;
}
~ RageTextureLock_OGL ( )
{
ASSERT ( m_iTexHandle = = 0 ) ; // locked!
2011-05-02 20:11:26 -05:00
glDeleteBuffersARB ( 1 , & m_iBuffer ) ;
2011-03-17 01:47:30 -04:00
}
/* This is called when our OpenGL context is invalidated. */
void Invalidate ( )
{
m_iTexHandle = 0 ;
}
void Lock ( unsigned iTexHandle , RageSurface * pSurface )
{
ASSERT ( m_iTexHandle = = 0 ) ;
ASSERT ( pSurface - > pixels = = NULL ) ;
CreateObject ( ) ;
m_iTexHandle = iTexHandle ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_PIXEL_UNPACK_BUFFER_ARB , m_iBuffer ) ;
2011-03-17 01:47:30 -04:00
int iSize = pSurface - > h * pSurface - > pitch ;
2011-05-02 20:11:26 -05:00
glBufferDataARB ( GL_PIXEL_UNPACK_BUFFER_ARB , iSize , NULL , GL_STREAM_DRAW ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
void * pSurfaceMemory = glMapBufferARB ( GL_PIXEL_UNPACK_BUFFER_ARB , GL_WRITE_ONLY ) ;
2011-03-17 01:47:30 -04:00
pSurface - > pixels = ( uint8_t * ) pSurfaceMemory ;
pSurface - > pixels_owned = false ;
}
void Unlock ( RageSurface * pSurface , bool bChanged )
{
2011-05-02 20:11:26 -05:00
glUnmapBufferARB ( GL_PIXEL_UNPACK_BUFFER_ARB ) ;
2011-03-17 01:47:30 -04:00
pSurface - > pixels = ( uint8_t * ) BUFFER_OFFSET ( 0 ) ;
2011-05-02 20:11:26 -05:00
if ( bChanged )
2011-03-17 01:47:30 -04:00
DISPLAY - > UpdateTexture ( m_iTexHandle , pSurface , 0 , 0 , pSurface - > w , pSurface - > h ) ;
pSurface - > pixels = NULL ;
m_iTexHandle = 0 ;
2011-05-02 20:11:26 -05:00
glBindBufferARB ( GL_PIXEL_UNPACK_BUFFER_ARB , 0 ) ;
2011-03-17 01:47:30 -04:00
}
private :
void CreateObject ( )
{
2011-05-02 20:11:26 -05:00
if ( m_iBuffer ! = 0 )
2011-03-17 01:47:30 -04:00
return ;
DebugFlushGLErrors ( ) ;
2011-05-02 20:11:26 -05:00
glGenBuffersARB ( 1 , & m_iBuffer ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
}
GLuint m_iBuffer ;
unsigned m_iTexHandle ;
} ;
2011-05-02 20:11:26 -05:00
RageTextureLock * RageDisplay_Legacy : : CreateTextureLock ( )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! GLEW_ARB_pixel_buffer_object )
2011-03-17 01:47:30 -04:00
return NULL ;
return new RageTextureLock_OGL ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : UpdateTexture (
2011-03-17 01:47:30 -04:00
unsigned iTexHandle ,
RageSurface * pImg ,
int iXOffset , int iYOffset , int iWidth , int iHeight )
{
glBindTexture ( GL_TEXTURE_2D , iTexHandle ) ;
bool bFreeImg ;
PixelFormat SurfacePixFmt = GetImgPixelFormat ( pImg , bFreeImg , iWidth , iHeight , false ) ;
glPixelStorei ( GL_UNPACK_ROW_LENGTH , pImg - > pitch / pImg - > format - > BytesPerPixel ) ;
GLenum glImageFormat = g_GLPixFmtInfo [ SurfacePixFmt ] . format ;
GLenum glImageType = g_GLPixFmtInfo [ SurfacePixFmt ] . type ;
/* If the image is paletted, but we're not sending it to a paletted image,
* set up glPixelMap. */
2011-05-02 20:11:26 -05:00
if ( pImg - > format - > palette )
2011-03-17 01:47:30 -04:00
{
GLenum glTexFormat = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INTERNAL_FORMAT ) , ( GLint * ) & glTexFormat ) ;
SetPixelMapForSurface ( glImageFormat , glTexFormat , pImg - > format - > palette ) ;
}
glTexSubImage2D ( GL_TEXTURE_2D , 0 ,
iXOffset , iYOffset ,
iWidth , iHeight ,
glImageFormat , glImageType , pImg - > pixels ) ;
/* Must unset PixelStore when we're done! */
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ;
glFlush ( ) ;
2011-05-02 20:11:26 -05:00
if ( bFreeImg )
2011-03-17 01:47:30 -04:00
delete pImg ;
}
class RenderTarget_FramebufferObject : public RenderTarget
{
public :
RenderTarget_FramebufferObject ( ) ;
~ RenderTarget_FramebufferObject ( ) ;
void Create ( const RenderTargetParam & param , int & iTextureWidthOut , int & iTextureHeightOut ) ;
unsigned GetTexture ( ) const { return m_iTexHandle ; }
void StartRenderingTo ( ) ;
void FinishRenderingTo ( ) ;
virtual bool InvertY ( ) const { return true ; }
private :
unsigned int m_iFrameBufferHandle ;
unsigned int m_iTexHandle ;
unsigned int m_iDepthBufferHandle ;
} ;
RenderTarget_FramebufferObject : : RenderTarget_FramebufferObject ( )
{
m_iFrameBufferHandle = 0 ;
m_iTexHandle = 0 ;
m_iDepthBufferHandle = 0 ;
}
RenderTarget_FramebufferObject : : ~ RenderTarget_FramebufferObject ( )
{
2011-05-02 20:11:26 -05:00
if ( m_iDepthBufferHandle )
glDeleteRenderbuffersEXT ( 1 , reinterpret_cast < GLuint * > ( & m_iDepthBufferHandle ) ) ;
if ( m_iFrameBufferHandle )
glDeleteFramebuffersEXT ( 1 , reinterpret_cast < GLuint * > ( & m_iFrameBufferHandle ) ) ;
if ( m_iTexHandle )
2011-03-17 01:47:30 -04:00
glDeleteTextures ( 1 , reinterpret_cast < GLuint * > ( & m_iTexHandle ) ) ;
}
void RenderTarget_FramebufferObject : : Create ( const RenderTargetParam & param , int & iTextureWidthOut , int & iTextureHeightOut )
{
m_Param = param ;
DebugFlushGLErrors ( ) ;
// Allocate OpenGL texture resource
glGenTextures ( 1 , reinterpret_cast < GLuint * > ( & m_iTexHandle ) ) ;
2012-12-27 12:45:04 -05:00
ASSERT ( m_iTexHandle ! = 0 ) ;
2011-03-17 01:47:30 -04:00
int iTextureWidth = power_of_two ( param . iWidth ) ;
int iTextureHeight = power_of_two ( param . iHeight ) ;
iTextureWidthOut = iTextureWidth ;
iTextureHeightOut = iTextureHeight ;
glBindTexture ( GL_TEXTURE_2D , m_iTexHandle ) ;
GLenum internalformat ;
GLenum type = param . bWithAlpha ? GL_RGBA : GL_RGB ;
2011-05-02 20:11:26 -05:00
if ( param . bFloat & & GLEW_ARB_texture_float )
2011-03-17 01:47:30 -04:00
internalformat = param . bWithAlpha ? GL_RGBA16F_ARB : GL_RGB16F_ARB ;
else
internalformat = param . bWithAlpha ? GL_RGBA8 : GL_RGB8 ;
glTexImage2D ( GL_TEXTURE_2D , 0 , internalformat ,
iTextureWidth , iTextureHeight , 0 , type , GL_UNSIGNED_BYTE , NULL ) ;
DebugAssertNoGLError ( ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
/* Create the framebuffer object. */
2011-05-02 20:11:26 -05:00
glGenFramebuffersEXT ( 1 , reinterpret_cast < GLuint * > ( & m_iFrameBufferHandle ) ) ;
2012-12-27 12:45:04 -05:00
ASSERT ( m_iFrameBufferHandle ! = 0 ) ;
2011-03-17 01:47:30 -04:00
/* Attach the texture to it. */
2011-05-02 20:11:26 -05:00
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , m_iFrameBufferHandle ) ;
glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_2D , m_iTexHandle , 0 ) ;
2011-03-17 01:47:30 -04:00
DebugAssertNoGLError ( ) ;
/* Attach a depth buffer, if requested. */
2011-05-02 20:11:26 -05:00
if ( param . bWithDepthBuffer )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glGenRenderbuffersEXT ( 1 , reinterpret_cast < GLuint * > ( & m_iDepthBufferHandle ) ) ;
2012-12-27 12:45:04 -05:00
ASSERT ( m_iDepthBufferHandle ! = 0 ) ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
glRenderbufferStorageEXT ( GL_RENDERBUFFER_EXT , GL_DEPTH_COMPONENT16 , iTextureWidth , iTextureHeight ) ;
glFramebufferRenderbufferEXT ( GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT , GL_RENDERBUFFER_EXT , m_iDepthBufferHandle ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
GLenum status = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) ;
2011-03-17 01:47:30 -04:00
switch ( status )
{
case GL_FRAMEBUFFER_COMPLETE_EXT :
break ;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT :
FAIL_M ( " GL_FRAMEBUFFER_UNSUPPORTED_EXT " ) ;
break ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT : FAIL_M ( " GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT " ) ; break ;
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( " Unexpected GL framebuffer status: %i " , status ) ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ;
2011-03-17 01:47:30 -04:00
}
void RenderTarget_FramebufferObject : : StartRenderingTo ( )
{
2011-05-02 20:11:26 -05:00
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , m_iFrameBufferHandle ) ;
2011-03-17 01:47:30 -04:00
}
void RenderTarget_FramebufferObject : : FinishRenderingTo ( )
{
2011-05-02 20:11:26 -05:00
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : SupportsRenderToTexture ( ) const
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
return GLEW_EXT_framebuffer_object | | g_pWind - > SupportsRenderToTexture ( ) ;
2011-03-17 01:47:30 -04:00
}
/*
* Render-to-texture can be implemented in several ways: the generic GL_ARB_pixel_buffer_object,
* or platform-specifically. PBO is not available on all hardware that supports RTT,
* particularly GeForce 2, but is simpler and faster when available.
*/
2011-05-02 20:11:26 -05:00
unsigned RageDisplay_Legacy : : CreateRenderTarget ( const RenderTargetParam & param , int & iTextureWidthOut , int & iTextureHeightOut )
2011-03-17 01:47:30 -04:00
{
RenderTarget * pTarget ;
2011-05-02 20:11:26 -05:00
if ( GLEW_EXT_framebuffer_object )
2011-03-17 01:47:30 -04:00
pTarget = new RenderTarget_FramebufferObject ;
else
pTarget = g_pWind - > CreateRenderTarget ( ) ;
pTarget - > Create ( param , iTextureWidthOut , iTextureHeightOut ) ;
unsigned iTexture = pTarget - > GetTexture ( ) ;
ASSERT ( g_mapRenderTargets . find ( iTexture ) = = g_mapRenderTargets . end ( ) ) ;
g_mapRenderTargets [ iTexture ] = pTarget ;
return iTexture ;
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetRenderTarget ( unsigned iTexture , bool bPreserveTexture )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( iTexture = = 0 )
2011-03-17 01:47:30 -04:00
{
g_bInvertY = false ;
glFrontFace ( GL_CCW ) ;
/* Pop matrixes affected by SetDefaultRenderStates. */
DISPLAY - > CameraPopMatrix ( ) ;
/* Reset the viewport. */
int fWidth = g_pWind - > GetActualVideoModeParams ( ) . width ;
int fHeight = g_pWind - > GetActualVideoModeParams ( ) . height ;
glViewport ( 0 , 0 , fWidth , fHeight ) ;
2011-05-02 20:11:26 -05:00
if ( g_pCurrentRenderTarget )
2011-03-17 01:47:30 -04:00
g_pCurrentRenderTarget - > FinishRenderingTo ( ) ;
g_pCurrentRenderTarget = NULL ;
return ;
}
/* If we already had a render target, disable it. */
2011-05-02 20:11:26 -05:00
if ( g_pCurrentRenderTarget ! = NULL )
SetRenderTarget ( 0 , true ) ;
2011-03-17 01:47:30 -04:00
/* Enable the new render target. */
2011-05-02 20:11:26 -05:00
ASSERT ( g_mapRenderTargets . find ( iTexture ) ! = g_mapRenderTargets . end ( ) ) ;
2011-03-17 01:47:30 -04:00
RenderTarget * pTarget = g_mapRenderTargets [ iTexture ] ;
pTarget - > StartRenderingTo ( ) ;
g_pCurrentRenderTarget = pTarget ;
/* Set the viewport to the size of the render target. */
2011-05-02 20:11:26 -05:00
glViewport ( 0 , 0 , pTarget - > GetParam ( ) . iWidth , pTarget - > GetParam ( ) . iHeight ) ;
2011-03-17 01:47:30 -04:00
/* If this render target implementation flips Y, compensate. Inverting will
* switch the winding order. */
g_bInvertY = pTarget - > InvertY ( ) ;
2011-05-02 20:11:26 -05:00
if ( g_bInvertY )
glFrontFace ( GL_CW ) ;
2011-03-17 01:47:30 -04:00
/* The render target may be in a different OpenGL context, so re-send
* state. Push matrixes affected by SetDefaultRenderStates. */
DISPLAY - > CameraPushMatrix ( ) ;
SetDefaultRenderStates ( ) ;
/* Clear the texture, if requested. Always set the associated state, for
* consistency. */
2011-05-02 20:11:26 -05:00
glClearColor ( 0 , 0 , 0 , 0 ) ;
SetZWrite ( true ) ;
2011-03-17 01:47:30 -04:00
/* If bPreserveTexture is false, clear the render target. Only clear the depth
* buffer if the target has one; otherwise we're clearing the real depth buffer. */
2011-05-02 20:11:26 -05:00
if ( ! bPreserveTexture )
2011-03-17 01:47:30 -04:00
{
int iBit = GL_COLOR_BUFFER_BIT ;
2011-05-02 20:11:26 -05:00
if ( pTarget - > GetParam ( ) . bWithDepthBuffer )
2011-03-17 01:47:30 -04:00
iBit | = GL_DEPTH_BUFFER_BIT ;
2011-05-02 20:11:26 -05:00
glClear ( iBit ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetPolygonMode ( PolygonMode pm )
2011-03-17 01:47:30 -04:00
{
GLenum m ;
2011-05-02 20:11:26 -05:00
switch ( pm )
2011-03-17 01:47:30 -04:00
{
case POLYGON_FILL : m = GL_FILL ; break ;
case POLYGON_LINE : m = GL_LINE ; break ;
2012-12-27 16:59:35 -05:00
default :
FAIL_M ( ssprintf ( " Invalid PolygonMode: %i " , pm ) ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
glPolygonMode ( GL_FRONT_AND_BACK , m ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetLineWidth ( float fWidth )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glLineWidth ( fWidth ) ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
RString RageDisplay_Legacy : : GetTextureDiagnostics ( unsigned iTexture ) const
2011-03-17 01:47:30 -04:00
{
/*
s << (bGenerateMipMaps? "gluBuild2DMipmaps":"glTexImage2D");
s << "(format " << GLToString(glTexFormat) <<
", " << pImg->w << "x" << pImg->h <<
", format " << GLToString(iFormat) <<
", type " << GLToString(glImageType) <<
", pixfmt " << pixfmt <<
", imgpixfmt " << SurfacePixFmt <<
")";
LOG->Trace( "%s", s.str().c_str() );
glBindTexture( GL_TEXTURE_2D, iTexture );
GLint iWidth;
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GLenum(GL_TEXTURE_WIDTH), (GLint *) &iWidth );
GLint iHeight;
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GLenum(GL_TEXTURE_HEIGHT), (GLint *) &iHeight );
GLint iFormat;
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GLenum(GL_TEXTURE_INTERNAL_FORMAT), (GLint *) &iFormat );
GL_CHECK_ERROR( "glGetTexLevelParameteriv(GL_TEXTURE_INTERNAL_FORMAT)" );
2011-05-02 20:11:26 -05:00
if (iFormat != glTexFormat)
2011-03-17 01:47:30 -04:00
{
sError = ssprintf( "Expected format %s, got %s instead",
GLToString(glTexFormat).c_str(), GLToString(iFormat).c_str() );
break;
}
*/
return RString ( ) ;
}
2011-05-02 20:11:26 -05:00
/*
* XXX: Things like this only have to be set once per context - making
* SetDefault call These kinds of functions is wasteful. -Colby
*/
void RageDisplay_Legacy : : SetAlphaTest ( bool b )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
// Previously this was 0.01, rather than 0x01.
glAlphaFunc ( GL_GREATER , 0.00390625 /* 1/256 */ ) ;
if ( b )
glEnable ( GL_ALPHA_TEST ) ;
2011-03-17 01:47:30 -04:00
else
2011-05-02 20:11:26 -05:00
glDisable ( GL_ALPHA_TEST ) ;
2011-03-17 01:47:30 -04:00
}
/*
* Although we pair texture formats (eg. GL_RGB8) and surface formats
* (pairs of eg. GL_RGB8,GL_UNSIGNED_SHORT_5_5_5_1), it's possible for
* a format to be supported for a texture format but not a surface
* format. This is abstracted, so you don't need to know about this
* as a user calling CreateTexture.
*
* One case of this is if packed pixels aren't supported. We can still
* use 16-bit color modes, but we have to send it in 32-bit. Almost
* everything supports packed pixels.
*
* Another case of this is incomplete packed pixels support. Some implementations
* neglect GL_UNSIGNED_SHORT_*_REV.
*/
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : SupportsSurfaceFormat ( PixelFormat pixfmt )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
switch ( g_GLPixFmtInfo [ pixfmt ] . type )
2011-03-17 01:47:30 -04:00
{
case GL_UNSIGNED_SHORT_1_5_5_5_REV :
2011-05-02 20:11:26 -05:00
return GLEW_EXT_bgra & & g_bReversePackedPixelsWorks ;
2011-03-17 01:47:30 -04:00
default :
return true ;
}
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : SupportsTextureFormat ( PixelFormat pixfmt , bool bRealtime )
2011-03-17 01:47:30 -04:00
{
/* If we support a pixfmt for texture formats but not for surface formats, then
* we'll have to convert the texture to a supported surface format before uploading.
* This is too slow for dynamic textures. */
2011-05-02 20:11:26 -05:00
if ( bRealtime & & ! SupportsSurfaceFormat ( pixfmt ) )
2011-03-17 01:47:30 -04:00
return false ;
2011-05-02 20:11:26 -05:00
switch ( g_GLPixFmtInfo [ pixfmt ] . format )
2011-03-17 01:47:30 -04:00
{
case GL_COLOR_INDEX :
2011-05-02 20:11:26 -05:00
return glColorTableEXT & & glGetColorTableParameterivEXT ;
2011-03-17 01:47:30 -04:00
case GL_BGR :
case GL_BGRA :
2012-05-20 21:00:14 -05:00
return ! ! GLEW_EXT_bgra ;
2011-03-17 01:47:30 -04:00
default :
return true ;
}
}
2011-05-02 20:11:26 -05:00
bool RageDisplay_Legacy : : SupportsPerVertexMatrixScale ( )
2011-03-17 01:47:30 -04:00
{
// Intel i915 on OSX 10.4.4 supports vertex programs but not hardware vertex buffers.
// Our software vertex rendering doesn't support vertex programs.
2011-05-02 20:11:26 -05:00
return glGenBuffersARB & & g_bTextureMatrixShader ! = 0 ;
2011-03-17 01:47:30 -04:00
}
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetSphereEnvironmentMapping ( TextureUnit tu , bool b )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! SetTextureUnit ( tu ) )
2011-03-17 01:47:30 -04:00
return ;
2011-05-02 20:11:26 -05:00
if ( b )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
glTexGeni ( GL_S , GL_TEXTURE_GEN_MODE , GL_SPHERE_MAP ) ;
glTexGeni ( GL_T , GL_TEXTURE_GEN_MODE , GL_SPHERE_MAP ) ;
glEnable ( GL_TEXTURE_GEN_S ) ;
glEnable ( GL_TEXTURE_GEN_T ) ;
2011-03-17 01:47:30 -04:00
}
else
{
2011-05-02 20:11:26 -05:00
glDisable ( GL_TEXTURE_GEN_S ) ;
glDisable ( GL_TEXTURE_GEN_T ) ;
2011-03-17 01:47:30 -04:00
}
}
2011-05-02 20:11:26 -05:00
GLint iCelTexture1 , iCelTexture2 = 0 ;
2011-03-17 01:47:30 -04:00
2011-05-02 20:11:26 -05:00
void RageDisplay_Legacy : : SetCelShaded ( int stage )
2011-03-17 01:47:30 -04:00
{
2011-05-02 20:11:26 -05:00
if ( ! GLEW_ARB_fragment_program & & ! GL_ARB_shading_language_100 )
2011-03-17 01:47:30 -04:00
return ; // not supported
2011-05-02 20:11:26 -05:00
switch ( stage )
2011-03-17 01:47:30 -04:00
{
case 1 :
2011-05-02 20:11:26 -05:00
glUseProgramObjectARB ( g_gShellShader ) ;
2011-03-17 01:47:30 -04:00
break ;
case 2 :
2011-05-02 20:11:26 -05:00
glUseProgramObjectARB ( g_gCelShader ) ;
2011-03-17 01:47:30 -04:00
break ;
default :
2011-05-02 20:11:26 -05:00
glUseProgramObjectARB ( 0 ) ;
2011-03-17 01:47:30 -04:00
break ;
}
}
/*
2011-05-02 20:11:26 -05:00
* Copyright (c) 2001-2011 Chris Danford, Glenn Maynard, Colby Klein
2011-03-17 01:47:30 -04:00
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/