librw/src/gl/gl3render.cpp
2020-08-18 11:03:07 +02:00

165 lines
3.8 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.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 <GL/glew.h>
#include "rwgl3.h"
#include "rwgl3shader.h"
#include "rwgl3impl.h"
namespace rw {
namespace gl3 {
#define MAX_LIGHTS
void
drawInst_simple(InstanceDataHeader *header, InstanceData *inst)
{
flushCache();
glDrawElements(header->primType, inst->numIndex,
GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset);
}
// Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer
void
drawInst_GSemu(InstanceDataHeader *header, InstanceData *inst)
{
uint32 hasAlpha;
int alphafunc, alpharef, gsalpharef;
int zwrite;
hasAlpha = getAlphaBlend();
if(hasAlpha){
zwrite = rw::GetRenderState(rw::ZWRITEENABLE);
alphafunc = rw::GetRenderState(rw::ALPHATESTFUNC);
if(zwrite){
alpharef = rw::GetRenderState(rw::ALPHATESTREF);
gsalpharef = rw::GetRenderState(rw::GSALPHATESTREF);
SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
SetRenderState(rw::ALPHATESTREF, gsalpharef);
drawInst_simple(header, inst);
SetRenderState(rw::ALPHATESTFUNC, rw::ALPHALESS);
SetRenderState(rw::ZWRITEENABLE, 0);
drawInst_simple(header, inst);
SetRenderState(rw::ZWRITEENABLE, 1);
SetRenderState(rw::ALPHATESTFUNC, alphafunc);
SetRenderState(rw::ALPHATESTREF, alpharef);
}else{
SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAALWAYS);
drawInst_simple(header, inst);
SetRenderState(rw::ALPHATESTFUNC, alphafunc);
}
}else
drawInst_simple(header, inst);
}
void
drawInst(InstanceDataHeader *header, InstanceData *inst)
{
if(rw::GetRenderState(rw::GSALPHATEST))
drawInst_GSemu(header, inst);
else
drawInst_simple(header, inst);
}
void
setAttribPointers(AttribDesc *attribDescs, int32 numAttribs)
{
AttribDesc *a;
for(a = attribDescs; a != &attribDescs[numAttribs]; a++){
glEnableVertexAttribArray(a->index);
glVertexAttribPointer(a->index, a->size, a->type, a->normalized,
a->stride, (void*)(uint64)a->offset);
}
}
void
disableAttribPointers(AttribDesc *attribDescs, int32 numAttribs)
{
AttribDesc *a;
for(a = attribDescs; a != &attribDescs[numAttribs]; a++)
glDisableVertexAttribArray(a->index);
}
int32
lightingCB(Atomic *atomic)
{
WorldLights lightData;
Light *directionals[8];
Light *locals[8];
lightData.directionals = directionals;
lightData.numDirectionals = 8;
lightData.locals = locals;
lightData.numLocals = 8;
if(atomic->geometry->flags & rw::Geometry::LIGHT){
((World*)engine->currentWorld)->enumerateLights(atomic, &lightData);
if((atomic->geometry->flags & rw::Geometry::NORMALS) == 0){
// Get rid of lights that need normals when we don't have any
lightData.numDirectionals = 0;
lightData.numLocals = 0;
}
return setLights(&lightData);
}else{
memset(&lightData, 0, sizeof(lightData));
return setLights(&lightData);
}
}
#define U(i) currentShader->uniformLocations[i]
void
defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
{
Material *m;
setWorldMatrix(atomic->getFrame()->getLTM());
lightingCB(atomic);
#ifdef RW_GL_USE_VAOS
glBindVertexArray(header->vao);
#else
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
setAttribPointers(header->attribDesc, header->numAttribs);
#endif
InstanceData *inst = header->inst;
int32 n = header->numMeshes;
defaultShader->use();
while(n--){
m = inst->material;
setMaterial(m->color, m->surfaceProps);
setTexture(0, m->texture);
rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF);
drawInst(header, inst);
inst++;
}
#ifndef RW_GL_USE_VAOS
disableAttribPointers(header->attribDesc, header->numAttribs);
#endif
}
}
}
#endif