2020-04-30 17:54:38 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2016-06-24 15:24:58 +02:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
void
|
|
|
|
freeInstanceData(Geometry *geometry)
|
2016-06-24 15:24:58 +02:00
|
|
|
{
|
2020-04-28 12:44:28 +02:00
|
|
|
if(geometry->instData == nil ||
|
|
|
|
geometry->instData->platform != PLATFORM_GL3)
|
2016-06-24 15:24:58 +02:00
|
|
|
return;
|
2020-04-28 12:44:28 +02:00
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
|
|
|
geometry->instData = nil;
|
|
|
|
glDeleteBuffers(1, &header->ibo);
|
|
|
|
glDeleteBuffers(1, &header->vbo);
|
|
|
|
rwFree(header->indexBuffer);
|
|
|
|
rwFree(header->vertexBuffer);
|
|
|
|
rwFree(header->attribDesc);
|
|
|
|
rwFree(header);
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
destroyNativeData(void *object, int32, int32)
|
|
|
|
{
|
|
|
|
freeInstanceData((Geometry*)object);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static InstanceDataHeader*
|
|
|
|
instanceMesh(rw::ObjPipeline *rwpipe, Geometry *geo)
|
|
|
|
{
|
2017-08-25 14:06:53 +02:00
|
|
|
InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY);
|
2016-06-24 15:24:58 +02:00
|
|
|
MeshHeader *meshh = geo->meshHeader;
|
|
|
|
geo->instData = header;
|
|
|
|
header->platform = PLATFORM_GL3;
|
|
|
|
|
2020-04-16 12:53:25 +02:00
|
|
|
header->serialNumber = meshh->serialNum;
|
2016-06-24 15:24:58 +02:00
|
|
|
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);
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2017-08-25 14:06:53 +02:00
|
|
|
header->indexBuffer = rwNewT(uint16, header->totalNumIndex, MEMDUR_EVENT | ID_GEOMETRY);
|
2016-06-24 15:24:58 +02:00
|
|
|
InstanceData *inst = header->inst;
|
2017-08-25 14:06:53 +02:00
|
|
|
Mesh *mesh = meshh->getMeshes();
|
2016-06-24 15:24:58 +02:00
|
|
|
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);
|
2016-06-24 15:24:58 +02:00
|
|
|
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);
|
2016-08-21 18:20:27 +02:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, header->totalNumIndex*2,
|
2016-06-24 15:24:58 +02:00
|
|
|
header->indexBuffer, GL_STATIC_DRAW);
|
2016-08-21 18:20:27 +02:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
|
|
|
{
|
|
|
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
|
|
|
Geometry *geo = atomic->geometry;
|
|
|
|
// don't try to (re)instance native data
|
|
|
|
if(geo->flags & Geometry::NATIVE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
|
|
|
if(geo->instData){
|
|
|
|
// Already have instanced data, so check if we have to reinstance
|
|
|
|
assert(header->platform == PLATFORM_GL3);
|
|
|
|
if(header->serialNumber != geo->meshHeader->serialNum){
|
|
|
|
// Mesh changed, so reinstance everything
|
|
|
|
freeInstanceData(geo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no instance or complete reinstance
|
|
|
|
if(geo->instData == nil){
|
|
|
|
geo->instData = instanceMesh(rwpipe, geo);
|
|
|
|
pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 0);
|
|
|
|
}else if(geo->lockedSinceInst)
|
|
|
|
pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 1);
|
|
|
|
|
|
|
|
geo->lockedSinceInst = 0;
|
2016-06-24 15:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
|
|
|
{
|
|
|
|
assert(0 && "can't uninstance");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
render(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
2016-06-29 12:53:02 +02:00
|
|
|
{
|
2016-06-24 15:24:58 +02:00
|
|
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
|
|
|
Geometry *geo = atomic->geometry;
|
2020-04-28 12:44:28 +02:00
|
|
|
pipe->instance(atomic);
|
2016-06-24 15:24:58 +02:00
|
|
|
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)
|
2016-06-29 12:53:02 +02:00
|
|
|
{
|
2016-06-24 15:24:58 +02:00
|
|
|
this->impl.instance = gl3::instance;
|
|
|
|
this->impl.uninstance = gl3::uninstance;
|
|
|
|
this->impl.render = gl3::render;
|
|
|
|
this->instanceCB = nil;
|
|
|
|
this->uninstanceCB = nil;
|
|
|
|
this->renderCB = nil;
|
2016-06-29 12:53:02 +02:00
|
|
|
}
|
2016-06-24 15:24:58 +02:00
|
|
|
|
|
|
|
void
|
2020-04-28 12:44:28 +02:00
|
|
|
defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance)
|
2016-06-24 15:24:58 +02:00
|
|
|
{
|
2020-04-28 12:44:28 +02:00
|
|
|
AttribDesc *attribs, *a;
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
bool isPrelit = !!(geo->flags & Geometry::PRELIT);
|
|
|
|
bool hasNormals = !!(geo->flags & Geometry::NORMALS);
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
if(!reinstance){
|
|
|
|
AttribDesc tmpAttribs[12];
|
|
|
|
uint32 stride;
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
//
|
|
|
|
// Create attribute descriptions
|
|
|
|
//
|
|
|
|
a = tmpAttribs;
|
|
|
|
stride = 0;
|
|
|
|
|
|
|
|
// Positions
|
|
|
|
a->index = ATTRIB_POS;
|
2016-06-24 15:24:58 +02:00
|
|
|
a->size = 3;
|
|
|
|
a->type = GL_FLOAT;
|
|
|
|
a->normalized = GL_FALSE;
|
|
|
|
a->offset = stride;
|
|
|
|
stride += 12;
|
|
|
|
a++;
|
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
// Normals
|
|
|
|
// TODO: compress
|
|
|
|
if(hasNormals){
|
|
|
|
a->index = ATTRIB_NORMAL;
|
|
|
|
a->size = 3;
|
|
|
|
a->type = GL_FLOAT;
|
|
|
|
a->normalized = GL_FALSE;
|
|
|
|
a->offset = stride;
|
|
|
|
stride += 12;
|
|
|
|
a++;
|
|
|
|
}
|
2016-06-24 15:24:58 +02:00
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
// Prelighting
|
|
|
|
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 - tmpAttribs;
|
|
|
|
for(a = tmpAttribs; a != &tmpAttribs[header->numAttribs]; a++)
|
|
|
|
a->stride = stride;
|
|
|
|
header->attribDesc = rwNewT(AttribDesc, header->numAttribs, MEMDUR_EVENT | ID_GEOMETRY);
|
|
|
|
memcpy(header->attribDesc, tmpAttribs,
|
|
|
|
header->numAttribs*sizeof(AttribDesc));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Allocate vertex buffer
|
|
|
|
//
|
|
|
|
header->vertexBuffer = rwNewT(uint8, header->totalNumVertex*stride, MEMDUR_EVENT | ID_GEOMETRY);
|
|
|
|
assert(header->vbo == 0);
|
|
|
|
glGenBuffers(1, &header->vbo);
|
2016-06-24 15:24:58 +02:00
|
|
|
}
|
|
|
|
|
2020-04-28 12:44:28 +02:00
|
|
|
attribs = header->attribDesc;
|
2016-06-24 15:24:58 +02:00
|
|
|
|
|
|
|
//
|
2020-04-28 12:44:28 +02:00
|
|
|
// Fill vertex buffer
|
2016-06-24 15:24:58 +02:00
|
|
|
//
|
2020-04-28 12:44:28 +02:00
|
|
|
|
|
|
|
uint8 *verts = header->vertexBuffer;
|
2016-06-24 15:24:58 +02:00
|
|
|
|
|
|
|
// Positions
|
2020-04-28 12:44:28 +02:00
|
|
|
if(!reinstance || geo->lockedSinceInst&Geometry::LOCKVERTICES){
|
|
|
|
for(a = attribs; a->index != ATTRIB_POS; a++)
|
|
|
|
;
|
|
|
|
instV3d(VERT_FLOAT3, verts + a->offset,
|
|
|
|
geo->morphTargets[0].vertices,
|
|
|
|
header->totalNumVertex, a->stride);
|
|
|
|
}
|
2016-06-24 15:24:58 +02:00
|
|
|
|
|
|
|
// Normals
|
2020-04-28 12:44:28 +02:00
|
|
|
if(hasNormals && (!reinstance || geo->lockedSinceInst&Geometry::LOCKNORMALS)){
|
2016-06-24 15:24:58 +02:00
|
|
|
for(a = attribs; a->index != ATTRIB_NORMAL; a++)
|
|
|
|
;
|
|
|
|
instV3d(VERT_FLOAT3, verts + a->offset,
|
|
|
|
geo->morphTargets[0].normals,
|
|
|
|
header->totalNumVertex, a->stride);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prelighting
|
2020-04-28 12:44:28 +02:00
|
|
|
if(isPrelit && (!reinstance || geo->lockedSinceInst&Geometry::LOCKPRELIGHT)){
|
2016-06-24 15:24:58 +02:00
|
|
|
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++;
|
|
|
|
}
|
2016-06-24 15:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Texture coordinates
|
|
|
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
2020-04-28 12:44:28 +02:00
|
|
|
if(!reinstance || geo->lockedSinceInst&(Geometry::LOCKTEXCOORDS<<n)){
|
|
|
|
for(a = attribs; a->index != ATTRIB_TEXCOORDS0+n; a++)
|
|
|
|
;
|
|
|
|
instTexCoords(VERT_FLOAT2, verts + a->offset,
|
|
|
|
geo->texCoords[n],
|
|
|
|
header->totalNumVertex, a->stride);
|
|
|
|
}
|
2016-06-24 15:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
|
2020-04-28 12:44:28 +02:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*attribs[0].stride,
|
2016-06-24 15:24:58 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-04-28 13:40:36 +02:00
|
|
|
#else
|
|
|
|
void *destroyNativeData(void *object, int32, int32) { return object; }
|
2016-06-24 15:24:58 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|