2003-05-22 05:28:37 +00:00
#include "global.h"
2006-07-24 05:48:21 +00:00
#include "RageDisplay_OGL.h"
#include "RageDisplay_OGL_Helpers.h"
using namespace RageDisplay_OGL_Helpers ;
2003-05-22 05:28:37 +00:00
2004-06-14 00:51:00 +00:00
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
2003-05-22 05:28:37 +00:00
#include "RageUtil.h"
#include "RageLog.h"
#include "RageException.h"
#include "RageTextureManager.h"
#include "RageMath.h"
#include "RageTypes.h"
#include "RageUtil.h"
2005-11-13 19:04:07 +00:00
#include "EnumHelper.h"
2005-12-04 17:58:25 +00:00
#include "Foreach.h"
2005-11-26 07:22:33 +00:00
#include "DisplayResolutions.h"
2006-02-06 20:41:05 +00:00
#include "LocalizedString.h"
2003-05-22 05:28:37 +00:00
#include "arch/LowLevelWindow/LowLevelWindow.h"
2005-03-15 00:30:26 +00:00
#include "arch/arch.h"
2006-07-24 05:48:21 +00:00
#include <set>
#include <sstream>
2005-05-11 04:43:54 +00:00
#if defined(_MSC_VER)
2003-05-27 00:25:46 +00:00
#pragma comment(lib, "opengl32.lib")
2004-01-23 06:20:28 +00:00
#pragma comment(lib, "glu32.lib")
2003-06-30 06:23:42 +00:00
#endif
2003-05-22 05:28:37 +00:00
//
// Globals
//
2003-10-09 06:33:11 +00:00
static bool g_bReversePackedPixelsWorks = true ;
2004-09-26 09:15:16 +00:00
static bool g_bColorIndexTableWorks = true ;
2003-07-09 03:16:28 +00:00
2003-05-22 05:28:37 +00:00
/* OpenGL system information that generally doesn't change at runtime. */
/* Range and granularity of points and lines: */
2005-12-11 05:30:02 +00:00
static float g_line_range [ 2 ];
static float g_point_range [ 2 ];
2003-05-22 05:28:37 +00:00
/* OpenGL version * 10: */
2005-12-11 05:30:02 +00:00
static int g_glVersion ;
2003-05-22 05:28:37 +00:00
2004-01-24 19:14:22 +00:00
/* GLU version * 10: */
2005-12-11 05:30:02 +00:00
static int g_gluVersion ;
2004-01-24 19:14:22 +00:00
2005-01-04 05:34:58 +00:00
static int g_iMaxTextureUnits = 0 ;
2005-05-28 03:50:07 +00:00
/* We don't actually use normals (we don't turn on lighting), there's just
2003-05-22 05:28:37 +00:00
* no GL_T2F_C4F_V3F. */
2005-12-11 05:30:02 +00:00
static const GLenum RageSpriteVertexFormat = GL_T2F_C4F_N3F_V3F ;
2003-05-22 05:28:37 +00:00
2005-02-01 03:04:32 +00:00
/* If we support texture matrix scaling, a handle to the vertex program: */
2005-02-11 04:06:52 +00:00
static GLhandleARB g_bTextureMatrixShader = 0 ;
2003-05-22 05:28:37 +00:00
2006-07-26 03:44:27 +00:00
static map < unsigned , RenderTarget *> g_mapRenderTargets ;
static RenderTarget * g_pCurrentRenderTarget = NULL ;
2005-11-13 18:22:52 +00:00
static LowLevelWindow * g_pWind ;
2003-05-22 05:28:37 +00:00
2006-07-26 03:44:27 +00:00
static bool g_bInvertY = false ;
2004-04-16 21:34:58 +00:00
static void InvalidateAllGeometry ();
2003-05-30 20:16:30 +00:00
2005-09-29 17:15:12 +00:00
static RageDisplay :: PixelFormatDesc PIXEL_FORMAT_DESC [ NUM_PixelFormat ] = {
2003-05-30 20:16:30 +00:00
{
2003-06-29 08:13:18 +00:00
/* R8G8B8A8 */
2003-05-30 20:16:30 +00:00
32 ,
2003-06-28 01:45:44 +00:00
{ 0xFF000000 ,
2003-05-30 20:16:30 +00:00
0x00FF0000 ,
2003-06-28 01:45:44 +00:00
0x0000FF00 ,
0x000000FF }
2003-05-30 20:16:30 +00:00
}, {
2003-06-28 01:45:44 +00:00
/* R4G4B4A4 */
2003-05-30 20:16:30 +00:00
16 ,
{ 0xF000 ,
0x0F00 ,
0x00F0 ,
0x000F },
}, {
2003-06-28 01:45:44 +00:00
/* R5G5B5A1 */
2003-05-30 20:16:30 +00:00
16 ,
{ 0xF800 ,
0x07C0 ,
0x003E ,
0x0001 },
}, {
2003-06-28 01:45:44 +00:00
/* R5G5B5 */
2003-05-30 20:16:30 +00:00
16 ,
{ 0xF800 ,
0x07C0 ,
0x003E ,
0x0000 },
}, {
2003-06-28 01:45:44 +00:00
/* R8G8B8 */
2003-05-30 20:16:30 +00:00
24 ,
2003-06-28 01:45:44 +00:00
{ 0xFF0000 ,
2003-05-30 20:16:30 +00:00
0x00FF00 ,
2003-06-28 01:45:44 +00:00
0x0000FF ,
2003-05-30 20:16:30 +00:00
0x000000 }
2003-06-30 03:13:53 +00:00
}, {
/* Paletted */
8 ,
{ 0 , 0 , 0 , 0 } /* N/A */
2003-06-29 08:13:18 +00:00
}, {
/* B8G8R8A8 */
24 ,
{ 0x0000FF ,
0x00FF00 ,
0xFF0000 ,
0x000000 }
2003-05-30 20:16:30 +00:00
}, {
2003-06-30 03:13:53 +00:00
/* A1B5G5R5 */
16 ,
{ 0x7C00 ,
0x03E0 ,
0x001F ,
0x8000 },
2003-05-30 20:16:30 +00:00
}
};
2005-09-29 17:15:12 +00:00
/* 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.
2003-07-09 03:16:28 +00:00
*
* 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.
*/
2003-05-30 20:16:30 +00:00
struct GLPixFmtInfo_t {
GLenum internalfmt ; /* target format */
GLenum format ; /* target format */
GLenum type ; /* data format */
2005-09-29 17:15:12 +00:00
} const g_GLPixFmtInfo [ NUM_PixelFormat ] = {
2003-05-30 20:16:30 +00:00
{
2003-06-29 08:13:18 +00:00
/* R8G8B8A8 */
2003-05-30 20:16:30 +00:00
GL_RGBA8 ,
GL_RGBA ,
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 ,
2003-06-30 03:13:53 +00:00
}, {
/* Paletted */
GL_COLOR_INDEX8_EXT ,
GL_COLOR_INDEX ,
GL_UNSIGNED_BYTE ,
2003-06-29 08:13:18 +00:00
}, {
/* B8G8R8 */
GL_RGB8 ,
GL_BGR ,
GL_UNSIGNED_BYTE ,
2003-05-30 20:16:30 +00:00
}, {
2003-06-30 03:13:53 +00:00
/* A1R5G5B5 (matches D3DFMT_A1R5G5B5) */
GL_RGB5_A1 ,
GL_BGRA ,
GL_UNSIGNED_SHORT_1_5_5_5_REV ,
2003-05-30 20:16:30 +00:00
}
};
2005-05-28 03:50:28 +00:00
static void FixLittleEndian ()
2003-06-11 01:19:02 +00:00
{
2004-06-13 07:35:08 +00:00
#if defined(ENDIAN_LITTLE)
2005-11-13 18:22:52 +00:00
static bool bInitialized = false ;
if ( bInitialized )
2003-06-11 01:19:02 +00:00
return ;
2005-11-13 18:22:52 +00:00
bInitialized = true ;
2003-06-11 01:19:02 +00:00
2005-09-29 17:15:12 +00:00
for ( int i = 0 ; i < NUM_PixelFormat ; ++ i )
2003-06-11 01:19:02 +00:00
{
2003-10-03 21:38:38 +00:00
RageDisplay :: PixelFormatDesc & pf = PIXEL_FORMAT_DESC [ i ];
2003-06-11 01:19:02 +00:00
2004-06-14 05:48:28 +00:00
/* OpenGL and RageSurface handle byte formats differently; we need
2003-06-28 01:45:44 +00:00
* to flip non-paletted masks to make them line up. */
2005-09-29 17:15:12 +00:00
if ( g_GLPixFmtInfo [ i ]. type != GL_UNSIGNED_BYTE || pf . bpp == 8 )
2003-06-11 01:19:02 +00:00
continue ;
for ( int mask = 0 ; mask < 4 ; ++ mask )
2003-06-11 01:22:14 +00:00
{
int m = pf . masks [ mask ];
switch ( pf . bpp )
{
2004-06-13 07:10:26 +00:00
case 24 : m = Swap24 ( m ); break ;
case 32 : m = Swap32 ( m ); break ;
2003-06-28 01:45:44 +00:00
default : ASSERT ( 0 );
2003-06-11 01:22:14 +00:00
}
pf . masks [ mask ] = m ;
}
2003-06-11 01:19:02 +00:00
}
#endif
}
2003-05-30 20:16:30 +00:00
2003-06-12 19:40:44 +00:00
static void FlushGLErrors ()
{
/* Making an OpenGL call doesn't also flush the error state; if we happen
* to have an error from a previous call, then the assert below will fail.
* Flush it. */
while ( glGetError () != GL_NO_ERROR )
;
}
2004-04-16 21:34:58 +00:00
#define AssertNoGLError() \
{ \
GLenum error = glGetError(); \
2005-12-30 13:19:40 +00:00
ASSERT_M( error == GL_NO_ERROR, GLToString(error) ); \
2004-04-12 03:07:44 +00:00
}
2004-04-16 05:31:08 +00:00
static void TurnOffHardwareVBO ()
{
2004-05-24 03:41:49 +00:00
if ( GLExt . glBindBufferARB )
2004-04-16 05:31:08 +00:00
{
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , 0 );
GLExt . glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , 0 );
2004-04-16 05:31:08 +00:00
}
}
2004-11-30 22:21:50 +00:00
RageDisplay_OGL :: RageDisplay_OGL ()
2003-05-22 05:28:37 +00:00
{
2003-05-27 00:48:40 +00:00
LOG -> Trace ( "RageDisplay_OGL::RageDisplay_OGL()" );
LOG -> MapLog ( "renderer" , "Current renderer: OpenGL" );
2003-05-22 05:28:37 +00:00
2005-05-28 03:50:28 +00:00
FixLittleEndian ();
2006-07-24 05:48:21 +00:00
RageDisplay_OGL_Helpers :: Init ();
2003-06-11 01:19:02 +00:00
2005-11-13 18:22:52 +00:00
g_pWind = NULL ;
2005-05-06 14:41:46 +00:00
g_bTextureMatrixShader = 0 ;
2004-11-30 22:21:50 +00:00
}
2006-01-22 01:00:06 +00:00
RString GetInfoLog ( GLhandleARB h )
2005-02-01 03:04:32 +00:00
{
GLint iLength ;
GLExt . glGetObjectParameterivARB ( h , GL_OBJECT_INFO_LOG_LENGTH_ARB , & iLength );
if ( ! iLength )
2006-01-22 01:00:06 +00:00
return RString ();
2005-02-01 03:04:32 +00:00
GLcharARB * pInfoLog = new GLcharARB [ iLength ];
GLExt . glGetInfoLogARB ( h , iLength , & iLength , pInfoLog );
2006-01-22 01:00:06 +00:00
RString sRet = pInfoLog ;
2005-02-01 03:04:32 +00:00
delete [] pInfoLog ;
return sRet ;
}
2006-01-22 01:00:06 +00:00
GLhandleARB CompileShader ( GLenum ShaderType , RString sBuffer )
2005-02-01 03:04:32 +00:00
{
GLhandleARB VertexShader = GLExt . glCreateShaderObjectARB ( GL_VERTEX_SHADER_ARB );
const GLcharARB * pData = sBuffer . data ();
int iLength = sBuffer . size ();
2005-03-23 21:04:40 +00:00
GLExt . glShaderSourceARB ( VertexShader , 1 , & pData , ( GLint * ) & iLength );
2005-02-01 03:04:32 +00:00
GLExt . glCompileShaderARB ( VertexShader );
GLint bCompileStatus = GL_FALSE ;
GLExt . glGetObjectParameterivARB ( VertexShader , GL_OBJECT_COMPILE_STATUS_ARB , & bCompileStatus );
if ( ! bCompileStatus )
{
LOG -> Trace ( "Compile failure: %s" , GetInfoLog ( VertexShader ). c_str () );
2005-02-11 04:06:52 +00:00
return 0 ;
2005-02-01 03:04:32 +00:00
}
return VertexShader ;
}
enum
{
ATTRIB_TEXTURE_MATRIX_SCALE = 1
};
/* XXX: How should we include these? Doing them like this is ugly. Linking them in
* from another file as a text symbol would be ideal, but that's completely different
* on each platform, so it'd be a maintenance nightmare. Reading them from a file would
* be annoying, too. */
const GLcharARB * g_TextureMatrixScaleShader =
" \
attribute vec4 TextureMatrixScale; \
void main( void ) \
{ \
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \
vec4 multiplied_tex_coord = gl_TextureMatrix[0] * gl_MultiTexCoord0; \
gl_TexCoord[0] = (multiplied_tex_coord * TextureMatrixScale) + \
2005-02-05 06:43:35 +00:00
(gl_MultiTexCoord0 * (vec4(1)-TextureMatrixScale)); \
2005-02-01 03:04:32 +00:00
gl_FrontColor = gl_Color; \
} \
" ;
void InitScalingScript ()
{
2005-02-11 04:06:52 +00:00
g_bTextureMatrixShader = 0 ;
2005-02-01 03:04:32 +00:00
if ( ! GLExt . m_bGL_ARB_shader_objects ||
! GLExt . m_bGL_ARB_vertex_shader ||
! GLExt . m_bGL_ARB_shading_language_100 )
return ;
GLhandleARB VertexShader = CompileShader ( GL_VERTEX_SHADER_ARB , g_TextureMatrixScaleShader );
2005-02-11 04:06:52 +00:00
if ( VertexShader == 0 )
2005-02-01 03:04:32 +00:00
return ;
g_bTextureMatrixShader = GLExt . glCreateProgramObjectARB ();
GLExt . glAttachObjectARB ( g_bTextureMatrixShader , VertexShader );
GLExt . glDeleteObjectARB ( VertexShader );
// Bind attributes.
GLExt . glBindAttribLocationARB ( g_bTextureMatrixShader , ATTRIB_TEXTURE_MATRIX_SCALE , "TextureMatrixScale" );
// Link the program.
GLExt . glLinkProgramARB ( g_bTextureMatrixShader );
GLint bLinkStatus = false ;
GLExt . glGetObjectParameterivARB ( g_bTextureMatrixShader , GL_OBJECT_LINK_STATUS_ARB , & bLinkStatus );
if ( ! bLinkStatus )
{
LOG -> Trace ( "Scaling shader link failed: %s" , GetInfoLog ( g_bTextureMatrixShader ). c_str () );
GLExt . glDeleteObjectARB ( g_bTextureMatrixShader );
return ;
}
GLExt . glVertexAttrib2fARB ( ATTRIB_TEXTURE_MATRIX_SCALE , 1 , 1 );
}
2006-02-06 20:41:05 +00:00
static LocalizedString OBTAIN_AN_UPDATED_VIDEO_DRIVER ( "RageDisplay_OGL" , "Obtain an updated driver from your video card manufacturer." );
static LocalizedString GLDIRECT_IS_NOT_COMPATIBLE ( "RageDisplay_OGL" , "GLDirect was detected. GLDirect is not compatible with this game and should be disabled." );
2006-02-06 20:14:02 +00:00
RString RageDisplay_OGL :: Init ( const VideoModeParams & p , bool bAllowUnacceleratedRenderer )
2004-11-30 22:21:50 +00:00
{
2005-11-13 18:22:52 +00:00
g_pWind = MakeLowLevelWindow ();
2003-05-22 05:28:37 +00:00
2004-11-30 20:01:07 +00:00
bool bIgnore = false ;
2006-01-22 01:00:06 +00:00
RString sError = SetVideoMode ( p , bIgnore );
2004-11-30 20:01:07 +00:00
if ( sError != "" )
2004-11-30 22:21:50 +00:00
return sError ;
2003-05-22 05:28:37 +00:00
// Log driver details
2005-01-04 05:34:58 +00:00
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 ( "OGL Extensions: %s" , glGetString ( GL_EXTENSIONS ) );
LOG -> Info ( "GLU Version: %s" , gluGetString ( GLU_VERSION ) );
2003-06-25 20:44:49 +00:00
2005-11-13 18:54:09 +00:00
if ( g_pWind -> IsSoftwareRenderer ( sError ) )
2003-06-25 20:44:49 +00:00
{
if ( ! bAllowUnacceleratedRenderer )
2006-02-06 20:41:05 +00:00
return sError + " " + OBTAIN_AN_UPDATED_VIDEO_DRIVER . GetValue () + " \n\n " ;
2005-11-13 18:54:09 +00:00
LOG -> Warn ( "Low-performance OpenGL renderer: " + sError );
2003-06-25 20:44:49 +00:00
}
2003-05-22 05:28:37 +00:00
2004-04-03 00:09:16 +00:00
#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!) */
if ( ! strncmp ( ( const char * ) glGetString ( GL_RENDERER ), "GLDirect" , 8 ) )
2006-02-06 20:41:05 +00:00
return GLDIRECT_IS_NOT_COMPATIBLE . GetValue () + " \n " ;
2004-04-03 00:09:16 +00:00
#endif
2003-05-22 05:28:37 +00:00
/* Log this, so if people complain that the radar looks bad on their
* system we can compare them: */
2005-11-13 18:22:52 +00:00
glGetFloatv ( GL_LINE_WIDTH_RANGE , g_line_range );
glGetFloatv ( GL_POINT_SIZE_RANGE , g_point_range );
2004-11-30 22:21:50 +00:00
2005-02-01 03:04:32 +00:00
InitScalingScript ();
2006-01-22 01:00:06 +00:00
return RString ();
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
RageDisplay_OGL ::~ RageDisplay_OGL ()
2003-05-22 05:28:37 +00:00
{
2005-11-13 18:22:52 +00:00
delete g_pWind ;
2003-05-22 05:28:37 +00:00
}
2005-11-26 07:22:33 +00:00
void RageDisplay_OGL :: GetDisplayResolutions ( DisplayResolutions & out ) const
{
2006-02-07 08:29:36 +00:00
out . clear ();
2005-11-26 07:22:33 +00:00
g_pWind -> GetDisplayResolutions ( out );
}
2006-02-06 23:40:28 +00:00
float RageDisplay_OGL :: GetMonitorAspectRatio () const
{
return g_pWind -> GetMonitorAspectRatio ();
}
2004-05-15 08:18:37 +00:00
static void CheckPalettedTextures ()
2003-05-30 20:16:30 +00:00
{
2006-01-22 01:00:06 +00:00
RString sError ;
2004-03-13 07:38:46 +00:00
do
2004-03-13 06:42:07 +00:00
{
2005-05-28 03:54:33 +00:00
if ( ! GLExt . HasExtension ( "GL_EXT_paletted_texture" ) )
2004-05-10 01:06:37 +00:00
{
2005-11-13 18:22:52 +00:00
sError = "GL_EXT_paletted_texture missing" ;
2004-05-10 01:06:37 +00:00
break ;
}
2004-05-24 03:41:49 +00:00
if ( GLExt . glColorTableEXT == NULL )
2004-03-13 07:38:46 +00:00
{
2005-11-13 18:22:52 +00:00
sError = "glColorTableEXT missing" ;
2004-03-13 07:38:46 +00:00
break ;
2003-11-13 18:04:31 +00:00
}
2004-05-24 03:41:49 +00:00
if ( GLExt . glGetColorTableParameterivEXT == NULL )
2004-03-13 07:38:46 +00:00
{
2005-11-13 18:22:52 +00:00
sError = "glGetColorTableParameterivEXT missing" ;
2004-03-13 07:38:46 +00:00
break ;
}
/* Check to see if paletted textures really work. */
2005-09-29 17:15:12 +00:00
GLenum glTexFormat = g_GLPixFmtInfo [ PixelFormat_PAL ]. internalfmt ;
GLenum glImageFormat = g_GLPixFmtInfo [ PixelFormat_PAL ]. format ;
GLenum glImageType = g_GLPixFmtInfo [ PixelFormat_PAL ]. type ;
2004-03-13 07:38:46 +00:00
2005-11-13 18:22:52 +00:00
int iBits = 8 ;
2004-03-13 07:38:46 +00:00
FlushGLErrors ();
#define GL_CHECK_ERROR(f) \
{ \
GLenum glError = glGetError(); \
if( glError != GL_NO_ERROR ) { \
2005-11-13 18:22:52 +00:00
sError = ssprintf(f " failed (%s)", GLToString(glError).c_str() ); \
2004-03-13 07:38:46 +00:00
break; \
} \
}
2005-11-13 18:22:52 +00:00
glTexImage2D ( GL_PROXY_TEXTURE_2D ,
2003-05-30 20:16:30 +00:00
0 , glTexFormat ,
16 , 16 , 0 ,
2005-11-13 18:22:52 +00:00
glImageFormat , glImageType , NULL );
2004-03-13 07:38:46 +00:00
GL_CHECK_ERROR ( "glTexImage2D" );
2003-05-30 20:16:30 +00:00
2005-11-13 18:22:52 +00:00
GLuint iFormat = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INTERNAL_FORMAT ), ( GLint * ) & iFormat );
2004-04-03 21:33:10 +00:00
GL_CHECK_ERROR ( "glGetTexLevelParameteriv(GL_TEXTURE_INTERNAL_FORMAT)" );
2005-11-13 18:22:52 +00:00
if ( iFormat != glTexFormat )
2003-10-09 06:33:11 +00:00
{
2005-11-13 18:22:52 +00:00
sError = ssprintf ( "Expected format %s, got %s instead" ,
GLToString ( glTexFormat ). c_str (), GLToString ( iFormat ). c_str () );
2004-03-13 07:38:46 +00:00
break ;
2003-10-09 06:33:11 +00:00
}
2004-03-13 07:38:46 +00:00
GLubyte palette [ 256 * 4 ];
memset ( palette , 0 , sizeof ( palette ));
2004-05-24 03:41:49 +00:00
GLExt . glColorTableEXT ( GL_PROXY_TEXTURE_2D , GL_RGBA8 , 256 , GL_RGBA , GL_UNSIGNED_BYTE , palette );
2004-03-13 07:38:46 +00:00
GL_CHECK_ERROR ( "glColorTableEXT" );
2003-05-30 20:16:30 +00:00
2005-11-13 18:22:52 +00:00
GLint iSize = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INDEX_SIZE_EXT ), & iSize );
2004-03-13 06:42:07 +00:00
GL_CHECK_ERROR ( "glGetTexLevelParameteriv(GL_TEXTURE_INDEX_SIZE_EXT)" );
2005-11-13 18:22:52 +00:00
if ( iBits > iSize || iSize > 8 )
2003-05-30 23:15:53 +00:00
{
2005-11-13 18:22:52 +00:00
sError = ssprintf ( "Expected %i-bit palette, got a %i-bit one instead" , iBits , int ( iSize ) );
2004-03-13 07:38:46 +00:00
break ;
2003-05-30 23:15:53 +00:00
}
2003-11-13 18:04:31 +00:00
2005-11-13 18:22:52 +00:00
GLint iRealWidth = 0 ;
GLExt . glGetColorTableParameterivEXT ( GL_PROXY_TEXTURE_2D , GL_COLOR_TABLE_WIDTH , & iRealWidth );
2003-11-14 00:07:47 +00:00
GL_CHECK_ERROR ( "glGetColorTableParameterivEXT(GL_COLOR_TABLE_WIDTH)" );
2005-11-13 18:22:52 +00:00
if ( iRealWidth != 1 << iBits )
2003-11-13 18:04:31 +00:00
{
2005-11-13 18:22:52 +00:00
sError = ssprintf ( "GL_COLOR_TABLE_WIDTH returned %i instead of %i" , int ( iRealWidth ), 1 << iBits );
2004-03-13 07:38:46 +00:00
break ;
2003-11-13 18:04:31 +00:00
}
2004-03-13 07:38:46 +00:00
2005-11-13 18:22:52 +00:00
GLint iRealFormat = 0 ;
GLExt . glGetColorTableParameterivEXT ( GL_PROXY_TEXTURE_2D , GL_COLOR_TABLE_FORMAT , & iRealFormat );
2003-11-13 18:04:31 +00:00
GL_CHECK_ERROR ( "glGetColorTableParameterivEXT(GL_COLOR_TABLE_FORMAT)" );
2005-11-13 18:22:52 +00:00
if ( iRealFormat != GL_RGBA8 )
2003-11-13 18:04:31 +00:00
{
2005-11-13 18:22:52 +00:00
sError = ssprintf ( "GL_COLOR_TABLE_FORMAT returned %s instead of GL_RGBA8" , GLToString ( iRealFormat ). c_str () );
2004-03-13 07:38:46 +00:00
break ;
2003-11-13 18:04:31 +00:00
}
2004-03-13 07:38:46 +00:00
} while ( 0 );
#undef GL_CHECK_ERROR
2003-05-30 20:16:30 +00:00
2005-11-13 18:22:52 +00:00
if ( sError == "" )
2004-03-13 07:38:46 +00:00
return ;
2003-05-30 20:16:30 +00:00
2004-05-15 08:18:37 +00:00
/* 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. */
2004-05-24 03:41:49 +00:00
GLExt . glColorTableEXT = NULL ;
GLExt . glGetColorTableParameterivEXT = NULL ;
2005-11-13 18:22:52 +00:00
LOG -> Info ( "Paletted textures disabled: %s." , sError . c_str () );
2003-05-30 20:16:30 +00:00
}
2003-07-09 03:16:28 +00:00
static void CheckReversePackedPixels ()
{
/* Try to create a texture. */
FlushGLErrors ();
2005-11-13 18:22:52 +00:00
glTexImage2D ( GL_PROXY_TEXTURE_2D ,
2003-07-09 03:16:28 +00:00
0 , GL_RGBA ,
16 , 16 , 0 ,
2005-11-13 18:22:52 +00:00
GL_BGRA , GL_UNSIGNED_SHORT_1_5_5_5_REV , NULL );
2003-07-09 03:16:28 +00:00
const GLenum glError = glGetError ();
if ( glError == GL_NO_ERROR )
2005-11-13 18:22:52 +00:00
{
2003-07-09 03:16:28 +00:00
g_bReversePackedPixelsWorks = true ;
2005-11-13 18:22:52 +00:00
}
2003-07-09 03:16:28 +00:00
else
{
g_bReversePackedPixelsWorks = false ;
2005-11-13 18:22:52 +00:00
LOG -> Info ( "GL_UNSIGNED_SHORT_1_5_5_5_REV failed (%s), disabled" ,
2003-07-09 03:16:28 +00:00
GLToString ( glError ). c_str () );
}
}
2003-05-22 05:28:37 +00:00
void SetupExtensions ()
{
2006-06-12 06:42:25 +00:00
const float fGLVersion = StringToFloat ( ( const char * ) glGetString ( GL_VERSION ) );
2003-05-22 05:28:37 +00:00
g_glVersion = int ( roundf ( fGLVersion * 10 ));
2006-06-12 06:42:25 +00:00
const float fGLUVersion = StringToFloat ( ( const char * ) gluGetString ( GLU_VERSION ) );
2004-01-24 19:14:22 +00:00
g_gluVersion = int ( roundf ( fGLUVersion * 10 ));
2005-11-13 18:22:52 +00:00
GLExt . Load ( g_pWind );
2004-05-24 03:56:08 +00:00
2005-01-30 19:50:55 +00:00
g_iMaxTextureUnits = 1 ;
if ( GLExt . glActiveTextureARB != NULL )
glGetIntegerv ( GL_MAX_TEXTURE_UNITS_ARB , ( GLint * ) & g_iMaxTextureUnits );
2004-05-24 03:56:08 +00:00
2004-05-15 08:18:37 +00:00
CheckPalettedTextures ();
2003-07-09 03:16:28 +00:00
CheckReversePackedPixels ();
2004-09-26 09:15:16 +00:00
{
GLint iMaxTableSize = 0 ;
glGetIntegerv ( GL_MAX_PIXEL_MAP_TABLE , & iMaxTableSize );
if ( iMaxTableSize < 256 )
{
/* 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. */
2004-10-05 10:36:11 +00:00
LOG -> Info ( "GL_MAX_PIXEL_MAP_TABLE is only %d" , int ( iMaxTableSize ) );
2004-09-26 09:15:16 +00:00
g_bColorIndexTableWorks = false ;
}
else
2005-11-13 18:22:52 +00:00
{
2004-09-26 09:15:16 +00:00
g_bColorIndexTableWorks = true ;
2005-11-13 18:22:52 +00:00
}
2004-09-26 09:15:16 +00:00
}
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: ResolutionChanged ()
2003-05-22 05:28:37 +00:00
{
2005-11-24 10:40:23 +00:00
//LOG->Warn( "RageDisplay_OGL::ResolutionChanged" );
2003-05-22 05:28:37 +00:00
/* Clear any junk that's in the framebuffer. */
2004-09-19 01:38:12 +00:00
if ( BeginFrame () )
EndFrame ();
2005-12-29 07:45:06 +00:00
RageDisplay :: ResolutionChanged ();
2003-05-22 05:28:37 +00:00
}
2003-06-05 19:29:27 +00:00
// Return true if mode change was successful.
// bNewDeviceOut is set true if a new device was created and textures
// need to be reloaded.
2006-01-22 01:00:06 +00:00
RString RageDisplay_OGL :: TryVideoMode ( const VideoModeParams & p , bool & bNewDeviceOut )
2003-05-22 05:28:37 +00:00
{
2005-11-24 10:40:23 +00:00
//LOG->Warn( "RageDisplay_OGL::TryVideoMode( %d, %d, %d, %d, %d, %d )", p.windowed, p.width, p.height, p.bpp, p.rate, p.vsync );
2006-01-22 01:00:06 +00:00
RString err ;
2005-11-13 18:22:52 +00:00
err = g_pWind -> TryVideoMode ( p , bNewDeviceOut );
2003-08-28 00:08:01 +00:00
if ( err != "" )
return err ; // failed to set video mode
2003-05-22 05:28:37 +00:00
2005-11-11 21:01:58 +00:00
/* Now that we've initialized, we can search for extensions. Do this before InvalidateAllGeometry,
* since AllocateBuffers needs it. */
SetupExtensions ();
2003-06-05 19:29:27 +00:00
if ( bNewDeviceOut )
2003-05-22 05:28:37 +00:00
{
/* We have a new OpenGL context, so we have to tell our textures that
* their OpenGL texture number is invalid. */
2005-11-13 18:22:52 +00:00
if ( TEXTUREMAN )
2003-05-22 05:28:37 +00:00
TEXTUREMAN -> InvalidateTextures ();
2004-04-16 21:34:58 +00:00
2006-07-26 03:44:27 +00:00
/* Delete all render targets. They may have associated resources other than
* the texture itself. */
2006-07-26 03:58:29 +00:00
FOREACHM ( unsigned , RenderTarget * , g_mapRenderTargets , rt )
2006-07-26 03:44:27 +00:00
delete rt -> second ;
g_mapRenderTargets . clear ();
2004-04-16 21:34:58 +00:00
/* Recreate all vertex buffers. */
InvalidateAllGeometry ();
2005-11-28 23:11:34 +00:00
InitScalingScript ();
2003-05-22 05:28:37 +00:00
}
/* Set vsync the Windows way, if we can. (What other extensions are there
* to do this, for other archs?) */
2004-05-24 03:41:49 +00:00
if ( GLExt . wglSwapIntervalEXT )
2006-02-01 07:52:33 +00:00
GLExt . wglSwapIntervalEXT ( p . vsync );
2003-05-22 05:28:37 +00:00
ResolutionChanged ();
2006-01-22 01:00:06 +00:00
return RString (); // successfully set mode
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
int RageDisplay_OGL :: GetMaxTextureSize () const
2003-05-22 05:28:37 +00:00
{
GLint size ;
2005-11-13 18:22:52 +00:00
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & size );
2003-05-22 05:28:37 +00:00
return size ;
}
2004-09-19 01:38:12 +00:00
bool RageDisplay_OGL :: BeginFrame ()
2003-05-22 05:28:37 +00:00
{
2006-01-18 09:18:17 +00: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 );
2006-07-26 01:44:59 +00:00
glClearColor ( 0 , 0 , 0 , 0 );
2003-11-18 20:33:18 +00:00
SetZWrite ( true );
2005-11-13 18:58:54 +00:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
2006-07-25 20:10:56 +00:00
return RageDisplay :: BeginFrame ();
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: EndFrame ()
2003-05-22 05:28:37 +00:00
{
2005-03-22 01:32:05 +00:00
glFlush ();
2005-03-17 01:21:13 +00:00
2006-01-17 01:43:11 +00:00
FrameLimitBeforeVsync ( g_pWind -> GetActualVideoModeParams (). rate );
2005-11-13 18:22:52 +00:00
g_pWind -> SwapBuffers ();
2006-01-17 01:44:47 +00:00
FrameLimitAfterVsync ();
2005-07-13 00:01:46 +00:00
2005-11-13 18:22:52 +00:00
g_pWind -> Update ();
2005-07-13 00:01:46 +00:00
2005-07-13 00:37:43 +00:00
RageDisplay :: EndFrame ();
2003-05-22 05:28:37 +00:00
}
2004-06-14 00:51:00 +00:00
RageSurface * RageDisplay_OGL :: CreateScreenshot ()
2003-05-22 05:28:37 +00:00
{
2005-11-13 18:22:52 +00:00
int width = g_pWind -> GetActualVideoModeParams (). width ;
int height = g_pWind -> GetActualVideoModeParams (). height ;
2003-06-05 19:29:27 +00:00
2005-09-29 17:15:12 +00:00
const PixelFormatDesc & desc = PIXEL_FORMAT_DESC [ PixelFormat_RGBA8 ];
2004-06-14 00:51:00 +00:00
RageSurface * image = CreateSurface ( width , height , desc . bpp ,
desc . masks [ 0 ], desc . masks [ 1 ], desc . masks [ 2 ], 0 );
2003-07-09 06:16:19 +00:00
2004-08-26 20:26:03 +00:00
FlushGLErrors ();
2005-04-09 05:06:14 +00:00
glReadBuffer ( GL_FRONT );
AssertNoGLError ();
2005-11-13 18:22:52 +00:00
glReadPixels ( 0 , 0 , g_pWind -> GetActualVideoModeParams (). width , g_pWind -> GetActualVideoModeParams (). height , GL_RGBA ,
2006-02-01 07:52:33 +00:00
GL_UNSIGNED_BYTE , image -> pixels );
2004-08-09 07:32:49 +00:00
AssertNoGLError ();
2003-05-22 05:28:37 +00:00
2004-08-26 20:36:44 +00:00
RageSurfaceUtils :: FlipVertically ( image );
2004-05-19 00:27:48 +00:00
return image ;
2003-05-22 05:28:37 +00:00
}
2005-11-11 21:16:48 +00:00
VideoModeParams RageDisplay_OGL :: GetActualVideoModeParams () const
{
2005-11-13 18:22:52 +00:00
return g_pWind -> GetActualVideoModeParams ();
2005-11-11 21:16:48 +00:00
}
2003-05-22 05:28:37 +00:00
2003-07-07 01:29:18 +00:00
static void SetupVertices ( const RageSpriteVertex v [], int iNumVerts )
2003-05-26 19:42:04 +00:00
{
static float * Vertex , * Texture , * Normal ;
static GLubyte * Color ;
static int Size = 0 ;
2005-11-13 18:22:52 +00:00
if ( iNumVerts > Size )
2003-05-26 19:42:04 +00: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 ];
}
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
for ( unsigned i = 0 ; i < unsigned ( iNumVerts ); ++ i )
2003-05-26 19:42:04 +00:00
{
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 ];
2003-05-27 05:26:53 +00:00
Normal [ i * 3 + 0 ] = v [ i ]. n [ 0 ];
Normal [ i * 3 + 1 ] = v [ i ]. n [ 1 ];
2003-05-27 08:39:36 +00:00
Normal [ i * 3 + 2 ] = v [ i ]. n [ 2 ];
2003-05-26 19:42:04 +00:00
}
2005-11-13 18:22:52 +00:00
glEnableClientState ( GL_VERTEX_ARRAY );
glVertexPointer ( 3 , GL_FLOAT , 0 , Vertex );
2003-05-26 19:42:04 +00:00
2005-11-13 18:22:52 +00:00
glEnableClientState ( GL_COLOR_ARRAY );
glColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , Color );
2003-05-26 19:42:04 +00:00
2005-11-13 18:22:52 +00:00
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer ( 2 , GL_FLOAT , 0 , Texture );
2003-05-26 19:42:04 +00:00
2005-11-13 18:22:52 +00:00
glEnableClientState ( GL_NORMAL_ARRAY );
glNormalPointer ( GL_FLOAT , 0 , Normal );
2003-05-26 19:42:04 +00:00
}
2004-04-08 08:35:38 +00:00
void RageDisplay_OGL :: SendCurrentMatrices ()
2003-07-07 01:29:18 +00:00
{
2004-10-24 22:59:10 +00:00
RageMatrix projection ;
RageMatrixMultiply ( & projection , GetCentering (), GetProjectionTop () );
2006-07-26 03:44:27 +00:00
if ( g_bInvertY )
{
RageMatrix flip ;
RageMatrixScale ( & flip , + 1 , - 1 , + 1 );
RageMatrixMultiply ( & projection , & flip , & projection );
}
2004-04-08 08:35:38 +00:00
glMatrixMode ( GL_PROJECTION );
2004-10-24 22:59:10 +00:00
glLoadMatrixf ( ( const float * ) & projection );
// OpenGL has just "modelView", whereas D3D has "world" and "view"
2004-04-08 08:35:38 +00:00
RageMatrix modelView ;
2004-10-24 22:59:10 +00:00
RageMatrixMultiply ( & modelView , GetViewTop (), GetWorldTop () );
2004-04-08 08:35:38 +00:00
glMatrixMode ( GL_MODELVIEW );
glLoadMatrixf ( ( const float * ) & modelView );
2004-10-24 22:59:10 +00:00
glMatrixMode ( GL_TEXTURE );
2004-08-09 00:46:42 +00:00
glLoadMatrixf ( ( const float * ) GetTextureTop () );
2004-04-08 08:35:38 +00:00
}
2004-04-16 05:09:02 +00:00
class RageCompiledGeometrySWOGL : public RageCompiledGeometry
2004-04-08 08:35:38 +00:00
{
public :
2004-04-16 05:09:02 +00:00
void Allocate ( const vector < msMesh > & vMeshes )
2004-04-08 08:35:38 +00:00
{
2004-04-16 05:09:02 +00:00
m_vPosition . resize ( GetTotalVertices () );
m_vTexture . resize ( GetTotalVertices () );
m_vNormal . resize ( GetTotalVertices () );
2005-02-01 03:04:32 +00:00
m_vTexMatrixScale . resize ( GetTotalVertices () );
2004-04-16 05:09:02 +00:00
m_vTriangles . resize ( GetTotalTriangles () );
2004-04-08 08:35:38 +00:00
}
2004-04-16 05:09:02 +00:00
void Change ( const vector < msMesh > & vMeshes )
2004-04-08 08:35:38 +00:00
{
2004-04-16 05:09:02 +00:00
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 ;
2003-07-07 01:29:18 +00:00
2004-08-19 00:36:11 +00:00
for ( unsigned j = 0 ; j < Vertices . size (); j ++ )
2004-04-16 05:09:02 +00:00
{
2004-08-19 00:36:11 +00:00
m_vPosition [ meshInfo . iVertexStart + j ] = Vertices [ j ]. p ;
m_vTexture [ meshInfo . iVertexStart + j ] = Vertices [ j ]. t ;
m_vNormal [ meshInfo . iVertexStart + j ] = Vertices [ j ]. n ;
2005-02-01 03:04:32 +00:00
m_vTexMatrixScale [ meshInfo . iVertexStart + j ] = Vertices [ j ]. TextureMatrixScale ;
2004-04-16 05:09:02 +00:00
}
2004-08-19 00:36:11 +00:00
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 ;
}
2004-04-16 05:09:02 +00:00
}
2004-04-08 08:35:38 +00:00
}
2004-04-16 05:09:02 +00:00
void Draw ( int iMeshIndex ) const
2004-04-08 08:35:38 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-16 05:09:02 +00:00
const MeshInfo & meshInfo = m_vMeshInfo [ iMeshIndex ];
2003-07-07 01:29:18 +00:00
2004-04-08 08:35:38 +00:00
glEnableClientState ( GL_VERTEX_ARRAY );
2004-04-16 05:09:02 +00:00
glVertexPointer ( 3 , GL_FLOAT , 0 , & m_vPosition [ 0 ]);
2004-04-08 08:35:38 +00:00
glDisableClientState ( GL_COLOR_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
2004-04-16 05:09:02 +00:00
glTexCoordPointer ( 2 , GL_FLOAT , 0 , & m_vTexture [ 0 ]);
2004-04-08 08:35:38 +00:00
glEnableClientState ( GL_NORMAL_ARRAY );
2004-04-16 05:09:02 +00:00
glNormalPointer ( GL_FLOAT , 0 , & m_vNormal [ 0 ]);
2004-04-08 08:35:38 +00:00
2005-10-20 19:18:32 +00:00
if ( meshInfo . m_bNeedsTextureMatrixScale )
{
// 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++ )
{
2006-01-22 01:00:06 +00:00
RString s;
2005-10-20 19:18:32 +00:00
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 );
}
2004-04-16 05:09:02 +00:00
glDrawElements (
GL_TRIANGLES ,
meshInfo . iTriangleCount * 3 ,
GL_UNSIGNED_SHORT ,
& m_vTriangles [ 0 ] + meshInfo . iTriangleStart );
2004-04-08 08:35:38 +00:00
}
2004-04-16 05:09:02 +00:00
2004-04-08 08:35:38 +00:00
protected :
2004-04-16 05:09:02 +00:00
vector < RageVector3 > m_vPosition ;
vector < RageVector2 > m_vTexture ;
vector < RageVector3 > m_vNormal ;
vector < msTriangle > m_vTriangles ;
2005-02-01 03:04:32 +00:00
vector < RageVector2 > m_vTexMatrixScale ;
2004-04-08 08:35:38 +00:00
};
2004-04-16 05:09:02 +00:00
class RageCompiledGeometryHWOGL : public RageCompiledGeometrySWOGL
2004-04-12 03:07:44 +00:00
{
protected :
// vertex buffer object names
GLuint m_nPositions ;
GLuint m_nTextureCoords ;
GLuint m_nNormals ;
GLuint m_nTriangles ;
2005-02-01 03:04:32 +00:00
GLuint m_nTextureMatrixScale ;
2004-04-16 21:34:58 +00:00
void AllocateBuffers ();
void UploadData ();
2004-04-12 03:07:44 +00:00
public :
2004-04-16 21:34:58 +00:00
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 ;
};
static set < RageCompiledGeometryHWOGL *> g_GeometryList ;
static void InvalidateAllGeometry ()
{
2005-11-11 21:01:58 +00:00
FOREACHS ( RageCompiledGeometryHWOGL * , g_GeometryList , it )
2004-04-16 21:34:58 +00:00
( * it ) -> Invalidate ();
}
RageCompiledGeometryHWOGL :: RageCompiledGeometryHWOGL ()
{
g_GeometryList . insert ( this );
2005-11-28 23:26:22 +00:00
m_nPositions = 0 ;
m_nTextureCoords = 0 ;
m_nNormals = 0 ;
m_nTriangles = 0 ;
m_nTextureMatrixScale = 0 ;
2004-04-16 21:34:58 +00:00
AllocateBuffers ();
}
RageCompiledGeometryHWOGL ::~ RageCompiledGeometryHWOGL ()
{
g_GeometryList . erase ( this );
FlushGLErrors ();
2004-05-24 03:41:49 +00:00
GLExt . glDeleteBuffersARB ( 1 , & m_nPositions );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glDeleteBuffersARB ( 1 , & m_nTextureCoords );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glDeleteBuffersARB ( 1 , & m_nNormals );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glDeleteBuffersARB ( 1 , & m_nTriangles );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
GLExt . glDeleteBuffersARB ( 1 , & m_nTextureMatrixScale );
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
}
void RageCompiledGeometryHWOGL :: AllocateBuffers ()
{
FlushGLErrors ();
if ( ! m_nPositions )
2004-04-12 03:07:44 +00:00
{
2004-05-24 03:41:49 +00:00
GLExt . glGenBuffersARB ( 1 , & m_nPositions );
2004-04-12 03:07:44 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
}
2004-04-12 03:07:44 +00:00
2004-04-16 21:34:58 +00:00
if ( ! m_nTextureCoords )
{
2004-05-24 03:41:49 +00:00
GLExt . glGenBuffersARB ( 1 , & m_nTextureCoords );
2004-04-12 03:07:44 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
}
2004-04-12 03:07:44 +00:00
2004-04-16 21:34:58 +00:00
if ( ! m_nNormals )
{
2004-05-24 03:41:49 +00:00
GLExt . glGenBuffersARB ( 1 , & m_nNormals );
2004-04-12 03:07:44 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
}
2004-04-12 03:07:44 +00:00
2004-04-16 21:34:58 +00:00
if ( ! m_nTriangles )
{
2004-05-24 03:41:49 +00:00
GLExt . glGenBuffersARB ( 1 , & m_nTriangles );
2004-04-12 03:07:44 +00:00
AssertNoGLError ();
}
2005-02-01 03:04:32 +00:00
if ( ! m_nTextureMatrixScale )
{
GLExt . glGenBuffersARB ( 1 , & m_nTextureMatrixScale );
AssertNoGLError ();
}
2004-04-16 21:34:58 +00:00
}
2004-04-12 03:07:44 +00:00
2004-04-16 21:34:58 +00:00
void RageCompiledGeometryHWOGL :: UploadData ()
{
2005-11-28 23:35:21 +00:00
FlushGLErrors ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector3 ),
& m_vPosition [ 0 ],
GL_STATIC_DRAW_ARB );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-04-12 03:07:44 +00:00
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector2 ),
& m_vTexture [ 0 ],
GL_STATIC_DRAW_ARB );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector3 ),
& m_vNormal [ 0 ],
GL_STATIC_DRAW_ARB );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ELEMENT_ARRAY_BUFFER_ARB ,
GetTotalTriangles () * sizeof ( msTriangle ),
& m_vTriangles [ 0 ],
GL_STATIC_DRAW_ARB );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
2005-10-20 14:15:13 +00:00
if ( m_bAnyNeedsTextureMatrixScale )
2005-02-01 03:04:32 +00:00
{
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
GLExt . glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector2 ),
& m_vTexMatrixScale [ 0 ],
GL_STATIC_DRAW_ARB );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
}
2004-04-16 21:34:58 +00:00
}
void RageCompiledGeometryHWOGL :: Invalidate ()
{
/* Our vertex buffers no longer exist. Reallocate and reupload. */
2005-11-28 23:26:22 +00:00
m_nPositions = 0 ;
m_nTextureCoords = 0 ;
m_nNormals = 0 ;
m_nTriangles = 0 ;
m_nTextureMatrixScale = 0 ;
2004-04-16 21:34:58 +00:00
AllocateBuffers ();
UploadData ();
}
void RageCompiledGeometryHWOGL :: Allocate ( const vector < msMesh > & vMeshes )
{
2005-11-28 23:35:21 +00:00
FlushGLErrors ();
2004-04-16 21:34:58 +00:00
RageCompiledGeometrySWOGL :: Allocate ( vMeshes );
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector3 ),
NULL ,
GL_STATIC_DRAW_ARB );
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector2 ),
NULL ,
GL_STATIC_DRAW_ARB );
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector3 ),
NULL ,
GL_STATIC_DRAW_ARB );
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBufferDataARB (
2004-04-16 21:34:58 +00:00
GL_ELEMENT_ARRAY_BUFFER_ARB ,
GetTotalTriangles () * sizeof ( msTriangle ),
NULL ,
GL_STATIC_DRAW_ARB );
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
GLExt . glBufferDataARB (
GL_ARRAY_BUFFER_ARB ,
GetTotalVertices () * sizeof ( RageVector2 ),
NULL ,
GL_STATIC_DRAW_ARB );
2004-04-16 21:34:58 +00:00
}
void RageCompiledGeometryHWOGL :: Change ( const vector < msMesh > & vMeshes )
{
RageCompiledGeometrySWOGL :: Change ( vMeshes );
UploadData ();
}
void RageCompiledGeometryHWOGL :: Draw ( int iMeshIndex ) const
{
FlushGLErrors ();
const MeshInfo & meshInfo = m_vMeshInfo [ iMeshIndex ];
2004-04-16 22:10:25 +00:00
if ( ! meshInfo . iVertexCount || ! meshInfo . iTriangleCount )
return ;
2004-04-16 21:34:58 +00:00
glEnableClientState ( GL_VERTEX_ARRAY );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nPositions );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
glVertexPointer ( 3 , GL_FLOAT , 0 , NULL );
AssertNoGLError ();
glDisableClientState ( GL_COLOR_ARRAY );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureCoords );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
glTexCoordPointer ( 2 , GL_FLOAT , 0 , NULL );
AssertNoGLError ();
// TRICKY: Don't bind and send normals if lighting is disabled. This
// will save some effort transforming these values.
GLboolean bLighting ;
glGetBooleanv ( GL_LIGHTING , & bLighting );
2004-04-17 18:11:03 +00:00
GLboolean bTextureGenS ;
2004-04-17 20:07:39 +00:00
glGetBooleanv ( GL_TEXTURE_GEN_S , & bTextureGenS );
2004-04-17 18:11:03 +00:00
GLboolean bTextureGenT ;
2004-04-17 20:07:39 +00:00
glGetBooleanv ( GL_TEXTURE_GEN_T , & bTextureGenT );
2004-04-17 18:11:03 +00:00
if ( bLighting || bTextureGenS || bTextureGenT )
2004-04-12 03:07:44 +00:00
{
2004-04-16 21:34:58 +00:00
glEnableClientState ( GL_NORMAL_ARRAY );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nNormals );
2004-04-16 05:09:02 +00:00
AssertNoGLError ();
2004-04-16 21:34:58 +00:00
glNormalPointer ( GL_FLOAT , 0 , NULL );
2004-04-16 05:09:02 +00:00
AssertNoGLError ();
2004-04-12 03:07:44 +00:00
}
2004-04-16 21:34:58 +00:00
else
2004-04-16 05:09:02 +00:00
{
2004-04-16 21:34:58 +00:00
glDisableClientState ( GL_NORMAL_ARRAY );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2004-04-16 05:09:02 +00:00
}
2004-04-12 03:07:44 +00:00
2005-10-20 14:15:13 +00:00
if ( meshInfo . m_bNeedsTextureMatrixScale )
2005-02-01 03:04:32 +00:00
{
2005-10-21 06:36:08 +00:00
if ( g_bTextureMatrixShader != 0 )
2005-10-20 14:15:13 +00: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. */
GLExt . glEnableVertexAttribArrayARB ( ATTRIB_TEXTURE_MATRIX_SCALE );
AssertNoGLError ();
GLExt . glBindBufferARB ( GL_ARRAY_BUFFER_ARB , m_nTextureMatrixScale );
AssertNoGLError ();
GLExt . glVertexAttribPointerARB ( ATTRIB_TEXTURE_MATRIX_SCALE , 2 , GL_FLOAT , false , 0 , NULL );
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
2005-10-20 14:15:13 +00:00
GLExt . glUseProgramObjectARB ( g_bTextureMatrixShader );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-10-20 14:15:13 +00:00
}
else
{
2005-10-20 18:19:44 +00: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++ )
{
2006-01-22 01:00:06 +00:00
RString s;
2005-10-20 18:19:44 +00:00
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 ;
2005-10-20 14:15:13 +00:00
glMatrixMode ( GL_TEXTURE );
2005-10-20 18:19:44 +00:00
glLoadMatrixf ( ( const float * ) mat );
2005-11-28 23:26:22 +00:00
AssertNoGLError ();
2005-10-20 14:15:13 +00:00
}
2005-02-01 03:04:32 +00:00
}
2004-05-24 03:41:49 +00:00
GLExt . glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , m_nTriangles );
2004-04-16 21:34:58 +00:00
AssertNoGLError ();
2004-04-12 03:07:44 +00:00
2004-04-16 05:09:02 +00:00
#define BUFFER_OFFSET(o) ((char*)(o))
2004-04-15 05:02:35 +00:00
2004-05-24 03:41:49 +00:00
ASSERT ( GLExt . glDrawRangeElements );
GLExt . glDrawRangeElements (
2004-04-16 21:34:58 +00: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 )) );
AssertNoGLError ();
2005-02-01 03:04:32 +00:00
2005-10-20 14:15:13 +00:00
if ( meshInfo . m_bNeedsTextureMatrixScale && g_bTextureMatrixShader != 0 )
2005-02-01 03:04:32 +00:00
{
GLExt . glDisableVertexAttribArrayARB ( ATTRIB_TEXTURE_MATRIX_SCALE );
2005-02-11 04:06:52 +00:00
GLExt . glUseProgramObjectARB ( 0 );
2005-02-01 03:04:32 +00:00
}
2004-04-16 21:34:58 +00:00
}
2004-04-12 03:07:44 +00:00
2004-04-16 05:09:02 +00:00
RageCompiledGeometry * RageDisplay_OGL :: CreateCompiledGeometry ()
2004-04-08 08:35:38 +00:00
{
2004-05-24 03:41:49 +00:00
if ( GLExt . glGenBuffersARB )
2004-04-16 05:09:02 +00:00
return new RageCompiledGeometryHWOGL ;
2004-04-12 03:07:44 +00:00
else
2004-04-16 05:09:02 +00:00
return new RageCompiledGeometrySWOGL ;
2004-04-08 08:35:38 +00:00
}
2004-04-16 05:09:02 +00:00
void RageDisplay_OGL :: DeleteCompiledGeometry ( RageCompiledGeometry * p )
2004-04-08 08:35:38 +00:00
{
delete p ;
2003-07-07 01:29:18 +00:00
}
2004-04-15 05:24:28 +00:00
void RageDisplay_OGL :: DrawQuadsInternal ( const RageSpriteVertex v [], int iNumVerts )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-05-22 05:28:37 +00:00
2003-05-26 19:42:04 +00:00
SetupVertices ( v , iNumVerts );
2003-05-22 05:28:37 +00:00
glDrawArrays ( GL_QUADS , 0 , iNumVerts );
}
2003-05-26 19:42:04 +00:00
2004-04-15 05:24:28 +00:00
void RageDisplay_OGL :: DrawQuadStripInternal ( const RageSpriteVertex v [], int iNumVerts )
2004-04-13 07:28:25 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-13 07:28:25 +00:00
SendCurrentMatrices ();
SetupVertices ( v , iNumVerts );
glDrawArrays ( GL_QUAD_STRIP , 0 , iNumVerts );
}
2004-04-15 05:24:28 +00:00
void RageDisplay_OGL :: DrawFanInternal ( const RageSpriteVertex v [], int iNumVerts )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-09-21 02:36:28 +00:00
2003-05-26 19:42:04 +00:00
SetupVertices ( v , iNumVerts );
2003-05-22 05:28:37 +00:00
glDrawArrays ( GL_TRIANGLE_FAN , 0 , iNumVerts );
}
2004-04-15 05:24:28 +00:00
void RageDisplay_OGL :: DrawStripInternal ( const RageSpriteVertex v [], int iNumVerts )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-09-21 02:36:28 +00:00
2003-05-26 19:42:04 +00:00
SetupVertices ( v , iNumVerts );
2003-05-22 05:28:37 +00:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , iNumVerts );
}
2004-04-15 05:24:28 +00:00
void RageDisplay_OGL :: DrawTrianglesInternal ( const RageSpriteVertex v [], int iNumVerts )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-09-21 02:36:28 +00:00
2003-05-26 19:42:04 +00:00
SetupVertices ( v , iNumVerts );
2003-05-22 05:28:37 +00:00
glDrawArrays ( GL_TRIANGLES , 0 , iNumVerts );
}
2004-04-16 05:09:02 +00:00
void RageDisplay_OGL :: DrawCompiledGeometryInternal ( const RageCompiledGeometry * p , int iMeshIndex )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-09-21 02:36:28 +00:00
2004-04-16 05:09:02 +00:00
p -> Draw ( iMeshIndex );
2003-05-22 05:28:37 +00:00
}
2005-11-13 18:22:52 +00:00
void RageDisplay_OGL :: DrawLineStripInternal ( const RageSpriteVertex v [], int iNumVerts , float fLineWidth )
2003-05-22 05:28:37 +00:00
{
2004-04-16 05:31:08 +00:00
TurnOffHardwareVBO ();
2005-11-11 21:16:48 +00:00
if ( ! GetActualVideoModeParams (). bSmoothLines )
2003-05-27 00:20:54 +00:00
{
2004-04-16 05:06:31 +00:00
/* Fall back on the generic polygon-based line strip. */
2005-11-13 18:22:52 +00:00
RageDisplay :: DrawLineStripInternal ( v , iNumVerts , fLineWidth );
2003-05-27 00:20:54 +00:00
return ;
}
2004-04-08 08:35:38 +00:00
SendCurrentMatrices ();
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* 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. */
2005-11-13 18:22:52 +00:00
glEnable ( GL_LINE_SMOOTH );
2003-05-22 05:28:37 +00:00
2005-12-04 17:58:25 +00:00
/* 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 ;
}
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* Clamp the width to the hardware max for both lines and points (whichever
* is more restrictive). */
2005-11-13 18:22:52 +00:00
fLineWidth = clamp ( fLineWidth , g_line_range [ 0 ], g_line_range [ 1 ] );
fLineWidth = clamp ( fLineWidth , g_point_range [ 0 ], g_point_range [ 1 ] );
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* 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? */
2005-11-13 18:22:52 +00:00
glLineWidth ( fLineWidth );
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* Draw the line loop: */
SetupVertices ( v , iNumVerts );
glDrawArrays ( GL_LINE_STRIP , 0 , iNumVerts );
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
glDisable ( GL_LINE_SMOOTH );
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* 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. */
2005-11-13 18:22:52 +00:00
glPointSize ( fLineWidth );
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
/* 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 );
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
if ( mat . m [ 0 ][ 0 ] < 1e-5 && mat . m [ 1 ][ 1 ] < 1e-5 )
2003-05-27 00:20:54 +00:00
return ;
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
glEnable ( GL_POINT_SMOOTH );
2003-05-22 05:28:37 +00:00
2003-05-27 00:20:54 +00:00
SetupVertices ( v , iNumVerts );
glDrawArrays ( GL_POINTS , 0 , iNumVerts );
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
glDisable ( GL_POINT_SMOOTH );
2003-05-22 05:28:37 +00:00
}
2004-02-04 09:55:18 +00:00
void RageDisplay_OGL :: ClearAllTextures ()
2003-05-22 05:28:37 +00:00
{
2005-11-05 03:08:09 +00:00
FOREACH_ENUM2 ( TextureUnit , i )
2006-07-23 03:19:49 +00:00
SetTexture ( i , 0 );
2004-02-04 09:55:18 +00:00
// HACK: Reset the active texture to 0.
// TODO: Change all texture functions to take a stage number.
2004-05-24 03:41:49 +00:00
if ( GLExt . glActiveTextureARB )
GLExt . glActiveTextureARB ( GL_TEXTURE0_ARB );
2004-02-04 09:55:18 +00:00
}
2005-01-04 05:34:58 +00:00
int RageDisplay_OGL :: GetNumTextureUnits ()
{
if ( GLExt . glActiveTextureARB == NULL )
return 1 ;
else
return g_iMaxTextureUnits ;
}
2006-07-23 03:19:49 +00:00
void RageDisplay_OGL :: SetTexture ( TextureUnit tu , unsigned iTexture )
2004-02-04 09:55:18 +00:00
{
2004-05-24 03:41:49 +00:00
if ( GLExt . glActiveTextureARB == NULL )
2004-02-04 09:55:18 +00:00
{
// multitexture isn't supported. Ignore all textures except for 0.
2005-11-05 03:08:09 +00:00
if ( tu != 0 )
2004-02-04 09:55:18 +00:00
return ;
}
else
{
2005-11-05 03:08:09 +00:00
switch ( tu )
2004-02-04 09:55:18 +00:00
{
case 0 :
2004-05-24 03:41:49 +00:00
GLExt . glActiveTextureARB ( GL_TEXTURE0_ARB );
2004-02-04 09:55:18 +00:00
break ;
case 1 :
2004-05-24 03:41:49 +00:00
GLExt . glActiveTextureARB ( GL_TEXTURE1_ARB );
2004-02-04 09:55:18 +00:00
break ;
default :
ASSERT ( 0 );
}
}
2006-07-23 03:19:49 +00:00
if ( iTexture )
2003-07-07 01:29:18 +00:00
{
glEnable ( GL_TEXTURE_2D );
2006-07-23 03:19:49 +00:00
glBindTexture ( GL_TEXTURE_2D , iTexture );
2003-07-07 01:29:18 +00:00
}
else
{
glDisable ( GL_TEXTURE_2D );
}
2003-05-22 05:28:37 +00:00
}
2005-11-13 18:22:52 +00:00
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetTextureModeModulate ()
2003-05-22 05:28:37 +00:00
{
2005-11-13 18:22:52 +00:00
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE );
2003-05-22 05:28:37 +00:00
}
2005-01-08 22:14:08 +00:00
void RageDisplay_OGL :: SetTextureModeGlow ()
2003-05-22 05:28:37 +00:00
{
2006-02-21 20:38:21 +00:00
if ( ! GLExt . m_bARB_texture_env_combine && ! GLExt . m_bEXT_texture_env_combine )
2003-05-22 05:28:37 +00:00
{
2005-01-08 22:14:08 +00:00
/* This is changing blend state, instead of texture state, which isn't
* great, but it's better than doing nothing. */
2003-05-22 05:28:37 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE );
return ;
}
2005-01-08 22:14:08 +00:00
/* Source color is the diffuse color only: */
2005-11-13 18:22:52 +00: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 );
2005-01-08 22:14:08 +00:00
/* Source alpha is texture alpha * diffuse alpha: */
2005-11-13 18:22:52 +00: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 );
2003-05-22 05:28:37 +00:00
}
2004-02-04 09:55:18 +00:00
void RageDisplay_OGL :: SetTextureModeAdd ()
{
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_ADD );
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetTextureFiltering ( bool b )
2003-05-22 05:28:37 +00:00
{
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetBlendMode ( BlendMode mode )
2003-05-22 05:28:37 +00:00
{
glEnable ( GL_BLEND );
2006-07-27 01:34:57 +00:00
if ( GLExt . glBlendEquation != NULL )
{
if ( mode == BLEND_INVERT_DEST )
GLExt . glBlendEquation ( GL_FUNC_SUBTRACT );
else
GLExt . glBlendEquation ( GL_FUNC_ADD );
}
2003-05-22 05:28:37 +00:00
switch ( mode )
{
case BLEND_NORMAL :
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
break ;
case BLEND_ADD :
2003-10-22 01:47:40 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE );
2003-05-22 05:28:37 +00:00
break ;
2006-07-27 01:34:57 +00:00
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. */
glBlendFunc ( GL_DST_COLOR , GL_SRC_COLOR );
break ;
case BLEND_INVERT_DEST :
/* out = src - dst. The source color should almost always be #FFFFFF, to make it "1 - dst". */
glBlendFunc ( GL_ONE , GL_ONE );
break ;
2003-05-22 05:28:37 +00:00
case BLEND_NO_EFFECT :
2003-11-18 20:33:18 +00:00
/* XXX: Would it be faster and have the same effect to say glDisable(GL_COLOR_WRITEMASK)? */
2003-05-22 05:28:37 +00:00
glBlendFunc ( GL_ZERO , GL_ONE );
break ;
default :
ASSERT ( 0 );
}
}
2003-11-18 20:33:18 +00:00
bool RageDisplay_OGL :: IsZWriteEnabled () const
2003-05-22 05:28:37 +00:00
{
bool a ;
2003-11-18 20:33:18 +00:00
glGetBooleanv ( GL_DEPTH_WRITEMASK , ( unsigned char * ) & a );
2003-05-22 05:28:37 +00:00
return a ;
}
2003-11-18 20:33:18 +00:00
bool RageDisplay_OGL :: IsZTestEnabled () const
2003-05-22 05:28:37 +00:00
{
2003-11-18 20:33:18 +00:00
GLenum a ;
2003-12-10 16:42:02 +00:00
glGetIntegerv ( GL_DEPTH_FUNC , ( GLint * ) & a );
2003-11-18 20:33:18 +00:00
return a != GL_ALWAYS ;
2003-05-22 05:28:37 +00:00
}
2003-11-18 20:33:18 +00:00
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: ClearZBuffer ()
2003-05-22 05:28:37 +00:00
{
2003-11-18 20:33:18 +00:00
bool write = IsZWriteEnabled ();
SetZWrite ( true );
2006-02-01 07:52:33 +00:00
glClear ( GL_DEPTH_BUFFER_BIT );
2003-11-18 20:33:18 +00:00
SetZWrite ( write );
}
void RageDisplay_OGL :: SetZWrite ( bool b )
{
glDepthMask ( b );
}
2005-05-06 04:05:02 +00:00
void RageDisplay_OGL :: SetZBias ( float f )
2005-05-06 03:24:41 +00:00
{
2005-05-06 04:05:02 +00: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 );
2005-05-06 03:24:41 +00:00
}
2004-05-15 09:26:21 +00:00
void RageDisplay_OGL :: SetZTestMode ( ZTestMode mode )
2003-11-18 20:33:18 +00:00
{
glEnable ( GL_DEPTH_TEST );
2004-05-15 09:26:21 +00:00
switch ( mode )
{
2006-02-01 07:52:33 +00:00
case ZTEST_OFF : glDepthFunc ( GL_ALWAYS ); break ;
2004-05-15 09:26:21 +00:00
case ZTEST_WRITE_ON_PASS : glDepthFunc ( GL_LEQUAL ); break ;
case ZTEST_WRITE_ON_FAIL : glDepthFunc ( GL_GREATER ); break ;
default : ASSERT ( 0 );
}
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetTextureWrapping ( bool b )
2003-05-22 05:28:37 +00:00
{
2003-09-06 05:32:42 +00:00
GLenum mode = b ? GL_REPEAT : GL_CLAMP_TO_EDGE ;
2003-05-22 05:28:37 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , mode );
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , mode );
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetMaterial (
2004-01-06 21:25:46 +00:00
const RageColor & emissive ,
const RageColor & ambient ,
const RageColor & diffuse ,
const RageColor & specular ,
2003-05-22 05:28:37 +00:00
float shininess
)
{
2004-04-24 10:18:15 +00:00
// 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.
2005-01-30 19:50:55 +00:00
// XXX: unintended: SetLighting must be called before SetMaterial
2004-04-24 10:18:15 +00:00
GLboolean bLighting ;
glGetBooleanv ( GL_LIGHTING , & bLighting );
if ( bLighting )
{
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
{
2005-07-07 22:07:13 +00:00
RageColor c = diffuse ;
c . r += emissive . r + ambient . r ;
c . g += emissive . g + ambient . g ;
c . b += emissive . b + ambient . b ;
glColor4fv ( c );
2004-04-24 10:18:15 +00:00
}
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetLighting ( bool b )
2003-05-22 05:28:37 +00:00
{
if ( b ) glEnable ( GL_LIGHTING );
else glDisable ( GL_LIGHTING );
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetLightOff ( int index )
2003-05-22 05:28:37 +00:00
{
glDisable ( GL_LIGHT0 + index );
}
2005-11-13 18:22:52 +00:00
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetLightDirectional (
2003-05-22 05:28:37 +00:00
int index ,
2004-01-06 21:25:46 +00:00
const RageColor & ambient ,
const RageColor & diffuse ,
const RageColor & specular ,
const RageVector3 & dir )
2003-05-22 05:28:37 +00:00
{
// Light coordinates are transformed by the modelview matrix, but
// we are being passed in world-space coords.
glPushMatrix ();
glLoadIdentity ();
glEnable ( GL_LIGHT0 + index );
2005-11-13 18:22:52 +00:00
glLightfv ( GL_LIGHT0 + index , GL_AMBIENT , ambient );
glLightfv ( GL_LIGHT0 + index , GL_DIFFUSE , diffuse );
glLightfv ( GL_LIGHT0 + index , GL_SPECULAR , specular );
2003-05-22 05:28:37 +00:00
float position [ 4 ] = { dir . x , dir . y , dir . z , 0 };
2005-11-13 18:22:52 +00:00
glLightfv ( GL_LIGHT0 + index , GL_POSITION , position );
2003-05-22 05:28:37 +00:00
glPopMatrix ();
}
2004-02-04 11:05:33 +00:00
void RageDisplay_OGL :: SetCullMode ( CullMode mode )
2003-05-22 05:28:37 +00:00
{
2004-02-04 11:05:33 +00:00
switch ( mode )
{
case CULL_BACK :
2003-05-22 05:28:37 +00:00
glEnable ( GL_CULL_FACE );
2004-02-04 11:05:33 +00:00
glCullFace ( GL_BACK );
break ;
case CULL_FRONT :
glEnable ( GL_CULL_FACE );
glCullFace ( GL_FRONT );
break ;
case CULL_NONE :
2006-02-01 07:52:33 +00:00
glDisable ( GL_CULL_FACE );
2004-02-04 11:05:33 +00:00
break ;
default :
ASSERT ( 0 );
}
2003-05-22 05:28:37 +00:00
}
2003-10-03 21:38:38 +00:00
const RageDisplay :: PixelFormatDesc * RageDisplay_OGL :: GetPixelFormatDesc ( PixelFormat pf ) const
2003-05-26 03:12:12 +00:00
{
2005-09-29 17:15:12 +00:00
ASSERT ( pf < NUM_PixelFormat );
2003-05-26 03:12:12 +00:00
return & PIXEL_FORMAT_DESC [ pf ];
}
2006-01-17 01:24:40 +00:00
bool RageDisplay_OGL :: SupportsThreadedRendering ()
{
return g_pWind -> SupportsThreadedRendering ();
}
2006-01-27 09:13:03 +00:00
void RageDisplay_OGL :: BeginConcurrentRenderingMainThread ()
{
g_pWind -> BeginConcurrentRenderingMainThread ();
}
void RageDisplay_OGL :: EndConcurrentRenderingMainThread ()
{
g_pWind -> EndConcurrentRenderingMainThread ();
}
2006-01-17 01:24:40 +00:00
void RageDisplay_OGL :: BeginConcurrentRendering ()
{
g_pWind -> BeginConcurrentRendering ();
2006-07-25 20:10:56 +00:00
RageDisplay :: BeginConcurrentRendering ();
2006-01-17 01:24:40 +00:00
}
void RageDisplay_OGL :: EndConcurrentRendering ()
{
g_pWind -> EndConcurrentRendering ();
}
2006-07-24 05:53:57 +00:00
void RageDisplay_OGL :: DeleteTexture ( unsigned iTexture )
2003-05-22 05:28:37 +00:00
{
2006-07-26 03:44:27 +00:00
if ( g_mapRenderTargets . find ( iTexture ) != g_mapRenderTargets . end () )
{
delete g_mapRenderTargets [ iTexture ];
g_mapRenderTargets . erase ( iTexture );
return ;
}
2003-06-12 19:40:44 +00:00
FlushGLErrors ();
2006-07-24 05:53:57 +00:00
glDeleteTextures ( 1 , reinterpret_cast < GLuint *> ( & iTexture ) );
2004-04-12 03:07:44 +00:00
AssertNoGLError ();
2003-05-22 05:28:37 +00:00
}
2005-11-13 18:22:52 +00:00
PixelFormat RageDisplay_OGL :: GetImgPixelFormat ( RageSurface * & img , bool & bFreeImg , int width , int height , bool bPalettedTexture )
2003-06-30 02:39:56 +00:00
{
PixelFormat pixfmt = FindPixelFormat ( img -> format -> BitsPerPixel , img -> format -> Rmask , img -> format -> Gmask , img -> format -> Bmask , img -> format -> Amask );
2004-09-26 09:15:16 +00:00
/* If img is paletted, we're setting up a non-paletted texture, and color indexes
* are too small, depalettize. */
bool bSupported = true ;
if ( ! bPalettedTexture && img -> fmt . BytesPerPixel == 1 && ! g_bColorIndexTableWorks )
bSupported = false ;
2005-10-02 03:35:56 +00:00
if ( pixfmt == PixelFormat_INVALID || ! SupportsSurfaceFormat ( pixfmt ) )
2004-09-26 09:15:16 +00:00
bSupported = false ;
if ( ! bSupported )
2003-06-30 02:39:56 +00: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. */
2005-09-29 17:15:12 +00:00
pixfmt = PixelFormat_RGBA8 ;
2003-07-09 03:16:28 +00:00
ASSERT ( SupportsSurfaceFormat ( pixfmt ) );
2003-06-30 02:39:56 +00:00
const PixelFormatDesc * pfd = DISPLAY -> GetPixelFormatDesc ( pixfmt );
2004-06-14 00:51:00 +00:00
RageSurface * imgconv = CreateSurface ( width , height ,
pfd -> bpp , pfd -> masks [ 0 ], pfd -> masks [ 1 ], pfd -> masks [ 2 ], pfd -> masks [ 3 ] );
2004-08-31 01:15:12 +00:00
RageSurfaceUtils :: Blit ( img , imgconv , width , height );
2003-06-30 02:39:56 +00:00
img = imgconv ;
2005-11-13 18:22:52 +00:00
bFreeImg = true ;
2003-06-30 02:39:56 +00:00
}
else
2005-10-02 03:35:56 +00:00
{
2005-11-13 18:22:52 +00:00
bFreeImg = false ;
2005-10-02 03:35:56 +00:00
}
2003-06-30 02:39:56 +00:00
return pixfmt ;
}
2004-09-26 09:15:16 +00:00
/* If we're sending a paletted surface to a non-paletted texture, set the palette. */
void SetPixelMapForSurface ( int glImageFormat , int glTexFormat , const RageSurfacePalette * palette )
{
if ( glImageFormat != GL_COLOR_INDEX || glTexFormat == GL_COLOR_INDEX8_EXT )
{
2004-09-30 04:52:06 +00:00
glPixelTransferi ( GL_MAP_COLOR , false );
2004-09-26 09:15:16 +00:00
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 );
}
FlushGLErrors ();
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 ] );
2004-09-30 04:52:06 +00:00
glPixelTransferi ( GL_MAP_COLOR , true );
2004-09-26 09:15:16 +00:00
GLenum error = glGetError ();
ASSERT_M ( error == GL_NO_ERROR , GLToString ( error ) );
}
2003-05-26 19:42:04 +00:00
unsigned RageDisplay_OGL :: CreateTexture (
2003-05-22 05:28:37 +00:00
PixelFormat pixfmt ,
2005-11-13 18:22:52 +00:00
RageSurface * pImg ,
2004-01-23 06:20:28 +00:00
bool bGenerateMipMaps )
2003-05-22 05:28:37 +00:00
{
2005-09-29 17:15:12 +00:00
ASSERT ( pixfmt < NUM_PixelFormat );
2005-11-13 18:22:52 +00:00
ASSERT ( pImg -> w == power_of_two ( pImg -> w ) && pImg -> h == power_of_two ( pImg -> h ) );
2003-08-29 03:03:29 +00:00
2004-01-24 19:14:22 +00:00
2006-02-01 07:44:33 +00:00
/* Find the pixel format of the surface we've been given. */
2005-11-13 18:22:52 +00:00
bool bFreeImg ;
2006-02-01 07:44:33 +00:00
PixelFormat SurfacePixFmt = GetImgPixelFormat ( pImg , bFreeImg , pImg -> w , pImg -> h , pixfmt == PixelFormat_PAL );
ASSERT ( SurfacePixFmt != PixelFormat_INVALID );
2003-06-30 02:39:56 +00:00
2005-09-29 17:15:12 +00:00
GLenum glTexFormat = g_GLPixFmtInfo [ pixfmt ]. internalfmt ;
2006-02-01 07:44:33 +00:00
GLenum glImageFormat = g_GLPixFmtInfo [ SurfacePixFmt ]. format ;
GLenum glImageType = g_GLPixFmtInfo [ SurfacePixFmt ]. type ;
2003-05-22 05:28:37 +00:00
2004-09-26 09:15:16 +00:00
/* If the image is paletted, but we're not sending it to a paletted image,
* set up glPixelMap. */
2005-11-13 18:22:52 +00:00
SetPixelMapForSurface ( glImageFormat , glTexFormat , pImg -> format -> palette );
2004-09-26 09:15:16 +00:00
2004-01-24 19:35:53 +00:00
// 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
2004-01-24 22:46:06 +00:00
if ( bGenerateMipMaps && g_gluVersion < 13 )
2004-01-24 19:35:53 +00:00
{
switch ( pixfmt )
{
// OpenGL 1.1 types
2005-09-29 17:15:12 +00:00
case PixelFormat_RGBA8 :
case PixelFormat_RGB8 :
case PixelFormat_PAL :
case PixelFormat_BGR8 :
2004-01-24 19:35:53 +00:00
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 ;
}
}
// allocate OpenGL texture resource
2006-07-24 06:11:37 +00:00
unsigned int iTexHandle ;
glGenTextures ( 1 , reinterpret_cast < GLuint *> ( & iTexHandle ) );
ASSERT ( iTexHandle );
2004-01-24 19:35:53 +00:00
2006-07-24 06:11:37 +00:00
glBindTexture ( GL_TEXTURE_2D , iTexHandle );
2005-11-13 18:22:52 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR );
GLint iMinFilter ;
2004-05-18 09:05:21 +00:00
if ( bGenerateMipMaps )
{
2005-11-13 18:22:52 +00:00
if ( g_pWind -> GetActualVideoModeParams (). bTrilinearFiltering )
iMinFilter = GL_LINEAR_MIPMAP_LINEAR ;
2004-05-18 09:05:21 +00:00
else
2005-11-13 18:22:52 +00:00
iMinFilter = GL_LINEAR_MIPMAP_NEAREST ;
2004-05-18 09:05:21 +00:00
}
else
{
2005-11-13 18:22:52 +00:00
iMinFilter = GL_LINEAR ;
2004-05-18 09:05:21 +00:00
}
2005-11-13 18:22:52 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , iMinFilter );
2004-05-18 08:43:21 +00:00
2005-11-13 18:22:52 +00:00
if ( g_pWind -> GetActualVideoModeParams (). bAnisotropicFiltering &&
2005-05-28 03:54:33 +00:00
GLExt . HasExtension ( "GL_EXT_texture_filter_anisotropic" ) )
2004-05-18 08:43:21 +00:00
{
2005-11-13 18:22:52 +00:00
GLfloat fLargestSupportedAnisotropy ;
glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & fLargestSupportedAnisotropy );
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , fLargestSupportedAnisotropy );
2004-05-18 08:43:21 +00:00
}
2004-01-24 19:35:53 +00:00
SetTextureWrapping ( false );
2005-11-13 18:22:52 +00:00
glPixelStorei ( GL_UNPACK_ROW_LENGTH , pImg -> pitch / pImg -> format -> BytesPerPixel );
2004-01-24 19:35:53 +00:00
2005-09-29 17:15:12 +00:00
if ( pixfmt == PixelFormat_PAL )
2004-01-24 22:18:12 +00:00
{
2004-09-26 08:56:32 +00:00
/* The texture is paletted; set the texture palette. */
2004-01-24 22:18:12 +00:00
GLubyte palette [ 256 * 4 ];
2005-11-13 18:22:52 +00:00
memset ( palette , 0 , sizeof ( palette ) );
2004-01-24 22:18:12 +00:00
int p = 0 ;
2004-09-26 08:56:32 +00:00
/* Copy the palette to the format OpenGL expects. */
2005-11-13 18:22:52 +00:00
for ( int i = 0 ; i < pImg -> format -> palette -> ncolors ; ++ i )
2004-01-24 22:18:12 +00:00
{
2005-11-13 18:22:52 +00:00
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 ;
2004-01-24 22:18:12 +00:00
}
/* Set the palette. */
2005-11-13 18:22:52 +00:00
GLExt . glColorTableEXT ( GL_TEXTURE_2D , GL_RGBA8 , 256 , GL_RGBA , GL_UNSIGNED_BYTE , palette );
2004-01-24 22:18:12 +00:00
2005-11-13 18:22:52 +00:00
GLint iRealFormat = 0 ;
GLExt . glGetColorTableParameterivEXT ( GL_TEXTURE_2D , GL_COLOR_TABLE_FORMAT , & iRealFormat );
ASSERT ( iRealFormat == GL_RGBA8 );
2004-01-24 22:18:12 +00:00
}
2004-09-26 08:53:01 +00:00
{
ostringstream s ;
2004-10-16 21:12:29 +00:00
s << ( bGenerateMipMaps ? "gluBuild2DMipmaps" : "glTexImage2D" );
2004-09-26 08:53:01 +00:00
s << "(format " << GLToString ( glTexFormat ) <<
2005-11-13 18:22:52 +00:00
", " << pImg -> w << "x" << pImg -> h <<
2004-09-26 08:53:01 +00:00
", format " << GLToString ( glImageFormat ) <<
", type " << GLToString ( glImageType ) <<
", pixfmt " << pixfmt <<
2006-02-01 07:44:33 +00:00
", imgpixfmt " << SurfacePixFmt <<
2004-10-23 02:18:17 +00:00
")" ;
2004-09-26 08:53:01 +00:00
LOG -> Trace ( "%s" , s . str (). c_str () );
}
2003-06-12 19:40:44 +00:00
FlushGLErrors ();
2003-05-31 09:10:18 +00:00
2004-01-23 06:20:28 +00:00
if ( bGenerateMipMaps )
{
2004-01-24 19:14:22 +00:00
GLenum error = gluBuild2DMipmaps (
2004-01-23 06:20:28 +00:00
GL_TEXTURE_2D , glTexFormat ,
2005-11-13 18:22:52 +00:00
pImg -> w , pImg -> h ,
glImageFormat , glImageType , pImg -> pixels );
2004-09-26 08:53:01 +00:00
ASSERT_M ( error == 0 , ( char * ) gluErrorString ( error ) );
2004-01-23 06:20:28 +00:00
}
else
{
glTexImage2D (
GL_TEXTURE_2D , 0 , glTexFormat ,
2005-11-13 18:22:52 +00:00
pImg -> w , pImg -> h , 0 ,
glImageFormat , glImageType , pImg -> pixels );
2004-01-24 19:14:22 +00:00
GLenum error = glGetError ();
2004-09-26 08:53:01 +00:00
ASSERT_M ( error == GL_NO_ERROR , GLToString ( error ) );
2004-01-23 06:20:28 +00:00
}
2003-05-22 05:28:37 +00:00
2003-06-28 02:19:31 +00:00
/* Sanity check: */
2005-09-29 17:15:12 +00:00
if ( pixfmt == PixelFormat_PAL )
2003-05-22 05:28:37 +00:00
{
2005-11-13 18:22:52 +00:00
GLint iSize = 0 ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INDEX_SIZE_EXT ), & iSize );
if ( iSize != 8 )
RageException :: Throw ( "Thought paletted textures worked, but they don't." );
2003-05-22 05:28:37 +00:00
}
2005-11-13 18:22:52 +00:00
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 );
2003-05-22 05:28:37 +00:00
glFlush ();
2005-11-13 18:22:52 +00:00
if ( bFreeImg )
delete pImg ;
2006-07-24 06:11:37 +00:00
return iTexHandle ;
2003-05-22 05:28:37 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: UpdateTexture (
2006-07-24 06:11:37 +00:00
unsigned iTexHandle ,
2005-11-13 18:22:52 +00:00
RageSurface * pImg ,
int iXOffset , int iYOffset , int iWidth , int iHeight )
2003-05-22 05:28:37 +00:00
{
2006-07-24 06:11:37 +00:00
glBindTexture ( GL_TEXTURE_2D , iTexHandle );
2003-05-22 05:28:37 +00:00
2005-11-13 18:22:52 +00:00
bool bFreeImg ;
2006-02-01 07:44:33 +00:00
PixelFormat SurfacePixFmt = GetImgPixelFormat ( pImg , bFreeImg , iWidth , iHeight , false );
2003-06-29 08:13:18 +00:00
2005-11-13 18:22:52 +00:00
glPixelStorei ( GL_UNPACK_ROW_LENGTH , pImg -> pitch / pImg -> format -> BytesPerPixel );
2003-08-29 04:46:54 +00:00
2006-02-01 07:44:33 +00:00
GLenum glImageFormat = g_GLPixFmtInfo [ SurfacePixFmt ]. format ;
GLenum glImageType = g_GLPixFmtInfo [ SurfacePixFmt ]. type ;
2003-05-22 05:28:37 +00:00
2006-04-06 09:43:44 +00:00
/* If the image is paletted, but we're not sending it to a paletted image,
* set up glPixelMap. */
if ( pImg -> format -> palette )
{
GLenum glTexFormat = 0 ;
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D , 0 , GLenum ( GL_TEXTURE_INTERNAL_FORMAT ), ( GLint * ) & glTexFormat );
SetPixelMapForSurface ( glImageFormat , glTexFormat , pImg -> format -> palette );
}
2005-11-13 18:22:52 +00:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 ,
iXOffset , iYOffset ,
iWidth , iHeight ,
glImageFormat , glImageType , pImg -> pixels );
2003-05-22 05:28:37 +00:00
/* Must unset PixelStore when we're done! */
2005-11-13 18:22:52 +00:00
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 );
2003-05-22 05:28:37 +00:00
glFlush ();
2003-06-29 08:13:18 +00:00
2005-11-13 18:22:52 +00:00
if ( bFreeImg )
delete pImg ;
2003-05-22 05:28:37 +00:00
}
2006-07-26 19:18:21 +00:00
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 ();
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 ()
{
if ( m_iDepthBufferHandle )
GLExt . glDeleteRenderbuffersEXT ( 1 , reinterpret_cast < GLuint *> ( & m_iDepthBufferHandle ) );
if ( m_iFrameBufferHandle )
GLExt . glDeleteFramebuffersEXT ( 1 , reinterpret_cast < GLuint *> ( & m_iFrameBufferHandle ) );
if ( m_iTexHandle )
glDeleteTextures ( 1 , reinterpret_cast < GLuint *> ( & m_iTexHandle ) );
}
void RenderTarget_FramebufferObject :: Create ( const RenderTargetParam & param , int & iTextureWidthOut , int & iTextureHeightOut )
{
FlushGLErrors ();
// Allocate OpenGL texture resource
glGenTextures ( 1 , reinterpret_cast < GLuint *> ( & m_iTexHandle ) );
ASSERT ( m_iTexHandle );
int iTextureWidth = power_of_two ( param . iWidth );
int iTextureHeight = power_of_two ( param . iHeight );
iTextureWidthOut = iTextureWidth ;
iTextureHeightOut = iTextureHeight ;
glBindTexture ( GL_TEXTURE_2D , m_iTexHandle );
glTexImage2D ( GL_TEXTURE_2D , 0 , param . bWithAlpha ? GL_RGBA8 : GL_RGB8 ,
iTextureWidth , iTextureHeight , 0 , param . bWithAlpha ? GL_RGBA : GL_RGB , GL_UNSIGNED_BYTE , NULL );
AssertNoGLError ();
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. */
GLExt . glGenFramebuffersEXT ( 1 , reinterpret_cast < GLuint *> ( & m_iFrameBufferHandle ) );
ASSERT ( m_iFrameBufferHandle );
/* Attach the texture to it. */
GLExt . glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , m_iFrameBufferHandle );
GLExt . glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_2D , m_iTexHandle , 0 );
AssertNoGLError ();
/* Attach a depth buffer, if requested. */
if ( param . bWithDepthBuffer )
{
GLExt . glGenRenderbuffersEXT ( 1 , reinterpret_cast < GLuint *> ( & m_iDepthBufferHandle ) );
ASSERT ( m_iDepthBufferHandle );
GLExt . glRenderbufferStorageEXT ( GL_RENDERBUFFER_EXT , GL_DEPTH_COMPONENT16 , iTextureWidth , iTextureHeight );
GLExt . glFramebufferRenderbufferEXT ( GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT , GL_RENDERBUFFER_EXT , m_iDepthBufferHandle );
}
GLenum status = GLExt . glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT );
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 :
ASSERT ( 0 );
}
2006-07-27 01:30:55 +00:00
GLExt . glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 );
2006-07-26 19:18:21 +00:00
}
void RenderTarget_FramebufferObject :: StartRenderingTo ()
{
GLExt . glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , m_iFrameBufferHandle );
}
void RenderTarget_FramebufferObject :: FinishRenderingTo ()
{
GLExt . glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 );
}
2006-07-26 03:44:27 +00:00
bool RageDisplay_OGL :: SupportsRenderToTexture () const
{
2006-07-26 19:18:21 +00:00
return GLExt . m_bGL_EXT_framebuffer_object || g_pWind -> SupportsRenderToTexture ();
2006-07-26 03:44:27 +00: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.
*/
unsigned RageDisplay_OGL :: CreateRenderTarget ( const RenderTargetParam & param , int & iTextureWidthOut , int & iTextureHeightOut )
{
2006-07-26 19:18:21 +00:00
RenderTarget * pTarget ;
if ( GLExt . m_bGL_EXT_framebuffer_object )
2006-07-28 21:03:57 +00:00
pTarget = new RenderTarget_FramebufferObject ;
2006-07-26 19:18:21 +00:00
else
2006-07-28 21:06:13 +00:00
pTarget = g_pWind -> CreateRenderTarget ();
2006-07-28 21:03:57 +00:00
pTarget -> Create ( param , iTextureWidthOut , iTextureHeightOut );
2006-07-26 19:18:21 +00:00
2006-07-26 03:44:27 +00:00
unsigned iTexture = pTarget -> GetTexture ();
ASSERT ( g_mapRenderTargets . find ( iTexture ) == g_mapRenderTargets . end () );
g_mapRenderTargets [ iTexture ] = pTarget ;
return iTexture ;
}
void RageDisplay_OGL :: SetRenderTarget ( unsigned iTexture , bool bPreserveTexture )
{
if ( iTexture == 0 )
{
g_bInvertY = false ;
glFrontFace ( GL_CCW );
if ( g_pCurrentRenderTarget )
g_pCurrentRenderTarget -> FinishRenderingTo ();
g_pCurrentRenderTarget = NULL ;
return ;
}
/* If we already had a render target, disable it. */
if ( g_pCurrentRenderTarget != NULL )
SetRenderTarget ( 0 , true );
/* Enable the new render target. */
ASSERT ( g_mapRenderTargets . find ( iTexture ) != g_mapRenderTargets . end () );
RenderTarget * pTarget = g_mapRenderTargets [ iTexture ];
pTarget -> StartRenderingTo ();
g_pCurrentRenderTarget = pTarget ;
/* If this render target implementation flips Y, compensate. Inverting will
* switch the winding order. */
g_bInvertY = pTarget -> InvertY ();
if ( g_bInvertY )
glFrontFace ( GL_CW );
/* The render target may be in a different OpenGL context, so re-send
* state. */
SetDefaultRenderStates ();
/* Clear the texture, if requested. Always set the associated state, for
* consistency. */
glClearColor ( 0 , 0 , 0 , 0 );
SetZWrite ( true );
if ( ! bPreserveTexture )
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
2004-06-19 21:00:38 +00:00
void RageDisplay_OGL :: SetPolygonMode ( PolygonMode pm )
{
GLenum m ;
switch ( pm )
{
case POLYGON_FILL : m = GL_FILL ; break ;
case POLYGON_LINE : m = GL_LINE ; break ;
2006-02-01 07:52:33 +00:00
default : ASSERT ( 0 ); return ;
2004-06-19 21:00:38 +00:00
}
glPolygonMode ( GL_FRONT_AND_BACK , m );
}
2004-06-20 01:26:28 +00:00
void RageDisplay_OGL :: SetLineWidth ( float fWidth )
2004-06-19 21:00:38 +00:00
{
2004-06-20 01:26:28 +00:00
glLineWidth ( fWidth );
2004-06-19 21:00:38 +00:00
}
2006-01-22 01:00:06 +00:00
RString RageDisplay_OGL :: GetTextureDiagnostics ( unsigned id ) const
2003-06-22 01:53:04 +00:00
{
2006-01-22 01:00:06 +00:00
return RString ();
2003-06-22 01:53:04 +00:00
}
2003-05-26 19:42:04 +00:00
void RageDisplay_OGL :: SetAlphaTest ( bool b )
2003-05-22 05:28:37 +00:00
{
glAlphaFunc ( GL_GREATER , 0.01f );
if ( b )
glEnable ( GL_ALPHA_TEST );
else
glDisable ( GL_ALPHA_TEST );
}
2003-05-25 00:43:44 +00:00
2003-09-21 18:07:29 +00:00
2003-07-09 03:16:28 +00: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.
*/
bool RageDisplay_OGL :: SupportsSurfaceFormat ( PixelFormat pixfmt )
{
2005-09-29 17:15:12 +00:00
switch ( g_GLPixFmtInfo [ pixfmt ]. type )
2003-07-09 03:16:28 +00:00
{
case GL_UNSIGNED_SHORT_1_5_5_5_REV :
2005-01-30 19:50:55 +00:00
return GLExt . m_bGL_EXT_bgra && g_bReversePackedPixelsWorks ;
2003-07-09 03:16:28 +00:00
default :
return true ;
}
}
2003-11-29 17:56:09 +00:00
2005-10-19 23:52:16 +00:00
bool RageDisplay_OGL :: SupportsTextureFormat ( PixelFormat pixfmt , bool bRealtime )
2003-11-29 17:56:09 +00: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. */
2005-10-19 23:52:16 +00:00
if ( bRealtime && ! SupportsSurfaceFormat ( pixfmt ) )
2003-11-29 17:56:09 +00:00
return false ;
2005-09-29 17:15:12 +00:00
switch ( g_GLPixFmtInfo [ pixfmt ]. format )
2003-11-29 17:56:09 +00:00
{
case GL_COLOR_INDEX :
2004-05-24 03:41:49 +00:00
return GLExt . glColorTableEXT && GLExt . glGetColorTableParameterivEXT ;
2003-11-29 17:56:09 +00:00
case GL_BGR :
case GL_BGRA :
2005-01-30 19:50:55 +00:00
return GLExt . m_bGL_EXT_bgra ;
2003-11-29 17:56:09 +00:00
default :
return true ;
}
}
2004-01-06 19:54:13 +00:00
2005-10-21 06:36:08 +00:00
bool RageDisplay_OGL :: SupportsPerVertexMatrixScale ()
{
2006-02-22 21:22:33 +00: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.
return GLExt . glGenBuffersARB && g_bTextureMatrixShader != 0 ;
2005-10-21 06:36:08 +00:00
}
2005-01-22 03:39:39 +00:00
void RageDisplay_OGL :: SetSphereEnvironmentMapping ( bool b )
2004-01-06 19:54:13 +00:00
{
if ( b )
{
2005-11-13 18:22:52 +00: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 );
2004-01-06 19:54:13 +00:00
}
else
{
2005-11-13 18:22:52 +00:00
glDisable ( GL_TEXTURE_GEN_S );
glDisable ( GL_TEXTURE_GEN_T );
2004-01-06 19:54:13 +00:00
}
}
2004-05-06 00:42:06 +00:00
/*
* Copyright (c) 2001-2004 Chris Danford, Glenn Maynard
* 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.
*/