librw/src/gl/gl3device.cpp

1318 lines
30 KiB
C++
Raw Normal View History

2020-04-30 17:54:38 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
2016-07-05 11:36:43 +02:00
#include "../rwbase.h"
#include "../rwerror.h"
#include "../rwplg.h"
2017-08-29 10:12:56 +02:00
#include "../rwrender.h"
#include "../rwengine.h"
2016-07-05 11:36:43 +02:00
#include "../rwpipeline.h"
#include "../rwobjects.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
2018-08-08 19:55:45 +02:00
#ifdef LIBRW_SDL2
#include <SDL.h>
#else
2017-08-09 10:57:32 +02:00
#include <GLFW/glfw3.h>
2018-08-08 19:55:45 +02:00
#endif
2016-07-05 11:36:43 +02:00
#include "rwgl3.h"
#include "rwgl3shader.h"
#include "rwgl3impl.h"
2016-07-05 11:36:43 +02:00
2017-08-09 10:57:32 +02:00
#define PLUGIN_ID 0
2016-07-05 11:36:43 +02:00
namespace rw {
namespace gl3 {
2020-04-24 17:41:48 +02:00
#ifndef LIBRW_SDL2
struct DisplayMode
{
GLFWvidmode mode;
int32 depth;
uint32 flags;
};
2020-04-24 17:41:48 +02:00
#endif
struct GlGlobals
{
2018-08-08 19:55:45 +02:00
#ifdef LIBRW_SDL2
SDL_Window *window;
SDL_GLContext glcontext;
#else
GLFWwindow *window;
GLFWmonitor *monitor;
int numMonitors;
int currentMonitor;
DisplayMode *modes;
int numModes;
int currentMode;
2020-04-24 17:41:48 +02:00
GLFWwindow **pWindow;
2018-08-08 19:55:45 +02:00
#endif
int presentWidth, presentHeight;
// for opening the window
int winWidth, winHeight;
const char *winTitle;
} glGlobals;
2016-07-05 11:36:43 +02:00
struct UniformState
{
2016-07-05 18:22:22 +02:00
int32 alphaFunc;
2016-07-05 11:36:43 +02:00
float32 alphaRef;
2016-07-05 18:22:22 +02:00
float32 fogStart;
float32 fogEnd;
2020-04-26 19:33:43 +02:00
float32 fogRange;
float32 fogDisable;
int32 pad[2];
2016-07-05 18:22:22 +02:00
RGBAf fogColor;
2016-07-05 11:36:43 +02:00
};
struct UniformScene
{
float32 proj[16];
float32 view[16];
};
struct UniformLight
{
2020-04-26 19:33:43 +02:00
float32 enabled, radius, minusCosAngle, hardSpot;
V3d position; int32 pad0;
V3d direction; int32 pad1;
RGBAf color;
2016-07-05 11:36:43 +02:00
};
#define MAX_LIGHTS 8
struct UniformObject
{
2017-08-04 19:54:03 +02:00
RawMatrix world;
RGBAf ambLight;
2020-04-26 19:33:43 +02:00
UniformLight directLights[MAX_LIGHTS];
UniformLight pointLights[MAX_LIGHTS];
UniformLight spotLights[MAX_LIGHTS];
2016-07-05 11:36:43 +02:00
};
2020-05-12 21:31:44 +02:00
const char *shaderDecl330 = "#version 330\n";
const char *shaderDecl310es =
"#version 310 es\n"\
"precision highp float;\n"\
"precision highp int;\n";
#ifdef RW_GLES3
const char *shaderDecl = shaderDecl310es;
#else
const char *vertShaderDecl = shaderDecl330;
#endif
static GLuint vao;
static GLuint ubo_state, ubo_scene, ubo_object;
static GLuint whitetex;
static UniformState uniformState;
static UniformScene uniformScene;
static UniformObject uniformObject;
int32 u_matColor;
2020-04-26 19:33:43 +02:00
int32 u_surfProps;
2020-04-26 19:33:43 +02:00
Shader *defaultShader;
2016-07-05 11:36:43 +02:00
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;
2020-04-28 14:09:26 +02:00
bool32 blendEnable;
uint32 srcblend, destblend;
uint32 zwrite;
uint32 ztest;
uint32 cullmode;
2020-04-26 19:33:43 +02:00
uint32 fogEnable;
float32 fogStart;
float32 fogEnd;
2020-04-28 14:09:26 +02:00
// emulation of PS2 GS
bool32 gsalpha;
uint32 gsalpharef;
RwRasterStateCache texstage[MAXNUMSTAGES];
};
static RwStateCache rwStateCache;
2016-07-05 11:36:43 +02:00
2017-08-09 10:57:32 +02:00
static int32 activeTexture;
2020-04-16 17:46:42 +02:00
static uint32 boundTexture[MAXNUMSTAGES];
2017-08-09 10:57:32 +02:00
static uint32 blendMap[] = {
GL_ZERO, // actually invalid
2016-07-05 11:36:43 +02:00
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,
};
2020-04-28 14:09:26 +02:00
void
setAlphaBlend(bool32 enable)
{
if(rwStateCache.blendEnable != enable){
rwStateCache.blendEnable = enable;
(enable ? glEnable : glDisable)(GL_BLEND);
}
}
bool32
getAlphaBlend(void)
{
return rwStateCache.blendEnable;
}
2020-04-26 19:33:43 +02:00
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
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
}else{
if(rwStateCache.ztest)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
glDepthFunc(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
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
}
glDepthMask(rwStateCache.zwrite);
}
}
2018-01-03 18:02:02 +01:00
static void
setAlphaTest(bool32 enable)
{
uint32 shaderfunc;
if(rwStateCache.alphaTestEnable != enable){
rwStateCache.alphaTestEnable = enable;
shaderfunc = rwStateCache.alphaTestEnable ? rwStateCache.alphaFunc : ALPHAALWAYS;
2018-01-03 18:02:02 +01:00
if(uniformState.alphaFunc != shaderfunc){
uniformState.alphaFunc = shaderfunc;
stateDirty = 1;
}
}
}
static void
setAlphaTestFunction(uint32 function)
{
uint32 shaderfunc;
if(rwStateCache.alphaFunc != function){
rwStateCache.alphaFunc = function;
shaderfunc = rwStateCache.alphaTestEnable ? rwStateCache.alphaFunc : ALPHAALWAYS;
2018-01-03 18:02:02 +01:00
if(uniformState.alphaFunc != shaderfunc){
uniformState.alphaFunc = shaderfunc;
stateDirty = 1;
}
}
}
2017-08-09 10:57:32 +02:00
static void
setVertexAlpha(bool32 enable)
2016-07-05 11:36:43 +02:00
{
if(rwStateCache.vertexAlpha != enable){
if(!rwStateCache.textureAlpha){
2020-04-28 14:09:26 +02:00
setAlphaBlend(enable);
2018-01-03 18:02:02 +01:00
setAlphaTest(enable);
2016-07-05 11:36:43 +02:00
}
rwStateCache.vertexAlpha = enable;
}
}
static void
setActiveTexture(int32 n)
{
if(activeTexture != n){
activeTexture = n;
2020-04-16 17:46:42 +02:00
glActiveTexture(GL_TEXTURE0+n);
}
}
2020-04-27 20:51:35 +02:00
uint32
2020-04-16 17:46:42 +02:00
bindTexture(uint32 texid)
{
2020-04-27 20:51:35 +02:00
uint32 prev = boundTexture[activeTexture];
2020-04-16 17:46:42 +02:00
boundTexture[activeTexture] = texid;
glBindTexture(GL_TEXTURE_2D, texid);
2020-04-27 20:51:35 +02:00
return prev;
2020-04-16 17:46:42 +02:00
}
// TODO: support mipmaps
static GLint filterConvMap_NoMIP[] = {
0, GL_NEAREST, GL_LINEAR,
GL_NEAREST, GL_LINEAR,
GL_NEAREST, GL_LINEAR
};
static GLint addressConvMap[] = {
0, GL_REPEAT, GL_MIRRORED_REPEAT,
2020-04-26 23:51:27 +02:00
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
};
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;
}
}
2017-08-09 10:57:32 +02:00
}
}
2018-07-04 19:21:34 +02:00
static void
setRasterStageOnly(uint32 stage, Raster *raster)
{
bool32 alpha;
if(raster != rwStateCache.texstage[stage].raster){
rwStateCache.texstage[stage].raster = raster;
2020-04-16 17:46:42 +02:00
setActiveTexture(stage);
2018-07-04 19:21:34 +02:00
if(raster){
assert(raster->platform == PLATFORM_GL3);
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
2020-04-16 17:46:42 +02:00
bindTexture(natras->texid);
2018-07-04 19:21:34 +02:00
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{
2020-04-16 17:46:42 +02:00
bindTexture(whitetex);
2018-07-04 19:21:34 +02:00
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);
alpha = 0;
}
if(stage == 0){
if(alpha != rwStateCache.textureAlpha){
rwStateCache.textureAlpha = alpha;
if(!rwStateCache.vertexAlpha){
2020-04-28 14:09:26 +02:00
setAlphaBlend(alpha);
2018-07-04 19:21:34 +02:00
setAlphaTest(alpha);
}
}
}
}
}
2017-08-09 10:57:32 +02:00
static void
setRasterStage(uint32 stage, Raster *raster)
2017-08-09 10:57:32 +02:00
{
bool32 alpha;
if(raster != rwStateCache.texstage[stage].raster){
rwStateCache.texstage[stage].raster = raster;
2020-04-16 17:46:42 +02:00
setActiveTexture(stage);
if(raster){
assert(raster->platform == PLATFORM_GL3);
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
2020-04-16 17:46:42 +02:00
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;
}
2020-04-26 23:51:27 +02:00
if(natras->addressV != addrV){
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, addressConvMap[addrV]);
natras->addressV = addrV;
}
alpha = natras->hasAlpha;
}else{
2020-04-16 17:46:42 +02:00
bindTexture(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);
alpha = 0;
}
if(stage == 0){
if(alpha != rwStateCache.textureAlpha){
rwStateCache.textureAlpha = alpha;
if(!rwStateCache.vertexAlpha){
2020-04-28 14:09:26 +02:00
setAlphaBlend(alpha);
setAlphaTest(alpha);
}
}
}
}
}
void
setTexture(int32 stage, Texture *tex)
{
2018-07-04 19:21:34 +02:00
if(tex == nil || tex->raster == nil){
setRasterStage(stage, nil);
return;
}
2018-07-04 19:21:34 +02:00
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;
2017-08-09 10:57:32 +02:00
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;
2017-08-09 10:57:32 +02:00
case VERTEXALPHA:
setVertexAlpha(value);
2016-07-05 11:36:43 +02:00
break;
case SRCBLEND:
if(rwStateCache.srcblend != value){
rwStateCache.srcblend = value;
glBlendFunc(blendMap[rwStateCache.srcblend], blendMap[rwStateCache.destblend]);
2016-07-05 11:36:43 +02:00
}
break;
case DESTBLEND:
if(rwStateCache.destblend != value){
rwStateCache.destblend = value;
glBlendFunc(blendMap[rwStateCache.srcblend], blendMap[rwStateCache.destblend]);
2016-07-05 11:36:43 +02:00
}
break;
case ZTESTENABLE:
2020-04-26 19:33:43 +02:00
setDepthTest(value);
2016-07-05 11:36:43 +02:00
break;
case ZWRITEENABLE:
2020-04-26 19:33:43 +02:00
setDepthWrite(value);
2016-07-05 11:36:43 +02:00
break;
2016-07-05 18:22:22 +02:00
case FOGENABLE:
2020-04-26 19:33:43 +02:00
if(rwStateCache.fogEnable != value){
rwStateCache.fogEnable = value;
2016-07-05 18:22:22 +02:00
stateDirty = 1;
}
break;
case FOGCOLOR:
// no cache check here...too lazy
2018-05-24 00:53:50 +02:00
RGBA c;
c.red = value;
c.green = value>>8;
c.blue = value>>16;
c.alpha = value>>24;
convColor(&uniformState.fogColor, &c);
2016-07-05 18:22:22 +02:00
stateDirty = 1;
break;
2018-01-03 18:02:02 +01:00
case CULLMODE:
if(rwStateCache.cullmode != value){
rwStateCache.cullmode = value;
if(rwStateCache.cullmode == CULLNONE)
2018-01-03 18:02:02 +01:00
glDisable(GL_CULL_FACE);
else{
glEnable(GL_CULL_FACE);
glCullFace(rwStateCache.cullmode == CULLBACK ? GL_BACK : GL_FRONT);
2018-01-03 18:02:02 +01:00
}
}
break;
2016-07-05 11:36:43 +02:00
case ALPHATESTFUNC:
2018-01-03 18:02:02 +01:00
setAlphaTestFunction(value);
2016-07-05 11:36:43 +02:00
break;
case ALPHATESTREF:
2016-07-05 18:22:22 +02:00
if(uniformState.alphaRef != value/255.0f){
uniformState.alphaRef = value/255.0f;
stateDirty = 1;
}
2016-07-05 11:36:43 +02:00
break;
2020-04-28 14:09:26 +02:00
case GSALPHATEST:
rwStateCache.gsalpha = value;
break;
case GSALPHATESTREF:
rwStateCache.gsalpharef = value;
2016-07-05 11:36:43 +02:00
}
}
static void*
2016-07-05 11:36:43 +02:00
getRenderState(int32 state)
{
uint32 val;
2016-07-05 18:22:22 +02:00
RGBA rgba;
2016-07-05 11:36:43 +02:00
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;
2016-07-05 11:36:43 +02:00
case VERTEXALPHA:
val = rwStateCache.vertexAlpha;
break;
2016-07-05 11:36:43 +02:00
case SRCBLEND:
val = rwStateCache.srcblend;
break;
2016-07-05 11:36:43 +02:00
case DESTBLEND:
val = rwStateCache.destblend;
break;
2016-07-05 11:36:43 +02:00
case ZTESTENABLE:
val = rwStateCache.ztest;
break;
2016-07-05 11:36:43 +02:00
case ZWRITEENABLE:
val = rwStateCache.zwrite;
break;
2016-07-05 18:22:22 +02:00
case FOGENABLE:
2020-04-26 19:33:43 +02:00
val = rwStateCache.fogEnable;
break;
2016-07-05 18:22:22 +02:00
case FOGCOLOR:
convColor(&rgba, &uniformState.fogColor);
val = RWRGBAINT(rgba.red, rgba.green, rgba.blue, rgba.alpha);
break;
2018-01-03 18:02:02 +01:00
case CULLMODE:
val = rwStateCache.cullmode;
break;
2016-07-05 11:36:43 +02:00
case ALPHATESTFUNC:
val = rwStateCache.alphaFunc;
break;
2016-07-05 11:36:43 +02:00
case ALPHATESTREF:
val = (uint32)(uniformState.alphaRef*255.0f);
break;
2020-04-28 14:09:26 +02:00
case GSALPHATEST:
val = rwStateCache.gsalpha;
break;
case GSALPHATESTREF:
val = rwStateCache.gsalpharef;
break;
default:
val = 0;
2016-07-05 11:36:43 +02:00
}
return (void*)(uintptr)val;
2016-07-05 11:36:43 +02:00
}
2017-08-09 10:57:32 +02:00
static void
2016-07-05 11:36:43 +02:00
resetRenderState(void)
{
rwStateCache.alphaFunc = ALPHAGREATEREQUAL;
2018-01-03 18:02:02 +01:00
uniformState.alphaFunc = 0;
2016-07-05 11:36:43 +02:00
uniformState.alphaRef = 10.0f/255.0f;
2020-04-26 19:33:43 +02:00
uniformState.fogDisable = 1.0f;
2016-07-05 18:22:22 +02:00
uniformState.fogStart = 0.0f;
2020-04-26 19:33:43 +02:00
uniformState.fogEnd = 0.0f;
uniformState.fogRange = 0.0f;
2016-07-05 18:22:22 +02:00
uniformState.fogColor = { 1.0f, 1.0f, 1.0f, 1.0f };
2020-04-28 14:09:26 +02:00
rwStateCache.gsalpha = 0;
rwStateCache.gsalpharef = 128;
2016-07-05 11:36:43 +02:00
stateDirty = 1;
rwStateCache.vertexAlpha = 0;
rwStateCache.textureAlpha = 0;
rwStateCache.alphaTestEnable = 0;
2016-07-05 11:36:43 +02:00
2020-04-28 14:09:26 +02:00
rwStateCache.blendEnable = 0;
glDisable(GL_BLEND);
rwStateCache.srcblend = BLENDSRCALPHA;
rwStateCache.destblend = BLENDINVSRCALPHA;
glBlendFunc(blendMap[rwStateCache.srcblend], blendMap[rwStateCache.destblend]);
2016-07-05 11:36:43 +02:00
rwStateCache.zwrite = GL_TRUE;
glDepthMask(rwStateCache.zwrite);
2016-07-05 11:36:43 +02:00
rwStateCache.ztest = 1;
2016-07-05 11:36:43 +02:00
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
rwStateCache.cullmode = CULLNONE;
2018-01-03 18:02:02 +01:00
glDisable(GL_CULL_FACE);
2020-04-16 17:46:42 +02:00
activeTexture = -1;
for(int i = 0; i < MAXNUMSTAGES; i++){
2020-04-16 17:46:42 +02:00
setActiveTexture(i);
bindTexture(whitetex);
2016-07-05 11:36:43 +02:00
}
2020-04-16 17:46:42 +02:00
setActiveTexture(0);
2016-07-05 11:36:43 +02:00
}
void
setWorldMatrix(Matrix *mat)
{
2017-08-04 19:54:03 +02:00
convMatrix(&uniformObject.world, mat);
2016-07-05 11:36:43 +02:00
objectDirty = 1;
}
2020-04-26 19:33:43 +02:00
int32
setLights(WorldLights *lightData)
2016-07-05 11:36:43 +02:00
{
2020-04-26 19:33:43 +02:00
int i, np, ns;
Light *l;
int32 bits;
uniformObject.ambLight = lightData->ambient;
memset(uniformObject.directLights, 0, sizeof(uniformObject.directLights));
memset(uniformObject.pointLights, 0, sizeof(uniformObject.pointLights));
memset(uniformObject.spotLights, 0, sizeof(uniformObject.spotLights));
bits = 0;
for(i = 0; i < lightData->numDirectionals && i < 8; i++){
l = lightData->directionals[i];
uniformObject.directLights[i].enabled = 1.0f;
uniformObject.directLights[i].color = l->color;
uniformObject.directLights[i].direction = l->getFrame()->getLTM()->at;
bits |= VSLIGHT_POINT;
}
2016-07-05 11:36:43 +02:00
2020-04-26 19:33:43 +02:00
np = 0;
ns = 0;
for(i = 0; i < lightData->numLocals; i++){
l = lightData->locals[i];
switch(l->getType()){
case Light::POINT:
if(np >= 8)
continue;
uniformObject.pointLights[np].enabled = 1.0f;
uniformObject.pointLights[np].color = l->color;
uniformObject.pointLights[np].position = l->getFrame()->getLTM()->pos;
uniformObject.pointLights[np].radius = l->radius;
np++;
bits |= VSLIGHT_POINT;
break;
case Light::SPOT:
case Light::SOFTSPOT:
if(np >= 8)
continue;
uniformObject.spotLights[ns].enabled = 1.0f;
uniformObject.spotLights[ns].color = l->color;
uniformObject.spotLights[ns].position = l->getFrame()->getLTM()->pos;
uniformObject.spotLights[ns].direction = l->getFrame()->getLTM()->at;
uniformObject.spotLights[ns].radius = l->radius;
uniformObject.spotLights[ns].minusCosAngle = l->minusCosAngle;
if(l->getType() == Light::SOFTSPOT)
uniformObject.spotLights[ns].hardSpot = 0.0f;
else
uniformObject.spotLights[ns].hardSpot = 1.0f;
ns++;
bits |= VSLIGHT_SPOT;
break;
}
2016-07-05 11:36:43 +02:00
}
2020-04-26 19:33:43 +02:00
2016-07-05 11:36:43 +02:00
objectDirty = 1;
2020-04-26 19:33:43 +02:00
return 0;
2016-07-05 11:36:43 +02:00
}
void
setProjectionMatrix(float32 *mat)
{
memcpy(&uniformScene.proj, mat, 64);
sceneDirty = 1;
}
void
setViewMatrix(float32 *mat)
{
memcpy(&uniformScene.view, mat, 64);
sceneDirty = 1;
}
void
flushCache(void)
{
if(objectDirty){
glBindBuffer(GL_UNIFORM_BUFFER, ubo_object);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformObject),
&uniformObject);
objectDirty = 0;
}
if(sceneDirty){
glBindBuffer(GL_UNIFORM_BUFFER, ubo_scene);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformScene),
&uniformScene);
sceneDirty = 0;
}
if(stateDirty){
2020-04-26 19:33:43 +02:00
uniformState.fogDisable = rwStateCache.fogEnable ? 0.0f : 1.0f;
uniformState.fogStart = rwStateCache.fogStart;
uniformState.fogEnd = rwStateCache.fogEnd;
uniformState.fogRange = 1.0f/(rwStateCache.fogStart - rwStateCache.fogEnd);
2016-07-05 11:36:43 +02:00
glBindBuffer(GL_UNIFORM_BUFFER, ubo_state);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformState),
&uniformState);
stateDirty = 0;
}
}
2017-08-09 10:57:32 +02:00
static void
2016-07-05 18:22:22 +02:00
clearCamera(Camera *cam, RGBA *col, uint32 mode)
{
RGBAf colf;
GLbitfield 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;
2020-04-26 21:20:51 +02:00
glDepthMask(GL_TRUE);
2016-07-05 18:22:22 +02:00
glClear(mask);
2020-04-26 21:20:51 +02:00
glDepthMask(rwStateCache.zwrite);
2016-07-05 18:22:22 +02:00
}
2017-08-09 10:57:32 +02:00
static void
2020-05-02 10:08:19 +02:00
showRaster(Raster *raster, uint32 flags)
2017-08-09 10:57:32 +02:00
{
// TODO: do this properly!
2018-08-08 19:55:45 +02:00
#ifdef LIBRW_SDL2
SDL_GL_SwapWindow(glGlobals.window);
#else
2020-05-02 10:08:19 +02:00
if(flags & Raster::FLIPWAITVSYNCH)
glfwSwapInterval(1);
else
glfwSwapInterval(0);
glfwSwapBuffers(glGlobals.window);
2018-08-08 19:55:45 +02:00
#endif
2017-08-09 10:57:32 +02:00
}
2020-04-16 09:10:11 +02:00
static bool32
rasterRenderFast(Raster *raster, int32 x, int32 y)
{
2020-04-16 17:46:42 +02:00
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);
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;
}
2020-04-16 09:10:11 +02:00
return 0;
}
2017-08-09 10:57:32 +02:00
static void
2016-07-05 11:36:43 +02:00
beginUpdate(Camera *cam)
{
float view[16], proj[16];
// View Matrix
Matrix inv;
2017-08-04 19:54:03 +02:00
Matrix::invert(&inv, cam->getFrame()->getLTM());
2016-07-05 11:36:43 +02:00
// 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;
2017-12-31 10:50:49 +01:00
memcpy(&cam->devView, &view, sizeof(RawMatrix));
2016-07-05 11:36:43 +02:00
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;
2016-07-06 11:44:59 +02:00
proj[8] = cam->viewOffset.x*invwx;
proj[9] = cam->viewOffset.y*invwy;
proj[12] = -proj[8];
proj[13] = -proj[9];
2016-07-05 11:36:43 +02:00
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{
2016-07-06 11:44:59 +02:00
proj[10] = -(cam->farPlane+cam->nearPlane)*invz;
proj[11] = 0.0f;
proj[14] = -2.0f*invz;
proj[15] = 1.0f;
2016-07-05 11:36:43 +02:00
}
2017-12-31 10:50:49 +01:00
memcpy(&cam->devProj, &proj, sizeof(RawMatrix));
2016-07-05 11:36:43 +02:00
setProjectionMatrix(proj);
2016-07-05 18:22:22 +02:00
2020-04-26 19:33:43 +02:00
if(rwStateCache.fogStart != cam->fogPlane){
rwStateCache.fogStart = cam->fogPlane;
2016-07-05 18:22:22 +02:00
stateDirty = 1;
}
2020-04-26 19:33:43 +02:00
if(rwStateCache.fogEnd != cam->farPlane){
rwStateCache.fogEnd = cam->farPlane;
2016-07-05 18:22:22 +02:00
stateDirty = 1;
}
int w, h;
2018-08-08 19:55:45 +02:00
#ifdef LIBRW_SDL2
SDL_GetWindowSize(glGlobals.window, &w, &h);
#else
glfwGetWindowSize(glGlobals.window, &w, &h);
2018-08-08 19:55:45 +02:00
#endif
if(w != glGlobals.presentWidth || h != glGlobals.presentHeight){
glViewport(0, 0, w, h);
glGlobals.presentWidth = w;
glGlobals.presentHeight = h;
}
2016-07-05 11:36:43 +02:00
}
2018-08-08 19:55:45 +02:00
#ifdef LIBRW_SDL2
static int
openSDL2(EngineOpenParams *openparams)
2018-08-08 19:55:45 +02:00
{
if (!openparams){
RWERROR((ERR_GENERAL, "openparams invalid"));
2018-08-08 19:55:45 +02:00
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)
2018-08-08 19:55:45 +02:00
flags |= SDL_WINDOW_FULLSCREEN;
win = SDL_CreateWindow(openparams->windowtitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, openparams->width, openparams->height, flags);
2018-08-08 19:55:45 +02:00
if(win == nil){
RWERROR((ERR_ENGINEOPEN, SDL_GetError()));
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return 0;
}
ctx = SDL_GL_CreateContext(win);
/* 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;
}
glGlobals.window = win;
glGlobals.glcontext = ctx;
*openparams->window = win;
2018-08-08 19:55:45 +02:00
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)
{
int i;
for(i = 1; i < glGlobals.numModes; i++){
if(glGlobals.modes[i].mode.width == mode->width &&
glGlobals.modes[i].mode.height == mode->height &&
glGlobals.modes[i].mode.redBits == mode->redBits &&
glGlobals.modes[i].mode.greenBits == mode->greenBits &&
glGlobals.modes[i].mode.blueBits == mode->blueBits){
// had this mode already, remember highest refresh rate
if(mode->refreshRate > glGlobals.modes[i].mode.refreshRate)
glGlobals.modes[i].mode.refreshRate = mode->refreshRate;
return;
}
}
// none found, add
glGlobals.modes[glGlobals.numModes].mode = *mode;
glGlobals.modes[glGlobals.numModes].flags = VIDEOMODEEXCLUSIVE;
glGlobals.numModes++;
}
static void
makeVideoModeList(void)
{
int i, num;
const GLFWvidmode *modes;
modes = glfwGetVideoModes(glGlobals.monitor, &num);
rwFree(glGlobals.modes);
glGlobals.modes = rwNewT(DisplayMode, num, 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);
}
}
2017-08-09 10:57:32 +02:00
static int
openGLFW(EngineOpenParams *openparams)
2017-08-09 10:57:32 +02:00
{
glGlobals.winWidth = openparams->width;
glGlobals.winHeight = openparams->height;
glGlobals.winTitle = openparams->windowtitle;
glGlobals.pWindow = openparams->window;
2017-08-09 10:57:32 +02:00
/* Init GLFW */
if(!glfwInit()){
RWERROR((ERR_GENERAL, "glfwInit() failed"));
return 0;
}
2017-12-31 10:50:49 +01:00
glfwWindowHint(GLFW_SAMPLES, 0);
2020-05-12 21:31:44 +02:00
#ifdef RW_GLES3
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#else
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
2017-08-09 10:57:32 +02:00
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
2020-05-12 21:31:44 +02:00
#endif
2017-08-09 10:57:32 +02:00
glGlobals.monitor = glfwGetMonitors(&glGlobals.numMonitors)[0];
makeVideoModeList();
return 1;
}
static int
closeGLFW(void)
{
glfwTerminate();
return 1;
}
2020-05-12 21:31:44 +02:00
static void
glfwerr(int error, const char *desc)
{
fprintf(stderr, "GLFW Error: %s\n", desc);
}
static int
startGLFW(void)
{
GLenum status;
GLFWwindow *win;
DisplayMode *mode;
mode = &glGlobals.modes[glGlobals.currentMode];
2020-05-12 21:31:44 +02:00
glfwSetErrorCallback(glfwerr);
glfwWindowHint(GLFW_RED_BITS, mode->mode.redBits);
glfwWindowHint(GLFW_GREEN_BITS, mode->mode.greenBits);
glfwWindowHint(GLFW_BLUE_BITS, mode->mode.blueBits);
glfwWindowHint(GLFW_REFRESH_RATE, mode->mode.refreshRate);
if(mode->flags & VIDEOMODEEXCLUSIVE)
win = glfwCreateWindow(mode->mode.width, mode->mode.height, glGlobals.winTitle, glGlobals.monitor, nil);
else
win = glfwCreateWindow(glGlobals.winWidth, glGlobals.winHeight, glGlobals.winTitle, nil, nil);
2017-08-09 10:57:32 +02:00
if(win == nil){
RWERROR((ERR_GENERAL, "glfwCreateWindow() failed"));
return 0;
}
glfwMakeContextCurrent(win);
/* Init GLEW */
glewExperimental = GL_TRUE;
status = glewInit();
if(status != GLEW_OK){
RWERROR((ERR_GENERAL, glewGetErrorString(status)));
glfwDestroyWindow(win);
return 0;
}
if(!GLEW_VERSION_3_3){
RWERROR((ERR_GENERAL, "OpenGL 3.3 needed"));
glfwDestroyWindow(win);
return 0;
}
glGlobals.window = win;
*glGlobals.pWindow = win;
2020-04-30 10:17:00 +02:00
glGlobals.presentWidth = 0;
glGlobals.presentHeight = 0;
2017-08-09 10:57:32 +02:00
return 1;
}
static int
stopGLFW(void)
2016-07-05 11:36:43 +02:00
{
glfwDestroyWindow(glGlobals.window);
2017-08-09 10:57:32 +02:00
return 1;
}
2018-08-08 19:55:45 +02:00
#endif
2016-07-05 11:36:43 +02:00
2017-08-09 10:57:32 +02:00
static int
initOpenGL(void)
{
registerBlock("Scene");
registerBlock("Object");
registerBlock("State");
u_matColor = registerUniform("u_matColor");
2020-04-26 19:33:43 +02:00
u_surfProps = registerUniform("u_surfProps");
2016-07-05 11:36:43 +02:00
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
0, GL_RGBA, GL_UNSIGNED_BYTE, &whitepixel);
2016-07-05 11:36:43 +02:00
resetRenderState();
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &ubo_state);
glBindBuffer(GL_UNIFORM_BUFFER, ubo_state);
glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("State"), ubo_state);
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformState), &uniformState,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glGenBuffers(1, &ubo_scene);
glBindBuffer(GL_UNIFORM_BUFFER, ubo_scene);
glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Scene"), ubo_scene);
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformScene), &uniformScene,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glGenBuffers(1, &ubo_object);
glBindBuffer(GL_UNIFORM_BUFFER, ubo_object);
glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Object"), ubo_object);
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformObject), &uniformObject,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
2020-04-26 19:33:43 +02:00
#include "shaders/default_vs_gl3.inc"
2017-08-29 10:12:56 +02:00
#include "shaders/simple_fs_gl3.inc"
2020-05-12 21:31:44 +02:00
const char *vs[] = { shaderDecl, header_vert_src, default_vert_src, nil };
const char *fs[] = { shaderDecl, simple_frag_src, nil };
2020-04-26 19:33:43 +02:00
defaultShader = Shader::create(vs, fs);
assert(defaultShader);
openIm2D();
2017-08-29 10:12:56 +02:00
openIm3D();
return 1;
}
2017-08-29 10:12:56 +02:00
static int
termOpenGL(void)
{
closeIm3D();
closeIm2D();
return 1;
}
static int
finalizeOpenGL(void)
{
2017-08-09 10:57:32 +02:00
return 1;
2016-07-05 11:36:43 +02:00
}
2017-08-09 10:57:32 +02:00
#ifdef LIBRW_SDL2
2017-08-09 10:57:32 +02:00
static int
deviceSystemSDL2(DeviceReq req, void *arg, int32 n)
2017-08-09 10:57:32 +02:00
{
switch(req){
2017-08-29 10:12:56 +02:00
case DEVICEOPEN:
return openSDL2((EngineOpenParams*)arg);
2017-08-29 10:12:56 +02:00
case DEVICECLOSE:
2018-08-08 19:55:45 +02:00
return closeSDL2();
2017-08-29 10:12:56 +02:00
2017-08-09 10:57:32 +02:00
case DEVICEINIT:
return initOpenGL();
2017-08-29 10:12:56 +02:00
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)
{
GLFWmonitor **monitors;
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 glGlobals.numMonitors;
case DEVICEGETCURRENTSUBSYSTEM:
return glGlobals.currentMonitor;
case DEVICESETSUBSYSTEM:
monitors = glfwGetMonitors(&glGlobals.numMonitors);
if(n >= glGlobals.numMonitors)
return 0;
glGlobals.currentMonitor = n;
glGlobals.monitor = monitors[glGlobals.currentMonitor];
return 1;
case DEVICEGETSUBSSYSTEMINFO:
monitors = glfwGetMonitors(&glGlobals.numMonitors);
if(n >= glGlobals.numMonitors)
return 0;
strncpy(((SubSystemInfo*)arg)->name, glfwGetMonitorName(monitors[n]), 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].mode.width;
rwmode->height = glGlobals.modes[n].mode.height;
rwmode->depth = glGlobals.modes[n].depth;
rwmode->flags = glGlobals.modes[n].flags;
return 1;
default:
assert(0 && "not implemented");
return 0;
2017-08-09 10:57:32 +02:00
}
return 1;
}
#endif
2017-08-09 10:57:32 +02:00
Device renderdevice = {
-1.0f, 1.0f,
gl3::beginUpdate,
null::endUpdate,
gl3::clearCamera,
gl3::showRaster,
2020-04-16 09:10:11 +02:00
gl3::rasterRenderFast,
2017-08-09 10:57:32 +02:00
gl3::setRenderState,
gl3::getRenderState,
gl3::im2DRenderLine,
gl3::im2DRenderTriangle,
gl3::im2DRenderPrimitive,
2017-08-09 10:57:32 +02:00
gl3::im2DRenderIndexedPrimitive,
2017-08-29 10:12:56 +02:00
gl3::im3DTransform,
2020-04-24 19:06:11 +02:00
gl3::im3DRenderPrimitive,
gl3::im3DRenderIndexedPrimitive,
2017-08-29 10:12:56 +02:00
gl3::im3DEnd,
#ifdef LIBRW_SDL2
gl3::deviceSystemSDL2
#else
gl3::deviceSystemGLFW
#endif
2017-08-09 10:57:32 +02:00
};
2016-07-05 11:36:43 +02:00
}
}
#endif
2017-08-29 14:05:45 +02:00