Files
librw-vita/src/gl/gl3device.cpp
T
2020-10-31 15:46:55 +01:00

1627 lines
38 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <vitashark.h>
extern "C"{
#include <math_neon.h>
};
#include "../rwbase.h"
#include "../rwerror.h"
#include "../rwplg.h"
#include "../rwrender.h"
#include "../rwengine.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#ifdef RW_OPENGL
#include "rwgl3.h"
#include "rwgl3shader.h"
#include "rwgl3impl.h"
#include "psp2_shaders.h"
#define PLUGIN_ID 0
uint16_t *gIndicesIm2DPtr[2];
uint16_t *gIndicesIm3DPtr[2];
float *gVertexBufferIm2DPtr[2];
float *gVertexBufferIm3DPtr[2];
uint16_t *gConstIndices;
float *gVertexBufferIm2D;
float *gVertexBufferIm3D;
uint16_t *gIndicesIm2D;
uint16_t *gIndicesIm3D;
uint8_t ImIdx = 0;
namespace rw {
namespace gl3 {
#ifndef LIBRW_SDL2
struct DisplayMode
{
int32 depth;
uint32 flags;
};
#endif
struct GlGlobals
{
#ifdef LIBRW_SDL2
SDL_Window *window;
SDL_GLContext glcontext;
#else
int numMonitors;
int currentMonitor;
DisplayMode *modes;
int numModes;
int currentMode;
#endif
int presentWidth, presentHeight;
// for opening the window
int winWidth, winHeight;
const char *winTitle;
} glGlobals;
int32 alphaFunc;
float32 alphaRef;
struct UniformState
{
float32 alphaRefLow;
float32 alphaRefHigh;
int32 pad[2];
float32 fogStart;
float32 fogEnd;
float32 fogRange;
float32 fogDisable;
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];
};
struct GLShaderState
{
RGBA matColor;
SurfaceProperties surfProps;
};
// this needs a define in the shaders as well!
//#define RW_GL_USE_UBOS
#ifndef RW_GLES2
static GLuint vao;
#endif
#ifdef RW_GL_USE_UBOS
static GLuint ubo_state, ubo_scene, ubo_object;
#endif
static GLuint whitetex;
static UniformState uniformState;
static UniformScene uniformScene;
static UniformObject uniformObject;
static GLShaderState shaderState;
#ifndef RW_GL_USE_UBOS
// State
int32 u_alphaRef;
int32 u_fogData;
//int32 u_fogStart;
//int32 u_fogEnd;
//int32 u_fogRange;
//int32 u_fogDisable;
int32 u_fogColor;
// Scene
int32 u_wvp;
// Object
int32 u_world;
int32 u_ambLight;
int32 u_lightParams;
int32 u_lightPosition;
int32 u_lightDirection;
int32 u_lightColor;
#endif
int32 u_matColor;
int32 u_surfProps;
Shader *defaultShader;
//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 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,
// 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;
};
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,
};
/*
* 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;
}
}
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.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;
}
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)
{
uint32 shaderfunc;
if(rwStateCache.alphaTestEnable != enable){
rwStateCache.alphaTestEnable = enable;
shaderfunc = rwStateCache.alphaTestEnable ? rwStateCache.alphaFunc : ALPHAALWAYS;
if(alphaFunc != shaderfunc){
alphaFunc = shaderfunc;
// uniformStateDirty[RWGL_ALPHAFUNC] = true;
// stateDirty = 1;
}
}
}
static void
setAlphaTestFunction(uint32 function)
{
uint32 shaderfunc;
if(rwStateCache.alphaFunc != function){
rwStateCache.alphaFunc = function;
shaderfunc = rwStateCache.alphaTestEnable ? rwStateCache.alphaFunc : ALPHAALWAYS;
if(alphaFunc != shaderfunc){
alphaFunc = shaderfunc;
// uniformStateDirty[RWGL_ALPHAFUNC] = true;
// stateDirty = 1;
}
}
}
static 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];
boundTexture[activeTexture] = texid;
glBindTexture(GL_TEXTURE_2D, texid);
return prev;
}
void
bindFramebuffer(uint32 fbo)
{
//glBindFramebuffer(GL_FRAMEBUFFER, fbo);
if(currentFramebuffer != fbo){
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
currentFramebuffer = fbo;
}
}
// TODO: support mipmaps
#ifdef PSP2_MIPMAPS
static GLint filterConvMap_NoMIP[] = {
0, GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR,
GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR,
GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR
};
#else
static GLint filterConvMap_NoMIP[] = {
0, GL_NEAREST, GL_LINEAR,
GL_NEAREST, GL_LINEAR,
GL_NEAREST, GL_LINEAR
};
#endif
static GLint addressConvMap[] = {
0, GL_REPEAT, GL_MIRRORED_REPEAT,
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE
};
static void
setFilterMode(uint32 stage, int32 filter)
{
if(rwStateCache.texstage[stage].filter != (Texture::FilterMode)filter){
rwStateCache.texstage[stage].filter = (Texture::FilterMode)filter;
Raster *raster = rwStateCache.texstage[stage].raster;
if(raster){
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, rwStateCache.texstage[stage].raster, nativeRasterOffset);
if(natras->filterMode != filter){
setActiveTexture(stage);
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;
}
}
}
}
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){
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, 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){
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, 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_GL3);
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
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{
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_GL3);
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
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){
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{
bindTexture(whitetex);
alpha = 0;
}
if(stage == 0){
if(alpha != rwStateCache.textureAlpha){
rwStateCache.textureAlpha = alpha;
if(!rwStateCache.vertexAlpha){
setAlphaBlend(alpha);
setAlphaTest(alpha);
}
}
}
}
}
void
setTexture(int32 stage, Texture *tex)
{
if(tex == nil || tex->raster == nil){
setRasterStage(stage, nil);
return;
}
setRasterStageOnly(stage, tex->raster);
setFilterMode(stage, tex->getFilter());
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 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 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;
alphaFunc = 0;
alphaRef = 10.0f/255.0f;
uniformState.fogDisable = 1.0f;
uniformState.fogStart = 0.0f;
uniformState.fogEnd = 0.0f;
uniformState.fogRange = 0.0f;
uniformState.fogColor = { 1.0f, 1.0f, 1.0f, 1.0f };
rwStateCache.gsalpha = 0;
rwStateCache.gsalpharef = 128;
// stateDirty = 1;
rwStateCache.vertexAlpha = 0;
rwStateCache.textureAlpha = 0;
rwStateCache.alphaTestEnable = 0;
memset(&oldGlState, 0xFF, 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);
activeTexture = -1;
for(int i = 0; i < MAXNUMSTAGES; i++){
setActiveTexture(i);
bindTexture(whitetex);
}
setActiveTexture(0);
}
void
setWorldMatrix(Matrix *mat)
{
convMatrix(&uniformObject.world, mat);
// objectDirty = 1;
}
int32
setLights(WorldLights *lightData)
{
int i, n;
Light *l;
int32 bits;
uniformObject.ambLight = lightData->ambient;
bits = 0;
if(lightData->numAmbients)
bits |= VSLIGHT_AMBIENT;
n = 0;
for(i = 0; i < lightData->numDirectionals && i < 8; i++){
l = lightData->directionals[i];
uniformObject.lightParams[n].type = 1.0f;
uniformObject.lightColor[n] = l->color;
memcpy_neon(&uniformObject.lightDirection[n], &l->getFrame()->getLTM()->at, sizeof(V3d));
bits |= VSLIGHT_POINT;
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:
uniformObject.lightParams[n].type = 2.0f;
uniformObject.lightParams[n].radius = l->radius;
uniformObject.lightColor[n] = l->color;
memcpy_neon(&uniformObject.lightPosition[n], &l->getFrame()->getLTM()->pos, sizeof(V3d));
bits |= VSLIGHT_POINT;
n++;
if(n >= MAX_LIGHTS)
goto out;
break;
case Light::SPOT:
case Light::SOFTSPOT:
uniformObject.lightParams[n].type = 3.0f;
uniformObject.lightParams[n].minusCosAngle = l->minusCosAngle;
uniformObject.lightParams[n].radius = l->radius;
uniformObject.lightColor[n] = l->color;
memcpy_neon(&uniformObject.lightPosition[n], &l->getFrame()->getLTM()->pos, sizeof(V3d));
memcpy_neon(&uniformObject.lightDirection[n], &l->getFrame()->getLTM()->at, sizeof(V3d));
// lower bound of falloff
if(l->getType() == Light::SOFTSPOT)
uniformObject.lightParams[n].hardSpot = 0.0f;
else
uniformObject.lightParams[n].hardSpot = 1.0f;
bits |= VSLIGHT_SPOT;
n++;
if(n >= MAX_LIGHTS)
goto out;
break;
}
}
uniformObject.lightParams[n].type = 0.0f;
out:
// objectDirty = 1;
return bits;
}
void
setProjectionMatrix(float32 *mat)
{
memcpy_neon(&uniformScene.proj, mat, 64);
// sceneDirty = 1;
}
void
setViewMatrix(float32 *mat)
{
memcpy_neon(&uniformScene.view, mat, 64);
// sceneDirty = 1;
}
Shader *lastShaderUploaded;
#define U(i) currentShader->uniformLocations[i]
rw::RGBAf matColorCache;
float surfPropsCache[4];
void
setMaterial(const RGBA &color, const SurfaceProperties &surfaceprops)
{
//bool force = lastShaderUploaded != currentShader;
//if(force || !equal(shaderState.matColor, color)){
convColor(&matColorCache, &color);
shaderState.matColor = color;
//}
//if(force ||
// shaderState.surfProps.ambient != surfaceprops.ambient ||
// shaderState.surfProps.specular != surfaceprops.specular ||
// shaderState.surfProps.diffuse != surfaceprops.diffuse){
surfPropsCache[0] = surfaceprops.ambient;
surfPropsCache[1] = surfaceprops.specular;
surfPropsCache[2] = surfaceprops.diffuse;
surfPropsCache[3] = 0.0f;
shaderState.surfProps = surfaceprops;
//}
}
void
flushCache(void)
{
flushGlRenderState();
glUniform4fv(U(u_matColor), 1, (GLfloat*)&matColorCache);
glUniform4fv(U(u_surfProps), 1, surfPropsCache);
// TODO: this is probably a stupid way to do it without UBOs
/*if(lastShaderUploaded != currentShader){
lastShaderUploaded = currentShader;
objectDirty = 1;
sceneDirty = 1;
stateDirty = 1;
int i;
for(i = 0; i < RWGL_NUM_STATES; i++)
uniformStateDirty[i] = true;
}*/
//if(objectDirty){
glUniformMatrix4fv(U(u_world), 1, 0, (float*)&uniformObject.world);
float wv[16], wvp[16];
matmul4_neon((float *)uniformScene.view, (float *)&uniformObject.world, (float *)wv);
matmul4_neon((float *)uniformScene.proj, (float *)wv, (float *)wvp);
glUniformMatrix4fv(U(u_wvp), 1, 0, (float*)wvp);
glUniform4fv(U(u_ambLight), 1, (float*)&uniformObject.ambLight);
glUniform4fv(U(u_lightParams), MAX_LIGHTS, (float*)uniformObject.lightParams);
//glUniform4fv(U(u_lightPosition), MAX_LIGHTS, (float*)uniformObject.lightPosition);
glUniform4fv(U(u_lightDirection), MAX_LIGHTS, (float*)uniformObject.lightDirection);
glUniform4fv(U(u_lightColor), MAX_LIGHTS, (float*)uniformObject.lightColor);
// objectDirty = 0;
//}
// if(stateDirty){
uniformState.fogDisable = rwStateCache.fogEnable ? 0.0f : 1.0f;
uniformState.fogStart = rwStateCache.fogStart;
uniformState.fogEnd = rwStateCache.fogEnd;
uniformState.fogRange = 1.0f/(rwStateCache.fogStart - rwStateCache.fogEnd);
//if(uniformStateDirty[RWGL_ALPHAFUNC] || uniformStateDirty[RWGL_ALPHAREF]){
switch(alphaFunc){
case ALPHAALWAYS:
default:
glUniform2f(U(u_alphaRef), -1000.0f, 1000.0f);
break;
case ALPHAGREATEREQUAL:
glUniform2f(U(u_alphaRef), alphaRef, 1000.0f);
break;
case ALPHALESS:
glUniform2f(U(u_alphaRef), -1000.0f, alphaRef);
break;
}
//uniformStateDirty[RWGL_ALPHAFUNC] = false;
//uniformStateDirty[RWGL_ALPHAREF] = false;
//}
/*if(uniformStateDirty[RWGL_FOG] ||
uniformStateDirty[RWGL_FOGSTART] ||
uniformStateDirty[RWGL_FOGEND]){*/
float fogData[4] = {
uniformState.fogStart,
uniformState.fogEnd,
uniformState.fogRange,
uniformState.fogDisable
};
glUniform4fv(U(u_fogData), 1, fogData);
// uniformStateDirty[RWGL_FOG] = false;
// uniformStateDirty[RWGL_FOGSTART] = false;
// uniformStateDirty[RWGL_FOGEND] = false;
//}
//if(uniformStateDirty[RWGL_FOGCOLOR]){
glUniform4fv(U(u_fogColor), 1, (float*)&uniformState.fogColor);
// uniformStateDirty[RWGL_FOGCOLOR] = false;
//}
}
static void
setFrameBuffer(Camera *cam)
{
Raster *fbuf = cam->frameBuffer;
Raster *zbuf = cam->zBuffer;
assert(fbuf);
Gl3Raster *natfb = PLUGINOFFSET(Gl3Raster, fbuf, nativeRasterOffset);
Gl3Raster *natzb = PLUGINOFFSET(Gl3Raster, 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){
// all good
assert(natzb->fboMate == fbuf);
}else{
if(natzb->fboMate){
// have to detatch from fbo first!
Gl3Raster *oldfb = PLUGINOFFSET(Gl3Raster, natzb->fboMate, nativeRasterOffset);
if(oldfb->fbo){
bindFramebuffer(oldfb->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
bindFramebuffer(natfb->fbo);
}
oldfb->fboMate = nil;
}
natfb->fboMate = zbuf;
natzb->fboMate = fbuf;
if(natfb->fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, natzb->texid, 0);
}
}else{
// remove z-buffer
if(natfb->fboMate && natfb->fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
natfb->fboMate = nil;
}*/
}
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_neon(&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] = -(cam->farPlane+cam->nearPlane)*invz;
proj[11] = 0.0f;
proj[14] = 2.0f*invz;
proj[15] = 1.0f;
}
memcpy_neon(&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);
#ifndef MIAMI_SUPPORT
vglStartRendering();
#endif
ImIdx = (ImIdx + 1) % 2;
gVertexBufferIm2D = gVertexBufferIm2DPtr[ImIdx];
gVertexBufferIm3D = gVertexBufferIm3DPtr[ImIdx];
gIndicesIm2D = gIndicesIm2DPtr[ImIdx];
gIndicesIm3D = gIndicesIm3DPtr[ImIdx];
int w, h;
if(cam->frameBuffer->type == Raster::CAMERA){
#ifdef LIBRW_SDL2
SDL_GetWindowSize(glGlobals.window, &w, &h);
#else
w = 960;
h = 544;
#endif
}else{
w = cam->frameBuffer->width;
h = cam->frameBuffer->height;
}
if(w != glGlobals.presentWidth || h != glGlobals.presentHeight){
glViewport(0, 0, w, h);
glGlobals.presentWidth = w;
glGlobals.presentHeight = h;
}
}
static
void
endUpdate(Camera *cam)
{
#ifndef MIAMI_SUPPORT
vglStopRendering();
#endif
}
void log2file(const char *format, ...) {
__gnuc_va_list arg;
int done;
va_start(arg, format);
char msg[512];
done = vsprintf(msg, format, arg);
va_end(arg);
int i;
sprintf(msg, "%s\n", msg);
FILE *log = fopen("ux0:/data/librw.log", "a+");
if (log != NULL) {
fwrite(msg, 1, strlen(msg), log);
fclose(log);
}
}
static void
clearCamera(Camera *cam, RGBA *col, uint32 mode)
{
RGBAf colf;
int mask;
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;
glDepthMask(GL_TRUE);
glClear((GLbitfield)mask);
glDepthMask(rwStateCache.zwrite);
}
static void
showRaster(Raster *raster, uint32 flags)
{
// TODO: do this properly!
#ifdef LIBRW_SDL2
SDL_GL_SwapWindow(glGlobals.window);
#else
if(flags & Raster::FLIPWAITVSYNCH)
vglWaitVblankStart(GL_TRUE);
else
vglWaitVblankStart(GL_FALSE);
#endif
//log2file("showRaster called");
#ifdef MIAMI_SUPPORT
vglStopRendering();
vglStartRendering();
#endif
}
static bool32
rasterRenderFast(Raster *raster, int32 x, int32 y)
{
Raster *src = raster;
Raster *dst = Raster::getCurrentContext();
Gl3Raster *natdst = PLUGINOFFSET(Gl3Raster, dst, nativeRasterOffset);
Gl3Raster *natsrc = PLUGINOFFSET(Gl3Raster, 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);
SceDisplayFrameBuf pParam;
pParam.size = sizeof(SceDisplayFrameBuf);
sceDisplayGetFrameBuf(&pParam, SCE_DISPLAY_SETBUF_NEXTFRAME);
sceGxmTransferCopy(960, 544, 0, SCE_GXM_COLOR_MASK_A,
SCE_GXM_TRANSFER_COLORKEY_NONE,
SCE_GXM_TRANSFER_FORMAT_U8U8U8U8_ABGR,
SCE_GXM_TRANSFER_LINEAR,
pParam.base, 0, 0, 960 * 4,
SCE_GXM_TRANSFER_FORMAT_U8U8U8_BGR,
SCE_GXM_TRANSFER_LINEAR,
(uint8_t*)vglGetTexDataPointer(GL_TEXTURE_2D) + (dst->height - 1) * dst->stride, 0, 0, -dst->stride,
NULL, SCE_GXM_TRANSFER_FRAGMENT_SYNC, NULL);
glBindTexture(GL_TEXTURE_2D, boundTexture[0]);
return 1;
}
break;
}
return 0;
}
#ifdef LIBRW_SDL2
static int
openSDL2(EngineOpenParams *openparams)
{
if (!openparams){
RWERROR((ERR_GENERAL, "openparams invalid"));
return 0;
}
GLenum status;
SDL_Window *win;
SDL_GLContext ctx;
/* Init SDL */
if(SDL_InitSubSystem(SDL_INIT_VIDEO)){
RWERROR((ERR_ENGINEOPEN, SDL_GetError()));
return 0;
}
SDL_ClearHints();
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
int flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
if (openparams->fullscreen)
flags |= SDL_WINDOW_FULLSCREEN;
win = SDL_CreateWindow(openparams->windowtitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, openparams->width, openparams->height, flags);
if(win == nil){
RWERROR((ERR_ENGINEOPEN, SDL_GetError()));
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
ctx = SDL_GL_CreateContext(win);
#ifndef LIBRW_GLAD
/* Init GLEW */
glewExperimental = GL_TRUE;
status = glewInit();
if(status != GLEW_OK){
RWERROR((ERR_ENGINEOPEN, glewGetErrorString(status)));
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(win);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
if(!GLEW_VERSION_3_3){
RWERROR((ERR_VERSION, "OpenGL 3.3 needed"));
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(win);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
#else
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
RWERROR((ERR_ENGINEOPEN, "gladLoadGLLoader failed"));
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(win);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
if(!GLAD_GL_VERSION_3_3) {
RWERROR((ERR_VERSION, "OpenGL 3.3 needed"));
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(win);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
#endif
glGlobals.window = win;
glGlobals.glcontext = ctx;
*openparams->window = win;
return 1;
}
static int
closeSDL2(void)
{
SDL_GL_DeleteContext(glGlobals.glcontext);
SDL_DestroyWindow(glGlobals.window);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 1;
}
#else
static void
addVideoMode(/*const GLFWvidmode *mode*/)
{
}
static void
makeVideoModeList(void)
#ifndef PSP2
{
int i, num;
const GLFWvidmode *modes;
modes = glfwGetVideoModes(glGlobals.monitor, &num);
rwFree(glGlobals.modes);
glGlobals.modes = rwNewT(DisplayMode, num+1, ID_DRIVER | MEMDUR_EVENT);
glGlobals.modes[0].mode = *glfwGetVideoMode(glGlobals.monitor);
glGlobals.modes[0].flags = 0;
glGlobals.numModes = 1;
for(i = 0; i < num; i++)
addVideoMode(&modes[i]);
for(i = 0; i < glGlobals.numModes; i++){
num = glGlobals.modes[i].mode.redBits +
glGlobals.modes[i].mode.greenBits +
glGlobals.modes[i].mode.blueBits;
// set depth to power of two
for(glGlobals.modes[i].depth = 1; glGlobals.modes[i].depth < num; glGlobals.modes[i].depth <<= 1);
}
}
#else
// stub video modes manually: 544p
{
}
#endif
static int
openGLFW(EngineOpenParams *openparams)
{
glGlobals.winWidth = openparams->width;
glGlobals.winHeight = openparams->height;
glGlobals.winTitle = openparams->windowtitle;
gVertexBufferIm2DPtr[0] = (float*)malloc(0x500000);
gVertexBufferIm2DPtr[1] = (float*)malloc(0x500000);
gVertexBufferIm3DPtr[0] = (float*)malloc(0x1800000);
gVertexBufferIm3DPtr[1] = (float*)malloc(0x1800000);
gIndicesIm2DPtr[0] = (uint16_t*)malloc(0x600000);
gIndicesIm2DPtr[1] = (uint16_t*)malloc(0x600000);
gIndicesIm3DPtr[0] = (uint16_t*)malloc(0x1800000);
gIndicesIm3DPtr[1] = (uint16_t*)malloc(0x1800000);
gConstIndices = (uint16_t*)malloc(sizeof(uint16_t) * 0xFFFF);
gVertexBufferIm2D = gVertexBufferIm2DPtr[0];
gVertexBufferIm3D = gVertexBufferIm3DPtr[0];
gIndicesIm2D = gIndicesIm2DPtr[0];
gIndicesIm3D = gIndicesIm3DPtr[0];
for (uint16_t i = 0; i < 0xFFFF; i++) {
gConstIndices[i] = i;
}
#ifdef PSP2_USE_SHADER_COMPILER
vglSetupRuntimeShaderCompiler(SHARK_OPT_UNSAFE, SHARK_ENABLE, SHARK_ENABLE, SHARK_ENABLE);
#else
vglEnableRuntimeShaderCompiler(GL_FALSE);
#endif
vglInitExtended(0x10000, 960, 544, 0x100000, SCE_GXM_MULTISAMPLE_4X);
vglUseVram(GL_TRUE);
#ifdef MIAMI_SUPPORT
vglStartRendering();
#endif
makeVideoModeList();
return 1;
}
static int
closeGLFW(void)
{
return 1;
}
static void
glfwerr(int error, const char *desc)
{
fprintf(stderr, "GLFW Error: %s\n", desc);
}
static int
startGLFW(void)
{
GLenum status;
printf("version %s\n", glGetString(GL_VERSION));
printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
glGlobals.presentWidth = 0;
glGlobals.presentHeight = 0;
return 1;
}
static int
stopGLFW(void)
{
return 1;
}
#endif
static int
initOpenGL(void)
{
#ifndef RW_GL_USE_UBOS
u_alphaRef = registerUniform("u_alphaRef");
u_fogData = registerUniform("u_fogData");
// u_fogStart = registerUniform("u_fogStart");
// u_fogEnd = registerUniform("u_fogEnd");
// u_fogRange = registerUniform("u_fogRange");
// u_fogDisable = registerUniform("u_fogDisable");
u_fogColor = registerUniform("u_fogColor");
u_wvp = registerUniform("u_wvp");
u_world = registerUniform("u_world");
u_ambLight = registerUniform("u_ambLight");
u_lightParams = registerUniform("u_lightParams");
u_lightPosition = registerUniform("u_lightPosition");
u_lightDirection = registerUniform("u_lightDirection");
u_lightColor = registerUniform("u_lightColor");
lastShaderUploaded = nil;
#else
registerBlock("Scene");
registerBlock("Object");
registerBlock("State");
#endif
u_matColor = registerUniform("u_matColor");
u_surfProps = registerUniform("u_surfProps");
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();
#ifdef PSP2_USE_SHADER_COMPILER
#ifdef RW_GLES2
#include "gl2_shaders/default_vs_gl2.inc"
#include "gl2_shaders/simple_fs_gl2.inc"
#else
#include "shaders/default_vs_gl3.inc"
#include "shaders/simple_fs_gl3.inc"
#endif
const char *vs[] = { header_vert_src, default_vert_src, nil };
const char *fs[] = { header_frag_src, simple_frag_src, nil };
defaultShader = Shader::create(vs, fs, false);
#else
const char *vs[] = { (const char*)default_v, (const char*)&size_default_v, nil };
const char *fs[] = { (const char*)simple_f, (const char*)&size_simple_f, nil };
defaultShader = Shader::create(vs, fs, false);
#endif
assert(defaultShader);
openIm2D();
openIm3D();
return 1;
}
static int
termOpenGL(void)
{
closeIm3D();
closeIm2D();
return 1;
}
static int
finalizeOpenGL(void)
{
return 1;
}
#ifdef LIBRW_SDL2
static int
deviceSystemSDL2(DeviceReq req, void *arg, int32 n)
{
switch(req){
case DEVICEOPEN:
return openSDL2((EngineOpenParams*)arg);
case DEVICECLOSE:
return closeSDL2();
case DEVICEINIT:
return initOpenGL();
case DEVICETERM:
return termOpenGL();
// TODO: implement subsystems and video modes
default:
assert(0 && "not implemented");
return 0;
}
return 1;
}
#else
static int
deviceSystemGLFW(DeviceReq req, void *arg, int32 n)
{
VideoMode *rwmode;
switch(req){
case DEVICEOPEN:
return openGLFW((EngineOpenParams*)arg);
case DEVICECLOSE:
return closeGLFW();
case DEVICEINIT:
return startGLFW() && initOpenGL();
case DEVICETERM:
return termOpenGL() && stopGLFW();
case DEVICEFINALIZE:
return finalizeOpenGL();
case DEVICEGETNUMSUBSYSTEMS:
return 1;
case DEVICEGETCURRENTSUBSYSTEM:
return 0;
case DEVICESETSUBSYSTEM:
return 1;
case DEVICEGETSUBSSYSTEMINFO:
strncpy(((SubSystemInfo*)arg)->name, "PSVita Screen Stub", sizeof(SubSystemInfo::name));
return 1;
case DEVICEGETNUMVIDEOMODES:
return 1;
case DEVICEGETCURRENTVIDEOMODE:
return 0;
case DEVICESETVIDEOMODE:
return 1;
case DEVICEGETVIDEOMODEINFO:
rwmode = (VideoMode*)arg;
rwmode->width = 960;
rwmode->height = 544;
rwmode->depth = 32;
rwmode->flags = VIDEOMODEEXCLUSIVE;
return 1;
default:
assert(0 && "not implemented");
return 0;
}
return 1;
}
#endif
Device renderdevice = {
-1.0f, 1.0f,
gl3::beginUpdate,
gl3::endUpdate,
gl3::clearCamera,
gl3::showRaster,
gl3::rasterRenderFast,
gl3::setRenderState,
gl3::getRenderState,
gl3::im2DRenderLine,
gl3::im2DRenderTriangle,
gl3::im2DRenderPrimitive,
gl3::im2DRenderIndexedPrimitive,
gl3::im3DTransform,
gl3::im3DRenderPrimitive,
gl3::im3DRenderIndexedPrimitive,
gl3::im3DEnd,
#ifdef LIBRW_SDL2
gl3::deviceSystemSDL2
#else
gl3::deviceSystemGLFW
#endif
};
}
}
#endif