1006 lines
21 KiB
C++
1006 lines
21 KiB
C++
#include "global.h"
|
|
|
|
#include "RageDisplay.h"
|
|
#include "RageDisplay_GLES2.h"
|
|
#include "RageUtil.h"
|
|
#include "RageLog.h"
|
|
#include "RageTimer.h"
|
|
#include "RageMath.h"
|
|
#include "RageTypes.h"
|
|
#include "RageUtil.h"
|
|
#include "RageSurface.h"
|
|
#include "RageTextureManager.h"
|
|
|
|
#include "DisplayResolutions.h"
|
|
|
|
#include "arch/LowLevelWindow/LowLevelWindow.h"
|
|
|
|
#include <GL/glew.h>
|
|
|
|
#ifdef NO_GL_FLUSH
|
|
#define glFlush()
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
RageDisplay::RagePixelFormatDesc
|
|
PIXEL_FORMAT_DESC[NUM_RagePixelFormat] = {
|
|
{
|
|
/* 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 RagePixelFormat_RGB5 texture, but to
|
|
* supply a surface matching RagePixelFormat_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_RagePixelFormat] = {
|
|
{
|
|
/* 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,
|
|
}, {
|
|
// TODO: These don't work on ES2. Work out what needs to happen.
|
|
/* 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_RagePixelFormat; ++i )
|
|
{
|
|
RageDisplay::RagePixelFormatDesc &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)
|
|
{
|
|
int m = pf.masks[mask];
|
|
switch( pf.bpp )
|
|
{
|
|
case 24: m = Swap24(m); break;
|
|
case 32: m = Swap32(m); break;
|
|
default:
|
|
FAIL_M(ssprintf("Unsupported BPP value: %i", pf.bpp));
|
|
}
|
|
pf.masks[mask] = m;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
namespace Caps
|
|
{
|
|
int iMaxTextureUnits = 1;
|
|
int iMaxTextureSize = 256;
|
|
}
|
|
namespace State
|
|
{
|
|
bool bZTestEnabled = false;
|
|
bool bZWriteEnabled = false;
|
|
bool bAlphaTestEnabled = false;
|
|
}
|
|
}
|
|
|
|
RageDisplay_GLES2::RageDisplay_GLES2()
|
|
{
|
|
LOG->Trace( "RageDisplay_GLES2::RageDisplay_GLES2()" );
|
|
LOG->MapLog("renderer", "Current renderer: OpenGL ES 2.0");
|
|
|
|
FixLittleEndian();
|
|
// RageDisplay_GLES2_Helpers::Init();
|
|
|
|
g_pWind = NULL;
|
|
}
|
|
|
|
RString
|
|
RageDisplay_GLES2::Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer )
|
|
{
|
|
g_pWind = LowLevelWindow::Create();
|
|
|
|
bool bIgnore = false;
|
|
RString sError = SetVideoMode( p, bIgnore );
|
|
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", Caps::iMaxTextureSize );
|
|
LOG->Info( "OGL Texture units: %i", Caps::iMaxTextureUnits );
|
|
|
|
/* Pretty-print the extension string: */
|
|
LOG->Info( "OGL Extensions:" );
|
|
{
|
|
// glGetString(GL_EXTENSIONS) doesn't work for GL3 core profiles.
|
|
// this will be useful in the future.
|
|
#if 0
|
|
vector<string> extensions;
|
|
const char *ext = 0;
|
|
for (int i = 0; (ext = (const char*)glGetStringi(GL_EXTENSIONS, i)); i++)
|
|
{
|
|
extensions.push_back(string(ext));
|
|
}
|
|
|
|
sort( extensions.begin(), extensions.end() );
|
|
size_t next = 0;
|
|
while( next < extensions.size() )
|
|
{
|
|
size_t last = next;
|
|
string type;
|
|
for( size_t i = next; i<extensions.size(); ++i )
|
|
{
|
|
vector<string> segments;
|
|
split(extensions[i], '_', segments);
|
|
string this_type;
|
|
if (segments.size() > 2)
|
|
this_type = join("_", segments.begin(), segments.begin()+2);
|
|
if (i > next && this_type != type)
|
|
break;
|
|
type = this_type;
|
|
last = i;
|
|
}
|
|
|
|
if (next == last)
|
|
{
|
|
printf( " %s\n", extensions[next].c_str() );
|
|
++next;
|
|
continue;
|
|
}
|
|
|
|
string sList = ssprintf( " %s: ", type.c_str() );
|
|
while( next <= last )
|
|
{
|
|
vector<string> segments;
|
|
split( extensions[next], '_', segments );
|
|
string ext_short = join( "_", segments.begin()+2, segments.end() );
|
|
sList += ext_short;
|
|
if (next < last)
|
|
sList += ", ";
|
|
if (next == last || sList.size() + extensions[next+1].size() > 78)
|
|
{
|
|
printf( "%s\n", sList.c_str() );
|
|
sList = " ";
|
|
}
|
|
++next;
|
|
}
|
|
}
|
|
#else
|
|
const char *szExtensionString = (const char *) glGetString(GL_EXTENSIONS);
|
|
vector<RString> asExtensions;
|
|
split( szExtensionString, " ", asExtensions );
|
|
sort( asExtensions.begin(), asExtensions.end() );
|
|
size_t iNextToPrint = 0;
|
|
while( iNextToPrint < asExtensions.size() )
|
|
{
|
|
size_t iLastToPrint = iNextToPrint;
|
|
RString sType;
|
|
for( size_t i = iNextToPrint; i<asExtensions.size(); ++i )
|
|
{
|
|
vector<RString> asBits;
|
|
split( asExtensions[i], "_", asBits );
|
|
RString sThisType;
|
|
if (asBits.size() > 2)
|
|
sThisType = join( "_", asBits.begin(), asBits.begin()+2 );
|
|
if (i > iNextToPrint && sThisType != sType)
|
|
break;
|
|
sType = sThisType;
|
|
iLastToPrint = i;
|
|
}
|
|
|
|
if (iNextToPrint == iLastToPrint)
|
|
{
|
|
LOG->Info( " %s", asExtensions[iNextToPrint].c_str() );
|
|
++iNextToPrint;
|
|
continue;
|
|
}
|
|
|
|
RString sList = ssprintf( " %s: ", sType.c_str() );
|
|
while( iNextToPrint <= iLastToPrint )
|
|
{
|
|
vector<RString> asBits;
|
|
split( asExtensions[iNextToPrint], "_", asBits );
|
|
RString sShortExt = join( "_", asBits.begin()+2, asBits.end() );
|
|
sList += sShortExt;
|
|
if (iNextToPrint < iLastToPrint)
|
|
sList += ", ";
|
|
if (iNextToPrint == iLastToPrint || sList.size() + asExtensions[iNextToPrint+1].size() > 120)
|
|
{
|
|
LOG->Info( "%s", sList.c_str() );
|
|
sList = " ";
|
|
}
|
|
++iNextToPrint;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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 );
|
|
|
|
return RString();
|
|
}
|
|
|
|
// 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_GLES2::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut )
|
|
{
|
|
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 = g_pWind->TryVideoMode( vm, bNewDeviceOut );
|
|
if (err != "")
|
|
return err; // failed to set video mode
|
|
|
|
if (bNewDeviceOut)
|
|
{
|
|
// NOTE: This isn't needed in an actual GLES2 context...
|
|
glewInit();
|
|
|
|
/* We have a new OpenGL context, so we have to tell our textures that
|
|
* their OpenGL texture number is invalid. */
|
|
if (TEXTUREMAN)
|
|
TEXTUREMAN->InvalidateTextures();
|
|
|
|
/* Delete all render targets. They may have associated resources other than
|
|
* the texture itself. */
|
|
//FOREACHM( unsigned, RenderTarget *, g_mapRenderTargets, rt )
|
|
// delete rt->second;
|
|
//g_mapRenderTargets.clear();
|
|
|
|
/* Recreate all vertex buffers. */
|
|
//InvalidateObjects();
|
|
|
|
//InitShaders();
|
|
}
|
|
|
|
ResolutionChanged();
|
|
|
|
return RString();
|
|
}
|
|
|
|
int RageDisplay_GLES2::GetMaxTextureSize() const
|
|
{
|
|
return Caps::iMaxTextureSize;
|
|
}
|
|
|
|
bool RageDisplay_GLES2::BeginFrame()
|
|
{
|
|
/* We do this in here, rather than ResolutionChanged, or we won't update the
|
|
* viewport for the concurrent rendering context. */
|
|
int fWidth = g_pWind->GetActualVideoModeParams().width;
|
|
int fHeight = g_pWind->GetActualVideoModeParams().height;
|
|
|
|
glViewport( 0, 0, fWidth, fHeight );
|
|
|
|
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
|
|
SetZWrite( true );
|
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
|
|
|
return RageDisplay::BeginFrame();
|
|
}
|
|
|
|
void RageDisplay_GLES2::EndFrame()
|
|
{
|
|
glFlush();
|
|
|
|
// XXX: This is broken on NVidia, as their xrandr sucks.
|
|
FrameLimitBeforeVsync( g_pWind->GetActualVideoModeParams().rate );
|
|
g_pWind->SwapBuffers();
|
|
FrameLimitAfterVsync();
|
|
|
|
g_pWind->Update();
|
|
|
|
RageDisplay::EndFrame();
|
|
}
|
|
|
|
RageDisplay_GLES2::~RageDisplay_GLES2()
|
|
{
|
|
delete g_pWind;
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::GetDisplayResolutions( DisplayResolutions &out ) const
|
|
{
|
|
out.clear();
|
|
g_pWind->GetDisplayResolutions( out );
|
|
}
|
|
|
|
RageSurface*
|
|
RageDisplay_GLES2::CreateScreenshot()
|
|
{
|
|
const RagePixelFormatDesc &desc = PIXEL_FORMAT_DESC[RagePixelFormat_RGB8];
|
|
RageSurface *image = CreateSurface(
|
|
640, 480, desc.bpp,
|
|
desc.masks[0], desc.masks[1], desc.masks[2], desc.masks[3] );
|
|
|
|
memset( image->pixels, 0, 480*image->pitch );
|
|
|
|
return image;
|
|
}
|
|
|
|
const RageDisplay::RagePixelFormatDesc*
|
|
RageDisplay_GLES2::GetPixelFormatDesc(RagePixelFormat pf) const
|
|
{
|
|
ASSERT( pf >= 0 && pf < NUM_RagePixelFormat );
|
|
return &PIXEL_FORMAT_DESC[pf];
|
|
}
|
|
|
|
RageMatrix
|
|
RageDisplay_GLES2::GetOrthoMatrix( float l, float r, float b, float t, float zn, float zf )
|
|
{
|
|
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;
|
|
}
|
|
|
|
class RageCompiledGeometryGLES2 : public RageCompiledGeometry
|
|
{
|
|
public:
|
|
|
|
void Allocate( const vector<msMesh> &vMeshes )
|
|
{
|
|
// TODO
|
|
}
|
|
void Change( const vector<msMesh> &vMeshes )
|
|
{
|
|
// TODO
|
|
}
|
|
void Draw( int iMeshIndex ) const
|
|
{
|
|
// TOO
|
|
}
|
|
};
|
|
|
|
RageCompiledGeometry*
|
|
RageDisplay_GLES2::CreateCompiledGeometry()
|
|
{
|
|
return new RageCompiledGeometryGLES2;
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DeleteCompiledGeometry( RageCompiledGeometry *p )
|
|
{
|
|
delete p;
|
|
}
|
|
|
|
RString
|
|
RageDisplay_GLES2::GetApiDescription() const
|
|
{
|
|
return "OpenGL ES 2.0";
|
|
}
|
|
|
|
VideoModeParams
|
|
RageDisplay_GLES2::GetActualVideoModeParams() const
|
|
{
|
|
return g_pWind->GetActualVideoModeParams();
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetBlendMode( BlendMode mode )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
bool
|
|
RageDisplay_GLES2::SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime )
|
|
{
|
|
/* 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 (realtime && !SupportsSurfaceFormat(pixfmt))
|
|
return false;
|
|
|
|
switch (g_GLPixFmtInfo[pixfmt].format)
|
|
{
|
|
case GL_COLOR_INDEX:
|
|
return false;
|
|
case GL_BGR:
|
|
case GL_BGRA:
|
|
//return !!GLEW_EXT_bgra;
|
|
return false; // no BGRA on ES2 (without exts)
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
RageDisplay_GLES2::SupportsPerVertexMatrixScale()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
unsigned
|
|
RageDisplay_GLES2::CreateTexture(
|
|
RagePixelFormat pixfmt,
|
|
RageSurface* img,
|
|
bool bGenerateMipMaps
|
|
)
|
|
{
|
|
// TODO
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::UpdateTexture(
|
|
unsigned iTexHandle,
|
|
RageSurface* img,
|
|
int xoffset, int yoffset, int width, int height
|
|
)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DeleteTexture( unsigned iTexHandle )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::ClearAllTextures()
|
|
{
|
|
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);
|
|
}
|
|
|
|
int
|
|
RageDisplay_GLES2::GetNumTextureUnits()
|
|
{
|
|
return Caps::iMaxTextureUnits;
|
|
}
|
|
|
|
static bool
|
|
SetTextureUnit( TextureUnit tu )
|
|
{
|
|
if ((int) tu > Caps::iMaxTextureUnits)
|
|
return false;
|
|
glActiveTexture( enum_add2(GL_TEXTURE0, tu) );
|
|
return true;
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetTexture( TextureUnit tu, unsigned iTexture )
|
|
{
|
|
if (!SetTextureUnit( tu ))
|
|
return;
|
|
|
|
if (iTexture)
|
|
{
|
|
glEnable( GL_TEXTURE_2D );
|
|
glBindTexture( GL_TEXTURE_2D, iTexture );
|
|
}
|
|
else
|
|
{
|
|
glDisable( GL_TEXTURE_2D );
|
|
}
|
|
}
|
|
|
|
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 )
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, b ? GL_LINEAR : GL_NEAREST);
|
|
|
|
GLint iMinFilter = 0;
|
|
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 );
|
|
}
|
|
|
|
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)
|
|
{
|
|
State::bZWriteEnabled = b;
|
|
glDepthMask( b );
|
|
}
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetZBias( float f )
|
|
{
|
|
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_GLES2::SetZTestMode( ZTestMode mode )
|
|
{
|
|
glEnable( GL_DEPTH_TEST );
|
|
switch( mode )
|
|
{
|
|
case ZTEST_OFF:
|
|
glDisable( GL_DEPTH_TEST );
|
|
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:
|
|
FAIL_M(ssprintf("Invalid ZTestMode: %i", mode));
|
|
}
|
|
State::bZTestEnabled = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
void RageDisplay_Legacy::SetBlendMode( BlendMode mode )
|
|
{
|
|
glEnable(GL_BLEND);
|
|
|
|
if (glBlendEquation != NULL)
|
|
{
|
|
if (mode == BLEND_INVERT_DEST)
|
|
glBlendEquation( GL_FUNC_SUBTRACT );
|
|
else if (mode == BLEND_SUBTRACT)
|
|
glBlendEquation( GL_FUNC_REVERSE_SUBTRACT );
|
|
else
|
|
glBlendEquation( GL_FUNC_ADD );
|
|
}
|
|
|
|
int iSourceRGB, iDestRGB;
|
|
int iSourceAlpha = GL_ONE, iDestAlpha = GL_ONE_MINUS_SRC_ALPHA;
|
|
switch( mode )
|
|
{
|
|
case BLEND_NORMAL:
|
|
iSourceRGB = GL_SRC_ALPHA; iDestRGB = GL_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case BLEND_ADD:
|
|
iSourceRGB = GL_SRC_ALPHA; iDestRGB = GL_ONE;
|
|
break;
|
|
case BLEND_SUBTRACT:
|
|
iSourceRGB = GL_SRC_ALPHA; iDestRGB = GL_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case BLEND_MODULATE:
|
|
iSourceRGB = GL_ZERO; iDestRGB = GL_SRC_COLOR;
|
|
break;
|
|
case BLEND_COPY_SRC:
|
|
iSourceRGB = GL_ONE; iDestRGB = GL_ZERO;
|
|
iSourceAlpha = GL_ONE; iDestAlpha = GL_ZERO;
|
|
break;
|
|
case BLEND_ALPHA_MASK:
|
|
iSourceRGB = GL_ZERO; iDestRGB = GL_ONE;
|
|
iSourceAlpha = GL_ZERO; iDestAlpha = GL_SRC_ALPHA;
|
|
break;
|
|
case BLEND_ALPHA_KNOCK_OUT:
|
|
iSourceRGB = GL_ZERO; iDestRGB = GL_ONE;
|
|
iSourceAlpha = GL_ZERO; iDestAlpha = GL_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case BLEND_ALPHA_MULTIPLY:
|
|
iSourceRGB = GL_SRC_ALPHA; iDestRGB = GL_ZERO;
|
|
break;
|
|
case BLEND_WEIGHTED_MULTIPLY:
|
|
// output = 2*(dst*src). 0.5,0.5,0.5 is identity; darker colors darken the image,
|
|
// and brighter colors lighten the image.
|
|
iSourceRGB = GL_DST_COLOR; iDestRGB = GL_SRC_COLOR;
|
|
break;
|
|
case BLEND_INVERT_DEST:
|
|
// out = src - dst. The source color should almost always be #FFFFFF, to make it "1 - dst".
|
|
iSourceRGB = GL_ONE; iDestRGB = GL_ONE;
|
|
break;
|
|
case BLEND_NO_EFFECT:
|
|
iSourceRGB = GL_ZERO; iDestRGB = GL_ONE;
|
|
iSourceAlpha = GL_ZERO; iDestAlpha = GL_ONE;
|
|
break;
|
|
DEFAULT_FAIL( mode );
|
|
}
|
|
|
|
if (GLEW_EXT_blend_equation_separate)
|
|
glBlendFuncSeparateEXT( iSourceRGB, iDestRGB, iSourceAlpha, iDestAlpha );
|
|
else
|
|
glBlendFunc( iSourceRGB, iDestRGB );
|
|
}
|
|
|
|
bool RageDisplay_Legacy::IsZWriteEnabled() const
|
|
{
|
|
bool a;
|
|
glGetBooleanv( GL_DEPTH_WRITEMASK, (unsigned char*)&a );
|
|
return a;
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
void
|
|
RageDisplay_GLES2::ClearZBuffer()
|
|
{
|
|
bool write = IsZWriteEnabled();
|
|
SetZWrite( true );
|
|
glClear( GL_DEPTH_BUFFER_BIT );
|
|
SetZWrite( write );
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetCullMode( CullMode mode )
|
|
{
|
|
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:
|
|
FAIL_M(ssprintf("Invalid CullMode: %i", mode));
|
|
}
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetAlphaTest( bool b )
|
|
{
|
|
void (*toggle)(GLenum) = b ? glEnable : glDisable;
|
|
if (State::bAlphaTestEnabled != b)
|
|
{
|
|
State::bAlphaTestEnabled = b;
|
|
toggle(GL_ALPHA_TEST);
|
|
}
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetMaterial(
|
|
const RageColor &emissive,
|
|
const RageColor &ambient,
|
|
const RageColor &diffuse,
|
|
const RageColor &specular,
|
|
float shininess
|
|
)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetLineWidth(float fWidth)
|
|
{
|
|
glLineWidth(fWidth);
|
|
}
|
|
|
|
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:
|
|
FAIL_M(ssprintf("Invalid PolygonMode: %i", pm));
|
|
}
|
|
glPolygonMode(GL_FRONT_AND_BACK, m);
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetLighting( bool b )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetLightOff( int index )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetLightDirectional(
|
|
int index,
|
|
const RageColor &ambient,
|
|
const RageColor &diffuse,
|
|
const RageColor &specular,
|
|
const RageVector3 &dir )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetSphereEnvironmentMapping( TextureUnit tu, bool b )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::SetCelShaded( int stage )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawQuadsInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawQuadStripInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawFanInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawStripInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawTrianglesInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawCompiledGeometryInternal( const RageCompiledGeometry *p, int
|
|
iMeshIndex )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void
|
|
RageDisplay_GLES2::DrawLineStripInternal( const RageSpriteVertex v[], int iNumVerts, float LineWidth )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
// Is this even used?
|
|
void
|
|
RageDisplay_GLES2::DrawSymmetricQuadStripInternal( const RageSpriteVertex v[], int iNumVerts )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
bool
|
|
RageDisplay_GLES2::SupportsSurfaceFormat( RagePixelFormat pixfmt )
|
|
{
|
|
switch (g_GLPixFmtInfo[pixfmt].type)
|
|
{
|
|
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
|
|
return false;
|
|
//return GLEW_EXT_bgra && g_bReversePackedPixelsWorks;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|