mirror of
https://gitlab.com/shinovon/re3-symbian.git
synced 2026-05-22 17:47:20 +03:00
1502 lines
36 KiB
C++
1502 lines
36 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "../rwbase.h"
|
|
#include "../rwerror.h"
|
|
#include "../rwplg.h"
|
|
#include "../rwrender.h"
|
|
#include "../rwengine.h"
|
|
#include "../rwpipeline.h"
|
|
#include "../rwobjects.h"
|
|
#ifdef RW_GLES1
|
|
|
|
#include "rwgles1.h"
|
|
#include "rwgles1impl.h"
|
|
|
|
#define PLUGIN_ID 0
|
|
|
|
namespace rw {
|
|
namespace gles1 {
|
|
|
|
GlGlobals glGlobals;
|
|
|
|
// terrible hack for GLES
|
|
bool32 needToReadBackTextures;
|
|
|
|
float32 alphaRef;
|
|
|
|
struct UniformState
|
|
{
|
|
float32 fogStart;
|
|
float32 fogEnd;
|
|
RGBAf fogColor;
|
|
};
|
|
|
|
struct UniformScene
|
|
{
|
|
float32 proj[16];
|
|
float32 view[16];
|
|
};
|
|
|
|
#define MAX_LIGHTS 8
|
|
|
|
struct UniformObject
|
|
{
|
|
RawMatrix world;
|
|
RGBAf ambLight;
|
|
struct {
|
|
float type;
|
|
float radius;
|
|
float minusCosAngle;
|
|
float hardSpot;
|
|
} lightParams[MAX_LIGHTS];
|
|
V4d lightPosition[MAX_LIGHTS];
|
|
V4d lightDirection[MAX_LIGHTS];
|
|
RGBAf lightColor[MAX_LIGHTS];
|
|
};
|
|
|
|
|
|
|
|
static GLuint vao;
|
|
static GLuint whitetex;
|
|
static UniformState uniformState;
|
|
static UniformScene uniformScene;
|
|
static UniformObject uniformObject;
|
|
|
|
int32 u_matColor;
|
|
int32 u_surfProps;
|
|
|
|
static bool32 stateDirty = 1;
|
|
static bool32 sceneDirty = 1;
|
|
static bool32 objectDirty = 1;
|
|
|
|
struct RwRasterStateCache {
|
|
Raster *raster;
|
|
Texture::Addressing addressingU;
|
|
Texture::Addressing addressingV;
|
|
Texture::FilterMode filter;
|
|
};
|
|
|
|
#define MAXNUMSTAGES 8
|
|
|
|
// cached RW render states
|
|
struct RwStateCache {
|
|
bool32 vertexAlpha;
|
|
uint32 alphaTestEnable;
|
|
uint32 alphaFunc;
|
|
bool32 textureAlpha;
|
|
bool32 blendEnable;
|
|
uint32 srcblend, destblend;
|
|
uint32 zwrite;
|
|
uint32 ztest;
|
|
uint32 cullmode;
|
|
uint32 stencilenable;
|
|
uint32 stencilpass;
|
|
uint32 stencilfail;
|
|
uint32 stencilzfail;
|
|
uint32 stencilfunc;
|
|
uint32 stencilref;
|
|
uint32 stencilmask;
|
|
uint32 stencilwritemask;
|
|
uint32 fogEnable;
|
|
float32 fogStart;
|
|
float32 fogEnd;
|
|
|
|
// emulation of PS2 GS
|
|
bool32 gsalpha;
|
|
uint32 gsalpharef;
|
|
|
|
RwRasterStateCache texstage[MAXNUMSTAGES];
|
|
};
|
|
static RwStateCache rwStateCache;
|
|
|
|
enum
|
|
{
|
|
// actual gl states
|
|
RWGL_BLEND,
|
|
RWGL_SRCBLEND,
|
|
RWGL_DESTBLEND,
|
|
RWGL_DEPTHTEST,
|
|
RWGL_DEPTHFUNC,
|
|
RWGL_DEPTHMASK,
|
|
RWGL_CULL,
|
|
RWGL_CULLFACE,
|
|
RWGL_STENCIL,
|
|
RWGL_STENCILFUNC,
|
|
RWGL_STENCILFAIL,
|
|
RWGL_STENCILZFAIL,
|
|
RWGL_STENCILPASS,
|
|
RWGL_STENCILREF,
|
|
RWGL_STENCILMASK,
|
|
RWGL_STENCILWRITEMASK,
|
|
|
|
// uniforms
|
|
RWGL_ALPHAFUNC,
|
|
RWGL_ALPHAREF,
|
|
RWGL_FOG,
|
|
RWGL_FOGSTART,
|
|
RWGL_FOGEND,
|
|
RWGL_FOGCOLOR,
|
|
|
|
RWGL_NUM_STATES
|
|
};
|
|
static bool uniformStateDirty[RWGL_NUM_STATES];
|
|
|
|
struct GlState {
|
|
bool32 blendEnable;
|
|
uint32 srcblend, destblend;
|
|
|
|
bool32 depthTest;
|
|
uint32 depthFunc;
|
|
|
|
uint32 depthMask;
|
|
|
|
bool32 cullEnable;
|
|
uint32 cullFace;
|
|
|
|
bool32 stencilEnable;
|
|
// glStencilFunc
|
|
uint32 stencilFunc;
|
|
uint32 stencilRef;
|
|
uint32 stencilMask;
|
|
// glStencilOp
|
|
uint32 stencilPass;
|
|
uint32 stencilFail;
|
|
uint32 stencilZFail;
|
|
// glStencilMask
|
|
uint32 stencilWriteMask;
|
|
};
|
|
static GlState curGlState, oldGlState;
|
|
|
|
static int32 activeTexture;
|
|
static uint32 boundTexture[MAXNUMSTAGES];
|
|
|
|
static uint32 currentFramebuffer;
|
|
|
|
static uint32 blendMap[] = {
|
|
GL_ZERO, // actually invalid
|
|
GL_ZERO,
|
|
GL_ONE,
|
|
GL_SRC_COLOR,
|
|
GL_ONE_MINUS_SRC_COLOR,
|
|
GL_SRC_ALPHA,
|
|
GL_ONE_MINUS_SRC_ALPHA,
|
|
GL_DST_ALPHA,
|
|
GL_ONE_MINUS_DST_ALPHA,
|
|
GL_DST_COLOR,
|
|
GL_ONE_MINUS_DST_COLOR,
|
|
GL_SRC_ALPHA_SATURATE,
|
|
};
|
|
|
|
static uint32 stencilOpMap[] = {
|
|
GL_KEEP, // actually invalid
|
|
GL_KEEP,
|
|
GL_ZERO,
|
|
GL_REPLACE,
|
|
GL_INCR,
|
|
GL_DECR,
|
|
GL_INVERT,
|
|
GL_INCR,//_WRAP,
|
|
GL_DECR//_WRAP
|
|
};
|
|
|
|
static uint32 stencilFuncMap[] = {
|
|
GL_NEVER, // actually invalid
|
|
GL_NEVER,
|
|
GL_LESS,
|
|
GL_EQUAL,
|
|
GL_LEQUAL,
|
|
GL_GREATER,
|
|
GL_NOTEQUAL,
|
|
GL_GEQUAL,
|
|
GL_ALWAYS
|
|
};
|
|
|
|
static float maxAnisotropy;
|
|
|
|
/*
|
|
* GL state cache
|
|
*/
|
|
|
|
void
|
|
setGlRenderState(uint32 state, uint32 value)
|
|
{
|
|
switch(state){
|
|
case RWGL_BLEND: curGlState.blendEnable = value; break;
|
|
case RWGL_SRCBLEND: curGlState.srcblend = value; break;
|
|
case RWGL_DESTBLEND: curGlState.destblend = value; break;
|
|
case RWGL_DEPTHTEST: curGlState.depthTest = value; break;
|
|
case RWGL_DEPTHFUNC: curGlState.depthFunc = value; break;
|
|
case RWGL_DEPTHMASK: curGlState.depthMask = value; break;
|
|
case RWGL_CULL: curGlState.cullEnable = value; break;
|
|
case RWGL_CULLFACE: curGlState.cullFace = value; break;
|
|
case RWGL_STENCIL: curGlState.stencilEnable = value; break;
|
|
case RWGL_STENCILFUNC: curGlState.stencilFunc = value; break;
|
|
case RWGL_STENCILFAIL: curGlState.stencilFail = value; break;
|
|
case RWGL_STENCILZFAIL: curGlState.stencilZFail = value; break;
|
|
case RWGL_STENCILPASS: curGlState.stencilPass = value; break;
|
|
case RWGL_STENCILREF: curGlState.stencilRef = value; break;
|
|
case RWGL_STENCILMASK: curGlState.stencilMask = value; break;
|
|
case RWGL_STENCILWRITEMASK: curGlState.stencilWriteMask = value; break;
|
|
}
|
|
}
|
|
|
|
void
|
|
flushGlRenderState(void)
|
|
{
|
|
if(oldGlState.blendEnable != curGlState.blendEnable){
|
|
oldGlState.blendEnable = curGlState.blendEnable;
|
|
(oldGlState.blendEnable ? glEnable : glDisable)(GL_BLEND);
|
|
}
|
|
|
|
if(oldGlState.srcblend != curGlState.srcblend ||
|
|
oldGlState.destblend != curGlState.destblend){
|
|
oldGlState.srcblend = curGlState.srcblend;
|
|
oldGlState.destblend = curGlState.destblend;
|
|
glBlendFunc(oldGlState.srcblend, oldGlState.destblend);
|
|
}
|
|
|
|
if(oldGlState.depthTest != curGlState.depthTest){
|
|
oldGlState.depthTest = curGlState.depthTest;
|
|
(oldGlState.depthTest ? glEnable : glDisable)(GL_DEPTH_TEST);
|
|
}
|
|
if(oldGlState.depthFunc != curGlState.depthFunc){
|
|
oldGlState.depthFunc = curGlState.depthFunc;
|
|
glDepthFunc(oldGlState.depthFunc);
|
|
}
|
|
if(oldGlState.depthMask != curGlState.depthMask){
|
|
oldGlState.depthMask = curGlState.depthMask;
|
|
glDepthMask(oldGlState.depthMask);
|
|
}
|
|
|
|
if(oldGlState.stencilEnable != curGlState.stencilEnable){
|
|
oldGlState.stencilEnable = curGlState.stencilEnable;
|
|
(oldGlState.stencilEnable ? glEnable : glDisable)(GL_STENCIL_TEST);
|
|
}
|
|
if(oldGlState.stencilFunc != curGlState.stencilFunc ||
|
|
oldGlState.stencilRef != curGlState.stencilRef ||
|
|
oldGlState.stencilMask != curGlState.stencilMask){
|
|
oldGlState.stencilFunc = curGlState.stencilFunc;
|
|
oldGlState.stencilRef = curGlState.stencilRef;
|
|
oldGlState.stencilMask = curGlState.stencilMask;
|
|
glStencilFunc(oldGlState.stencilFunc, oldGlState.stencilRef, oldGlState.stencilMask);
|
|
}
|
|
if(oldGlState.stencilPass != curGlState.stencilPass ||
|
|
oldGlState.stencilFail != curGlState.stencilFail ||
|
|
oldGlState.stencilZFail != curGlState.stencilZFail){
|
|
oldGlState.stencilPass = curGlState.stencilPass;
|
|
oldGlState.stencilFail = curGlState.stencilFail;
|
|
oldGlState.stencilZFail = curGlState.stencilZFail;
|
|
glStencilOp(oldGlState.stencilFail, oldGlState.stencilZFail, oldGlState.stencilPass);
|
|
}
|
|
if(oldGlState.stencilWriteMask != curGlState.stencilWriteMask){
|
|
oldGlState.stencilWriteMask = curGlState.stencilWriteMask;
|
|
glStencilMask(oldGlState.stencilWriteMask);
|
|
}
|
|
|
|
if(oldGlState.cullEnable != curGlState.cullEnable){
|
|
oldGlState.cullEnable = curGlState.cullEnable;
|
|
(oldGlState.cullEnable ? glEnable : glDisable)(GL_CULL_FACE);
|
|
}
|
|
if(oldGlState.cullFace != curGlState.cullFace){
|
|
oldGlState.cullFace = curGlState.cullFace;
|
|
glCullFace(oldGlState.cullFace);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
setAlphaBlend(bool32 enable)
|
|
{
|
|
if(rwStateCache.blendEnable != enable){
|
|
rwStateCache.blendEnable = enable;
|
|
setGlRenderState(RWGL_BLEND, enable);
|
|
}
|
|
}
|
|
|
|
bool32
|
|
getAlphaBlend(void)
|
|
{
|
|
return rwStateCache.blendEnable;
|
|
}
|
|
|
|
bool32 getAlphaTest(void) { return rwStateCache.alphaTestEnable; }
|
|
|
|
static void
|
|
setDepthTest(bool32 enable)
|
|
{
|
|
if(rwStateCache.ztest != enable){
|
|
rwStateCache.ztest = enable;
|
|
if(rwStateCache.zwrite && !enable){
|
|
// If we still want to write, enable but set mode to always
|
|
setGlRenderState(RWGL_DEPTHTEST, true);
|
|
setGlRenderState(RWGL_DEPTHFUNC, GL_ALWAYS);
|
|
}else{
|
|
setGlRenderState(RWGL_DEPTHTEST, rwStateCache.ztest);
|
|
setGlRenderState(RWGL_DEPTHFUNC, GL_LEQUAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
setDepthWrite(bool32 enable)
|
|
{
|
|
enable = enable ? GL_TRUE : GL_FALSE;
|
|
if(rwStateCache.zwrite != enable){
|
|
rwStateCache.zwrite = enable;
|
|
if(enable && !rwStateCache.ztest){
|
|
// Have to switch on ztest so writing can work
|
|
setGlRenderState(RWGL_DEPTHTEST, true);
|
|
setGlRenderState(RWGL_DEPTHFUNC, GL_ALWAYS);
|
|
}
|
|
setGlRenderState(RWGL_DEPTHMASK, rwStateCache.zwrite);
|
|
}
|
|
}
|
|
|
|
static void setAlphaTest(bool32 enable)
|
|
{
|
|
if(rwStateCache.alphaTestEnable != enable){
|
|
rwStateCache.alphaTestEnable = enable;
|
|
uniformStateDirty[RWGL_ALPHAFUNC] = true;
|
|
stateDirty = 1;
|
|
}
|
|
}
|
|
|
|
static void setAlphaTestFunction(uint32 function)
|
|
{
|
|
if(rwStateCache.alphaFunc != function){
|
|
rwStateCache.alphaFunc = function;
|
|
uniformStateDirty[RWGL_ALPHAFUNC] = true;
|
|
stateDirty = 1;
|
|
}
|
|
}
|
|
|
|
void setVertexAlpha(bool32 enable)
|
|
{
|
|
if(rwStateCache.vertexAlpha != enable){
|
|
if(!rwStateCache.textureAlpha){
|
|
setAlphaBlend(enable);
|
|
setAlphaTest(enable);
|
|
}
|
|
rwStateCache.vertexAlpha = enable;
|
|
}
|
|
}
|
|
|
|
static void
|
|
setActiveTexture(int32 n)
|
|
{
|
|
if(activeTexture != n){
|
|
activeTexture = n;
|
|
glActiveTexture(GL_TEXTURE0+n);
|
|
}
|
|
}
|
|
|
|
uint32
|
|
bindTexture(uint32 texid)
|
|
{
|
|
uint32 prev = boundTexture[activeTexture];
|
|
if(prev != texid){
|
|
boundTexture[activeTexture] = texid;
|
|
glBindTexture(GL_TEXTURE_2D, texid);
|
|
}
|
|
return prev;
|
|
}
|
|
|
|
void
|
|
bindFramebuffer(uint32 fbo)
|
|
{
|
|
if(currentFramebuffer != fbo){
|
|
// glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
currentFramebuffer = fbo;
|
|
}
|
|
}
|
|
|
|
static GLint filterConvMap_NoMIP[] = {
|
|
0, GL_NEAREST, GL_LINEAR,
|
|
GL_NEAREST, GL_LINEAR,
|
|
GL_NEAREST, GL_LINEAR
|
|
};
|
|
static GLint filterConvMap_MIP[] = {
|
|
0, GL_NEAREST, GL_LINEAR,
|
|
GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
|
|
GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR
|
|
};
|
|
|
|
static GLint addressConvMap[] = {
|
|
0, GL_REPEAT, GL_REPEAT, //GL_MIRRORED_REPEAT,
|
|
#ifdef __SYMBIAN32__
|
|
// TODO
|
|
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE
|
|
#else
|
|
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
|
|
#endif
|
|
};
|
|
|
|
static void
|
|
setFilterMode(uint32 stage, int32 filter, int32 maxAniso = 1)
|
|
{
|
|
if(rwStateCache.texstage[stage].filter != (Texture::FilterMode)filter){
|
|
rwStateCache.texstage[stage].filter = (Texture::FilterMode)filter;
|
|
Raster *raster = rwStateCache.texstage[stage].raster;
|
|
if(raster){
|
|
Gl1Raster *natras = PLUGINOFFSET(Gl1Raster, rwStateCache.texstage[stage].raster, nativeRasterOffset);
|
|
if(natras->filterMode != filter){
|
|
setActiveTexture(stage);
|
|
// if(natras->autogenMipmap || natras->numLevels > 1){
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_MIP[filter]);
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]);
|
|
// }else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]);
|
|
}
|
|
natras->filterMode = filter;
|
|
}
|
|
if(natras->maxAnisotropy != maxAniso){
|
|
setActiveTexture(stage);
|
|
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)maxAniso);
|
|
natras->maxAnisotropy = maxAniso;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
setAddressU(uint32 stage, int32 addressing)
|
|
{
|
|
if(rwStateCache.texstage[stage].addressingU != (Texture::Addressing)addressing){
|
|
rwStateCache.texstage[stage].addressingU = (Texture::Addressing)addressing;
|
|
Raster *raster = rwStateCache.texstage[stage].raster;
|
|
if(raster){
|
|
Gl1Raster *natras = PLUGINOFFSET(Gl1Raster, raster, nativeRasterOffset);
|
|
if(natras->addressU == addressing){
|
|
setActiveTexture(stage);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, addressConvMap[addressing]);
|
|
natras->addressU = addressing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
setAddressV(uint32 stage, int32 addressing)
|
|
{
|
|
if(rwStateCache.texstage[stage].addressingV != (Texture::Addressing)addressing){
|
|
rwStateCache.texstage[stage].addressingV = (Texture::Addressing)addressing;
|
|
Raster *raster = rwStateCache.texstage[stage].raster;
|
|
if(raster){
|
|
Gl1Raster *natras = PLUGINOFFSET(Gl1Raster, rwStateCache.texstage[stage].raster, nativeRasterOffset);
|
|
if(natras->addressV == addressing){
|
|
setActiveTexture(stage);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, addressConvMap[addressing]);
|
|
natras->addressV = addressing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
setRasterStageOnly(uint32 stage, Raster *raster)
|
|
{
|
|
bool32 alpha;
|
|
if(raster != rwStateCache.texstage[stage].raster){
|
|
rwStateCache.texstage[stage].raster = raster;
|
|
setActiveTexture(stage);
|
|
if(raster){
|
|
assert(raster->platform == PLATFORM_GLES1);
|
|
Gl1Raster *natras = PLUGINOFFSET(Gl1Raster, raster, nativeRasterOffset);
|
|
glEnable(GL_TEXTURE_2D);
|
|
bindTexture(natras->texid);
|
|
|
|
rwStateCache.texstage[stage].filter = (rw::Texture::FilterMode)natras->filterMode;
|
|
rwStateCache.texstage[stage].addressingU = (rw::Texture::Addressing)natras->addressU;
|
|
rwStateCache.texstage[stage].addressingV = (rw::Texture::Addressing)natras->addressV;
|
|
|
|
alpha = natras->hasAlpha;
|
|
}else{
|
|
glDisable(GL_TEXTURE_2D);
|
|
bindTexture(whitetex);
|
|
alpha = 0;
|
|
}
|
|
|
|
if(stage == 0){
|
|
if(alpha != rwStateCache.textureAlpha){
|
|
rwStateCache.textureAlpha = alpha;
|
|
if(!rwStateCache.vertexAlpha){
|
|
setAlphaBlend(alpha);
|
|
setAlphaTest(alpha);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
setRasterStage(uint32 stage, Raster *raster)
|
|
{
|
|
bool32 alpha;
|
|
if(raster != rwStateCache.texstage[stage].raster){
|
|
rwStateCache.texstage[stage].raster = raster;
|
|
setActiveTexture(stage);
|
|
if(raster){
|
|
assert(raster->platform == PLATFORM_GLES1);
|
|
Gl1Raster *natras = PLUGINOFFSET(Gl1Raster, raster, nativeRasterOffset);
|
|
glEnable(GL_TEXTURE_2D);
|
|
bindTexture(natras->texid);
|
|
uint32 filter = rwStateCache.texstage[stage].filter;
|
|
uint32 addrU = rwStateCache.texstage[stage].addressingU;
|
|
uint32 addrV = rwStateCache.texstage[stage].addressingV;
|
|
if(natras->filterMode != filter){
|
|
// if(natras->autogenMipmap || natras->numLevels > 1){
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_MIP[filter]);
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]);
|
|
// }else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterConvMap_NoMIP[filter]);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterConvMap_NoMIP[filter]);
|
|
}
|
|
natras->filterMode = filter;
|
|
}
|
|
if(natras->addressU != addrU){
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, addressConvMap[addrU]);
|
|
natras->addressU = addrU;
|
|
}
|
|
if(natras->addressV != addrV){
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, addressConvMap[addrV]);
|
|
natras->addressV = addrV;
|
|
}
|
|
alpha = natras->hasAlpha;
|
|
}else{
|
|
glDisable(GL_TEXTURE_2D);
|
|
bindTexture(whitetex);
|
|
alpha = 0;
|
|
}
|
|
|
|
if(stage == 0){
|
|
if(alpha != rwStateCache.textureAlpha){
|
|
rwStateCache.textureAlpha = alpha;
|
|
if(!rwStateCache.vertexAlpha){
|
|
setAlphaBlend(alpha);
|
|
setAlphaTest(alpha);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
evictRaster(Raster *raster)
|
|
{
|
|
int i;
|
|
for(i = 0; i < MAXNUMSTAGES; i++){
|
|
//assert(rwStateCache.texstage[i].raster != raster);
|
|
if(rwStateCache.texstage[i].raster != raster)
|
|
continue;
|
|
setRasterStage(i, nil);
|
|
}
|
|
}
|
|
|
|
void
|
|
setTexture(int32 stage, Texture *tex)
|
|
{
|
|
if(tex == nil || tex->raster == nil){
|
|
setRasterStage(stage, nil);
|
|
return;
|
|
}
|
|
setRasterStageOnly(stage, tex->raster);
|
|
setFilterMode(stage, tex->getFilter(), tex->getMaxAnisotropy());
|
|
setAddressU(stage, tex->getAddressU());
|
|
setAddressV(stage, tex->getAddressV());
|
|
}
|
|
|
|
static void
|
|
setRenderState(int32 state, void *pvalue)
|
|
{
|
|
uint32 value = (uint32)(uintptr)pvalue;
|
|
switch(state){
|
|
case TEXTURERASTER:
|
|
setRasterStage(0, (Raster*)pvalue);
|
|
break;
|
|
case TEXTUREADDRESS:
|
|
setAddressU(0, value);
|
|
setAddressV(0, value);
|
|
break;
|
|
case TEXTUREADDRESSU:
|
|
setAddressU(0, value);
|
|
break;
|
|
case TEXTUREADDRESSV:
|
|
setAddressV(0, value);
|
|
break;
|
|
case TEXTUREFILTER:
|
|
setFilterMode(0, value);
|
|
break;
|
|
case VERTEXALPHA:
|
|
setVertexAlpha(value);
|
|
break;
|
|
case SRCBLEND:
|
|
if(rwStateCache.srcblend != value){
|
|
rwStateCache.srcblend = value;
|
|
setGlRenderState(RWGL_SRCBLEND, blendMap[rwStateCache.srcblend]);
|
|
}
|
|
break;
|
|
case DESTBLEND:
|
|
if(rwStateCache.destblend != value){
|
|
rwStateCache.destblend = value;
|
|
setGlRenderState(RWGL_DESTBLEND, blendMap[rwStateCache.destblend]);
|
|
}
|
|
break;
|
|
case ZTESTENABLE:
|
|
setDepthTest(value);
|
|
break;
|
|
case ZWRITEENABLE:
|
|
setDepthWrite(value);
|
|
break;
|
|
case FOGENABLE:
|
|
if(rwStateCache.fogEnable != value){
|
|
rwStateCache.fogEnable = value;
|
|
uniformStateDirty[RWGL_FOG] = true;
|
|
stateDirty = 1;
|
|
}
|
|
break;
|
|
case FOGCOLOR:
|
|
// no cache check here...too lazy
|
|
RGBA c;
|
|
c.red = value;
|
|
c.green = value>>8;
|
|
c.blue = value>>16;
|
|
c.alpha = value>>24;
|
|
convColor(&uniformState.fogColor, &c);
|
|
uniformStateDirty[RWGL_FOGCOLOR] = true;
|
|
stateDirty = 1;
|
|
break;
|
|
case CULLMODE:
|
|
if(rwStateCache.cullmode != value){
|
|
rwStateCache.cullmode = value;
|
|
if(rwStateCache.cullmode == CULLNONE)
|
|
setGlRenderState(RWGL_CULL, false);
|
|
else{
|
|
setGlRenderState(RWGL_CULL, true);
|
|
setGlRenderState(RWGL_CULLFACE, rwStateCache.cullmode == CULLBACK ? GL_BACK : GL_FRONT);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STENCILENABLE:
|
|
if(rwStateCache.stencilenable != value){
|
|
rwStateCache.stencilenable = value;
|
|
setGlRenderState(RWGL_STENCIL, value);
|
|
}
|
|
break;
|
|
case STENCILFAIL:
|
|
if(rwStateCache.stencilfail != value){
|
|
rwStateCache.stencilfail = value;
|
|
setGlRenderState(RWGL_STENCILFAIL, stencilOpMap[value]);
|
|
}
|
|
break;
|
|
case STENCILZFAIL:
|
|
if(rwStateCache.stencilzfail != value){
|
|
rwStateCache.stencilzfail = value;
|
|
setGlRenderState(RWGL_STENCILZFAIL, stencilOpMap[value]);
|
|
}
|
|
break;
|
|
case STENCILPASS:
|
|
if(rwStateCache.stencilpass != value){
|
|
rwStateCache.stencilpass = value;
|
|
setGlRenderState(RWGL_STENCILPASS, stencilOpMap[value]);
|
|
}
|
|
break;
|
|
case STENCILFUNCTION:
|
|
if(rwStateCache.stencilfunc != value){
|
|
rwStateCache.stencilfunc = value;
|
|
setGlRenderState(RWGL_STENCILFUNC, stencilFuncMap[value]);
|
|
}
|
|
break;
|
|
case STENCILFUNCTIONREF:
|
|
if(rwStateCache.stencilref != value){
|
|
rwStateCache.stencilref = value;
|
|
setGlRenderState(RWGL_STENCILREF, value);
|
|
}
|
|
break;
|
|
case STENCILFUNCTIONMASK:
|
|
if(rwStateCache.stencilmask != value){
|
|
rwStateCache.stencilmask = value;
|
|
setGlRenderState(RWGL_STENCILMASK, value);
|
|
}
|
|
break;
|
|
case STENCILFUNCTIONWRITEMASK:
|
|
if(rwStateCache.stencilwritemask != value){
|
|
rwStateCache.stencilwritemask = value;
|
|
setGlRenderState(RWGL_STENCILWRITEMASK, value);
|
|
}
|
|
break;
|
|
|
|
case ALPHATESTFUNC:
|
|
setAlphaTestFunction(value);
|
|
break;
|
|
case ALPHATESTREF:
|
|
if(alphaRef != value/255.0f){
|
|
alphaRef = value/255.0f;
|
|
uniformStateDirty[RWGL_ALPHAREF] = true;
|
|
stateDirty = 1;
|
|
}
|
|
break;
|
|
case GSALPHATEST:
|
|
rwStateCache.gsalpha = value;
|
|
break;
|
|
case GSALPHATESTREF:
|
|
rwStateCache.gsalpharef = value;
|
|
}
|
|
}
|
|
|
|
static void*
|
|
getRenderState(int32 state)
|
|
{
|
|
uint32 val;
|
|
RGBA rgba;
|
|
switch(state){
|
|
case TEXTURERASTER:
|
|
return rwStateCache.texstage[0].raster;
|
|
case TEXTUREADDRESS:
|
|
if(rwStateCache.texstage[0].addressingU == rwStateCache.texstage[0].addressingV)
|
|
val = rwStateCache.texstage[0].addressingU;
|
|
else
|
|
val = 0; // invalid
|
|
break;
|
|
case TEXTUREADDRESSU:
|
|
val = rwStateCache.texstage[0].addressingU;
|
|
break;
|
|
case TEXTUREADDRESSV:
|
|
val = rwStateCache.texstage[0].addressingV;
|
|
break;
|
|
case TEXTUREFILTER:
|
|
val = rwStateCache.texstage[0].filter;
|
|
break;
|
|
|
|
case VERTEXALPHA:
|
|
val = rwStateCache.vertexAlpha;
|
|
break;
|
|
case SRCBLEND:
|
|
val = rwStateCache.srcblend;
|
|
break;
|
|
case DESTBLEND:
|
|
val = rwStateCache.destblend;
|
|
break;
|
|
case ZTESTENABLE:
|
|
val = rwStateCache.ztest;
|
|
break;
|
|
case ZWRITEENABLE:
|
|
val = rwStateCache.zwrite;
|
|
break;
|
|
case FOGENABLE:
|
|
val = rwStateCache.fogEnable;
|
|
break;
|
|
case FOGCOLOR:
|
|
convColor(&rgba, &uniformState.fogColor);
|
|
val = RWRGBAINT(rgba.red, rgba.green, rgba.blue, rgba.alpha);
|
|
break;
|
|
case CULLMODE:
|
|
val = rwStateCache.cullmode;
|
|
break;
|
|
|
|
case STENCILENABLE:
|
|
val = rwStateCache.stencilenable;
|
|
break;
|
|
case STENCILFAIL:
|
|
val = rwStateCache.stencilfail;
|
|
break;
|
|
case STENCILZFAIL:
|
|
val = rwStateCache.stencilzfail;
|
|
break;
|
|
case STENCILPASS:
|
|
val = rwStateCache.stencilpass;
|
|
break;
|
|
case STENCILFUNCTION:
|
|
val = rwStateCache.stencilfunc;
|
|
break;
|
|
case STENCILFUNCTIONREF:
|
|
val = rwStateCache.stencilref;
|
|
break;
|
|
case STENCILFUNCTIONMASK:
|
|
val = rwStateCache.stencilmask;
|
|
break;
|
|
case STENCILFUNCTIONWRITEMASK:
|
|
val = rwStateCache.stencilwritemask;
|
|
break;
|
|
|
|
case ALPHATESTFUNC:
|
|
val = rwStateCache.alphaFunc;
|
|
break;
|
|
case ALPHATESTREF:
|
|
val = (uint32)(alphaRef*255.0f);
|
|
break;
|
|
case GSALPHATEST:
|
|
val = rwStateCache.gsalpha;
|
|
break;
|
|
case GSALPHATESTREF:
|
|
val = rwStateCache.gsalpharef;
|
|
break;
|
|
default:
|
|
val = 0;
|
|
}
|
|
return (void*)(uintptr)val;
|
|
}
|
|
|
|
static void
|
|
resetRenderState(void)
|
|
{
|
|
rwStateCache.alphaFunc = ALPHAGREATEREQUAL;
|
|
alphaRef = 10.0f/255.0f;
|
|
uniformState.fogStart = 0.0f;
|
|
uniformState.fogEnd = 0.0f;
|
|
uniformState.fogColor.red = 1.0f;
|
|
uniformState.fogColor.green = 1.0f;
|
|
uniformState.fogColor.blue = 1.0f;
|
|
uniformState.fogColor.alpha = 1.0f;
|
|
rwStateCache.gsalpha = 0;
|
|
rwStateCache.gsalpharef = 128;
|
|
stateDirty = 1;
|
|
|
|
rwStateCache.vertexAlpha = 0;
|
|
rwStateCache.textureAlpha = 0;
|
|
rwStateCache.alphaTestEnable = 0;
|
|
|
|
memset(&oldGlState, 0xFE, sizeof(oldGlState));
|
|
|
|
rwStateCache.blendEnable = 0;
|
|
setGlRenderState(RWGL_BLEND, false);
|
|
rwStateCache.srcblend = BLENDSRCALPHA;
|
|
rwStateCache.destblend = BLENDINVSRCALPHA;
|
|
setGlRenderState(RWGL_SRCBLEND, blendMap[rwStateCache.srcblend]);
|
|
setGlRenderState(RWGL_DESTBLEND, blendMap[rwStateCache.destblend]);
|
|
|
|
rwStateCache.zwrite = GL_TRUE;
|
|
setGlRenderState(RWGL_DEPTHMASK, rwStateCache.zwrite);
|
|
|
|
rwStateCache.ztest = 1;
|
|
setGlRenderState(RWGL_DEPTHTEST, true);
|
|
setGlRenderState(RWGL_DEPTHFUNC, GL_LEQUAL);
|
|
|
|
rwStateCache.cullmode = CULLNONE;
|
|
setGlRenderState(RWGL_CULL, false);
|
|
setGlRenderState(RWGL_CULLFACE, GL_BACK);
|
|
|
|
rwStateCache.stencilenable = 0;
|
|
setGlRenderState(RWGL_STENCIL, GL_FALSE);
|
|
rwStateCache.stencilfail = STENCILKEEP;
|
|
setGlRenderState(RWGL_STENCILFAIL, GL_KEEP);
|
|
rwStateCache.stencilzfail = STENCILKEEP;
|
|
setGlRenderState(RWGL_STENCILZFAIL, GL_KEEP);
|
|
rwStateCache.stencilpass = STENCILKEEP;
|
|
setGlRenderState(RWGL_STENCILPASS, GL_KEEP);
|
|
rwStateCache.stencilfunc = STENCILALWAYS;
|
|
setGlRenderState(RWGL_STENCILFUNC, GL_ALWAYS);
|
|
rwStateCache.stencilref = 0;
|
|
setGlRenderState(RWGL_STENCILREF, 0);
|
|
rwStateCache.stencilmask = 0xFFFFFFFF;
|
|
setGlRenderState(RWGL_STENCILMASK, 0xFFFFFFFF);
|
|
rwStateCache.stencilwritemask = 0xFFFFFFFF;
|
|
setGlRenderState(RWGL_STENCILWRITEMASK, 0xFFFFFFFF);
|
|
|
|
activeTexture = -1;
|
|
for(int i = 0; i < MAXNUMSTAGES; i++){
|
|
setActiveTexture(i);
|
|
bindTexture(whitetex);
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
setActiveTexture(0);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
void
|
|
setWorldMatrix(Matrix *mat)
|
|
{
|
|
convMatrix(&uniformObject.world, mat);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadMatrixf(uniformScene.view);
|
|
glMultMatrixf((float*)&uniformObject.world);
|
|
objectDirty = 1;
|
|
}
|
|
|
|
int32
|
|
setLights(WorldLights *lightData)
|
|
{
|
|
int i, n;
|
|
Light *l;
|
|
int32 bits = 0;
|
|
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat*)&lightData->ambient);
|
|
|
|
if(lightData->numAmbients)
|
|
bits |= VSLIGHT_AMBIENT;
|
|
|
|
n = 0;
|
|
for(i = 0; i < MAX_LIGHTS; i++)
|
|
glDisable(GL_LIGHT0 + i);
|
|
|
|
for(i = 0; i < lightData->numDirectionals && i < 8; i++){
|
|
l = lightData->directionals[i];
|
|
glEnable(GL_LIGHT0 + n);
|
|
GLfloat dir[4] = { -l->getFrame()->getLTM()->at.x, -l->getFrame()->getLTM()->at.y, -l->getFrame()->getLTM()->at.z, 0.0f };
|
|
glLightfv(GL_LIGHT0 + n, GL_POSITION, dir);
|
|
glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, (GLfloat*)&l->color);
|
|
glLightfv(GL_LIGHT0 + n, GL_SPECULAR, (GLfloat*)&l->color);
|
|
bits |= VSLIGHT_DIRECT;
|
|
n++;
|
|
if(n >= MAX_LIGHTS) goto out;
|
|
}
|
|
|
|
for(i = 0; i < lightData->numLocals; i++){
|
|
Light *l = lightData->locals[i];
|
|
|
|
switch(l->getType()){
|
|
case Light::POINT:
|
|
glEnable(GL_LIGHT0 + n);
|
|
{
|
|
GLfloat pos[4] = { l->getFrame()->getLTM()->pos.x, l->getFrame()->getLTM()->pos.y, l->getFrame()->getLTM()->pos.z, 1.0f };
|
|
glLightfv(GL_LIGHT0 + n, GL_POSITION, pos);
|
|
glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, (GLfloat*)&l->color);
|
|
glLightf(GL_LIGHT0 + n, GL_CONSTANT_ATTENUATION, 1.0f);
|
|
glLightf(GL_LIGHT0 + n, GL_LINEAR_ATTENUATION, l->radius > 0.0f ? 1.0f / l->radius : 0.0f);
|
|
}
|
|
bits |= VSLIGHT_POINT;
|
|
n++;
|
|
if(n >= MAX_LIGHTS) goto out;
|
|
break;
|
|
case Light::SPOT:
|
|
case Light::SOFTSPOT:
|
|
glEnable(GL_LIGHT0 + n);
|
|
{
|
|
GLfloat pos[4] = { l->getFrame()->getLTM()->pos.x, l->getFrame()->getLTM()->pos.y, l->getFrame()->getLTM()->pos.z, 1.0f };
|
|
GLfloat dir[4] = { l->getFrame()->getLTM()->at.x, l->getFrame()->getLTM()->at.y, l->getFrame()->getLTM()->at.z, 0.0f };
|
|
glLightfv(GL_LIGHT0 + n, GL_POSITION, pos);
|
|
glLightfv(GL_LIGHT0 + n, GL_SPOT_DIRECTION, dir);
|
|
glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, (GLfloat*)&l->color);
|
|
glLightf(GL_LIGHT0 + n, GL_SPOT_CUTOFF, 45.0f);
|
|
}
|
|
bits |= VSLIGHT_SPOT;
|
|
n++;
|
|
if(n >= MAX_LIGHTS) goto out;
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
if(n > 0 || lightData->numAmbients > 0)
|
|
//pruebo a ver que tal sin luz
|
|
//glEnable(GL_LIGHTING);
|
|
glDisable(GL_LIGHTING);
|
|
else
|
|
glDisable(GL_LIGHTING);
|
|
|
|
objectDirty = 1;
|
|
return bits;
|
|
}
|
|
|
|
void
|
|
setProjectionMatrix(float32 *mat)
|
|
{
|
|
memcpy(&uniformScene.proj, mat, 64);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadMatrixf(uniformScene.proj);
|
|
sceneDirty = 1;
|
|
}
|
|
|
|
void
|
|
setViewMatrix(float32 *mat)
|
|
{
|
|
memcpy(&uniformScene.view, mat, 64);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadMatrixf(uniformScene.view);
|
|
glMultMatrixf((float*)&uniformObject.world);
|
|
sceneDirty = 1;
|
|
}
|
|
|
|
|
|
void
|
|
setMaterial(const RGBA &color, const SurfaceProperties &surfaceprops, float extraSurfProp)
|
|
{
|
|
rw::RGBAf col;
|
|
convColor(&col, &color);
|
|
glColor4f(col.red, col.green, col.blue, col.alpha);
|
|
|
|
GLfloat ambient[4] = { col.red * surfaceprops.ambient, col.green * surfaceprops.ambient, col.blue * surfaceprops.ambient, col.alpha };
|
|
GLfloat diffuse[4] = { col.red * surfaceprops.diffuse, col.green * surfaceprops.diffuse, col.blue * surfaceprops.diffuse, col.alpha };
|
|
GLfloat specular[4] = { surfaceprops.specular, surfaceprops.specular, surfaceprops.specular, 1.0f };
|
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
|
|
}
|
|
|
|
void
|
|
flushCache(void)
|
|
{
|
|
flushGlRenderState();
|
|
|
|
if(uniformStateDirty[RWGL_ALPHAFUNC] || uniformStateDirty[RWGL_ALPHAREF]){
|
|
if (rwStateCache.alphaTestEnable) {
|
|
glEnable(GL_ALPHA_TEST);
|
|
int func = GL_ALWAYS;
|
|
switch(rwStateCache.alphaFunc){
|
|
case ALPHAALWAYS:
|
|
func = GL_ALWAYS;
|
|
break;
|
|
case ALPHAGREATEREQUAL:
|
|
func = GL_GEQUAL;
|
|
break;
|
|
case ALPHALESS:
|
|
func = GL_LESS;
|
|
break;
|
|
}
|
|
glAlphaFunc(func, alphaRef);
|
|
} else {
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
uniformStateDirty[RWGL_ALPHAFUNC] = false;
|
|
uniformStateDirty[RWGL_ALPHAREF] = false;
|
|
}
|
|
|
|
if(uniformStateDirty[RWGL_FOG] ||
|
|
uniformStateDirty[RWGL_FOGSTART] ||
|
|
uniformStateDirty[RWGL_FOGEND] ||
|
|
uniformStateDirty[RWGL_FOGCOLOR]){
|
|
if (rwStateCache.fogEnable) {
|
|
glEnable(GL_FOG);
|
|
glFogf(GL_FOG_MODE, GL_LINEAR);
|
|
glFogf(GL_FOG_START, rwStateCache.fogStart);
|
|
glFogf(GL_FOG_END, rwStateCache.fogEnd);
|
|
GLfloat fcolor[4] = { uniformState.fogColor.red, uniformState.fogColor.green, uniformState.fogColor.blue, uniformState.fogColor.alpha };
|
|
glFogfv(GL_FOG_COLOR, fcolor);
|
|
} else {
|
|
glDisable(GL_FOG);
|
|
}
|
|
uniformStateDirty[RWGL_FOG] = false;
|
|
uniformStateDirty[RWGL_FOGSTART] = false;
|
|
uniformStateDirty[RWGL_FOGEND] = false;
|
|
uniformStateDirty[RWGL_FOGCOLOR] = false;
|
|
}
|
|
}
|
|
|
|
static void
|
|
setFrameBuffer(Camera *cam)
|
|
{
|
|
Raster *fbuf = cam->frameBuffer->parent;
|
|
Raster *zbuf = cam->zBuffer->parent;
|
|
assert(fbuf);
|
|
|
|
Gl1Raster *natfb = PLUGINOFFSET(Gl1Raster, fbuf, nativeRasterOffset);
|
|
Gl1Raster *natzb = PLUGINOFFSET(Gl1Raster, zbuf, nativeRasterOffset);
|
|
assert(fbuf->type == Raster::CAMERA || fbuf->type == Raster::CAMERATEXTURE);
|
|
|
|
// Have to make sure depth buffer is attached to FB's fbo
|
|
bindFramebuffer(natfb->fbo);
|
|
if (zbuf) {
|
|
if(natfb->fboMate != zbuf){
|
|
// glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, GETGL3RASTEREXT(zbuf)->texid);
|
|
natfb->fboMate = zbuf;
|
|
}
|
|
} else if(natfb->fboMate) {
|
|
// glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
|
natfb->fboMate = nil;
|
|
}
|
|
}
|
|
|
|
static Rect
|
|
getFramebufferRect(Raster *frameBuffer)
|
|
{
|
|
Rect r;
|
|
Raster *fb = frameBuffer->parent;
|
|
if(fb->type == Raster::CAMERA){
|
|
r.w = glGlobals.modes[0].width;
|
|
r.h = glGlobals.modes[0].height;
|
|
}else{
|
|
r.w = fb->width;
|
|
r.h = fb->height;
|
|
}
|
|
r.x = 0;
|
|
r.y = 0;
|
|
|
|
// Got a subraster
|
|
if(frameBuffer != fb){
|
|
r.x = frameBuffer->offsetX;
|
|
// GL y offset is from bottom
|
|
r.y = r.h - frameBuffer->height - frameBuffer->offsetY;
|
|
r.w = frameBuffer->width;
|
|
r.h = frameBuffer->height;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static void
|
|
setViewport(Raster *frameBuffer)
|
|
{
|
|
Rect r = getFramebufferRect(frameBuffer);
|
|
if(r.w != glGlobals.presentWidth || r.h != glGlobals.presentHeight ||
|
|
r.x != glGlobals.presentOffX || r.y != glGlobals.presentOffY){
|
|
glViewport(r.x, r.y, r.w, r.h);
|
|
glGlobals.presentWidth = r.w;
|
|
glGlobals.presentHeight = r.h;
|
|
glGlobals.presentOffX = r.x;
|
|
glGlobals.presentOffY = r.y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
beginUpdate(Camera *cam)
|
|
{
|
|
float view[16], proj[16];
|
|
// View Matrix
|
|
Matrix inv;
|
|
Matrix::invert(&inv, cam->getFrame()->getLTM());
|
|
// Since we're looking into positive Z,
|
|
// flip X to ge a left handed view space.
|
|
view[0] = -inv.right.x;
|
|
view[1] = inv.right.y;
|
|
view[2] = inv.right.z;
|
|
view[3] = 0.0f;
|
|
view[4] = -inv.up.x;
|
|
view[5] = inv.up.y;
|
|
view[6] = inv.up.z;
|
|
view[7] = 0.0f;
|
|
view[8] = -inv.at.x;
|
|
view[9] = inv.at.y;
|
|
view[10] = inv.at.z;
|
|
view[11] = 0.0f;
|
|
view[12] = -inv.pos.x;
|
|
view[13] = inv.pos.y;
|
|
view[14] = inv.pos.z;
|
|
view[15] = 1.0f;
|
|
memcpy(&cam->devView, &view, sizeof(RawMatrix));
|
|
setViewMatrix(view);
|
|
|
|
// Projection Matrix
|
|
float32 invwx = 1.0f/cam->viewWindow.x;
|
|
float32 invwy = 1.0f/cam->viewWindow.y;
|
|
float32 invz = 1.0f/(cam->farPlane-cam->nearPlane);
|
|
|
|
proj[0] = invwx;
|
|
proj[1] = 0.0f;
|
|
proj[2] = 0.0f;
|
|
proj[3] = 0.0f;
|
|
|
|
proj[4] = 0.0f;
|
|
proj[5] = invwy;
|
|
proj[6] = 0.0f;
|
|
proj[7] = 0.0f;
|
|
|
|
proj[8] = cam->viewOffset.x*invwx;
|
|
proj[9] = cam->viewOffset.y*invwy;
|
|
proj[12] = -proj[8];
|
|
proj[13] = -proj[9];
|
|
if(cam->projection == Camera::PERSPECTIVE){
|
|
proj[10] = (cam->farPlane+cam->nearPlane)*invz;
|
|
proj[11] = 1.0f;
|
|
|
|
proj[14] = -2.0f*cam->nearPlane*cam->farPlane*invz;
|
|
proj[15] = 0.0f;
|
|
}else{
|
|
proj[10] = 2.0f*invz;
|
|
proj[11] = 0.0f;
|
|
|
|
proj[14] = -(cam->farPlane+cam->nearPlane)*invz;
|
|
proj[15] = 1.0f;
|
|
}
|
|
memcpy(&cam->devProj, &proj, sizeof(RawMatrix));
|
|
setProjectionMatrix(proj);
|
|
|
|
if(rwStateCache.fogStart != cam->fogPlane){
|
|
rwStateCache.fogStart = cam->fogPlane;
|
|
uniformStateDirty[RWGL_FOGSTART] = true;
|
|
stateDirty = 1;
|
|
}
|
|
if(rwStateCache.fogEnd != cam->farPlane){
|
|
rwStateCache.fogEnd = cam->farPlane;
|
|
uniformStateDirty[RWGL_FOGEND] = true;
|
|
stateDirty = 1;
|
|
}
|
|
|
|
setFrameBuffer(cam);
|
|
|
|
setViewport(cam->frameBuffer);
|
|
}
|
|
|
|
static void
|
|
endUpdate(Camera *cam)
|
|
{
|
|
}
|
|
|
|
static void
|
|
clearCamera(Camera *cam, RGBA *col, uint32 mode)
|
|
{
|
|
RGBAf colf;
|
|
GLbitfield mask;
|
|
|
|
setFrameBuffer(cam);
|
|
|
|
// make sure we're only clearing the part of the framebuffer
|
|
// that is subrastered
|
|
bool setScissor = cam->frameBuffer != cam->frameBuffer->parent;
|
|
if(setScissor){
|
|
Rect r = getFramebufferRect(cam->frameBuffer);
|
|
glScissor(r.x, r.y, r.w, r.h);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
convColor(&colf, col);
|
|
glClearColor(colf.red, colf.green, colf.blue, colf.alpha);
|
|
mask = 0;
|
|
if(mode & Camera::CLEARIMAGE)
|
|
mask |= GL_COLOR_BUFFER_BIT;
|
|
if(mode & Camera::CLEARZ)
|
|
mask |= GL_DEPTH_BUFFER_BIT;
|
|
if(mode & Camera::CLEARSTENCIL)
|
|
mask |= GL_STENCIL_BUFFER_BIT;
|
|
glDepthMask(GL_TRUE);
|
|
glClear(mask);
|
|
glDepthMask(rwStateCache.zwrite);
|
|
|
|
if(setScissor)
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
static void
|
|
showRaster(Raster *raster, uint32 flags)
|
|
{
|
|
// glViewport(raster->offsetX, raster->offsetY,
|
|
// raster->width, raster->height);
|
|
// TODO check if context is lost
|
|
eglSwapBuffers(eglGetCurrentDisplay(), eglGetCurrentSurface(EGL_DRAW));
|
|
}
|
|
|
|
static bool32
|
|
rasterRenderFast(Raster *raster, int32 x, int32 y)
|
|
{
|
|
Raster *src = raster;
|
|
Raster *dst = Raster::getCurrentContext();
|
|
Gl1Raster *natdst = PLUGINOFFSET(Gl1Raster, dst, nativeRasterOffset);
|
|
Gl1Raster *natsrc = PLUGINOFFSET(Gl1Raster, src, nativeRasterOffset);
|
|
|
|
switch(dst->type){
|
|
case Raster::NORMAL:
|
|
case Raster::TEXTURE:
|
|
case Raster::CAMERATEXTURE:
|
|
switch(src->type){
|
|
case Raster::CAMERA:
|
|
setActiveTexture(0);
|
|
glBindTexture(GL_TEXTURE_2D, natdst->texid);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, (dst->height-src->height)-y,
|
|
0, 0, src->width, src->height);
|
|
glBindTexture(GL_TEXTURE_2D, boundTexture[0]);
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
openSymbian(EngineOpenParams *openparams)
|
|
{
|
|
glGlobals.winWidth = openparams->width;
|
|
glGlobals.winHeight = openparams->height;
|
|
|
|
glGlobals.modes = (DisplayMode*)rwMalloc(sizeof(DisplayMode), ID_DRIVER | MEMDUR_EVENT);
|
|
glGlobals.modes[0].width = openparams->width;
|
|
glGlobals.modes[0].height = openparams->height;
|
|
glGlobals.modes[0].depth = 32;
|
|
glGlobals.modes[0].flags = VIDEOMODEEXCLUSIVE;
|
|
|
|
glGlobals.numModes = 1;
|
|
glGlobals.currentMode = 0;
|
|
|
|
glGlobals.numMonitors = 1;
|
|
glGlobals.currentMonitor = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
closeSymbian(void)
|
|
{
|
|
if(glGlobals.modes){
|
|
rwFree(glGlobals.modes);
|
|
glGlobals.modes = nil;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
startSymbian(void)
|
|
{
|
|
glGlobals.presentWidth = glGlobals.winWidth;
|
|
glGlobals.presentHeight = glGlobals.winHeight;
|
|
glGlobals.presentOffX = 0;
|
|
glGlobals.presentOffY = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
stopSymbian(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
initOpenGL(void)
|
|
{
|
|
glClearColor(0.25, 0.25, 0.25, 1.0);
|
|
|
|
byte whitepixel[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
|
glGenTextures(1, &whitetex);
|
|
glBindTexture(GL_TEXTURE_2D, whitetex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, &whitepixel);
|
|
|
|
resetRenderState();
|
|
|
|
glEnable(GL_NORMALIZE);
|
|
|
|
openIm2D();
|
|
openIm3D();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
termOpenGL(void)
|
|
{
|
|
closeIm3D();
|
|
closeIm2D();
|
|
|
|
glDeleteTextures(1, &whitetex);
|
|
whitetex = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
finalizeOpenGL(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
deviceSystemSymbian(DeviceReq req, void *arg, int32 n)
|
|
{
|
|
VideoMode *rwmode;
|
|
|
|
switch(req){
|
|
case DEVICEOPEN:
|
|
return openSymbian((EngineOpenParams*)arg);
|
|
|
|
case DEVICECLOSE:
|
|
return closeSymbian();
|
|
|
|
case DEVICEINIT:
|
|
return startSymbian() && initOpenGL();
|
|
|
|
case DEVICETERM:
|
|
return termOpenGL() && stopSymbian();
|
|
|
|
case DEVICEFINALIZE:
|
|
return finalizeOpenGL();
|
|
|
|
case DEVICEGETNUMSUBSYSTEMS:
|
|
return glGlobals.numMonitors;
|
|
|
|
case DEVICEGETCURRENTSUBSYSTEM:
|
|
return glGlobals.currentMonitor;
|
|
|
|
case DEVICESETSUBSYSTEM:
|
|
if(n >= glGlobals.numMonitors)
|
|
return 0;
|
|
glGlobals.currentMonitor = n;
|
|
return 1;
|
|
|
|
case DEVICEGETSUBSSYSTEMINFO:
|
|
if(n >= glGlobals.numMonitors)
|
|
return 0;
|
|
strncpy(((SubSystemInfo*)arg)->name, "Symbian Display", 80 /*sizeof(SubSystemInfo::name)*/);
|
|
return 1;
|
|
|
|
case DEVICEGETNUMVIDEOMODES:
|
|
return glGlobals.numModes;
|
|
|
|
case DEVICEGETCURRENTVIDEOMODE:
|
|
return glGlobals.currentMode;
|
|
|
|
case DEVICESETVIDEOMODE:
|
|
if(n >= glGlobals.numModes)
|
|
return 0;
|
|
glGlobals.currentMode = n;
|
|
return 1;
|
|
|
|
case DEVICEGETVIDEOMODEINFO:
|
|
rwmode = (VideoMode*)arg;
|
|
rwmode->width = glGlobals.modes[n].width;
|
|
rwmode->height = glGlobals.modes[n].height;
|
|
rwmode->depth = glGlobals.modes[n].depth;
|
|
rwmode->flags = glGlobals.modes[n].flags;
|
|
return 1;
|
|
|
|
case DEVICEGETMAXMULTISAMPLINGLEVELS:
|
|
return 1;
|
|
|
|
case DEVICEGETMULTISAMPLINGLEVELS:
|
|
return 1;
|
|
|
|
case DEVICESETMULTISAMPLINGLEVELS:
|
|
glGlobals.numSamples = 1;
|
|
return 1;
|
|
|
|
default:
|
|
assert(0 && "not implemented");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
Device renderdevice = {
|
|
-1.0f, 1.0f,
|
|
gles1::beginUpdate,
|
|
gles1::endUpdate,
|
|
gles1::clearCamera,
|
|
gles1::showRaster,
|
|
gles1::rasterRenderFast,
|
|
gles1::setRenderState,
|
|
gles1::getRenderState,
|
|
gles1::im2DRenderLine,
|
|
gles1::im2DRenderTriangle,
|
|
gles1::im2DRenderPrimitive,
|
|
gles1::im2DRenderIndexedPrimitive,
|
|
gles1::im3DTransform,
|
|
gles1::im3DRenderPrimitive,
|
|
gles1::im3DRenderIndexedPrimitive,
|
|
gles1::im3DEnd,
|
|
gles1::deviceSystemSymbian
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#else
|
|
// urgh, probably should get rid of that eventually
|
|
#include "rwgles1.h"
|
|
namespace rw {
|
|
namespace gles1 {
|
|
bool32 needToReadBackTextures;
|
|
}
|
|
}
|
|
#endif
|