diff --git a/src/RageDisplay_GLES2.cpp b/src/RageDisplay_GLES2.cpp index 905f1256bf..06982ebb98 100644 --- a/src/RageDisplay_GLES2.cpp +++ b/src/RageDisplay_GLES2.cpp @@ -1,435 +1,228 @@ #include "global.h" -#include "RageDisplay_OGL.h" -#include "RageDisplay_OGL_Helpers.h" -using namespace RageDisplay_Legacy_Helpers; - -#include "RageFile.h" -#include "RageSurface.h" -#include "RageSurfaceUtils.h" +#include "RageDisplay.h" +#include "RageDisplay_GLES2.h" #include "RageUtil.h" #include "RageLog.h" -#include "RageTextureManager.h" +#include "RageTimer.h" #include "RageMath.h" #include "RageTypes.h" #include "RageUtil.h" -#include "EnumHelper.h" -#include "Foreach.h" +#include "RageSurface.h" +#include "RageTextureManager.h" + #include "DisplayResolutions.h" -#include "LocalizedString.h" #include "arch/LowLevelWindow/LowLevelWindow.h" -#include - -#if defined(WINDOWS) -#include -#endif - -#if defined(_MSC_VER) -#pragma comment(lib, "opengl32.lib") -#pragma comment(lib, "glu32.lib") -#endif +#include #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]; - -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 GLuint g_bTextureMatrixShader = 0; - -static map 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() +namespace { -#if defined(ENDIAN_LITTLE) - static bool bInitialized = false; - if (bInitialized) - 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. */ - if (g_GLPixFmtInfo[i].type != GL_UNSIGNED_BYTE || pf.bpp == 8) - continue; - - for( int mask = 0; mask < 4; ++mask) + RageDisplay::PixelFormatDesc + PIXEL_FORMAT_DESC[NUM_PixelFormat] = { { - int m = pf.masks[mask]; - switch( pf.bpp ) + /* 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, + } + }; + + LowLevelWindow *g_pWind; + + void FixLittleEndian() + { +#if defined(ENDIAN_LITTLE) + static bool bInitialized = false; + if (bInitialized) + 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. */ + if (g_GLPixFmtInfo[i].type != GL_UNSIGNED_BYTE || pf.bpp == 8) + continue; + + for( int mask = 0; mask < 4; ++mask) { - case 24: m = Swap24(m); break; - case 32: m = Swap32(m); break; - default: ASSERT(0); + int m = pf.masks[mask]; + switch( pf.bpp ) + { + case 24: m = Swap24(m); break; + case 32: m = Swap32(m); break; + default: ASSERT(0); + } + pf.masks[mask] = m; } - pf.masks[mask] = m; } - } #endif + } + namespace Caps + { + int iMaxTextureUnits = 1; + int iMaxTextureSize = 256; + } + namespace State + { + bool bZTestEnabled = false; + bool bZWriteEnabled = false; + bool bAlphaTestEnabled = false; + } } -static void TurnOffHardwareVBO() +RageDisplay_GLES2::RageDisplay_GLES2() { - /* not an option for GLES2! */ -} - -RageDisplay_Legacy::RageDisplay_Legacy() -{ - LOG->Trace( "RageDisplay_Legacy::RageDisplay_Legacy()" ); - LOG->MapLog("renderer", "Current renderer: OpenGL"); + LOG->Trace( "RageDisplay_GLES2::RageDisplay_GLES2()" ); + LOG->MapLog("renderer", "Current renderer: OpenGL ES 2.0"); FixLittleEndian(); - RageDisplay_Legacy_Helpers::Init(); +// RageDisplay_GLES2_Helpers::Init(); g_pWind = NULL; - g_bTextureMatrixShader = 0; } -RString GetInfoLog( GLuint h ) -{ - GLint iLength; - glGetProgramParameterivARB( h, GL_PROGRAM_INFO_LOG_LENGTH, &iLength ); - if (!iLength) - return RString(); - - GLchar *pInfoLog = new GLchar[iLength]; - glGetProgramInfoLog( h, iLength, &iLength, pInfoLog ); - RString sRet = pInfoLog; - delete [] pInfoLog; - TrimRight( sRet ); - return sRet; -} - -GLuint CompileShader( GLenum ShaderType, RString sFile, vector asDefines ) -{ - RString sBuffer; - { - RageFile file; - if (!file.Open(sFile)) - { - LOG->Warn( "Error compiling shader %s: %s", sFile.c_str(), file.GetError().c_str() ); - return 0; - } - - if (file.Read(sBuffer, file.GetFileSize()) == -1) - { - LOG->Warn( "Error compiling shader %s: %s", sFile.c_str(), file.GetError().c_str() ); - return 0; - } - } - - LOG->Trace( "Compiling shader %s", sFile.c_str() ); - - GLuint hShader = glCreateShader(ShaderType); - vector apData; - vector 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() ); - glShaderSource( hShader, apData.size(), &apData[0], &aiLength[0] ); - - glCompileShader( hShader ); - - RString sInfo = GetInfoLog( hShader ); - - GLint bCompileStatus = GL_FALSE; - glGetShaderParameteriv( hShader, GL_COMPILE_STATUS, &bCompileStatus ); - if (!bCompileStatus) - { - LOG->Warn( "Error compiling shader %s:\n%s", sFile.c_str(), sInfo.c_str() ); - glDeleteShader( hShader ); - return 0; - } - - if (!sInfo.empty()) - LOG->Trace( "Messages compiling shader %s:\n%s", sFile.c_str(), sInfo.c_str() ); - - return hShader; -} - -GLuint LoadShader( GLenum ShaderType, RString sFile, vector asDefines ) -{ - // XXX: dumb, but I don't feel like refactoring ragedisplay for this. -Colby - GLuint secondaryShader = 0; - if (sFile == "Data/Shaders/GLSL/Cel.vert") - secondaryShader = CompileShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Cel.frag", asDefines); - else if (sFile == "Data/Shaders/GLSL/Shell.vert") - secondaryShader = CompileShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Shell.frag", asDefines); - - GLuint hShader = CompileShader( ShaderType, sFile, asDefines ); - if (hShader == 0) - return 0; - - GLuint hProgram = glCreateProgram(); - glAttachShader( hProgram, hShader ); - - if (secondaryShader) - { - glAttachShader( hProgram, secondaryShader ); - glDeleteShader( secondaryShader ); - } - glDeleteProgram( hShader ); - - // Link the program. - glLinkProgram( hProgram ); - GLint bLinkStatus = false; - glGetProgramParameteriv( hProgram, GL_LINK_STATUS, &bLinkStatus ); - - if (!bLinkStatus) - { - LOG->Warn( "Error linking shader %s: %s", sFile.c_str(), GetInfoLog(hProgram).c_str() ); - glDeleteProgram( hProgram ); - return 0; - } - return hProgram; -} - -static int g_iAttribTextureMatrixScale; - -/* XXX: refactor -Colby */ -static GLuint g_bUnpremultiplyShader = 0; -static GLuint g_bColorBurnShader = 0; -static GLuint g_bColorDodgeShader = 0; -static GLuint g_bVividLightShader = 0; -static GLuint g_hHardMixShader = 0; -static GLuint g_hOverlayShader = 0; -static GLuint g_hScreenShader = 0; -static GLuint g_hYUYV422Shader = 0; -static GLuint g_gShellShader = 0; -static GLuint g_gCelShader = 0; - -void InitShaders() -{ - vector asDefines; - - // used for scrolling textures (I think) - g_bTextureMatrixShader = LoadShader( GL_VERTEX_SHADER, "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, "Data/Shaders/GLSL/Shell.vert", asDefines ); - g_gCelShader = LoadShader( GL_VERTEX_SHADER, "Data/Shaders/GLSL/Cel.vert", asDefines ); - - // effects - g_bUnpremultiplyShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Unpremultiply.frag", asDefines ); - g_bColorBurnShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Color burn.frag", asDefines ); - g_bColorDodgeShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Color dodge.frag", asDefines ); - g_bVividLightShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Vivid light.frag", asDefines ); - g_hHardMixShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Hard mix.frag", asDefines ); - g_hOverlayShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Overlay.frag", asDefines ); - g_hScreenShader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/Screen.frag", asDefines ); - g_hYUYV422Shader = LoadShader( GL_FRAGMENT_SHADER, "Data/Shaders/GLSL/YUYV422.frag", asDefines ); - - // Bind attributes. - if (g_bTextureMatrixShader) - { - FlushGLErrors(); - g_iAttribTextureMatrixScale = glGetAttribLocation( g_bTextureMatrixShader, "TextureMatrixScale" ); - if (g_iAttribTextureMatrixScale == -1) - { - LOG->Trace( "Scaling shader link failed: couldn't bind attribute \"TextureMatrixScale\"" ); - glDeleteProgram( g_bTextureMatrixShader ); - g_bTextureMatrixShader = 0; - } - else - { - AssertNoGLError(); - - glVertexAttrib2f( g_iAttribTextureMatrixScale, 1, 1 ); - GLenum iError = glGetError(); - if (iError == GL_INVALID_OPERATION) - { - LOG->Trace( "Scaling shader failed: glVertexAttrib2f returned GL_INVALID_OPERATION" ); - glDeleteProgram( g_bTextureMatrixShader ); - g_bTextureMatrixShader = 0; - } - else - { - ASSERT_M( iError == GL_NO_ERROR, GLToString(iError) ); - } - } - } -} - -static LocalizedString OBTAIN_AN_UPDATED_VIDEO_DRIVER ( "RageDisplay_GLES2", "Obtain an updated driver from your video card manufacturer." ); -RString RageDisplay_Legacy::Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer ) +RString +RageDisplay_GLES2::Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer ) { g_pWind = LowLevelWindow::Create(); @@ -438,14 +231,17 @@ RString RageDisplay_Legacy::Init( const VideoModeParams &p, bool bAllowUnacceler if (sError != "") return sError; + // Get GPU capabilities up front so we don't have to query later. + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &Caps::iMaxTextureSize ); + glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &Caps::iMaxTextureUnits ); + // 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) ); + LOG->Info( "OGL Max texture size: %i", Caps::iMaxTextureSize ); + LOG->Info( "OGL Texture units: %i", Caps::iMaxTextureUnits ); /* Pretty-print the extension string: */ LOG->Info( "OGL Extensions:" ); @@ -498,197 +294,34 @@ RString RageDisplay_Legacy::Init( const VideoModeParams &p, bool bAllowUnacceler } } - if (g_pWind->IsSoftwareRenderer(sError)) - { - if (!bAllowUnacceleratedRenderer) - return sError + " " + OBTAIN_AN_UPDATED_VIDEO_DRIVER.GetValue() + "\n\n"; - LOG->Warn( "Low-performance OpenGL renderer: %s", sError.c_str() ); - } + glewExperimental = true; + glewInit(); /* 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 ); + //glGetFloatv( GL_LINE_WIDTH_RANGE, g_line_range ); + //glGetFloatv( GL_POINT_SIZE_RANGE, g_point_range ); return RString(); } -RageDisplay_Legacy::~RageDisplay_Legacy() -{ - delete g_pWind; -} - -void RageDisplay_Legacy::GetDisplayResolutions( DisplayResolutions &out ) const -{ - out.clear(); - g_pWind->GetDisplayResolutions( out ); -} - -static void CheckPalettedTextures() -{ - RString sError; - do - { - /* 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(); \ - if (glError != GL_NO_ERROR) { \ - 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)" ); - if (iFormat != glTexFormat) - { - 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)); - glColorTableEXT(GL_PROXY_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, palette); - 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)" ); - if (iBits > iSize || iSize > 8) - { - sError = ssprintf( "Expected %i-bit palette, got a %i-bit one instead", iBits, int(iSize) ); - break; - } - - GLint iRealWidth = 0; - glGetColorTableParameterivEXT( GL_PROXY_TEXTURE_2D, GL_COLOR_TABLE_WIDTH, &iRealWidth ); - GL_CHECK_ERROR( "glGetColorTableParameterivEXT(GL_COLOR_TABLE_WIDTH)" ); - if (iRealWidth != 1 << iBits) - { - sError = ssprintf( "GL_COLOR_TABLE_WIDTH returned %i instead of %i", int(iRealWidth), 1 << iBits ); - break; - } - - GLint iRealFormat = 0; - glGetColorTableParameterivEXT( GL_PROXY_TEXTURE_2D, GL_COLOR_TABLE_FORMAT, &iRealFormat ); - GL_CHECK_ERROR( "glGetColorTableParameterivEXT(GL_COLOR_TABLE_FORMAT)" ); - if (iRealFormat != GL_RGBA8) - { - sError = ssprintf( "GL_COLOR_TABLE_FORMAT returned %s instead of GL_RGBA8", GLToString(iRealFormat).c_str() ); - break; - } - } while(0); -#undef GL_CHECK_ERROR - - if (sError == "") - 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. */ - glColorTableEXT = NULL; - glGetColorTableParameterivEXT = NULL; - 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(); - if (glError == GL_NO_ERROR) - { - 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 ); - - glewInit(); - - g_iMaxTextureUnits = 1; - - glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, (GLint *) &g_iMaxTextureUnits ); - - CheckPalettedTextures(); - CheckReversePackedPixels(); - - { - 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. */ - LOG->Info( "GL_MAX_PIXEL_MAP_TABLE is only %d", int(iMaxTableSize) ); - g_bColorIndexTableWorks = false; - } - else - { - g_bColorIndexTableWorks = true; - } - } -} - -void RageDisplay_Legacy::ResolutionChanged() -{ - //LOG->Warn( "RageDisplay_Legacy::ResolutionChanged" ); - - /* Clear any junk that's in the framebuffer. */ - if (BeginFrame()) - 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. -RString RageDisplay_Legacy::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) +RString RageDisplay_GLES2::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) { - //LOG->Warn( "RageDisplay_Legacy::TryVideoMode( %d, %d, %d, %d, %d, %d )", p.windowed, p.width, p.height, p.bpp, p.rate, p.vsync ); + VideoModeParams vm = p; + vm.windowed = 1; // force windowed until I trust this thing. + LOG->Warn( "RageDisplay_GLES2::TryVideoMode( %d, %d, %d, %d, %d, %d )", + vm.windowed, vm.width, vm.height, vm.bpp, vm.rate, vm.vsync ); RString err; - err = g_pWind->TryVideoMode( p, bNewDeviceOut ); + err = g_pWind->TryVideoMode( vm, bNewDeviceOut ); if (err != "") 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(); + // NOTE: This isn't needed in an actual GLES2 context... + glewInit(); if (bNewDeviceOut) { @@ -699,29 +332,27 @@ RString RageDisplay_Legacy::TryVideoMode( const VideoModeParams &p, bool &bNewDe /* 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(); + //FOREACHM( unsigned, RenderTarget *, g_mapRenderTargets, rt ) + // delete rt->second; + //g_mapRenderTargets.clear(); /* Recreate all vertex buffers. */ - InvalidateObjects(); + //InvalidateObjects(); - InitShaders(); + //InitShaders(); } ResolutionChanged(); - return RString(); // successfully set mode + return RString(); } -int RageDisplay_Legacy::GetMaxTextureSize() const +int RageDisplay_GLES2::GetMaxTextureSize() const { - GLint size; - glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size ); - return size; + return Caps::iMaxTextureSize; } -bool RageDisplay_Legacy::BeginFrame() +bool RageDisplay_GLES2::BeginFrame() { /* We do this in here, rather than ResolutionChanged, or we won't update the * viewport for the concurrent rendering context. */ @@ -730,17 +361,18 @@ bool RageDisplay_Legacy::BeginFrame() glViewport( 0, 0, fWidth, fHeight ); - glClearColor( 0,0,0,0 ); + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); SetZWrite( true ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); return RageDisplay::BeginFrame(); } -void RageDisplay_Legacy::EndFrame() +void RageDisplay_GLES2::EndFrame() { glFlush(); + // XXX: This is broken on NVidia, as their xrandr sucks. FrameLimitBeforeVsync( g_pWind->GetActualVideoModeParams().rate ); g_pWind->SwapBuffers(); FrameLimitAfterVsync(); @@ -750,920 +382,227 @@ void RageDisplay_Legacy::EndFrame() RageDisplay::EndFrame(); } -RageSurface* RageDisplay_Legacy::CreateScreenshot() +RageDisplay_GLES2::~RageDisplay_GLES2() { - int width = g_pWind->GetActualVideoModeParams().width; - int height = g_pWind->GetActualVideoModeParams().height; + delete g_pWind; +} - 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 ); +void +RageDisplay_GLES2::GetDisplayResolutions( DisplayResolutions &out ) const +{ + out.clear(); + g_pWind->GetDisplayResolutions( out ); +} - DebugFlushGLErrors(); +RageSurface* +RageDisplay_GLES2::CreateScreenshot() +{ + const PixelFormatDesc &desc = PIXEL_FORMAT_DESC[PixelFormat_RGB8]; + RageSurface *image = CreateSurface( + 640, 480, desc.bpp, + desc.masks[0], desc.masks[1], desc.masks[2], desc.masks[3] ); - 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 ); + memset( image->pixels, 0, 480*image->pitch ); return image; } -RageSurface *RageDisplay_Legacy::GetTexture( unsigned iTexture ) +const RageDisplay::PixelFormatDesc* +RageDisplay_GLES2::GetPixelFormatDesc(PixelFormat pf) const { - if (iTexture == 0) - 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; + ASSERT( pf >= 0 && pf < NUM_PixelFormat ); + return &PIXEL_FORMAT_DESC[pf]; } -VideoModeParams RageDisplay_Legacy::GetActualVideoModeParams() const +RageMatrix +RageDisplay_GLES2::GetOrthoMatrix( float l, float r, float b, float t, float zn, float zf ) { - return g_pWind->GetActualVideoModeParams(); + RageMatrix m( + 2/(r-l), 0, 0, 0, + 0, 2/(t-b), 0, 0, + 0, 0, -2/(zf-zn), 0, + -(r+l)/(r-l), -(t+b)/(t-b), -(zf+zn)/(zf-zn), 1 ); + return m; } -static void SetupVertices( const RageSpriteVertex v[], int iNumVerts ) -{ - static float *Vertex, *Texture, *Normal; - static GLubyte *Color; - static int Size = 0; - if (iNumVerts > Size) - { - 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]; - } - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - - glEnableClientState( GL_VERTEX_ARRAY ); - glVertexAttribPointer( 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 ); - - glClientActiveTexture( GL_TEXTURE1 ); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - glTexCoordPointer( 2, GL_FLOAT, 0, Texture ); - glClientActiveTexture( GL_TEXTURE0 ); - - glEnableClientState( GL_NORMAL_ARRAY ); - glNormalPointer( GL_FLOAT, 0, Normal ); -} - -void RageDisplay_Legacy::SendCurrentMatrices() -{ - RageMatrix projection; - RageMatrixMultiply( &projection, GetCentering(), GetProjectionTop() ); - - if (g_bInvertY) - { - 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 +class RageCompiledGeometryGLES2 : public RageCompiledGeometry { public: void Allocate( const vector &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()) ); + // TODO } void Change( const vector &vMeshes ) { - for( unsigned i=0; i &Vertices = mesh.Vertices; - const vector &Triangles = mesh.Triangles; - - for( unsigned j=0; jTrace( 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 ); + // TOO } - -protected: - vector m_vPosition; - vector m_vTexture; - vector m_vNormal; - vector m_vTriangles; - vector m_vTexMatrixScale; }; -class InvalidateObject; -static set g_InvalidateList; -class InvalidateObject +RageCompiledGeometry* +RageDisplay_GLES2::CreateCompiledGeometry() { -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(); + return new RageCompiledGeometryGLES2; } -// TODO: interleaved arrays -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 &vMeshes ); - void Change( const vector &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(); - - glDeleteBuffers( 1, &m_nPositions ); - DebugAssertNoGLError(); - glDeleteBuffers( 1, &m_nTextureCoords ); - DebugAssertNoGLError(); - glDeleteBuffers( 1, &m_nNormals ); - DebugAssertNoGLError(); - glDeleteBuffers( 1, &m_nTriangles ); - DebugAssertNoGLError(); - glDeleteBuffers( 1, &m_nTextureMatrixScale ); - DebugAssertNoGLError(); -} - -void RageCompiledGeometryHWOGL::AllocateBuffers() -{ - DebugFlushGLErrors(); - - if (!m_nPositions) - { - glGenBuffers( 1, &m_nPositions ); - DebugAssertNoGLError(); - } - - if (!m_nTextureCoords) - { - glGenBuffers( 1, &m_nTextureCoords ); - DebugAssertNoGLError(); - } - - if (!m_nNormals) - { - glGenBuffers( 1, &m_nNormals ); - DebugAssertNoGLError(); - } - - if (!m_nTriangles) - { - glGenBuffers( 1, &m_nTriangles ); - DebugAssertNoGLError(); - } - - if (!m_nTextureMatrixScale) - { - glGenBuffers( 1, &m_nTextureMatrixScale ); - DebugAssertNoGLError(); - } -} - -void RageCompiledGeometryHWOGL::UploadData() -{ - DebugFlushGLErrors(); - - glBindBuffer(GL_ARRAY_BUFFER, m_nPositions); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector3), - &m_vPosition[0], - GL_STATIC_DRAW); - DebugAssertNoGLError(); - - glBindBuffer(GL_ARRAY_BUFFER, m_nTextureCoords); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector2), - &m_vTexture[0], - GL_STATIC_DRAW); - DebugAssertNoGLError(); - - glBindBuffer(GL_ARRAY_BUFFER, m_nNormals); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector3), - &m_vNormal[0], - GL_STATIC_DRAW); - DebugAssertNoGLError(); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nTriangles); - DebugAssertNoGLError(); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - GetTotalTriangles()*sizeof(msTriangle), - &m_vTriangles[0], - GL_STATIC_DRAW); - DebugAssertNoGLError(); - - - if (m_bAnyNeedsTextureMatrixScale) - { - glBindBuffer(GL_ARRAY_BUFFER, m_nTextureMatrixScale); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector2), - &m_vTexMatrixScale[0], - GL_STATIC_DRAW); - 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 &vMeshes ) -{ - DebugFlushGLErrors(); - - RageCompiledGeometrySWOGL::Allocate( vMeshes ); - glBindBuffer( GL_ARRAY_BUFFER, m_nPositions ); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector3), - NULL, - GL_STATIC_DRAW ); - DebugAssertNoGLError(); - - glBindBuffer( GL_ARRAY_BUFFER, m_nTextureCoords ); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector2), - NULL, - GL_STATIC_DRAW ); - DebugAssertNoGLError(); - - glBindBuffer( GL_ARRAY_BUFFER, m_nNormals ); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector3), - NULL, - GL_STATIC_DRAW ); - DebugAssertNoGLError(); - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_nTriangles ); - DebugAssertNoGLError(); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - GetTotalTriangles()*sizeof(msTriangle), - NULL, - GL_STATIC_DRAW ); - DebugAssertNoGLError(); - - glBindBuffer( GL_ARRAY_BUFFER, m_nTextureMatrixScale ); - DebugAssertNoGLError(); - glBufferData( - GL_ARRAY_BUFFER, - GetTotalVertices()*sizeof(RageVector2), - NULL, - GL_STATIC_DRAW ); -} - -void RageCompiledGeometryHWOGL::Change( const vector &vMeshes ) -{ - RageCompiledGeometrySWOGL::Change( vMeshes ); - - UploadData(); -} - -void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const -{ - DebugFlushGLErrors(); - - const MeshInfo& meshInfo = m_vMeshInfo[iMeshIndex]; - if (!meshInfo.iVertexCount || !meshInfo.iTriangleCount) - return; - - glEnableClientState(GL_VERTEX_ARRAY); - DebugAssertNoGLError(); - glBindBuffer( GL_ARRAY_BUFFER, m_nPositions ); - DebugAssertNoGLError(); - glVertexPointer(3, GL_FLOAT, 0, NULL ); - DebugAssertNoGLError(); - - glDisableClientState(GL_COLOR_ARRAY); - DebugAssertNoGLError(); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - DebugAssertNoGLError(); - glBindBuffer( GL_ARRAY_BUFFER, m_nTextureCoords ); - 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 ); - - if (bLighting || bTextureGenS || bTextureGenT) - { - glEnableClientState(GL_NORMAL_ARRAY); - DebugAssertNoGLError(); - glBindBuffer( GL_ARRAY_BUFFER, m_nNormals ); - DebugAssertNoGLError(); - glNormalPointer(GL_FLOAT, 0, NULL); - DebugAssertNoGLError(); - } - else - { - glDisableClientState(GL_NORMAL_ARRAY); - DebugAssertNoGLError(); - } - - if (meshInfo.m_bNeedsTextureMatrixScale) - { - if (g_bTextureMatrixShader != 0) - { - /* 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. */ - glEnableVertexAttribArray( g_iAttribTextureMatrixScale ); - DebugAssertNoGLError(); - glBindBuffer( GL_ARRAY_BUFFER, m_nTextureMatrixScale ); - DebugAssertNoGLError(); - glVertexAttribPointer( g_iAttribTextureMatrixScale, 2, GL_FLOAT, false, 0, NULL ); - DebugAssertNoGLError(); - - glUseProgramObject( g_bTextureMatrixShader ); - 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(); - } - } - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_nTriangles ); - DebugAssertNoGLError(); - -#define BUFFER_OFFSET(o) ((char*)(o)) - - ASSERT( glDrawRangeElements); - glDrawRangeElements( - 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(); - - if (meshInfo.m_bNeedsTextureMatrixScale && g_bTextureMatrixShader != 0) - { - glDisableVertexAttribArray( g_iAttribTextureMatrixScale ); - glUseProgram( 0 ); - } -} - -RageCompiledGeometry* RageDisplay_Legacy::CreateCompiledGeometry() -{ - return new RageCompiledGeometryHWOGL; -} - -void RageDisplay_Legacy::DeleteCompiledGeometry( RageCompiledGeometry* p ) +void +RageDisplay_GLES2::DeleteCompiledGeometry( RageCompiledGeometry *p ) { delete p; } -void RageDisplay_Legacy::DrawQuadsInternal( const RageSpriteVertex v[], int iNumVerts ) +RString +RageDisplay_GLES2::GetApiDescription() const { - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_QUADS, 0, iNumVerts ); + return "OpenGL ES 2.0"; } -void RageDisplay_Legacy::DrawQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ) +VideoModeParams +RageDisplay_GLES2::GetActualVideoModeParams() const { - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_QUAD_STRIP, 0, iNumVerts ); + return g_pWind->GetActualVideoModeParams(); } -void RageDisplay_Legacy::DrawSymmetricQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ) +void +RageDisplay_GLES2::SetBlendMode( BlendMode mode ) { - int iNumPieces = (iNumVerts-3)/3; - int iNumTriangles = iNumPieces*4; - int iNumIndices = iNumTriangles*3; - - // make a temporary index buffer - static vector 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] ); + // TODO } -void RageDisplay_Legacy::DrawFanInternal( const RageSpriteVertex v[], int iNumVerts ) +bool +RageDisplay_GLES2::SupportsTextureFormat( PixelFormat pixfmt, bool realtime ) { - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_TRIANGLE_FAN, 0, iNumVerts ); -} - -void RageDisplay_Legacy::DrawStripInternal( const RageSpriteVertex v[], int iNumVerts ) -{ - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_TRIANGLE_STRIP, 0, iNumVerts ); -} - -void RageDisplay_Legacy::DrawTrianglesInternal( const RageSpriteVertex v[], int iNumVerts ) -{ - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_TRIANGLES, 0, iNumVerts ); -} - -void RageDisplay_Legacy::DrawCompiledGeometryInternal( const RageCompiledGeometry *p, int iMeshIndex ) -{ - TurnOffHardwareVBO(); - SendCurrentMatrices(); - - p->Draw( iMeshIndex ); -} - -void RageDisplay_Legacy::DrawLineStripInternal( const RageSpriteVertex v[], int iNumVerts, float fLineWidth ) -{ - TurnOffHardwareVBO(); - - if (!GetActualVideoModeParams().bSmoothLines) - { - /* 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 ); - - if (mat.m[0][0] < 1e-5 && mat.m[1][1] < 1e-5) - return; - - glEnable( GL_POINT_SMOOTH ); - - SetupVertices( v, iNumVerts ); - glDrawArrays( GL_POINTS, 0, iNumVerts ); - - glDisable( GL_POINT_SMOOTH ); -} - -static bool SetTextureUnit( TextureUnit tu ) -{ - if ((int) tu > g_iMaxTextureUnits) - return false; - glActiveTexture( enum_add2(GL_TEXTURE0, tu) ); + // TODO return true; } -void RageDisplay_Legacy::ClearAllTextures() +bool +RageDisplay_GLES2::SupportsPerVertexMatrixScale() { - FOREACH_ENUM( TextureUnit, i ) - SetTexture( i, 0 ); - - // HACK: Reset the active texture to 0. - // TODO: Change all texture functions to take a stage number. - glActiveTexture(GL_TEXTURE0); + return true; } -int RageDisplay_Legacy::GetNumTextureUnits() +unsigned +RageDisplay_GLES2::CreateTexture( + PixelFormat pixfmt, + RageSurface* img, + bool bGenerateMipMaps + ) { - if (GLEW_ARB_multitexture) - return 1; - else - return g_iMaxTextureUnits; + // TODO + return 1; } -void RageDisplay_Legacy::SetTexture( TextureUnit tu, unsigned iTexture ) +void +RageDisplay_GLES2::UpdateTexture( + unsigned iTexHandle, + RageSurface* img, + int xoffset, int yoffset, int width, int height + ) { - if (!SetTextureUnit( tu )) - return; + // TODO +} - if (iTexture) +void +RageDisplay_GLES2::DeleteTexture( unsigned iTexHandle ) +{ + // TODO +} + +void +RageDisplay_GLES2::ClearAllTextures() +{ + // TODO +} + +int +RageDisplay_GLES2::GetNumTextureUnits() +{ + return Caps::iMaxTextureUnits; +} + +void +RageDisplay_GLES2::SetTexture( TextureUnit tu, unsigned iTexture ) +{ + // TODO +} + +void +RageDisplay_GLES2::SetTextureMode( TextureUnit tu, TextureMode tm ) +{ + // TODO +} + +void +RageDisplay_GLES2::SetTextureWrapping( TextureUnit tu, bool b ) +{ + // TODO +} + +void +RageDisplay_GLES2::SetTextureFiltering( TextureUnit tu, bool b ) +{ + // TODO +} + +bool +RageDisplay_GLES2::IsZWriteEnabled() const +{ + return State::bZWriteEnabled; +} + +bool +RageDisplay_GLES2::IsZTestEnabled() const +{ + return State::bZTestEnabled; +} + +void +RageDisplay_GLES2::SetZWrite( bool b ) +{ + if (State::bZWriteEnabled != b) { - glEnable( GL_TEXTURE_2D ); - glBindTexture( GL_TEXTURE_2D, iTexture ); - } - else - { - glDisable( GL_TEXTURE_2D ); + State::bZWriteEnabled = b; + glDepthMask( b ); } } -void RageDisplay_Legacy::SetTextureMode( TextureUnit tu, TextureMode tm ) +void +RageDisplay_GLES2::SetZBias( float f ) { - if (!SetTextureUnit( tu )) - return; + float fNear = SCALE( f, 0.0f, 1.0f, 0.05f, 0.0f ); + float fFar = SCALE( f, 0.0f, 1.0f, 1.0f, 0.95f ); - // XXX: handle with shaders? texenv doesn't exist in modern GL. - switch( tm ) + glDepthRange( fNear, fFar ); +} + +void +RageDisplay_GLES2::SetZTestMode( ZTestMode mode ) +{ + glEnable( GL_DEPTH_TEST ); + switch( mode ) { - 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: - if (!GLEW_ARB_texture_env_combine && !GLEW_EXT_texture_env_combine) - { - /* 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: - 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); - - // Source alpha is texture alpha * diffuse alpha: - 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); + case ZTEST_OFF: + glDepthFunc( GL_ALWAYS ); + State::bZTestEnabled = false; break; + case ZTEST_WRITE_ON_PASS: glDepthFunc( GL_LEQUAL ); break; + case ZTEST_WRITE_ON_FAIL: glDepthFunc( GL_GREATER ); break; + default: ASSERT( 0 ); } + State::bZTestEnabled = true; } -void RageDisplay_Legacy::SetTextureFiltering( TextureUnit tu, bool b ) -{ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, b ? GL_LINEAR : GL_NEAREST); - - GLint iMinFilter; - if (b) - { - GLint iWidth1 = -1; - GLint iWidth2 = -1; - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &iWidth1); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 1, GL_TEXTURE_WIDTH, &iWidth2); - if (iWidth1 > 1 && iWidth2 != 0) - { - /* Mipmaps are enabled. */ - if (g_pWind->GetActualVideoModeParams().bTrilinearFiltering) - 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 ); -} -void RageDisplay_Legacy::SetEffectMode( EffectMode effect ) -{ - GLuint hShader = 0; - switch (effect) - { - 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(); - glUseProgram( hShader ); - if (hShader == 0) - return; - GLint iTexture1 = glGetUniformLocation( hShader, "Texture1" ); - GLint iTexture2 = glGetUniformLocation( hShader, "Texture2" ); - glUniform1i( iTexture1, 0 ); - glUniform1i( iTexture2, 1 ); - if (effect == EffectMode_YUYV422) - { - GLint iTextureWidthUniform = glGetUniformLocation( hShader, "TextureWidth" ); - GLint iWidth; - glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &iWidth ); - glUniform1i( iTextureWidthUniform, iWidth ); - } +/* - DebugAssertNoGLError(); -} - -bool RageDisplay_Legacy::IsEffectModeSupported( EffectMode effect ) -{ - 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; -} void RageDisplay_Legacy::SetBlendMode( BlendMode mode ) { @@ -1711,12 +650,12 @@ void RageDisplay_Legacy::SetBlendMode( BlendMode mode ) 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. */ + // 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". */ + // 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: @@ -1726,10 +665,12 @@ void RageDisplay_Legacy::SetBlendMode( BlendMode mode ) DEFAULT_FAIL( mode ); } - glBlendFuncSeparate( iSourceRGB, iDestRGB, iSourceAlpha, iDestAlpha ); + if (GLEW_EXT_blend_equation_separate) + glBlendFuncSeparateEXT( iSourceRGB, iDestRGB, iSourceAlpha, iDestAlpha ); + else + glBlendFunc( iSourceRGB, iDestRGB ); } -// XXX: track this ourselves. bool RageDisplay_Legacy::IsZWriteEnabled() const { bool a; @@ -1737,14 +678,13 @@ bool RageDisplay_Legacy::IsZWriteEnabled() const return a; } -bool RageDisplay_Legacy::IsZTestEnabled() const -{ - GLenum a; - glGetIntegerv( GL_DEPTH_FUNC, (GLint*)&a ); - return a != GL_ALWAYS; -} -void RageDisplay_Legacy::ClearZBuffer() +*/ + + + +void +RageDisplay_GLES2::ClearZBuffer() { bool write = IsZWriteEnabled(); SetZWrite( true ); @@ -1752,45 +692,25 @@ void RageDisplay_Legacy::ClearZBuffer() SetZWrite( write ); } -void RageDisplay_Legacy::SetZWrite( bool b ) +void +RageDisplay_GLES2::SetCullMode( CullMode mode ) { - glDepthMask( b ); + // TODO } -void RageDisplay_Legacy::SetZBias( float f ) +void +RageDisplay_GLES2::SetAlphaTest( bool b ) { - 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 ); -} - -void RageDisplay_Legacy::SetZTestMode( ZTestMode mode ) -{ - glEnable( GL_DEPTH_TEST ); - switch( mode ) + void (*toggle)(GLenum) = b ? glEnable : glDisable; + if (State::bAlphaTestEnabled != b) { - 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; - default: ASSERT( 0 ); + State::bAlphaTestEnabled = b; + toggle(GL_ALPHA_TEST); } } -void RageDisplay_Legacy::SetTextureWrapping( TextureUnit tu, bool b ) -{ - /* 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 ); -} - -// XXX: This is completely incompatible with GLES and GL3+. Replace with shader. -void RageDisplay_Legacy::SetMaterial( +void +RageDisplay_GLES2::SetMaterial( const RageColor &emissive, const RageColor &ambient, const RageColor &diffuse, @@ -1798,814 +718,102 @@ void RageDisplay_Legacy::SetMaterial( 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 ); - - 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 - { - RageColor c = diffuse; - c.r += emissive.r + ambient.r; - c.g += emissive.g + ambient.g; - c.b += emissive.b + ambient.b; - glColor4fv( c ); - } + // TODO } -// XXX: FFP -void RageDisplay_Legacy::SetLighting( bool b ) +void +RageDisplay_GLES2::SetLighting( bool b ) { - if (b) - glEnable(GL_LIGHTING); - else - glDisable(GL_LIGHTING); + // TODO } -void RageDisplay_Legacy::SetLightOff( int index ) +void +RageDisplay_GLES2::SetLightOff( int index ) { - glDisable( GL_LIGHT0+index ); + // TODO } -// XXX: FFP -void RageDisplay_Legacy::SetLightDirectional( +void +RageDisplay_GLES2::SetLightDirectional( 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(); + // TODO } -void RageDisplay_Legacy::SetCullMode( CullMode mode ) +void +RageDisplay_GLES2::SetSphereEnvironmentMapping( TextureUnit tu, bool b ) { - 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: - ASSERT(0); - } + // TODO } -const RageDisplay::PixelFormatDesc *RageDisplay_Legacy::GetPixelFormatDesc(PixelFormat pf) const +void +RageDisplay_GLES2::SetCelShaded( int stage ) { - ASSERT( pf < NUM_PixelFormat ); - return &PIXEL_FORMAT_DESC[pf]; + // TODO } -bool RageDisplay_Legacy::SupportsThreadedRendering() +void +RageDisplay_GLES2::DrawQuadsInternal( const RageSpriteVertex v[], int iNumVerts ) { - return g_pWind->SupportsThreadedRendering(); + // TODO } -void RageDisplay_Legacy::BeginConcurrentRenderingMainThread() +void +RageDisplay_GLES2::DrawQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ) { - g_pWind->BeginConcurrentRenderingMainThread(); + // TODO } -void RageDisplay_Legacy::EndConcurrentRenderingMainThread() +void +RageDisplay_GLES2::DrawFanInternal( const RageSpriteVertex v[], int iNumVerts ) { - g_pWind->EndConcurrentRenderingMainThread(); + // TODO } -void RageDisplay_Legacy::BeginConcurrentRendering() +void +RageDisplay_GLES2::DrawStripInternal( const RageSpriteVertex v[], int iNumVerts ) { - g_pWind->BeginConcurrentRendering(); - RageDisplay::BeginConcurrentRendering(); + // TODO } -void RageDisplay_Legacy::EndConcurrentRendering() +void +RageDisplay_GLES2::DrawTrianglesInternal( const RageSpriteVertex v[], int iNumVerts ) { - g_pWind->EndConcurrentRendering(); + // TODO } -void RageDisplay_Legacy::DeleteTexture( unsigned iTexture ) +void +RageDisplay_GLES2::DrawCompiledGeometryInternal( const RageCompiledGeometry *p, int + iMeshIndex ) { - if (iTexture == 0) - return; - - if (g_mapRenderTargets.find(iTexture) != g_mapRenderTargets.end()) - { - delete g_mapRenderTargets[iTexture]; - g_mapRenderTargets.erase( iTexture ); - return; - } - - DebugFlushGLErrors(); - glDeleteTextures( 1, reinterpret_cast(&iTexture) ); - DebugAssertNoGLError(); + // TODO } - -PixelFormat RageDisplay_Legacy::GetImgPixelFormat( RageSurface* &img, bool &bFreeImg, int width, int height, bool bPalettedTexture ) +void +RageDisplay_GLES2::DrawLineStripInternal( const RageSpriteVertex v[], int iNumVerts, float LineWidth ) { - 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; - if (!bPalettedTexture && img->fmt.BytesPerPixel == 1 && !g_bColorIndexTableWorks) - bSupported = false; - - if (pixfmt == PixelFormat_Invalid || !SupportsSurfaceFormat(pixfmt)) - bSupported = false; - - if (!bSupported) - { - /* 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; + // TODO } -/* If we're sending a paletted surface to a non-paletted texture, set the palette. */ -void SetPixelMapForSurface( int glImageFormat, int glTexFormat, const RageSurfacePalette *palette ) +void +RageDisplay_GLES2::DrawSymmetricQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ) { - if (glImageFormat != GL_COLOR_INDEX || glTexFormat == GL_COLOR_INDEX8_EXT) - { - 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(); + // TODO } -unsigned RageDisplay_Legacy::CreateTexture( - PixelFormat pixfmt, - RageSurface* pImg, - bool bGenerateMipMaps ) +bool +RageDisplay_GLES2::SupportsSurfaceFormat( PixelFormat pixfmt ) { - 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 - if (bGenerateMipMaps && g_gluVersion < 13) - { - 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(&iTexHandle) ); - ASSERT( iTexHandle ); - - glBindTexture( GL_TEXTURE_2D, iTexHandle ); - - if (g_pWind->GetActualVideoModeParams().bAnisotropicFiltering && - GLEW_EXT_texture_filter_anisotropic ) - { - 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 ); - - - if (pixfmt == PixelFormat_PAL) - { - /* 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. */ - glColorTableEXT( GL_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, palette ); - - GLint iRealFormat = 0; - glGetColorTableParameterivEXT( GL_TEXTURE_2D, GL_COLOR_TABLE_FORMAT, &iRealFormat ); - 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(); - - // XXX: don't use GLU - if (bGenerateMipMaps) - { - 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 ); - if (pImg->pixels) - glTexSubImage2D( GL_TEXTURE_2D, 0, - 0, 0, - pImg->w, pImg->h, - glImageFormat, glImageType, pImg->pixels ); - - DebugAssertNoGLError(); - } - - - /* Sanity check: */ - if (pixfmt == PixelFormat_PAL) - { - 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." ); - } - - glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); - glFlush(); - - if (bFreeImg) - 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! - glDeleteBuffers( 1, &m_iBuffer ); - } - - /* This is called when our OpenGL context is invalidated. */ - void Invalidate() - { - m_iTexHandle = 0; - } - - // XXX: This doesn't work in GLES without extensions - void Lock( unsigned iTexHandle, RageSurface *pSurface ) - { - ASSERT( m_iTexHandle == 0 ); - ASSERT( pSurface->pixels == NULL ); - - CreateObject(); - - m_iTexHandle = iTexHandle; - glBindBuffer( GL_PIXEL_UNPACK_BUFFER, m_iBuffer ); - - int iSize = pSurface->h * pSurface->pitch; - glBufferData( GL_PIXEL_UNPACK_BUFFER, iSize, NULL, GL_STREAM_DRAW ); - - void *pSurfaceMemory = glMapBuffer( GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY ); - pSurface->pixels = (uint8_t *) pSurfaceMemory; - pSurface->pixels_owned = false; - } - - void Unlock( RageSurface *pSurface, bool bChanged ) - { - glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER ); - - pSurface->pixels = (uint8_t *) BUFFER_OFFSET(0); - - if (bChanged) - DISPLAY->UpdateTexture( m_iTexHandle, pSurface, 0, 0, pSurface->w, pSurface->h ); - - pSurface->pixels = NULL; - - m_iTexHandle = 0; - glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0 ); - } - -private: - void CreateObject() - { - if (m_iBuffer != 0) - return; - - DebugFlushGLErrors(); - glGenBuffers( 1, &m_iBuffer ); - DebugAssertNoGLError(); - } - - GLuint m_iBuffer; - - unsigned m_iTexHandle; -}; - -RageTextureLock *RageDisplay_Legacy::CreateTextureLock() -{ - //if (!GLEW_ARB_pixel_buffer_object) - return NULL; - - //return new RageTextureLock_OGL; -} - -void RageDisplay_Legacy::UpdateTexture( - 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; - - 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(); - - if (bFreeImg) - delete pImg; -} - -class RenderTarget_FramebufferObject: public RenderTarget -{ -public: - RenderTarget_FramebufferObject(); - ~RenderTarget_FramebufferObject(); - void Create( const RenderTargetParam ¶m, 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() -{ - if (m_iDepthBufferHandle) - glDeleteRenderbuffersEXT( 1, reinterpret_cast(&m_iDepthBufferHandle) ); - if (m_iFrameBufferHandle) - glDeleteFramebuffersEXT( 1, reinterpret_cast(&m_iFrameBufferHandle) ); - if (m_iTexHandle) - glDeleteTextures( 1, reinterpret_cast(&m_iTexHandle) ); -} - -void RenderTarget_FramebufferObject::Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ) -{ - m_Param = param; - - DebugFlushGLErrors(); - - // Allocate OpenGL texture resource - glGenTextures( 1, reinterpret_cast(&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 ); - GLenum internalformat; - GLenum type = param.bWithAlpha? GL_RGBA:GL_RGB; - - if (param.bFloat && GLEW_ARB_texture_float) - 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. */ - glGenFramebuffers( 1, reinterpret_cast(&m_iFrameBufferHandle) ); - ASSERT( m_iFrameBufferHandle ); - - /* Attach the texture to it. */ - glBindFramebuffer( GL_FRAMEBUFFER, m_iFrameBufferHandle ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_iTexHandle, 0 ); - DebugAssertNoGLError(); - - /* Attach a depth buffer, if requested. */ - if (param.bWithDepthBuffer) - { - glGenRenderbuffers( 1, reinterpret_cast(&m_iDepthBufferHandle) ); - ASSERT( m_iDepthBufferHandle ); - - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, iTextureWidth, iTextureHeight ); - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_iDepthBufferHandle ); - } - - GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER ); - switch(status) - { - case GL_FRAMEBUFFER_COMPLETE: - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - FAIL_M( "GL_FRAMEBUFFER_UNSUPPORTED" ); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT" ); break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" ); break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS" ); break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_FORMATS" ); break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER" ); break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: FAIL_M( "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER" ); break; - default: - ASSERT(0); - } - - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); -} - -void RenderTarget_FramebufferObject::StartRenderingTo() -{ - glBindFramebuffer( GL_FRAMEBUFFER, m_iFrameBufferHandle ); -} - -void RenderTarget_FramebufferObject::FinishRenderingTo() -{ - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); -} - -bool RageDisplay_Legacy::SupportsRenderToTexture() const -{ - return GLEW_EXT_framebuffer_object || g_pWind->SupportsRenderToTexture(); -} - -/* - * 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_Legacy::CreateRenderTarget( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ) -{ - RenderTarget *pTarget = new RenderTarget_FramebufferObject; - - pTarget->Create( param, iTextureWidthOut, iTextureHeightOut ); - - unsigned iTexture = pTarget->GetTexture(); - - ASSERT( g_mapRenderTargets.find(iTexture) == g_mapRenderTargets.end() ); - g_mapRenderTargets[iTexture] = pTarget; - return iTexture; -} - -void RageDisplay_Legacy::SetRenderTarget( unsigned iTexture, bool bPreserveTexture ) -{ - if (iTexture == 0) - { - 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 ); - - 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; - - /* Set the viewport to the size of the render target. */ - glViewport(0, 0, pTarget->GetParam().iWidth, pTarget->GetParam().iHeight); - - /* 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. Push matrixes affected by SetDefaultRenderStates. */ - DISPLAY->CameraPushMatrix(); - SetDefaultRenderStates(); - - /* Clear the texture, if requested. Always set the associated state, for - * consistency. */ - glClearColor(0,0,0,0); - SetZWrite(true); - - /* 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. */ - if (!bPreserveTexture) - { - int iBit = GL_COLOR_BUFFER_BIT; - if (pTarget->GetParam().bWithDepthBuffer) - iBit |= GL_DEPTH_BUFFER_BIT; - glClear(iBit); - } -} - -void RageDisplay_GLES2::SetPolygonMode(PolygonMode pm) -{ - GLenum m; - switch (pm) - { - case POLYGON_FILL: m = GL_FILL; break; - case POLYGON_LINE: m = GL_LINE; break; - default: ASSERT(0); return; - } - glPolygonMode(GL_FRONT_AND_BACK, m); -} - -void RageDisplay_GLES2::SetLineWidth(float fWidth) -{ - glLineWidth(fWidth); -} - -RString RageDisplay_GLES2::GetTextureDiagnostics(unsigned iTexture) const -{ - /* - 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)" ); - if (iFormat != glTexFormat) - { - sError = ssprintf( "Expected format %s, got %s instead", - GLToString(glTexFormat).c_str(), GLToString(iFormat).c_str() ); - break; - } -*/ - return RString(); -} - -/* - * XXX: Things like this only have to be set once per context - making - * SetDefault call These kinds of functions is wasteful. -Colby - */ -void RageDisplay_GLES2::SetAlphaTest(bool b) -{ - // Previously this was 0.01, rather than 0x01. - glAlphaFunc(GL_GREATER, 0.00390625 /* 1/256 */); - if (b) - glEnable(GL_ALPHA_TEST); - else - glDisable(GL_ALPHA_TEST); -} - - -/* - * 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_GLES2::SupportsSurfaceFormat(PixelFormat pixfmt) -{ - switch (g_GLPixFmtInfo[pixfmt].type) - { - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return GLEW_EXT_bgra && g_bReversePackedPixelsWorks; - default: - return true; - } -} - - -bool RageDisplay_GLES2::SupportsTextureFormat(PixelFormat pixfmt, bool bRealtime) -{ - /* 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. */ - if (bRealtime && !SupportsSurfaceFormat(pixfmt)) - return false; - - switch (g_GLPixFmtInfo[pixfmt].format) - { - case GL_COLOR_INDEX: - return glColorTableEXT && glGetColorTableParameterivEXT; - case GL_BGR: - case GL_BGRA: - return !!GLEW_EXT_bgra; - default: - return true; - } -} - -bool RageDisplay_GLES2::SupportsPerVertexMatrixScale() -{ - // Required functionality is mandatory with GLES2+ - // Intel i915 on OSX 10.4.4 supports vertex programs but not hardware vertex buffers. - // Our software vertex rendering doesn't support vertex programs. + // TODO return true; } -void RageDisplay_GLES2::SetSphereEnvironmentMapping(TextureUnit tu, bool b) -{ - if (!SetTextureUnit(tu)) - return; - - if (b) - { - 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); - } - else - { - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } -} - -void RageDisplay_GLES2::SetCelShaded( int stage ) -{ - switch (stage) - { - case 1: - glUseProgram(g_gShellShader); - break; - case 2: - glUseProgram(g_gCelShader); - break; - default: - glUseProgram(0); - break; - } -} - /* - * Copyright (c) 2001-2012 Colby Klein, Chris Danford, Glenn Maynard + * Copyright (c) 2012 Colby Klein * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -2628,4 +836,3 @@ void RageDisplay_GLES2::SetCelShaded( int stage ) * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ - diff --git a/src/RageDisplay_GLES2.h b/src/RageDisplay_GLES2.h new file mode 100644 index 0000000000..98ab274155 --- /dev/null +++ b/src/RageDisplay_GLES2.h @@ -0,0 +1,108 @@ +#ifndef RAGE_DISPLAY_GLES2_H +#define RAGE_DISPLAY_GLES2_H + +class RageDisplay_GLES2: public RageDisplay +{ +public: + RageDisplay_GLES2(); + virtual ~RageDisplay_GLES2(); + virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer ); + + virtual RString GetApiDescription() const; + virtual void GetDisplayResolutions( DisplayResolutions &out ) const; + const PixelFormatDesc *GetPixelFormatDesc(PixelFormat pf) const; + + bool BeginFrame(); + void EndFrame(); + VideoModeParams GetActualVideoModeParams() const; + void SetBlendMode( BlendMode mode ); + bool SupportsTextureFormat( PixelFormat pixfmt, bool realtime=false ); + bool SupportsPerVertexMatrixScale(); + unsigned CreateTexture( + PixelFormat pixfmt, + RageSurface* img, + bool bGenerateMipMaps ); + void UpdateTexture( + unsigned iTexHandle, + RageSurface* img, + int xoffset, int yoffset, int width, int height ); + void DeleteTexture( unsigned iTexHandle ); + void ClearAllTextures(); + int GetNumTextureUnits(); + void SetTexture( TextureUnit tu, unsigned iTexture ); + void SetTextureMode( TextureUnit tu, TextureMode tm ); + void SetTextureWrapping( TextureUnit tu, bool b ); + int GetMaxTextureSize() const; + void SetTextureFiltering( TextureUnit tu, bool b ); + bool IsZWriteEnabled() const; + bool IsZTestEnabled() const; + void SetZWrite( bool b ); + void SetZBias( float f ); + void SetZTestMode( ZTestMode mode ); + void ClearZBuffer(); + void SetCullMode( CullMode mode ); + void SetAlphaTest( bool b ); + void SetMaterial( + const RageColor &emissive, + const RageColor &ambient, + const RageColor &diffuse, + const RageColor &specular, + float shininess + ); + void SetLighting( bool b ); + void SetLightOff( int index ); + void SetLightDirectional( + int index, + const RageColor &ambient, + const RageColor &diffuse, + const RageColor &specular, + const RageVector3 &dir ); + + void SetSphereEnvironmentMapping( TextureUnit tu, bool b ); + void SetCelShaded( int stage ); + + RageCompiledGeometry* CreateCompiledGeometry(); + void DeleteCompiledGeometry( RageCompiledGeometry* p ); + +protected: + void DrawQuadsInternal( const RageSpriteVertex v[], int iNumVerts ); + void DrawQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ); + void DrawFanInternal( const RageSpriteVertex v[], int iNumVerts ); + void DrawStripInternal( const RageSpriteVertex v[], int iNumVerts ); + void DrawTrianglesInternal( const RageSpriteVertex v[], int iNumVerts ); + void DrawCompiledGeometryInternal( const RageCompiledGeometry *p, int iMeshIndex ); + void DrawLineStripInternal( const RageSpriteVertex v[], int iNumVerts, float LineWidth ); + void DrawSymmetricQuadStripInternal( const RageSpriteVertex v[], int iNumVerts ); + + RString TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ); + RageSurface* CreateScreenshot(); + RageMatrix GetOrthoMatrix( float l, float r, float b, float t, float zn, float zf ); + bool SupportsSurfaceFormat( PixelFormat pixfmt ); +}; + +#endif +/* + * Copyright (c) 2012 Colby Klein + * 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. + */ +