| /* |
| Copyright (c) 2011-2013 NVIDIA Corporation |
| Copyright (c) 2011-2012 Cass Everitt |
| Copyright (c) 2012 Scott Nations |
| Copyright (c) 2012 Mathias Schott |
| Copyright (c) 2012 Nigel Stewart |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| Redistributions of source code must retain the above copyright notice, this |
| list of conditions and the following disclaimer. |
| |
| Redistributions in binary form must reproduce the above copyright notice, |
| this list of conditions and the following disclaimer in the documentation |
| and/or other materials provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| |
| Regal fixed-function emulation. |
| Cass Everitt |
| |
| */ |
| |
| #ifndef __REGAL_IFF_H__ |
| #define __REGAL_IFF_H__ |
| |
| #include "RegalUtil.h" |
| |
| #define REGAL_IMMEDIATE_BUFFER_SIZE 8192 |
| |
| // Configurable |
| |
| #define REGAL_FIXED_FUNCTION_PROGRAM_CACHE_SIZE_BITS 8 |
| |
| // Derived |
| |
| #define REGAL_FIXED_FUNCTION_PROGRAM_CACHE_SIZE (1<<REGAL_FIXED_FUNCTION_PROGRAM_CACHE_SIZE_BITS) |
| |
| // OpenGL spec is four fixed-function texture units. |
| // Regal can emulate eight, default is four |
| |
| #ifndef REGAL_EMU_IFF_TEXTURE_UNITS |
| #define REGAL_EMU_IFF_TEXTURE_UNITS 4 |
| #endif |
| |
| #ifndef REGAL_EMU_IFF_VERTEX_ATTRIBS |
| #define REGAL_EMU_IFF_VERTEX_ATTRIBS 16 |
| #endif |
| |
| #define REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH 128 |
| #define REGAL_FIXED_FUNCTION_MAX_LIGHTS 8 |
| #define REGAL_FIXED_FUNCTION_MAX_CLIP_PLANES 8 |
| |
| #if REGAL_EMULATION |
| |
| REGAL_GLOBAL_BEGIN |
| |
| #include <climits> |
| #include <cstring> |
| |
| #include <map> |
| #include <vector> |
| #include <string> |
| #include <algorithm> |
| |
| #include "RegalEmu.h" |
| #include "RegalPrivate.h" |
| #include "RegalContext.h" |
| #include "RegalContextInfo.h" |
| #include "RegalSharedMap.h" |
| #include "RegalFloat4.h" |
| #include "linear.h" |
| |
| REGAL_GLOBAL_END |
| |
| REGAL_NAMESPACE_BEGIN |
| |
| namespace Emu { |
| |
| |
| // lookup array, Must Be kept in sync with enum TexenvMode; TEM_* values |
| const GLenum texenvModeGL[] = { |
| GL_FALSE, |
| GL_REPLACE, |
| GL_MODULATE, |
| GL_ADD, |
| GL_DECAL, |
| GL_BLEND, |
| GL_COMBINE |
| }; |
| |
| // lookup array, Must Be kept in sync with enum TexenvCombine; TEC_* values |
| const GLenum texenvCombineGL[] = { |
| GL_FALSE, |
| GL_REPLACE, |
| GL_MODULATE, |
| GL_ADD, |
| GL_ADD_SIGNED, |
| GL_INTERPOLATE, |
| GL_SUBTRACT, |
| GL_DOT3_RGB, |
| GL_DOT3_RGBA |
| }; |
| |
| // lookup array, Must Be kept in sync with enum TexenvCombineSrc; TCS_* values |
| const GLenum texenvCombineSrcGL[] = { |
| GL_FALSE, |
| GL_CONSTANT, |
| GL_PRIMARY_COLOR, |
| GL_PREVIOUS, |
| GL_TEXTURE, |
| GL_TEXTURE0, |
| GL_TEXTURE1, |
| GL_TEXTURE2, |
| GL_TEXTURE3 |
| }; |
| |
| // lookup array, Must Be kept in sync with enum TexenvCombineOp; TCO_* values |
| const GLenum texenvCombineOpGL[] = { |
| GL_FALSE, |
| GL_SRC_COLOR, |
| GL_ONE_MINUS_SRC_COLOR, |
| GL_SRC_ALPHA, |
| GL_ONE_MINUS_SRC_ALPHA |
| }; |
| |
| enum RegalFFUniformEnum { |
| FFU_foo = 0, |
| FFU_Modelview, |
| FFU_ModelviewInverse, |
| FFU_ModelviewInverseTranspose, |
| FFU_Projection, |
| FFU_ProjectionInverse, |
| FFU_ModelviewProjection, |
| FFU_ModelviewProjectionInverse, |
| FFU_TextureMatrix0, |
| FFU_TextureMatrix1, |
| FFU_TextureMatrix2, |
| FFU_TextureMatrix3, |
| FFU_TextureMatrix4, |
| FFU_TextureMatrix5, |
| FFU_TextureMatrix6, |
| FFU_TextureMatrix7, |
| FFU_TextureMatrix8, |
| FFU_TextureMatrix9, |
| FFU_TextureMatrix10, |
| FFU_TextureMatrix11, |
| FFU_TextureMatrix12, |
| FFU_TextureMatrix13, |
| FFU_TextureMatrix14, |
| FFU_TextureMatrix15, |
| FFU_TextureEnvColor0, |
| FFU_TextureEnvColor1, |
| FFU_TextureEnvColor2, |
| FFU_TextureEnvColor3, |
| FFU_TextureEnvColor4, |
| FFU_TextureEnvColor5, |
| FFU_TextureEnvColor6, |
| FFU_TextureEnvColor7, |
| FFU_TextureEnvColor8, |
| FFU_TextureEnvColor9, |
| FFU_TextureEnvColor10, |
| FFU_TextureEnvColor11, |
| FFU_TextureEnvColor12, |
| FFU_TextureEnvColor13, |
| FFU_TextureEnvColor14, |
| FFU_TextureEnvColor15, |
| FFU_Texgen0ObjS, |
| FFU_Texgen0ObjT, |
| FFU_Texgen0ObjR, |
| FFU_Texgen0ObjQ, |
| FFU_Texgen0EyeS, |
| FFU_Texgen0EyeT, |
| FFU_Texgen0EyeR, |
| FFU_Texgen0EyeQ, |
| FFU_Texgen1ObjS, |
| FFU_Texgen1ObjT, |
| FFU_Texgen1ObjR, |
| FFU_Texgen1ObjQ, |
| FFU_Texgen1EyeS, |
| FFU_Texgen1EyeT, |
| FFU_Texgen1EyeR, |
| FFU_Texgen1EyeQ, |
| FFU_Texgen2ObjS, |
| FFU_Texgen2ObjT, |
| FFU_Texgen2ObjR, |
| FFU_Texgen2ObjQ, |
| FFU_Texgen2EyeS, |
| FFU_Texgen2EyeT, |
| FFU_Texgen2EyeR, |
| FFU_Texgen2EyeQ, |
| FFU_Texgen3ObjS, |
| FFU_Texgen3ObjT, |
| FFU_Texgen3ObjR, |
| FFU_Texgen3ObjQ, |
| FFU_Texgen3EyeS, |
| FFU_Texgen3EyeT, |
| FFU_Texgen3EyeR, |
| FFU_Texgen3EyeQ, |
| FFU_Light0, |
| FFU_Light1, |
| FFU_Light2, |
| FFU_Light3, |
| FFU_Light4, |
| FFU_Light5, |
| FFU_Light6, |
| FFU_Light7, |
| FFU_MaterialFront, |
| FFU_MaterialBack, |
| FFU_LightModelAmbient, |
| FFU_ClipPlane0, |
| FFU_ClipPlane1, |
| FFU_ClipPlane2, |
| FFU_ClipPlane3, |
| FFU_ClipPlane4, |
| FFU_ClipPlane5, |
| FFU_ClipPlane6, |
| FFU_ClipPlane7, |
| FFU_Fog, |
| FFU_ConstantColor, |
| FFU_Attrib, |
| FFU_AlphaRef, |
| }; |
| |
| struct RegalFFUniformInfo { |
| RegalFFUniformEnum val; |
| const GLchar * name; |
| }; |
| |
| static const RegalFFUniformInfo regalFFUniformInfo[] = { |
| { FFU_foo, "foo" }, |
| { FFU_Modelview, "rglModelview" }, |
| { FFU_ModelviewInverse, "rglModelviewInverse" }, |
| { FFU_ModelviewInverseTranspose, "rglModelviewInverseTranspose" }, |
| { FFU_Projection, "rglProjection" }, |
| { FFU_ProjectionInverse, "rglProjectionInverse" }, |
| { FFU_ModelviewProjection, "rglModelviewProjection" }, |
| { FFU_ModelviewProjectionInverse, "rglModelviewProjectionInverse" }, |
| { FFU_TextureMatrix0, "rglTextureMatrix0" }, |
| { FFU_TextureMatrix1, "rglTextureMatrix1" }, |
| { FFU_TextureMatrix2, "rglTextureMatrix2" }, |
| { FFU_TextureMatrix3, "rglTextureMatrix3" }, |
| { FFU_TextureMatrix4, "rglTextureMatrix4" }, |
| { FFU_TextureMatrix5, "rglTextureMatrix5" }, |
| { FFU_TextureMatrix6, "rglTextureMatrix6" }, |
| { FFU_TextureMatrix7, "rglTextureMatrix7" }, |
| { FFU_TextureMatrix8, "rglTextureMatrix8" }, |
| { FFU_TextureMatrix9, "rglTextureMatrix9" }, |
| { FFU_TextureMatrix10, "rglTextureMatrix10" }, |
| { FFU_TextureMatrix11, "rglTextureMatrix11" }, |
| { FFU_TextureMatrix12, "rglTextureMatrix12" }, |
| { FFU_TextureMatrix13, "rglTextureMatrix13" }, |
| { FFU_TextureMatrix14, "rglTextureMatrix14" }, |
| { FFU_TextureMatrix15, "rglTextureMatrix15" }, |
| { FFU_TextureEnvColor0, "rglTexEnvColor0" }, |
| { FFU_TextureEnvColor1, "rglTexEnvColor1" }, |
| { FFU_TextureEnvColor2, "rglTexEnvColor2" }, |
| { FFU_TextureEnvColor3, "rglTexEnvColor3" }, |
| { FFU_TextureEnvColor4, "rglTexEnvColor4" }, |
| { FFU_TextureEnvColor5, "rglTexEnvColor5" }, |
| { FFU_TextureEnvColor6, "rglTexEnvColor6" }, |
| { FFU_TextureEnvColor7, "rglTexEnvColor7" }, |
| { FFU_TextureEnvColor8, "rglTexEnvColor8" }, |
| { FFU_TextureEnvColor9, "rglTexEnvColor9" }, |
| { FFU_TextureEnvColor10, "rglTexEnvColor10" }, |
| { FFU_TextureEnvColor11, "rglTexEnvColor11" }, |
| { FFU_TextureEnvColor12, "rglTexEnvColor12" }, |
| { FFU_TextureEnvColor13, "rglTexEnvColor13" }, |
| { FFU_TextureEnvColor14, "rglTexEnvColor14" }, |
| { FFU_TextureEnvColor15, "rglTexEnvColor15" }, |
| { FFU_Texgen0ObjS, "rglTexGen0ObjS" }, |
| { FFU_Texgen0ObjT, "rglTexGen0ObjT" }, |
| { FFU_Texgen0ObjR, "rglTexGen0ObjR" }, |
| { FFU_Texgen0ObjQ, "rglTexGen0ObjQ" }, |
| { FFU_Texgen0EyeS, "rglTexGen0EyeS" }, |
| { FFU_Texgen0EyeT, "rglTexGen0EyeT" }, |
| { FFU_Texgen0EyeR, "rglTexGen0EyeR" }, |
| { FFU_Texgen0EyeQ, "rglTexGen0EyeQ" }, |
| { FFU_Texgen1ObjS, "rglTexGen1ObjS" }, |
| { FFU_Texgen1ObjT, "rglTexGen1ObjT" }, |
| { FFU_Texgen1ObjR, "rglTexGen1ObjR" }, |
| { FFU_Texgen1ObjQ, "rglTexGen1ObjQ" }, |
| { FFU_Texgen1EyeS, "rglTexGen1EyeS" }, |
| { FFU_Texgen1EyeT, "rglTexGen1EyeT" }, |
| { FFU_Texgen1EyeR, "rglTexGen1EyeR" }, |
| { FFU_Texgen1EyeQ, "rglTexGen1EyeQ" }, |
| { FFU_Texgen2ObjS, "rglTexGen2ObjS" }, |
| { FFU_Texgen2ObjT, "rglTexGen2ObjT" }, |
| { FFU_Texgen2ObjR, "rglTexGen2ObjR" }, |
| { FFU_Texgen2ObjQ, "rglTexGen2ObjQ" }, |
| { FFU_Texgen2EyeS, "rglTexGen2EyeS" }, |
| { FFU_Texgen2EyeT, "rglTexGen2EyeT" }, |
| { FFU_Texgen2EyeR, "rglTexGen2EyeR" }, |
| { FFU_Texgen2EyeQ, "rglTexGen2EyeQ" }, |
| { FFU_Texgen3ObjS, "rglTexGen3ObjS" }, |
| { FFU_Texgen3ObjT, "rglTexGen3ObjT" }, |
| { FFU_Texgen3ObjR, "rglTexGen3ObjR" }, |
| { FFU_Texgen3ObjQ, "rglTexGen3ObjQ" }, |
| { FFU_Texgen3EyeS, "rglTexGen3EyeS" }, |
| { FFU_Texgen3EyeT, "rglTexGen3EyeT" }, |
| { FFU_Texgen3EyeR, "rglTexGen3EyeR" }, |
| { FFU_Texgen3EyeQ, "rglTexGen3EyeQ" }, |
| { FFU_Light0, "rglLight0[0]" }, |
| { FFU_Light1, "rglLight1[0]" }, |
| { FFU_Light2, "rglLight2[0]" }, |
| { FFU_Light3, "rglLight3[0]" }, |
| { FFU_Light4, "rglLight4[0]" }, |
| { FFU_Light5, "rglLight5[0]" }, |
| { FFU_Light6, "rglLight6[0]" }, |
| { FFU_Light7, "rglLight7[0]" }, |
| { FFU_MaterialFront, "rglMaterialFront" }, |
| { FFU_MaterialBack, "rglMaterialBack" }, |
| { FFU_LightModelAmbient, "rglLightModelAmbient" }, |
| { FFU_ClipPlane0, "rglClipPlane0" }, |
| { FFU_ClipPlane1, "rglClipPlane1" }, |
| { FFU_ClipPlane2, "rglClipPlane2" }, |
| { FFU_ClipPlane3, "rglClipPlane3" }, |
| { FFU_ClipPlane4, "rglClipPlane4" }, |
| { FFU_ClipPlane5, "rglClipPlane5" }, |
| { FFU_ClipPlane6, "rglClipPlane6" }, |
| { FFU_ClipPlane7, "rglClipPlane7" }, |
| { FFU_Fog, "rglFog" }, |
| { FFU_ConstantColor, "rglConstantColor" }, |
| { FFU_Attrib, "rglAttrib[0]" }, |
| { FFU_AlphaRef, "rglAlphaRef" }, |
| }; |
| |
| template <typename T> bool RFFIsVector( const T p ) { UNUSED_PARAMETER(p); return false; } |
| template <typename T> bool RFFIsVector( const T * p ) { UNUSED_PARAMETER(p); return true; } |
| |
| template <typename T> GLfloat RFFToFloat( int i, const T p ) { UNUSED_PARAMETER(i); return GLfloat( p ); } |
| template <typename T> GLfloat RFFToFloat( int i, const T * p ) { return GLfloat( p[i] ); } |
| template <typename T> GLfloat RFFToFloatN( int i, const T p ) { UNUSED_PARAMETER(i); return GLfloat( p ); } |
| template <typename T> GLfloat RFFToFloatN( int i, const T * p ) { return GLfloat( p[i] ); } |
| template <> inline GLfloat RFFToFloatN( int i, const GLint p ) { UNUSED_PARAMETER(i); return GLfloat( double( p ) / double( INT_MAX ) ); } |
| template <> inline GLfloat RFFToFloatN( int i, const int * p ) { return GLfloat( double( p[i] ) / double( INT_MAX ) ); } |
| |
| |
| |
| struct Iff |
| { |
| Iff() |
| : progcount(0) |
| { |
| } |
| |
| Iff(const Iff &other) |
| : progcount(0) |
| { |
| UNUSED_PARAMETER(other); |
| } |
| |
| Iff &operator=(const Iff &other) |
| { |
| UNUSED_PARAMETER(other); |
| if (&other!=this) |
| { |
| } |
| return *this; |
| } |
| |
| ~Iff() |
| { |
| } |
| |
| void Cleanup( RegalContext &ctx ); |
| |
| // Info |
| int progcount; |
| |
| // Vertex arrays |
| GLuint catIndex; |
| GLuint ffAttrMap[ REGAL_EMU_IFF_VERTEX_ATTRIBS ]; |
| GLuint ffAttrInvMap[ REGAL_EMU_IFF_VERTEX_ATTRIBS ]; |
| GLuint ffAttrTexBegin; |
| GLuint ffAttrTexEnd; |
| GLuint ffAttrNumTex; |
| GLuint maxVertexAttribs; |
| |
| void InitVertexArray(RegalContext &ctx) |
| { |
| maxVertexAttribs = ctx.info->maxVertexAttribs; |
| |
| if( maxVertexAttribs >= 16 ) { |
| RegalAssert( REGAL_EMU_IFF_VERTEX_ATTRIBS == 16); |
| //RegalOutput( "Setting up for %d Vertex Attribs\n", maxVertexAttribs ); |
| for( int i = 0; i < 16; i++ ) { |
| ffAttrMap[i] = RFF2AMap16[i]; |
| ffAttrInvMap[i] = RFF2AInvMap16[i]; |
| } |
| ffAttrTexBegin = RFF2ATexBegin16; |
| ffAttrTexEnd = RFF2ATexEnd16; |
| } else { |
| RegalAssert( maxVertexAttribs >= 8 ); |
| //RegalOutput( "Setting up for 8 Vertex Attribs" ); |
| for( int i = 0; i < 8; i++ ) { |
| ffAttrMap[i] = RFF2AMap8[i]; |
| ffAttrInvMap[i] = RFF2AInvMap8[i]; |
| } |
| for( int i = 8; i < REGAL_EMU_IFF_VERTEX_ATTRIBS; i++ ) { |
| ffAttrMap[i] = GLuint(-1); |
| ffAttrInvMap[i] = GLuint(-1); |
| } |
| ffAttrTexBegin = RFF2ATexBegin8; |
| ffAttrTexEnd = RFF2ATexEnd8; |
| } |
| ffAttrNumTex = ffAttrTexEnd - ffAttrTexBegin; |
| catIndex = 0; |
| } |
| |
| GLuint ClientStateToIndex( GLenum state ) { |
| switch( state ) { |
| case GL_VERTEX_ARRAY: return ffAttrMap[ RFF2A_Vertex ]; |
| case GL_NORMAL_ARRAY: return ffAttrMap[ RFF2A_Normal ]; |
| case GL_COLOR_ARRAY: return ffAttrMap[ RFF2A_Color ]; |
| case GL_SECONDARY_COLOR_ARRAY: return ffAttrMap[ RFF2A_SecondaryColor ]; |
| case GL_FOG_COORD_ARRAY: return ffAttrMap[ RFF2A_FogCoord ]; |
| case GL_EDGE_FLAG_ARRAY: return ffAttrMap[ RFF2A_EdgeFlag ]; |
| case GL_TEXTURE_COORD_ARRAY: { |
| if( catIndex < ffAttrNumTex ) { |
| return ffAttrTexBegin + catIndex; |
| } |
| break; |
| } |
| default: break; |
| } |
| return ~0u; |
| } |
| |
| void EnableClientState( RegalContext * ctx, GLenum state ) { |
| const GLuint idx = ClientStateToIndex( state ); |
| if( idx == GLuint(~0) ) { |
| return; |
| } |
| RestoreVao( ctx ); |
| RegalAssert( idx < maxVertexAttribs ); |
| if ( idx < maxVertexAttribs ) { |
| ctx->dispatcher.emulation.glEnableVertexAttribArray( idx ); |
| EnableArray( ctx, idx ); // keep ffn up to date |
| } |
| } |
| |
| void DisableClientState( RegalContext * ctx, GLenum state ) { |
| const GLuint idx = ClientStateToIndex( state ); |
| if( idx == GLuint(~0) ) { |
| return; |
| } |
| RestoreVao( ctx ); |
| RegalAssert( idx < maxVertexAttribs ); |
| if ( idx < maxVertexAttribs ) { |
| ctx->dispatcher.emulation.glDisableVertexAttribArray( idx ); |
| DisableArray( ctx, idx ); // keep ffn up to date |
| } |
| } |
| |
| void VertexPointer( RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) |
| { |
| //<> if ( insideBeginEnd == true ) |
| //<> return; |
| |
| switch (size) |
| { |
| case 2: |
| case 3: |
| case 4: |
| break; |
| default: |
| return; |
| } |
| |
| switch (type) |
| { |
| case GL_SHORT: |
| case GL_INT: |
| case GL_FLOAT: |
| case GL_DOUBLE: |
| break; |
| default: |
| return; |
| } |
| |
| if (stride < 0) |
| return; |
| |
| RestoreVao( ctx ); |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrMap[ RFF2A_Vertex ], size, type, GL_FALSE, stride, pointer ); |
| } |
| |
| void NormalPointer( RegalContext * ctx, GLenum type, GLsizei stride, const GLvoid *pointer ) { |
| RestoreVao( ctx ); |
| GLboolean n = type == GL_FLOAT ? GL_FALSE : GL_TRUE; |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrMap[ RFF2A_Normal ], 3, type, n, stride, pointer ); |
| } |
| |
| void ColorPointer( RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) { |
| RestoreVao( ctx ); |
| GLboolean n = type == GL_FLOAT ? GL_FALSE : GL_TRUE; |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrMap[ RFF2A_Color ], size, type, n, stride, pointer ); |
| } |
| |
| void SecondaryColorPointer( RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) { |
| RestoreVao( ctx ); |
| GLboolean n = type == GL_FLOAT ? GL_FALSE : GL_TRUE; |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrMap[ RFF2A_SecondaryColor ], size, type, n, stride, pointer ); |
| } |
| |
| void FogCoordPointer( RegalContext * ctx, GLenum type, GLsizei stride, const GLvoid *pointer ) { |
| RestoreVao( ctx ); |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrMap[ RFF2A_FogCoord ], 1, type, GL_FALSE, stride, pointer ); |
| } |
| |
| void EdgeFlagPointer( RegalContext * ctx, GLsizei stride, const GLvoid *pointer ) { |
| RestoreVao( ctx ); |
| GLuint index = ffAttrMap[ RFF2A_EdgeFlag ]; |
| if( index == RFF2A_Invalid ) { |
| return; |
| } |
| ctx->dispatcher.emulation.glVertexAttribPointer( index, 1, GL_UNSIGNED_BYTE, GL_FALSE, stride, pointer ); |
| } |
| |
| void TexCoordPointer( RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) { |
| if( catIndex >= ffAttrNumTex ) { |
| // FIXME: set an error here! |
| return; |
| } |
| RestoreVao( ctx ); |
| ctx->dispatcher.emulation.glVertexAttribPointer( ffAttrTexBegin + catIndex, size, type, GL_FALSE, stride, pointer ); |
| } |
| |
| void GetAttrib( RegalContext * ctx, GLuint index, GLenum pname, GLdouble * d ) { |
| ctx->dispatcher.emulation.glGetVertexAttribdv( index, pname, d ); |
| } |
| |
| void GetAttrib( RegalContext * ctx, GLuint index, GLenum pname, GLfloat * f ) { |
| ctx->dispatcher.emulation.glGetVertexAttribfv( index, pname, f ); |
| } |
| |
| void GetAttrib( RegalContext * ctx, GLuint index, GLenum pname, GLint * i ) { |
| ctx->dispatcher.emulation.glGetVertexAttribiv( index, pname, i ); |
| } |
| |
| template <typename T> bool VaGet( RegalContext * ctx, GLenum pname, T * params ) { |
| |
| GLuint index = 0; |
| switch (pname) { |
| case GL_VERTEX_ARRAY_BUFFER_BINDING: |
| case GL_VERTEX_ARRAY_SIZE: |
| case GL_VERTEX_ARRAY_TYPE: |
| case GL_VERTEX_ARRAY_STRIDE: |
| case GL_VERTEX_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_Vertex ]; |
| break; |
| case GL_NORMAL_ARRAY_BUFFER_BINDING: |
| case GL_NORMAL_ARRAY_TYPE: |
| case GL_NORMAL_ARRAY_STRIDE: |
| case GL_NORMAL_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_Normal ]; |
| break; |
| case GL_COLOR_ARRAY_BUFFER_BINDING: |
| case GL_COLOR_ARRAY_SIZE: |
| case GL_COLOR_ARRAY_TYPE: |
| case GL_COLOR_ARRAY_STRIDE: |
| case GL_COLOR_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_Color ]; |
| //if( pname == GL_COLOR_ARRAY_SIZE ) RegalOutput( "Passing index = %d to VA GetAttrib for COLOR_INDEX_SIZE\n", index ); |
| break; |
| case GL_SECONDARY_COLOR_ARRAY_SIZE: |
| // This is a convenient lie. --Cass |
| *params = 3; |
| break; |
| case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING: |
| case GL_SECONDARY_COLOR_ARRAY_TYPE: |
| case GL_SECONDARY_COLOR_ARRAY_STRIDE: |
| case GL_SECONDARY_COLOR_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_SecondaryColor ]; |
| break; |
| case GL_FOG_COORD_ARRAY_BUFFER_BINDING: |
| case GL_FOG_COORD_ARRAY_TYPE: |
| case GL_FOG_COORD_ARRAY_STRIDE: |
| case GL_FOG_COORD_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_FogCoord ]; |
| break; |
| |
| case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING: |
| case GL_EDGE_FLAG_ARRAY_STRIDE: |
| case GL_EDGE_FLAG_ARRAY_POINTER: |
| index = ffAttrMap[ RFF2A_EdgeFlag ]; |
| break; |
| |
| case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: |
| case GL_TEXTURE_COORD_ARRAY_SIZE: |
| case GL_TEXTURE_COORD_ARRAY_TYPE: |
| case GL_TEXTURE_COORD_ARRAY_STRIDE: |
| case GL_TEXTURE_COORD_ARRAY_POINTER: { |
| if( catIndex >= ffAttrNumTex ) { |
| // FIXME need to set an error here! |
| return false; |
| } |
| index = ffAttrTexBegin + catIndex; |
| } |
| break; |
| |
| // INDEX arrays are not supported |
| case GL_INDEX_ARRAY_TYPE: |
| *params = GL_FLOAT; |
| break; |
| case GL_INDEX_ARRAY_BUFFER_BINDING: |
| case GL_INDEX_ARRAY_STRIDE: |
| case GL_INDEX_ARRAY_POINTER: |
| default: |
| return false; |
| } |
| |
| switch (pname) { |
| case GL_VERTEX_ARRAY_BUFFER_BINDING: |
| case GL_NORMAL_ARRAY_BUFFER_BINDING: |
| case GL_COLOR_ARRAY_BUFFER_BINDING: |
| case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING: |
| case GL_FOG_COORD_ARRAY_BUFFER_BINDING: |
| case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING: |
| case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: |
| pname = GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; |
| break; |
| case GL_VERTEX_ARRAY_SIZE: |
| case GL_COLOR_ARRAY_SIZE: |
| case GL_TEXTURE_COORD_ARRAY_SIZE: |
| pname = GL_VERTEX_ATTRIB_ARRAY_SIZE; |
| break; |
| |
| case GL_VERTEX_ARRAY_TYPE: |
| case GL_NORMAL_ARRAY_TYPE: |
| case GL_COLOR_ARRAY_TYPE: |
| case GL_SECONDARY_COLOR_ARRAY_TYPE: |
| case GL_FOG_COORD_ARRAY_TYPE: |
| case GL_TEXTURE_COORD_ARRAY_TYPE: |
| pname = GL_VERTEX_ATTRIB_ARRAY_TYPE; |
| break; |
| |
| case GL_VERTEX_ARRAY_STRIDE: |
| case GL_NORMAL_ARRAY_STRIDE: |
| case GL_COLOR_ARRAY_STRIDE: |
| case GL_SECONDARY_COLOR_ARRAY_STRIDE: |
| case GL_FOG_COORD_ARRAY_STRIDE: |
| case GL_EDGE_FLAG_ARRAY_STRIDE: |
| case GL_TEXTURE_COORD_ARRAY_STRIDE: |
| pname = GL_VERTEX_ATTRIB_ARRAY_STRIDE; |
| break; |
| |
| case GL_VERTEX_ARRAY_POINTER: |
| case GL_NORMAL_ARRAY_POINTER: |
| case GL_COLOR_ARRAY_POINTER: |
| case GL_SECONDARY_COLOR_ARRAY_POINTER: |
| case GL_FOG_COORD_ARRAY_POINTER: |
| case GL_EDGE_FLAG_ARRAY_POINTER: |
| case GL_TEXTURE_COORD_ARRAY_POINTER: |
| pname = GL_VERTEX_ATTRIB_ARRAY_POINTER; |
| break; |
| |
| default: |
| return false; |
| } |
| RestoreVao( ctx ); |
| if( index == RFF2A_Invalid ) { |
| // What to return in this case? |
| return false; |
| } |
| GetAttrib( ctx, index, pname, params ); |
| return true; |
| } |
| |
| bool IsEnabled( RegalContext * ctx, GLenum pname, GLboolean &enabled ) |
| { |
| State::Store & st = ffstate.raw; |
| int idx = 0; |
| switch( pname ) { |
| case GL_TEXTURE_GEN_S: |
| case GL_TEXTURE_GEN_T: |
| case GL_TEXTURE_GEN_R: |
| case GL_TEXTURE_GEN_Q: |
| idx = pname - GL_TEXTURE_GEN_S; |
| if( activeTextureIndex >= REGAL_EMU_IFF_TEXTURE_UNITS ) { |
| return false; |
| } |
| enabled = st.tex[ activeTextureIndex ].texgen[ idx ].enable; |
| return true; |
| default: |
| break; |
| } |
| |
| const GLuint index = ClientStateToIndex( pname ); |
| if( index == GLuint(~0) ) { |
| return false; |
| } |
| RegalAssert( index < maxVertexAttribs ); |
| GLint ret; |
| GetAttrib( ctx, index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &ret ); |
| enabled = static_cast<GLboolean>(ret); |
| return true; |
| } |
| |
| // immediate mode |
| |
| struct Attributes { Float4 attr[ REGAL_EMU_IFF_VERTEX_ATTRIBS ]; }; |
| |
| bool immActive; |
| GLuint immProvoking; |
| int immCurrent; |
| GLenum immPrim; |
| Attributes immVab; |
| GLubyte immArray[ REGAL_IMMEDIATE_BUFFER_SIZE * REGAL_EMU_IFF_VERTEX_ATTRIBS * 16 ]; |
| |
| GLuint immVbo; |
| GLuint immVao; |
| GLuint immQuadsVbo; |
| GLuint immShadowVao; |
| |
| void InitImmediate(RegalContext &ctx) |
| { |
| immActive = false; |
| immProvoking = 0; |
| immCurrent = 0; |
| immPrim = GL_POINTS; |
| for( GLuint i = 0; i < maxVertexAttribs; i++ ) { |
| Float4 & a = immVab.attr[i]; |
| a.x = a.y = a.z = 0.0f; a.w = 1.0f; |
| } |
| |
| memset(immArray,0,sizeof(immArray)); |
| memset(&immVab, 0, sizeof(immVab)); |
| |
| immShadowVao = 0; |
| |
| DispatchTableGL &tbl = ctx.dispatcher.emulation; |
| tbl.glGenVertexArrays( 1, & immVao ); |
| tbl.glBindVertexArray( immVao ); |
| BindVertexArray( &ctx, immVao ); // to keep ffn current |
| tbl.glGenBuffers( 1, & immVbo ); |
| tbl.glGenBuffers( 1, & immQuadsVbo ); |
| tbl.glBindBuffer( GL_ARRAY_BUFFER, immVbo ); |
| #if REGAL_SYS_EMSCRIPTEN |
| // We need this to be an allocated buffer for WebGL, because a dangling VertexAttribPointer |
| // doesn't work. XXX -- this might be a Firefox bug, check? |
| tbl.glBufferData( GL_ARRAY_BUFFER, sizeof( immArray ), NULL, GL_STATIC_DRAW ); |
| #endif |
| for( GLuint i = 0; i < maxVertexAttribs; i++ ) { |
| EnableArray( &ctx, i ); // to keep ffn current |
| tbl.glEnableVertexAttribArray( i ); |
| tbl.glVertexAttribPointer( i, 4, GL_FLOAT, GL_FALSE, maxVertexAttribs * 16, (GLubyte *)NULL + i * 16 ); |
| } |
| tbl.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, immQuadsVbo ); |
| GLushort quadIndexes[ REGAL_IMMEDIATE_BUFFER_SIZE * 3 / 2 ]; |
| for ( GLushort i = 0; i < REGAL_IMMEDIATE_BUFFER_SIZE / 4; i++ ) { |
| quadIndexes[ i * 6 + 0 ] = i * 4 + 0; // first triangle |
| quadIndexes[ i * 6 + 1 ] = i * 4 + 1; |
| quadIndexes[ i * 6 + 2 ] = i * 4 + 2; |
| quadIndexes[ i * 6 + 3 ] = i * 4 + 0; // second triangle |
| quadIndexes[ i * 6 + 4 ] = i * 4 + 2; |
| quadIndexes[ i * 6 + 5 ] = i * 4 + 3; |
| } |
| tbl.glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( quadIndexes ), quadIndexes, GL_STATIC_DRAW ); |
| tbl.glBindVertexArray( 0 ); |
| BindVertexArray( &ctx, 0 ); // to keep ffn current |
| |
| // The initial texture coordinates are (s; t; r; q) = (0; 0; 0; 1) |
| // for each texture coordinate set. |
| |
| for( catIndex = 0; catIndex < REGAL_EMU_MAX_TEXTURE_UNITS; catIndex++ ) { |
| Attr<4>( &ctx, AttrIndex( RFF2A_TexCoord ), 0, 0, 0, 1 ); |
| } |
| catIndex = 0; |
| |
| // The initial current normal has coordinates (0; 0; 1). |
| |
| Attr<3>( &ctx, AttrIndex( RFF2A_Normal ), 0, 0, 1 ); |
| |
| // The initial RGBA color is (R;G;B;A) = (1; 1; 1; 1) and |
| // the initial RGBA secondary color is (0; 0; 0; 1). |
| |
| Attr<4>( &ctx, AttrIndex( RFF2A_Color ), 1, 1, 1, 1 ); |
| Attr<4>( &ctx, AttrIndex( RFF2A_SecondaryColor ), 0, 0, 0, 1 ); |
| |
| // The initial fog coordinate is zero. |
| |
| // ... so nothing to do for fog coordinate |
| |
| // The initial color index is 1. |
| // The initial values for all generic vertex attributes are (0:0; 0:0; 0:0; 1:0). |
| } |
| |
| void DeleteVertexArrays( RegalContext * ctx, GLsizei n, const GLuint * arrays ) |
| { |
| RegalAssert( ctx != NULL ); |
| for( GLsizei i = 0; i < n; i++ ) { |
| GLuint name = arrays[ i ]; |
| if( name != immVao ) { |
| ctx->dispatcher.emulation.glDeleteVertexArrays( 1, &name ); |
| } |
| } |
| } |
| |
| GLboolean IsVertexArray( RegalContext * ctx, GLuint name ) |
| { |
| RegalAssert( ctx != NULL ); |
| if (name == immVao ) |
| return GL_FALSE; |
| return ctx->dispatcher.emulation.glIsVertexArray( name ); |
| } |
| |
| void ShadowVao( RegalContext *ctx, GLuint vao ) { |
| immShadowVao = vao; |
| if( immActive == false ) { |
| BindVertexArray( ctx, vao ); |
| } |
| } |
| |
| void ShadowClientActiveTexture( GLenum unit ) { |
| catIndex = unit - GL_TEXTURE0; |
| } |
| |
| void Begin( RegalContext * ctx, GLenum mode ) { |
| if( immActive == false ) { |
| immActive = true; |
| ctx->dispatcher.emulation.glBindVertexArray( immVao ); |
| BindVertexArray( ctx, immVao ); // keep ffn current |
| } |
| PreDraw( ctx ); |
| immCurrent = 0; |
| immPrim = mode; |
| } |
| |
| void End( RegalContext * ctx ) { |
| Flush( ctx ); |
| } |
| |
| void RestoreVao( RegalContext * ctx ) { |
| if( immActive == true ) { |
| //RegalOutput( "Restoring vao to %d in Iff\n", immShadowVao ); |
| ctx->dispatcher.emulation.glBindVertexArray( immShadowVao ); |
| BindVertexArray( ctx, immShadowVao ); |
| immActive = false; |
| } |
| } |
| |
| void Flush( RegalContext * ctx ) |
| { |
| if (immCurrent>0) { // Do nothing for empty buffer |
| DispatchTableGL &tbl = ctx->dispatcher.emulation; |
| tbl.glBufferData( GL_ARRAY_BUFFER, immCurrent * sizeof( Attributes ), immArray, GL_DYNAMIC_DRAW ); |
| if( ( ctx->info->core == true || ctx->info->es2 ) && immPrim == GL_QUADS ) { |
| tbl.glDrawElements( GL_TRIANGLES, ( immCurrent / 4 ) * 6, GL_UNSIGNED_SHORT, 0 ); |
| } else { |
| GLenum derivedPrim = immPrim; |
| GLsizei derivedCount = immCurrent; |
| if( ( ctx->info->core == true || ctx->info->es2 ) ) { |
| switch( immPrim ) { |
| case GL_POLYGON: |
| derivedPrim = GL_TRIANGLE_FAN; |
| break; |
| case GL_QUAD_STRIP: |
| derivedPrim = GL_TRIANGLE_STRIP; |
| derivedCount = derivedCount & ~GLsizei(1); |
| break; |
| default: |
| break; |
| } |
| } |
| tbl.glDrawArrays( derivedPrim, 0, derivedCount ); |
| } |
| } |
| } |
| |
| void Provoke( RegalContext * ctx ) { |
| memcpy( immArray + immCurrent * maxVertexAttribs * 16, &immVab.attr[0].x, maxVertexAttribs * 16 ); |
| immCurrent++; |
| |
| if ( immCurrent >= REGAL_IMMEDIATE_BUFFER_SIZE ) { |
| Flush( ctx ); |
| int restartVerts = 0; |
| switch( immPrim ) { |
| case GL_QUADS: |
| restartVerts = REGAL_IMMEDIATE_BUFFER_SIZE % 4; |
| break; |
| case GL_TRIANGLES: |
| restartVerts = REGAL_IMMEDIATE_BUFFER_SIZE % 3; |
| break; |
| case GL_LINES: |
| restartVerts = REGAL_IMMEDIATE_BUFFER_SIZE % 2; |
| break; |
| case GL_QUAD_STRIP: |
| restartVerts = 2; |
| break; |
| case GL_TRIANGLE_STRIP: |
| restartVerts = 2; |
| break; |
| case GL_LINE_STRIP: |
| restartVerts = 1; |
| break; |
| default: |
| break; |
| } |
| |
| // For triangle fan we need the first and last vertices |
| // for restarting. All others concern the most recent n. |
| |
| if (immPrim==GL_TRIANGLE_FAN) |
| { |
| memcpy( immArray + maxVertexAttribs * 16, immArray + (REGAL_IMMEDIATE_BUFFER_SIZE - 1) * maxVertexAttribs * 16, maxVertexAttribs * 16); |
| immCurrent = 2; |
| } |
| else |
| { |
| int offset = REGAL_IMMEDIATE_BUFFER_SIZE - restartVerts; |
| memcpy( immArray, immArray + offset * maxVertexAttribs * 16, restartVerts * maxVertexAttribs * 16); |
| immCurrent = restartVerts; |
| } |
| } |
| } |
| |
| template <int N, bool Norm, typename T> void Attribute( RegalContext * ctx, GLuint idx, const T * v ) { |
| if( idx >= maxVertexAttribs ) { |
| // FIXME: set an error |
| return; |
| } |
| Float4 & a = immVab.attr[ idx ]; |
| a.x = ToFloat<Norm>( v[0] ); |
| a.y = N > 1 ? ToFloat<Norm>( v[1] ) : 0.0f; |
| a.z = N > 2 ? ToFloat<Norm>( v[2] ) : 0.0f; |
| a.w = N > 3 ? ToFloat<Norm>( v[3] ) : 1.0f; |
| ffstate.uniform.ver = ffstate.uniform.vabVer = ver.Update(); |
| if( idx == immProvoking ) { |
| Provoke( ctx ); |
| } |
| } |
| |
| |
| template <int N, typename T> void Attr( RegalContext *ctx, GLuint idx, T x, T y = 0, T z = 0, T w = 1 ) { |
| T v[4] = { x, y, z, w }; |
| Attribute<N,false>( ctx, idx,v ); |
| } |
| |
| template <int N, typename T> void AttrN( RegalContext *ctx, GLuint idx, T x, T y = 0, T z = 0, T w = 1 ) { |
| T v[4] = { x, y, z, w }; |
| Attribute<N,true>( ctx, idx, v ); |
| } |
| template <int N, typename T> void Attr( RegalContext *ctx, GLuint idx, const T * v ) { |
| Attribute<N,false>( ctx, idx, v ); |
| } |
| |
| template <int N, typename T> void AttrN( RegalContext *ctx, GLuint idx, const T * v ) { |
| Attribute<N,true>( ctx, idx, v ); |
| } |
| |
| GLuint AttrIndex( RegalFixedFunctionAttrib attr, int cat = -1 ) const { |
| if( attr < RFF2A_TexCoord ) { |
| return ffAttrMap[ attr ]; |
| } |
| if( cat < 0 ) { |
| cat = catIndex; |
| } |
| if( attr == RFF2A_TexCoord && GLuint(cat) < ffAttrNumTex ) { |
| return ffAttrTexBegin + cat; |
| } |
| return ~0u; |
| } |
| |
| |
| // fixed function |
| |
| enum CompareFunc { |
| CF_Invalid, |
| CF_Never, |
| CF_Less, |
| CF_Equal, |
| CF_Lequal, |
| CF_Greater, |
| CF_NotEqual, |
| CF_Gequal, |
| CF_Always |
| }; |
| |
| enum TexturePriority { |
| TP_1D = 0, |
| TP_2D = 1, |
| TP_Rect = 2, |
| TP_3D = 3, |
| TP_CubeMap = 4 |
| }; |
| |
| enum TextureTargetBitfield { |
| TT_None = 0, |
| TT_1D = 1<<TP_1D, |
| TT_2D = 1<<TP_2D, |
| TT_Rect = 1<<TP_Rect, |
| TT_3D = 1<<TP_3D, |
| TT_CubeMap = 1<<TP_CubeMap |
| }; |
| |
| enum TexgenMode { |
| TG_ObjectLinear = 1, |
| TG_EyeLinear = 2, |
| TG_SphereMap = 3, |
| TG_NormalMap = 4, |
| TG_ReflectionMap = 5 |
| }; |
| |
| enum FogMode { |
| FG_Linear = 1, |
| FG_Exp = 2, |
| FG_Exp2 = 3 |
| }; |
| |
| enum ColorMaterialMode { |
| CM_None = 0, |
| CM_Emission = 1, |
| CM_Ambient = 2, |
| CM_Diffuse = 3, |
| CM_Specular = 4, |
| CM_AmbientAndDiffuse = 5 |
| }; |
| |
| // enums must be in sync with look up array texenvModeGL |
| enum TexenvMode { |
| TEM_Invalid, |
| TEM_Replace, |
| TEM_Modulate, |
| TEM_Add, |
| TEM_Decal, |
| TEM_Blend, |
| TEM_Combine |
| }; |
| |
| |
| // enums must be in sync with look up array texenvCombineGL |
| enum TexenvCombine { |
| TEC_Invalid, |
| TEC_Replace, |
| TEC_Modulate, |
| TEC_Add, |
| TEC_AddSigned, |
| TEC_Interpolate, |
| TEC_Subtract, |
| TEC_Dot3Rgb, |
| TEC_Dot3Rgba |
| }; |
| |
| // enums must be in sync with look up array texenvCombineSrcGL |
| enum TexenvCombineSrc { |
| TCS_Invalid, |
| TCS_Constant, |
| TCS_PrimaryColor, |
| TCS_Previous, |
| TCS_Texture, |
| TCS_Texture0, |
| TCS_Texture1, |
| TCS_Texture2, |
| TCS_Texture3, |
| }; |
| |
| // enums must be in sync with look up array texenvCombineOpGL |
| enum TexenvCombineOp { |
| TCO_Invalid, |
| TCO_Color, |
| TCO_OneMinusColor, |
| TCO_Alpha, |
| TCO_OneMinusAlpha |
| }; |
| |
| struct TexenvCombineState |
| { |
| TexenvCombineState(bool isRgb) |
| { |
| memset( this, 0, sizeof(TexenvCombineState) ); |
| mode = TEC_Modulate; |
| src0 = TCS_Texture; |
| src1 = TCS_Previous; |
| src2 = TCS_Constant; |
| op0 = op1 = (isRgb ? TCO_Color : TCO_Alpha); |
| op2 = TCO_Alpha; |
| scale = 1.0f; |
| } |
| |
| TexenvCombineState( const TexenvCombineState &other ) |
| { |
| memcpy(this, &other, sizeof(TexenvCombineState) ); |
| } |
| |
| TexenvCombineState &operator=(const TexenvCombineState &other) |
| { |
| if (&other!=this) |
| memcpy(this, &other, sizeof(TexenvCombineState)); |
| return *this; |
| } |
| |
| TexenvCombine mode; |
| TexenvCombineSrc src0; |
| TexenvCombineSrc src1; |
| TexenvCombineSrc src2; |
| TexenvCombineOp op0; |
| TexenvCombineOp op1; |
| TexenvCombineOp op2; |
| GLfloat scale; |
| }; |
| |
| struct TextureEnv |
| { |
| TextureEnv() |
| : mode(TEM_Modulate), rgb(true), a(false) |
| { |
| } |
| |
| TexenvMode mode; |
| TexenvCombineState rgb, a; |
| }; |
| |
| struct TextureUnit |
| { |
| TextureUnit() |
| { |
| memset(this,0,sizeof(TextureUnit)); |
| env = TextureEnv(); |
| } |
| |
| TextureUnit(const TextureUnit &other) |
| { |
| memcpy(this,&other,sizeof(TextureUnit)); |
| } |
| |
| TextureUnit &operator=(const TextureUnit &other) |
| { |
| if (&other!=this) |
| memcpy(this,&other,sizeof(TextureUnit)); |
| return *this; |
| } |
| |
| GLubyte ttb; |
| GLint fmt; |
| TextureEnv env; |
| }; |
| |
| struct Version { |
| Version() |
| : val( 0 ) |
| , updated( false ) |
| {} |
| GLuint64 Current() const { |
| return val; |
| } |
| GLuint64 Update() { |
| if( updated == false ) { |
| val++; |
| updated = true; |
| } |
| return val; |
| } |
| void Reset() { |
| updated = false; |
| } |
| GLuint64 val; |
| bool updated; |
| }; |
| |
| struct State { |
| |
| struct Texgen |
| { |
| Texgen() |
| { |
| memset(this, 0, sizeof(Texgen)); |
| mode = TG_EyeLinear; |
| } |
| |
| Texgen(const Texgen &other) |
| { |
| memcpy(this, &other, sizeof(Texgen)); |
| } |
| |
| Texgen &operator=(const Texgen &other) |
| { |
| if (&other!=this) |
| memcpy(this, &other, sizeof(Texgen)); |
| return *this; |
| } |
| |
| GLboolean enable; |
| TexgenMode mode; |
| }; |
| |
| struct TexgenUniform |
| { |
| TexgenUniform() |
| { |
| memset(this, 0, sizeof(TexgenUniform)); |
| } |
| Float4 obj; |
| Float4 eye; |
| GLuint64 objVer; |
| GLuint64 eyeVer; |
| }; |
| |
| struct Texture |
| { |
| Texture() |
| { |
| memset(this, 0, sizeof(Texture)); |
| texgen[0] = texgen[1] = texgen[2] = texgen[3] = Texgen(); |
| unit = TextureUnit(); |
| } |
| |
| Texture(const Texture &other) |
| { |
| memcpy(this, &other, sizeof(Texture)); |
| } |
| |
| Texture &operator=(const Texture &other) |
| { |
| if (&other!=this) |
| memcpy(this, &other, sizeof(Texture)); |
| return *this; |
| } |
| |
| GLubyte enables; |
| bool useMatrix; |
| Texgen texgen[4]; |
| TextureUnit unit; |
| }; |
| |
| struct TextureUniform { |
| TextureUniform() |
| { |
| texgen[0].obj = texgen[0].eye = Float4( 1, 0, 0, 0 ); |
| texgen[1].obj = texgen[1].eye = Float4( 0, 1, 0, 0 ); |
| } |
| TexgenUniform texgen[4]; |
| }; |
| |
| struct AlphaTest { |
| AlphaTest() |
| { |
| memset( this, 0, sizeof( *this ) ); |
| enable = false; |
| comp = CF_Always; |
| } |
| AlphaTest( const AlphaTest & cpy ) { |
| memcpy( this, &cpy, sizeof( *this) ); |
| } |
| |
| GLboolean enable; |
| CompareFunc comp; |
| }; |
| |
| struct AlphaTestUniform { |
| AlphaTestUniform() |
| : alphaRef( 0 ) |
| , ver( 0 ) |
| {} |
| GLfloat alphaRef; |
| GLuint64 ver; |
| }; |
| |
| struct Clip { |
| Clip() |
| : enable( false ) |
| { |
| } |
| bool enable; |
| }; |
| |
| struct ClipUniform { |
| ClipUniform() |
| : plane( 0, 0, 0, 0 ) |
| , ver( 0 ) |
| {} |
| Float4 plane; |
| GLuint64 ver; |
| }; |
| |
| struct Fog { |
| Fog() |
| { |
| memset( this, 0, sizeof( *this ) ); |
| enable = false; |
| useDepth = true; |
| mode = FG_Exp; |
| } |
| Fog( const Fog & cpy ) { |
| memcpy( this, &cpy, sizeof( *this) ); |
| } |
| bool enable; |
| bool useDepth; |
| FogMode mode : 4; |
| }; |
| |
| struct FogUniform { |
| FogUniform() |
| : ver( 0 ) |
| { |
| params[0] = Float4( 1, 0, 1, 0 ); |
| params[1] = Float4( 0, 0, 0, 0 ); |
| } |
| Float4 params[2]; // .x = density, .y = start, .z = end, .w = d/c |
| GLuint64 ver; |
| }; |
| |
| struct Light { |
| Light() |
| { |
| memset( this, 0, sizeof( *this ) ); |
| enable = false; |
| spotlight = false; |
| attenuate = false; |
| local = false; |
| } |
| Light( const Light & cpy ) { |
| memcpy( this, &cpy, sizeof( *this) ); |
| } |
| |
| bool enable; |
| bool spotlight; |
| bool attenuate; |
| bool local; |
| }; |
| |
| struct LightUniform { |
| LightUniform() |
| : position( 0, 0, 1, 0 ) |
| , spotDirection( 0.0f, 0.0f, -1.0f, 180.0f ) |
| , attenuation( 1, 0, 0, 0 ) |
| , ver( 0 ) |
| {} |
| Float4 ambient; |
| Float4 diffuse; |
| Float4 specular; |
| Float4 position; |
| Float4 spotDirection; // spotCutoff is in .w |
| Float4 attenuation; // spotExponent is in .w |
| GLuint64 ver; |
| }; |
| |
| struct MaterialUniform { |
| MaterialUniform() |
| : ambient( 0.2f, 0.2f, 0.2f, 1.0f ) |
| , diffuse( 0.8f, 0.8f, 0.8f, 1.0f ) |
| , specular( 0, 0, 0, 1 ) |
| , emission( 0, 0, 0, 1 ) |
| , shininess( 0, 0, 0, 0 ) |
| , ver( 0 ) |
| {} |
| Float4 ambient; |
| Float4 diffuse; |
| Float4 specular; |
| Float4 emission; |
| Float4 shininess; // shininess is in .x |
| GLuint64 ver; |
| }; |
| |
| // Iff::State::Store |
| |
| struct Store |
| { |
| Store() |
| { |
| memset(this, 0, sizeof(Store)); |
| |
| // all the booleans and uints want zero initialization anyway, so don't bother doing them individually |
| alphaTest = AlphaTest(); |
| fog = Fog(); |
| colorMaterialTarget0 = colorMaterialTarget1 = CM_AmbientAndDiffuse; |
| for (int ii=0; ii<REGAL_FIXED_FUNCTION_MAX_LIGHTS; ii++) { |
| light[ii] = Light(); |
| } |
| for (int ii=0; ii<REGAL_EMU_IFF_TEXTURE_UNITS; ii++) { |
| tex[ii] = Texture(); |
| for (int jj=0; jj<4; jj++) { |
| tex[ii].texgen[jj].enable = false; |
| tex[ii].texgen[jj].mode = TG_EyeLinear; |
| } |
| } |
| for (int ii=0; ii<REGAL_FIXED_FUNCTION_MAX_CLIP_PLANES; ii++) { |
| clip[ii] = Clip(); |
| } |
| } |
| |
| Store(const Store &other) |
| { |
| memcpy(this, &other, sizeof(Store)); |
| } |
| |
| Store &operator=(const Store &other) |
| { |
| if (&other!=this) |
| memcpy(this, &other, sizeof(Store)); |
| return *this; |
| } |
| |
| GLuint hash; |
| bool colorSum; |
| bool rescaleNormal; |
| bool normalize; |
| bool shadeModelFlat; |
| bool lighting; |
| bool lightModelLocalViewer; |
| bool lightModelTwoSide; |
| bool lightModelSeparateSpecular; |
| bool colorMaterial; |
| GLuint attrArrayFlags; |
| ColorMaterialMode colorMaterialTarget0; |
| ColorMaterialMode colorMaterialTarget1; |
| AlphaTest alphaTest; |
| Fog fog; |
| Light light[ REGAL_FIXED_FUNCTION_MAX_LIGHTS ]; |
| Texture tex[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| Clip clip[ REGAL_FIXED_FUNCTION_MAX_CLIP_PLANES ]; |
| GLuint64 ver; |
| }; |
| |
| struct StoreUniform { |
| StoreUniform() |
| : ver( 0 ) |
| { |
| for (int ii=0; ii<REGAL_EMU_IFF_TEXTURE_UNITS; ii++) { |
| tex[ii].texgen[0].obj = tex[ii].texgen[0].eye = Float4( 1, 0, 0, 0 ); |
| tex[ii].texgen[1].obj = tex[ii].texgen[1].eye = Float4( 0, 1, 0, 0 ); |
| } |
| light[0].ambient = Float4( 0, 0, 0, 1 ); |
| light[0].diffuse = light[0].specular = Float4( 1, 1, 1, 1 ); |
| for (int ii=1; ii<REGAL_FIXED_FUNCTION_MAX_LIGHTS; ii++) { |
| light[ii].ambient = light[ii].diffuse = light[ii].specular = Float4( 0, 0, 0, 1 ); |
| } |
| lightModelAmbient = mat[0].ambient = mat[1].ambient = Float4( 0.2f, 0.2f, 0.2f, 1.0f ); |
| mat[0].diffuse = mat[1].diffuse = Float4( 0.8f, 0.8f, 0.8f, 1.0f ); |
| } |
| |
| TextureUniform tex[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| AlphaTestUniform alphaTest; |
| ClipUniform clip[ REGAL_FIXED_FUNCTION_MAX_CLIP_PLANES ]; |
| LightUniform light[ REGAL_FIXED_FUNCTION_MAX_LIGHTS ]; |
| MaterialUniform mat[ 2 ]; |
| FogUniform fog; |
| Float4 lightModelAmbient; |
| GLuint64 vabVer; |
| GLuint64 ver; |
| }; |
| |
| State() : raw(), processed() { } |
| State(const State &other) : raw(), processed() { UNUSED_PARAMETER(other); } |
| ~State() {} |
| |
| Store raw; |
| Store processed; |
| StoreUniform uniform; |
| |
| bool SetEnable( Iff * ffn, bool enable, GLenum cap ); |
| |
| void SetTexInfo( Version & ver, GLuint activeTex, TextureUnit & unit ) { |
| if( activeTex >= REGAL_EMU_IFF_TEXTURE_UNITS ) { |
| return; |
| } |
| raw.tex[ activeTex ].unit = unit; |
| raw.ver = ver.Update(); |
| } |
| |
| void SetLight( Iff * ffn, GLenum light, GLenum pname, const GLfloat * params ); |
| void SetMaterial( Iff * ffn, GLenum face, GLenum pname, const GLfloat * params ); |
| void GetMaterial( Iff * ffn, GLenum face, GLenum pname, GLfloat * params ); |
| void SetTexgen( Iff * ffn, int coord, GLenum space, const GLfloat * params ); |
| void GetTexgen( Iff * ffn, int coord, GLenum space, GLfloat * params ); |
| void SetAlphaFunc( Iff * ffn, CompareFunc comp, GLfloat ref ); |
| void SetClip( Iff * ffn, GLenum plane, const GLfloat * equation ); |
| |
| TextureTargetBitfield GetTextureEnable( int unit ) const { |
| return TextureTargetBitfield( ( processed.tex[unit].enables ) ); |
| } |
| |
| GLuint64 Ver() const { |
| return uniform.ver; |
| } |
| |
| GLubyte HighestPriorityTextureEnable( GLubyte enables ) { |
| for( int i = TP_CubeMap; i >= 0; i-- ) { |
| if( enables & ( 1 << i ) ) { |
| return static_cast<GLubyte>(1 << i); |
| } |
| } |
| return 0; |
| } |
| void Process( Iff * ffn ); |
| }; |
| |
| struct MatrixStack { |
| struct El { |
| El() |
| : ver( 1 ) |
| {} |
| r3::Matrix4f mat; |
| GLuint64 ver; |
| }; |
| MatrixStack() { |
| stack.push_back( El() ); |
| } |
| void Push() { |
| RegalAssert( stack.size() < REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH ); |
| if( stack.size() < REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH ) { |
| stack.push_back( stack.back() ); |
| } |
| } |
| |
| void Pop() { |
| /* The stack size warning messages ought to be the responsibility |
| of the debug layer, rather than emulation. (Opt-in only) |
| Should emulation set an error in the underflow situation here? */ |
| |
| /* RegalAssert( stack.size()>1 ); */ |
| if ( stack.size()>1 ) |
| stack.pop_back(); |
| } |
| |
| r3::Matrix4f &Top() { RegalAssert( stack.size() ); return stack.back().mat; } |
| const r3::Matrix4f &Top() const { RegalAssert( stack.size() ); return stack.back().mat; } |
| |
| GLuint64 &Ver() { RegalAssert( stack.size() ); return stack.back().ver; } |
| const GLuint64 &Ver() const { RegalAssert( stack.size() ); return stack.back().ver; } |
| |
| std::size_t size() const { return stack.size(); } |
| |
| El &operator[](const std::size_t i) { RegalAssert( stack.size() ); return stack[i]; } |
| const El &operator[](const std::size_t i) const { RegalAssert( stack.size() ); return stack[i]; } |
| |
| private: |
| std::vector<El> stack; |
| }; |
| |
| // Iff::Program |
| |
| struct Program |
| { |
| |
| // Iff::Program::UniformInfo |
| |
| struct UniformInfo |
| { |
| UniformInfo(const GLint s = -1, const GLuint64 v = 0) |
| { |
| memset(this, 0, sizeof(UniformInfo)); |
| slot = s; |
| ver = v; |
| } |
| |
| UniformInfo(const UniformInfo &other) |
| { |
| memcpy(this, &other, sizeof(UniformInfo)); |
| } |
| |
| UniformInfo &operator=(const UniformInfo &other) |
| { |
| if (&other!=this) |
| memcpy(this, &other, sizeof(UniformInfo)); |
| return *this; |
| } |
| |
| GLint slot; |
| GLuint64 ver; |
| }; |
| |
| // Iff::Program |
| |
| Program() |
| : pg(0), |
| uniforms(), |
| store() |
| { |
| // Clear plain-old-data (POD) memory |
| memset(this, 0, reinterpret_cast<char *>(&this->uniforms)-reinterpret_cast<char *>(this)); |
| } |
| |
| Program(const Program &other) |
| : pg(0), |
| uniforms(other.uniforms), |
| store(other.store) |
| { |
| // Copy plain-old-data (POD) memory |
| memcpy(this, &other, reinterpret_cast<char *>(&this->uniforms)-reinterpret_cast<char *>(this)); |
| } |
| |
| Program &operator=(const Program &other) |
| { |
| if (&other!=this) |
| { |
| // Copy plain-old-data (POD) memory |
| memcpy(this, &other, reinterpret_cast<char *>(&this->uniforms)-reinterpret_cast<char *>(this)); |
| uniforms = other.uniforms; |
| store = other.store; |
| } |
| return *this; |
| } |
| |
| // POD |
| |
| GLuint pg; |
| GLuint vs, fs; |
| GLuint64 ver; |
| int progcount; |
| |
| // non-POD |
| |
| std::map< RegalFFUniformEnum, UniformInfo> uniforms; |
| State::Store store; |
| |
| void Init( RegalContext * ctx, const State::Store & sstore, const GLchar *vsSrc, const GLchar *fsSrc ); |
| void Shader( RegalContext * ctx, DispatchTableGL & tbl, GLenum type, GLuint & shader, const GLchar *src ); |
| void Attribs( RegalContext * ctx ); |
| void UserShaderModeAttribs( RegalContext * ctx ); |
| void Samplers( RegalContext * ctx, DispatchTableGL & tbl ); |
| void Uniforms( RegalContext * ctx, DispatchTableGL & tbl ); |
| }; |
| |
| MatrixStack modelview; |
| MatrixStack projection; |
| MatrixStack texture[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| |
| GLenum shadowMatrixMode; |
| TextureUnit textureUnit[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| Float4 textureEnvColor[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| GLuint64 textureEnvColorVer[ REGAL_EMU_IFF_TEXTURE_UNITS ]; |
| GLuint textureBinding[ REGAL_EMU_MAX_TEXTURE_UNITS]; |
| GLuint shadowActiveTextureIndex; |
| GLuint activeTextureIndex; |
| GLuint programPipeline; |
| GLuint program; |
| Program * currprog; |
| |
| MatrixStack *currMatrixStack; |
| |
| Version ver; |
| State ffstate; |
| |
| Program ffprogs[ 1 << REGAL_FIXED_FUNCTION_PROGRAM_CACHE_SIZE_BITS ]; |
| |
| shared_map<GLuint, GLint> textureObjToFmt; |
| |
| // Program uniforms are tied to context state, so we cannot share IFF |
| // programs, however we share user programs in general. |
| std::map<GLenum, GLenum> fmtmap; |
| std::map<GLuint, GLenum> shaderTypeMap; |
| std::map<GLuint, Program> shprogmap; |
| |
| GLuint currVao; |
| std::map<GLuint, GLuint> vaoAttrMap; |
| |
| bool gles; // what about ES1? |
| bool legacy; // 2.x mac |
| |
| void InitFixedFunction(RegalContext &ctx); |
| |
| void PreDraw( RegalContext * ctx ) { |
| if( programPipeline != 0 ) { |
| // FIXME: Eventually will need to handle empty or partially populated PPO |
| return; |
| } |
| ver.Reset(); |
| if( program != 0 ) { |
| UseShaderProgram( ctx ); |
| } else { |
| UseFixedFunctionProgram( ctx ); |
| } |
| } |
| |
| void SetCurrentMatrixStack( GLenum mode ) { |
| switch( mode ) { |
| case GL_MODELVIEW: currMatrixStack = &modelview; break; |
| case GL_PROJECTION: currMatrixStack = &projection; break; |
| case GL_TEXTURE: |
| if( activeTextureIndex > GLuint( REGAL_EMU_IFF_TEXTURE_UNITS - 1 ) ) { |
| break; |
| } |
| currMatrixStack = &texture[ activeTextureIndex ]; |
| break; |
| case GL_TEXTURE0: |
| case GL_TEXTURE1: |
| case GL_TEXTURE2: |
| case GL_TEXTURE3: { |
| GLuint idx = mode - GL_TEXTURE0; |
| if( idx > GLuint( REGAL_EMU_IFF_TEXTURE_UNITS - 1 ) ) { |
| break; |
| } |
| currMatrixStack = &texture[ idx ]; |
| break; |
| } |
| default: |
| RegalAssert( true && "WTF." ); |
| break; |
| } |
| } |
| |
| bool ShadowMatrixMode( GLenum mode ) { |
| shadowMatrixMode = mode; |
| return true; |
| } |
| |
| bool ShadowActiveTexture( GLenum tex ) { |
| shadowActiveTextureIndex = tex - GL_TEXTURE0; |
| return false; |
| } |
| |
| bool ShadowEnable( GLenum cap ) { |
| return EnableIndexed( cap, shadowActiveTextureIndex ); |
| } |
| |
| bool ShadowDisable( GLenum cap ) { |
| return DisableIndexed( cap, shadowActiveTextureIndex ); |
| } |
| |
| bool EnableIndexed( GLenum cap, GLuint index ) { |
| activeTextureIndex = index; |
| bool ret = ffstate.SetEnable( this, true, cap ); |
| return ret; |
| } |
| |
| bool DisableIndexed( GLenum cap, GLuint index ) { |
| activeTextureIndex = index; |
| bool ret = ffstate.SetEnable( this, false, cap ); |
| return ret; |
| } |
| |
| bool ShadowUseProgram( GLuint prog ) { |
| program = prog; |
| return prog == 0; // pass the call along only if it's non-zero |
| } |
| |
| bool ShadowBindProgramPipeline( GLuint progPipeline ) { |
| programPipeline = progPipeline; |
| return false; // always pass this through since we're not emulating it |
| } |
| |
| void ShadowMultiTexBinding( GLenum texunit, GLenum target, GLuint obj ); |
| void ShadowTexBinding( GLenum target, GLuint obj ) { |
| ShadowMultiTexBinding( GL_TEXTURE0 + shadowActiveTextureIndex, target, obj ); |
| } |
| |
| void ShadowTextureInfo( GLuint obj, GLenum target, GLint internalFormat ); |
| void ShadowMultiTexInfo( GLenum texunit, GLenum target, GLint internalFormat ); |
| void ShadowTexInfo( GLenum target, GLint internalFormat ); |
| |
| void TexEnv( GLenum texunit, GLenum target, GLenum pname, const GLfloat *v ); |
| void TexEnv( GLenum texunit, GLenum target, GLenum pname, const GLint *v ); |
| void TexEnv( GLenum texunit, GLenum target, GLenum pname, GLfloat v ) { TexEnv( texunit, target, pname, &v ); } |
| void TexEnv( GLenum texunit, GLenum target, GLenum pname, GLint v ) { TexEnv( texunit, target, pname, &v ); } |
| |
| template <typename T> |
| void TexEnv( GLenum target, GLenum pname, T v ) { TexEnv( GL_TEXTURE0 + shadowActiveTextureIndex, target, pname, v ); } |
| |
| template <typename T> |
| bool GetTexEnv( GLenum target, GLenum pname, T * params ) { |
| if( target != GL_TEXTURE_ENV ) { |
| return false; |
| } |
| switch( pname ) { |
| case GL_TEXTURE_ENV_MODE: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| *params = static_cast<T>(texenvModeGL[ textureUnit[ activeTextureIndex ].env.mode ]); |
| break; |
| } |
| case GL_TEXTURE_ENV_COLOR: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| Float4 & c = textureEnvColor[ activeTextureIndex ]; |
| params[0] = T( c.x ); |
| params[1] = T( c.y ); |
| params[2] = T( c.z ); |
| params[3] = T( c.w ); |
| break; |
| } |
| case GL_COMBINE_RGB: |
| case GL_COMBINE_ALPHA: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| TexenvCombineState & c = (pname == GL_COMBINE_RGB ? |
| textureUnit[ activeTextureIndex ].env.rgb : |
| textureUnit[ activeTextureIndex ].env.a); |
| *params = static_cast<T>(texenvCombineGL[ c.mode ]); |
| break; |
| } |
| case GL_SOURCE0_RGB: |
| case GL_SOURCE1_RGB: |
| case GL_SOURCE2_RGB: |
| case GL_SOURCE0_ALPHA: |
| case GL_SOURCE1_ALPHA: |
| case GL_SOURCE2_ALPHA: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| int idx = pname - GL_SOURCE0_RGB; |
| bool isRgb = true; |
| if ( idx > 3 ) { |
| isRgb = false; |
| idx = pname - GL_SOURCE0_ALPHA; |
| } |
| TexenvCombineState & c = (isRgb ? |
| textureUnit[ activeTextureIndex ].env.rgb : |
| textureUnit[ activeTextureIndex ].env.a); |
| TexenvCombineSrc src = c.src0; |
| switch ( idx ) |
| { |
| case 0: src = c.src0; break; |
| case 1: src = c.src1; break; |
| case 2: src = c.src2; break; |
| default: break; |
| } |
| *params = static_cast<T>(texenvCombineSrcGL[ src ]); |
| break; |
| } |
| case GL_OPERAND0_RGB: |
| case GL_OPERAND1_RGB: |
| case GL_OPERAND2_RGB: |
| case GL_OPERAND0_ALPHA: |
| case GL_OPERAND1_ALPHA: |
| case GL_OPERAND2_ALPHA: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| int idx = pname - GL_OPERAND0_RGB; |
| bool isRgb = true; |
| if( idx > 3 ) { |
| isRgb = false; |
| idx = pname - GL_OPERAND0_ALPHA; |
| } |
| TexenvCombineState & c = (isRgb ? |
| textureUnit[ activeTextureIndex ].env.rgb : |
| textureUnit[ activeTextureIndex ].env.a); |
| TexenvCombineOp op = c.op0; |
| switch ( idx ) |
| { |
| case 0: op = c.op0; break; |
| case 1: op = c.op1; break; |
| case 2: op = c.op2; break; |
| default: break; |
| } |
| *params = static_cast<T>(texenvCombineOpGL[ op ]); |
| break; |
| } |
| case GL_RGB_SCALE: |
| case GL_ALPHA_SCALE: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| TexenvCombineState & c = (pname == GL_RGB_SCALE ? |
| textureUnit[ activeTextureIndex ].env.rgb : |
| textureUnit[ activeTextureIndex ].env.a); |
| *params = static_cast<T>(c.scale); |
| break; |
| } |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| void ShadeModel( GLenum mode ) { |
| State::Store & r = ffstate.raw; |
| switch( mode ) { |
| case GL_FLAT: |
| if ( r.shadeModelFlat == false ) { |
| r.shadeModelFlat = true; |
| r.ver = ver.Update(); |
| } |
| break; |
| case GL_SMOOTH: |
| if ( r.shadeModelFlat == true ) { |
| r.shadeModelFlat = false; |
| r.ver = ver.Update(); |
| } |
| break; |
| } |
| } |
| |
| template <typename T> void Light( GLenum light, GLenum pname, const T param ) { |
| int comp = 4; |
| switch( pname ) { |
| case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: case GL_POSITION: break; |
| case GL_SPOT_DIRECTION: comp = 3; break; |
| case GL_SPOT_EXPONENT: case GL_SPOT_CUTOFF: |
| case GL_CONSTANT_ATTENUATION: case GL_LINEAR_ATTENUATION: |
| case GL_QUADRATIC_ATTENUATION: comp = 1; break; |
| default: return; |
| } |
| GLfloat v[4]; |
| for( int i = 0; i < comp; i++ ) v[ i ] = RFFToFloatN( i, param ); |
| ffstate.SetLight( this, light, pname, v ); |
| } |
| |
| template <typename T> void Material( GLenum face, GLenum pname, const T param ) { |
| int comp = 4; |
| switch( pname ) { |
| case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: |
| case GL_AMBIENT_AND_DIFFUSE: case GL_EMISSION: break; |
| case GL_SHININESS: comp = 1; break; |
| default: return; |
| } |
| GLfloat v[4]; |
| for( int i = 0; i < comp; i++ ) v[ i ] = RFFToFloatN( i, param ); |
| ffstate.SetMaterial( this, face, pname, v ); |
| } |
| |
| template <typename T> void GetMaterial( GLenum face, GLenum pname, T *params ) { |
| int comp = 4; |
| switch( pname ) { |
| case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: |
| case GL_AMBIENT_AND_DIFFUSE: case GL_EMISSION: break; |
| case GL_SHININESS: comp = 1; break; |
| default: return; |
| } |
| GLfloat v[4]; |
| ffstate.GetMaterial( this, face, pname, v ); |
| for( int i = 0; i < comp; i++ ) params[i] = static_cast<T>(v[i]); |
| } |
| |
| template <typename T> void LightModel( GLenum pname, const T param ) { |
| State::Store & r = ffstate.raw; |
| State::StoreUniform & u = ffstate.uniform; |
| switch( pname ) { |
| case GL_LIGHT_MODEL_AMBIENT: { |
| GLfloat *v = & u.lightModelAmbient.x; |
| for( int i = 0; i < 4; i++ ) v[i] = RFFToFloatN( i, param ); |
| break; |
| } |
| case GL_LIGHT_MODEL_LOCAL_VIEWER: r.lightModelLocalViewer = RFFToFloat( 0, param ) != 0.0f; break; |
| case GL_LIGHT_MODEL_TWO_SIDE: r.lightModelTwoSide = RFFToFloat( 0, param ) != 0.0f; break; |
| case GL_LIGHT_MODEL_COLOR_CONTROL: r.lightModelSeparateSpecular = RFFToFloat(0, param) == GL_SEPARATE_SPECULAR_COLOR; break; |
| default: return; |
| } |
| u.ver = r.ver = ver.Update(); |
| } |
| |
| void ColorMaterial( GLenum face, GLenum mode ) { |
| ColorMaterialMode m; |
| switch( mode ) { |
| case GL_EMISSION: m = CM_Emission; break; |
| case GL_AMBIENT: m = CM_Ambient; break; |
| case GL_DIFFUSE: m = CM_Diffuse; break; |
| case GL_SPECULAR: m = CM_Specular; break; |
| case GL_AMBIENT_AND_DIFFUSE: m = CM_AmbientAndDiffuse; break; |
| default: return; |
| } |
| switch( face ) { |
| case GL_FRONT: |
| ffstate.raw.colorMaterialTarget0 = m; |
| ffstate.raw.colorMaterialTarget1 = CM_None; |
| break; |
| case GL_BACK: |
| ffstate.raw.colorMaterialTarget0 = CM_None; |
| ffstate.raw.colorMaterialTarget1 = m; |
| break; |
| case GL_FRONT_AND_BACK: |
| ffstate.raw.colorMaterialTarget0 = m; |
| ffstate.raw.colorMaterialTarget1 = m; |
| break; |
| default: |
| return; |
| } |
| ffstate.raw.ver = ver.Update(); |
| } |
| |
| template <typename T> void TexGen( GLenum coord, GLenum pname, const T param ) { |
| RegalAssert(activeTextureIndex < REGAL_EMU_IFF_TEXTURE_UNITS); |
| if( activeTextureIndex >= REGAL_EMU_IFF_TEXTURE_UNITS ) { |
| return; |
| } |
| State::Store & st = ffstate.raw; |
| int idx = 0; |
| switch( coord ) { |
| case GL_S: case GL_T: case GL_R: case GL_Q: idx = coord - GL_S; break; |
| default: |
| RegalAssert(coord==GL_S || coord==GL_T || coord==GL_R || coord==GL_Q || coord==GL_S); |
| return; |
| } |
| switch( pname ) { |
| case GL_TEXTURE_GEN_MODE: { |
| State::Texgen & tg = st.tex[ activeTextureIndex ].texgen[ idx ]; |
| switch( GLenum( RFFToFloat( 0, param ) ) ) { |
| case GL_OBJECT_LINEAR: tg.mode = TG_ObjectLinear; break; |
| case GL_EYE_LINEAR: tg.mode = TG_EyeLinear; break; |
| case GL_SPHERE_MAP: tg.mode = TG_SphereMap; break; |
| case GL_NORMAL_MAP: tg.mode = TG_NormalMap; break; |
| case GL_REFLECTION_MAP: tg.mode = TG_ReflectionMap; break; |
| default: |
| RegalAssert(0); |
| return; |
| } |
| break; |
| } |
| case GL_EYE_PLANE: |
| case GL_OBJECT_PLANE: { |
| if (!RFFIsVector( param )) |
| { |
| RegalAssert(0); |
| return; |
| } |
| Float4 plane; |
| plane.x = RFFToFloat( 0, param ); |
| plane.y = RFFToFloat( 1, param ); |
| plane.z = RFFToFloat( 2, param ); |
| plane.w = RFFToFloat( 3, param ); |
| ffstate.SetTexgen( this, idx, pname, & plane.x ); |
| return; |
| } |
| default: |
| RegalAssert(0); |
| return; |
| |
| } |
| ffstate.uniform.ver = st.ver = ver.Update(); |
| } |
| |
| void AlphaFunc( GLenum comp, const GLfloat ref ) { |
| CompareFunc cf = CF_Always; |
| switch( comp ) { |
| case GL_NEVER: cf = CF_Never; break; |
| case GL_LESS: cf = CF_Less; break; |
| case GL_EQUAL: cf = CF_Equal; break; |
| case GL_LEQUAL: cf = CF_Lequal; break; |
| case GL_NOTEQUAL: cf = CF_NotEqual; break; |
| case GL_GREATER: cf = CF_Greater; break; |
| case GL_GEQUAL: cf = CF_Gequal; break; |
| case GL_ALWAYS: cf = CF_Always; break; |
| default: break; // should be an error... |
| } |
| ffstate.SetAlphaFunc( this, cf, ref ); |
| } |
| |
| void ClipPlane( GLenum plane, const GLdouble * equation ) { |
| Float4 eqn( equation[0], equation[1], equation[2], equation[3] ); |
| ffstate.SetClip( this, plane, & eqn.x ); |
| } |
| |
| template <typename T> void Fog( GLenum pname, const T param ) { |
| State::Store & r = ffstate.raw; |
| State::StoreUniform & u = ffstate.uniform; |
| switch( pname ) { |
| case GL_FOG_MODE: { |
| FogMode m = FG_Exp; |
| switch( GLenum( RFFToFloat( 0, param ) ) ) { |
| case GL_LINEAR: m = FG_Linear; break; |
| case GL_EXP: m = FG_Exp; break; |
| case GL_EXP2: m = FG_Exp2; break; |
| default: return; |
| } |
| r.fog.mode = m; |
| break; |
| } |
| case GL_FOG_DENSITY: { |
| u.fog.params[0].x = RFFToFloat( 0, param ); |
| u.fog.ver = ver.Update(); |
| break; |
| } |
| case GL_FOG_START: { |
| u.fog.params[0].y = RFFToFloat( 0, param ); |
| u.fog.ver = ver.Update(); |
| break; |
| } |
| case GL_FOG_END: { |
| u.fog.params[0].z = RFFToFloat( 0, param ); |
| u.fog.ver = ver.Update(); |
| break; |
| } |
| case GL_FOG_COLOR: { |
| u.fog.params[1].x = RFFToFloat( 0, param ); |
| u.fog.params[1].y = RFFToFloat( 1, param ); |
| u.fog.params[1].z = RFFToFloat( 2, param ); |
| u.fog.params[1].w = RFFToFloat( 3, param ); |
| u.fog.ver = ver.Update(); |
| break; |
| } |
| case GL_FOG_COORD_SRC: { |
| bool d = true; |
| switch( GLenum( RFFToFloat( 0, param ) ) ) { |
| case GL_FRAGMENT_DEPTH: d = true; break; |
| case GL_FOG_COORD: d = false; break; |
| default: return; |
| } |
| r.fog.useDepth = d; |
| break; |
| } |
| default: return; |
| } |
| u.ver = r.ver = ver.Update(); |
| } |
| |
| template <typename T> bool GetIndexedTexGenv( RegalContext * ctx, GLuint textureIndex, |
| GLenum coord, GLenum pname, T * params ) |
| { |
| UNUSED_PARAMETER(ctx); |
| |
| if( textureIndex >= REGAL_EMU_IFF_TEXTURE_UNITS ) { |
| return false; |
| } |
| int idx = 0; |
| switch( coord ) { |
| case GL_S: case GL_T: case GL_R: case GL_Q: idx = coord - GL_S; break; |
| default: return false; |
| } |
| switch( pname ) |
| { |
| case GL_TEXTURE_GEN_MODE: |
| { |
| GLenum glmode = GL_EYE_LINEAR; |
| switch ( ffstate.raw.tex[ textureIndex ].texgen[ idx ].mode ) |
| { |
| case TG_ObjectLinear: |
| glmode = GL_OBJECT_LINEAR; |
| break; |
| case TG_EyeLinear: |
| glmode = GL_EYE_LINEAR; |
| break; |
| case TG_SphereMap: |
| glmode = GL_SPHERE_MAP; |
| break; |
| case TG_NormalMap: |
| glmode = GL_NORMAL_MAP; |
| break; |
| case TG_ReflectionMap: |
| glmode = GL_REFLECTION_MAP; |
| break; |
| default: |
| return false; |
| } |
| *params = static_cast<T>(glmode); |
| break; |
| } |
| case GL_OBJECT_PLANE: |
| case GL_EYE_PLANE: |
| { |
| Float4 plane; |
| ffstate.GetTexgen( this, idx, pname, & plane.x ); |
| *(params+0) = static_cast<T>(plane.x); |
| *(params+1) = static_cast<T>(plane.y); |
| *(params+2) = static_cast<T>(plane.z); |
| *(params+3) = static_cast<T>(plane.w); |
| break; |
| } |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| template <typename T> bool GetTexGenv( RegalContext * ctx, GLenum coord, |
| GLenum pname, T * params ) |
| { |
| return GetIndexedTexGenv( ctx, shadowActiveTextureIndex, coord, pname, params ); |
| } |
| |
| template <typename T> bool GetMultiTexGenv( RegalContext * ctx, GLenum texunit, |
| GLenum coord, GLenum pname, T * params ) |
| { |
| return GetIndexedTexGenv( ctx, texunit - GL_TEXTURE0, coord, pname, params ); |
| } |
| |
| template <typename T> bool Get( RegalContext * ctx, GLenum pname, T * params ) |
| { |
| State::Store & r = ffstate.raw; |
| State::StoreUniform & u = ffstate.uniform; |
| |
| // FIXME: implement all FF gets! |
| if( VaGet( ctx, pname, params ) ) |
| return true; |
| |
| switch( pname ) { |
| case GL_CURRENT_PROGRAM: |
| *params = static_cast<T>(program); |
| break; |
| case GL_MAX_MODELVIEW_STACK_DEPTH: |
| *params = static_cast<T>(REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH); |
| break; |
| case GL_MAX_PROJECTION_STACK_DEPTH: |
| *params = static_cast<T>(REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH); |
| break; |
| case GL_MAX_TEXTURE_STACK_DEPTH: |
| *params = static_cast<T>(REGAL_FIXED_FUNCTION_MATRIX_STACK_DEPTH); |
| break; |
| case GL_SMOOTH_POINT_SIZE_RANGE: |
| // FIXME: Pass through actual GL's limit. |
| *params = static_cast<T>(1); |
| break; |
| case GL_SMOOTH_LINE_WIDTH_RANGE: |
| // FIXME: Pass through actual GL's limit. |
| *params = static_cast<T>(1); |
| break; |
| case GL_MODELVIEW_STACK_DEPTH: |
| *params = static_cast<T>(modelview.size()); |
| break; |
| case GL_PROJECTION_STACK_DEPTH: |
| *params = static_cast<T>(projection.size()); |
| break; |
| case GL_TEXTURE_STACK_DEPTH: |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| *params = static_cast<T>(texture[activeTextureIndex].size()); |
| break; |
| case GL_MODELVIEW_MATRIX: { |
| const GLfloat * p = modelview.Top().Ptr(); |
| for( int i = 0; i < 16; i++ ) params[i] = static_cast<T>(p[i]); |
| break; |
| } |
| case GL_PROJECTION_MATRIX: { |
| const GLfloat * p = projection.Top().Ptr(); |
| for( int i = 0; i < 16; i++ ) params[i] = static_cast<T>(p[i]); |
| break; |
| } |
| case GL_TEXTURE_MATRIX: { |
| RegalAssert(activeTextureIndex<REGAL_EMU_IFF_TEXTURE_UNITS); |
| const GLfloat * p = texture[ activeTextureIndex ].Top().Ptr(); |
| for( int i = 0; i < 16; i++ ) params[i] = static_cast<T>(p[i]); |
| break; |
| } |
| case GL_MATRIX_MODE: { |
| *params = static_cast<T>(shadowMatrixMode); |
| break; |
| } |
| case GL_MAX_LIGHTS: { |
| *params = static_cast<T>(REGAL_FIXED_FUNCTION_MAX_LIGHTS); |
| break; |
| } |
| case GL_MAX_TEXTURE_UNITS: { |
| *params = static_cast<T>(REGAL_EMU_IFF_TEXTURE_UNITS); |
| break; |
| } |
| case GL_MAX_CLIP_PLANES: { |
| *params = static_cast<T>(REGAL_FIXED_FUNCTION_MAX_CLIP_PLANES); |
| break; |
| } |
| case GL_FOG_MODE: { |
| *params = static_cast<T>(r.fog.mode); |
| break; |
| } |
| case GL_FOG_DENSITY: { |
| *params = static_cast<T>(u.fog.params[0].x); |
| break; |
| } |
| case GL_FOG_START: { |
| *params = static_cast<T>(u.fog.params[0].y); |
| break; |
| } |
| case GL_FOG_END: { |
| *params = static_cast<T>(u.fog.params[0].z); |
| break; |
| } |
| case GL_FOG_COLOR: { |
| const GLfloat * p = &u.fog.params[1].x; |
| for( int i = 0; i < 4; i++ ) |
| params[i] = static_cast<T>(p[i]); |
| break; |
| } |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| void MatrixPush( GLenum mode ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Push(); |
| } |
| |
| void MatrixPop( GLenum mode ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Pop(); |
| UpdateMatrixVer(); |
| } |
| |
| void UpdateMatrixVer() { |
| currMatrixStack->Ver() = ffstate.uniform.ver = ver.Update(); |
| if( currMatrixStack != &modelview && currMatrixStack != &projection ) { |
| ffstate.raw.ver = ffstate.uniform.ver; |
| } |
| } |
| |
| void MatrixLoadIdentity( GLenum mode ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MakeIdentity(); |
| UpdateMatrixVer(); |
| } |
| |
| void MatrixLoad( GLenum mode, const r3::Matrix4f & m ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top() = m; |
| UpdateMatrixVer(); |
| } |
| |
| void MatrixLoadTranspose( GLenum mode, const r3::Matrix4f & m ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top() = m.Transpose(); |
| UpdateMatrixVer(); |
| } |
| |
| void MatrixMult( GLenum mode, const r3::Matrix4f & m ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( m ); |
| UpdateMatrixVer(); |
| } |
| |
| void MatrixMultTranspose( GLenum mode, const r3::Matrix4f & m ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( m.Transpose() ); |
| UpdateMatrixVer(); |
| } |
| |
| template <typename T> void MatrixRotate( GLenum mode, T angle, T x, T y, T z ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( r3::Rotationf( r3::Vec3f( x, y, z ), r3::ToRadians( static_cast<float>(angle) ) ).GetMatrix4() ); |
| UpdateMatrixVer(); |
| } |
| |
| template <typename T> void MatrixTranslate( GLenum mode, T x, T y, T z ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( r3::Matrix4f::Translate( r3::Vec3f( x, y, z ) ) ); |
| UpdateMatrixVer(); |
| } |
| |
| template <typename T> void MatrixScale( GLenum mode, T x, T y, T z ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( r3::Matrix4f::Scale( r3::Vec3f( x, y, z ) ) ); |
| UpdateMatrixVer(); |
| } |
| |
| template <typename T> void MatrixFrustum( GLenum mode, T left, T right, T bottom, T top, T zNear, T zFar ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( r3::Frustum<float>( static_cast<float>(left), static_cast<float>(right), static_cast<float>(bottom), static_cast<float>(top), static_cast<float>(zNear), static_cast<float>(zFar) ) ); |
| UpdateMatrixVer(); |
| } |
| |
| template <typename T> void MatrixOrtho( GLenum mode, T left, T right, T bottom, T top, T zNear, T zFar ) { |
| SetCurrentMatrixStack( mode ); |
| currMatrixStack->Top().MultRight( r3::Ortho<float>( static_cast<float>(left), static_cast<float>(right), static_cast<float>(bottom), static_cast<float>(top), static_cast<float>(zNear), static_cast<float>(zFar) ) ); |
| UpdateMatrixVer(); |
| } |
| |
| void PushMatrix() { MatrixPush( shadowMatrixMode ); } |
| void PopMatrix() { MatrixPop( shadowMatrixMode ); } |
| void LoadIdentity() { MatrixLoadIdentity( shadowMatrixMode ); } |
| void LoadMatrix( const r3::Matrix4f & m ) { MatrixLoad( shadowMatrixMode, m ); } |
| void LoadTransposeMatrix( const r3::Matrix4f & m ) { MatrixLoadTranspose( shadowMatrixMode, m ); } |
| void MultMatrix( const r3::Matrix4f & m ) { MatrixMult( shadowMatrixMode, m ); } |
| void MultTransposeMatrix( const r3::Matrix4f & m ) { MatrixMultTranspose( shadowMatrixMode, m ); } |
| template <typename T> void Rotate( T angle, T x, T y, T z ) { MatrixRotate( shadowMatrixMode, angle, x, y, z ); } |
| template <typename T> void Translate( T x, T y, T z ) { MatrixTranslate( shadowMatrixMode, x, y, z ); } |
| template <typename T> void Scale( T x, T y, T z ) { MatrixScale( shadowMatrixMode, x, y, z ); } |
| template <typename T> void Frustum( T left, T right, T bottom, T top, T zNear, T zFar ) { MatrixFrustum( shadowMatrixMode, left, right, bottom, top, zNear, zFar ); } |
| template <typename T> void Ortho( T left, T right, T bottom, T top, T zNear, T zFar ) { MatrixOrtho( shadowMatrixMode, left, right, bottom, top, zNear, zFar ); } |
| |
| |
| // cache viewport |
| struct Viewport { |
| Viewport() : zn( 0.0f ), zf( 1.0f ) {} |
| GLint x, y; |
| GLsizei w, h; |
| GLfloat zn, zf; |
| }; |
| Viewport viewport; |
| |
| void Viewport( GLint x, GLint y, GLsizei w, GLsizei h ) { |
| viewport.x = x; |
| viewport.y = y; |
| viewport.w = w; |
| viewport.h = h; |
| } |
| |
| void DepthRange( GLfloat znear, GLfloat zfar ) { |
| viewport.zn = znear; |
| viewport.zf = zfar; |
| } |
| |
| template <typename T> void RasterPosition( RegalContext * ctx, T x, T y, T z = 0 ) { |
| const GLdouble xd = ToDouble<true>(x); |
| const GLdouble yd = ToDouble<true>(y); |
| const GLdouble zd = ToDouble<true>(z); |
| RasterPos( ctx, xd, yd, zd ); |
| } |
| |
| template <typename T> void WindowPosition( RegalContext * ctx, T x, T y, T z = 0 ) { |
| const GLdouble xd = ToDouble<true>(x); |
| const GLdouble yd = ToDouble<true>(y); |
| const GLdouble zd = ToDouble<true>(z); |
| WindowPos( ctx, xd, yd, zd ); |
| } |
| |
| void RasterPos( RegalContext * ctx, GLdouble x, GLdouble y, GLdouble z ) { |
| r3::Vec3f pos( x, y, z ); |
| r3::Vec3f s( 0.5f * GLfloat(viewport.w), 0.5f * GLfloat(viewport.h), 0.5f * GLfloat( viewport.zf - viewport.zn ) ); |
| r3::Vec3f b( GLfloat(viewport.x), GLfloat(viewport.y), 0.5f + GLfloat(viewport.zn) ); |
| r3::Matrix4f sb; |
| sb.SetScale( s ); |
| sb.SetTranslate( s + b ); |
| r3::Matrix4f m = sb * projection.Top() * modelview.Top(); |
| m.MultMatrixVec( pos ); |
| WindowPos( ctx, pos.x, pos.y, pos.z ); |
| } |
| |
| void WindowPos( RegalContext * ctx, GLdouble x, GLdouble y, GLdouble z ) { |
| if( ctx->isCore() || ctx->isCompat() ) { |
| // todo - cache rasterpos and implement glDrawPixels and glBitmap |
| return; |
| } |
| ctx->dispatcher.emulation.glWindowPos3d( x, y, z ); |
| } |
| |
| void BindVertexArray( RegalContext * ctx, GLuint vao ) { |
| UNUSED_PARAMETER(ctx); |
| vaoAttrMap[ currVao ] = ffstate.raw.attrArrayFlags; |
| currVao = vao; |
| ffstate.raw.attrArrayFlags = vaoAttrMap[ currVao ]; |
| ffstate.uniform.vabVer = ver.Update(); |
| } |
| |
| void EnableArray( RegalContext * ctx, GLuint index ) { |
| RestoreVao( ctx ); |
| ffstate.raw.attrArrayFlags |= 1 << index; |
| ffstate.raw.ver = ffstate.uniform.vabVer = ver.Update(); |
| } |
| |
| void DisableArray( RegalContext * ctx, GLuint index ) { |
| RestoreVao( ctx ); |
| ffstate.raw.attrArrayFlags &= ~( 1 << index ); |
| ffstate.raw.ver = ffstate.uniform.vabVer = ver.Update(); |
| } |
| |
| void UpdateUniforms( RegalContext * ctx ); |
| void UseFixedFunctionProgram( RegalContext * ctx ); |
| void UseShaderProgram( RegalContext * ctx ); |
| |
| void ShaderSource( RegalContext *ctx, GLuint shader, GLsizei count, const GLchar * const * string, const GLint *length); |
| void LinkProgram( RegalContext *ctx, GLuint program ); |
| |
| GLuint CreateShader( RegalContext *ctx, GLenum shaderType ) { |
| GLuint sh = ctx->dispatcher.emulation.glCreateShader( shaderType ); |
| shaderTypeMap[ sh ] = shaderType; |
| return sh; |
| } |
| |
| // |
| void Init( RegalContext &ctx ) |
| { |
| shadowMatrixMode = 0; |
| shadowActiveTextureIndex = 0; |
| activeTextureIndex = 0; |
| program = 0; |
| programPipeline = 0; |
| currprog = NULL; |
| currVao = 0; |
| gles = false; |
| legacy = false; |
| |
| RegalContext *sharingWith = ctx.groupInitializedContext(); |
| if (sharingWith) |
| textureObjToFmt = sharingWith->iff->textureObjToFmt; |
| |
| InitVertexArray(ctx); |
| InitFixedFunction(ctx); |
| InitImmediate(ctx); |
| } |
| }; |
| |
| }; // namespace Emu |
| |
| REGAL_NAMESPACE_END |
| |
| #endif // REGAL_EMULATION |
| |
| #endif // __REGAL_FIXED_FUNCTION_H__ |