librw/src/gl/gl3pipe.cpp

249 lines
5.9 KiB
C++
Raw Normal View History

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "../rwbase.h"
#include "../rwerror.h"
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#endif
#include "rwgl3.h"
#include "rwgl3shader.h"
namespace rw {
namespace gl3 {
// TODO: make some of these things platform-independent
#ifdef RW_OPENGL
static void
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
{
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry;
2017-08-21 23:15:31 +02:00
// TODO: allow for REINSTANCE
if(geo->instData)
return;
2017-08-25 14:06:53 +02:00
InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY);
MeshHeader *meshh = geo->meshHeader;
geo->instData = header;
header->platform = PLATFORM_GL3;
2020-04-16 12:53:25 +02:00
header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
header->totalNumVertex = geo->numVertices;
header->totalNumIndex = meshh->totalIndices;
2017-08-25 14:06:53 +02:00
header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);
2017-08-25 14:06:53 +02:00
header->indexBuffer = rwNewT(uint16, header->totalNumIndex, MEMDUR_EVENT | ID_GEOMETRY);
InstanceData *inst = header->inst;
2017-08-25 14:06:53 +02:00
Mesh *mesh = meshh->getMeshes();
uint32 offset = 0;
for(uint32 i = 0; i < header->numMeshes; i++){
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
2018-01-03 18:02:02 +01:00
&inst->minVert, &inst->numVertices);
2018-07-04 19:21:34 +02:00
assert(inst->minVert != 0xFFFFFFFF);
inst->numIndex = mesh->numIndices;
inst->material = mesh->material;
inst->vertexAlpha = 0;
inst->program = 0;
inst->offset = offset;
memcpy((uint8*)header->indexBuffer + inst->offset,
mesh->indices, inst->numIndex*2);
offset += inst->numIndex*2;
mesh++;
inst++;
}
header->vertexBuffer = nil;
header->numAttribs = 0;
header->attribDesc = nil;
header->ibo = 0;
header->vbo = 0;
glGenBuffers(1, &header->ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, header->totalNumIndex*2,
header->indexBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
pipe->instanceCB(geo, header);
}
static void
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
{
assert(0 && "can't uninstance");
}
static void
render(rw::ObjPipeline *rwpipe, Atomic *atomic)
{
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry;
2017-08-21 23:15:31 +02:00
// TODO: allow for REINSTANCE
if(geo->instData == nil)
pipe->instance(atomic);
assert(geo->instData != nil);
assert(geo->instData->platform == PLATFORM_GL3);
if(pipe->renderCB)
pipe->renderCB(atomic, (InstanceDataHeader*)geo->instData);
}
ObjPipeline::ObjPipeline(uint32 platform)
: rw::ObjPipeline(platform)
{
this->impl.instance = gl3::instance;
this->impl.uninstance = gl3::uninstance;
this->impl.render = gl3::render;
this->instanceCB = nil;
this->uninstanceCB = nil;
this->renderCB = nil;
}
void
defaultInstanceCB(Geometry *geo, InstanceDataHeader *header)
{
AttribDesc attribs[12], *a;
uint32 stride;
//
// Create attribute descriptions
//
a = attribs;
stride = 0;
// Positions
a->index = ATTRIB_POS;
a->size = 3;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 12;
a++;
// Normals
// TODO: compress
2017-03-16 11:42:59 +01:00
bool hasNormals = !!(geo->flags & Geometry::NORMALS);
if(hasNormals){
a->index = ATTRIB_NORMAL;
a->size = 3;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 12;
a++;
}
// Prelighting
2017-03-16 11:42:59 +01:00
bool isPrelit = !!(geo->flags & Geometry::PRELIT);
if(isPrelit){
a->index = ATTRIB_COLOR;
a->size = 4;
a->type = GL_UNSIGNED_BYTE;
a->normalized = GL_TRUE;
a->offset = stride;
stride += 4;
a++;
}
// Texture coordinates
for(int32 n = 0; n < geo->numTexCoordSets; n++){
a->index = ATTRIB_TEXCOORDS0+n;
a->size = 2;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 8;
a++;
}
header->numAttribs = a - attribs;
for(a = attribs; a != &attribs[header->numAttribs]; a++)
a->stride = stride;
2017-08-25 14:06:53 +02:00
header->attribDesc = rwNewT(AttribDesc, header->numAttribs, MEMDUR_EVENT | ID_GEOMETRY);
memcpy(header->attribDesc, attribs,
header->numAttribs*sizeof(AttribDesc));
//
// Allocate and fill vertex buffer
//
2017-08-25 14:06:53 +02:00
uint8 *verts = rwNewT(uint8, header->totalNumVertex*stride, MEMDUR_EVENT | ID_GEOMETRY);
header->vertexBuffer = verts;
// Positions
for(a = attribs; a->index != ATTRIB_POS; a++)
;
instV3d(VERT_FLOAT3, verts + a->offset,
geo->morphTargets[0].vertices,
header->totalNumVertex, a->stride);
// Normals
if(hasNormals){
for(a = attribs; a->index != ATTRIB_NORMAL; a++)
;
instV3d(VERT_FLOAT3, verts + a->offset,
geo->morphTargets[0].normals,
header->totalNumVertex, a->stride);
}
// Prelighting
if(isPrelit){
for(a = attribs; a->index != ATTRIB_COLOR; a++)
;
2018-01-03 18:02:02 +01:00
int n = header->numMeshes;
InstanceData *inst = header->inst;
while(n--){
2018-07-04 19:21:34 +02:00
assert(inst->minVert != 0xFFFFFFFF);
2018-01-03 18:02:02 +01:00
inst->vertexAlpha = instColor(VERT_RGBA,
verts + a->offset + a->stride*inst->minVert,
geo->colors + inst->minVert,
inst->numVertices, a->stride);
inst++;
}
}
// Texture coordinates
for(int32 n = 0; n < geo->numTexCoordSets; n++){
for(a = attribs; a->index != ATTRIB_TEXCOORDS0+n; a++)
;
2017-08-05 01:44:37 +02:00
instTexCoords(VERT_FLOAT2, verts + a->offset,
geo->texCoords[n],
header->totalNumVertex, a->stride);
}
glGenBuffers(1, &header->vbo);
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*stride,
header->vertexBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void
defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header)
{
assert(0 && "can't uninstance");
}
ObjPipeline*
makeDefaultPipeline(void)
{
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
pipe->instanceCB = defaultInstanceCB;
pipe->uninstanceCB = defaultUninstanceCB;
pipe->renderCB = defaultRenderCB;
return pipe;
}
#endif
}
}