mirror of
https://github.com/aap/librw.git
synced 2025-12-19 17:09:51 +00:00
moved gl3 code here; added files i forgot last time
This commit is contained in:
276
src/gl/gl3pipe.cpp
Normal file
276
src/gl/gl3pipe.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#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"
|
||||
#include "../rwplugins.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
|
||||
|
||||
void
|
||||
initializePlatform(void)
|
||||
{
|
||||
#ifdef RW_OPENGL
|
||||
driver[PLATFORM_GL3].defaultPipeline = makeDefaultPipeline();
|
||||
matFXGlobals.pipelines[PLATFORM_GL3] = makeMatFXPipeline();
|
||||
skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline();
|
||||
#endif
|
||||
|
||||
initializeRender();
|
||||
}
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
|
||||
static void
|
||||
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||
{
|
||||
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||
Geometry *geo = atomic->geometry;
|
||||
if(geo->geoflags & Geometry::NATIVE)
|
||||
return;
|
||||
geo->geoflags |= Geometry::NATIVE;
|
||||
InstanceDataHeader *header = new InstanceDataHeader;
|
||||
MeshHeader *meshh = geo->meshHeader;
|
||||
geo->instData = header;
|
||||
header->platform = PLATFORM_GL3;
|
||||
|
||||
header->serialNumber = 0;
|
||||
header->numMeshes = meshh->numMeshes;
|
||||
header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
||||
header->totalNumVertex = geo->numVertices;
|
||||
header->totalNumIndex = meshh->totalIndices;
|
||||
header->inst = new InstanceData[header->numMeshes];
|
||||
|
||||
header->indexBuffer = new uint16[header->totalNumIndex];
|
||||
InstanceData *inst = header->inst;
|
||||
Mesh *mesh = meshh->mesh;
|
||||
uint32 offset = 0;
|
||||
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
|
||||
&inst->minVert, nil);
|
||||
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_ARRAY_BUFFER, header->ibo);
|
||||
glBufferData(GL_ARRAY_BUFFER, header->totalNumIndex*2,
|
||||
header->indexBuffer, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_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;
|
||||
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||
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
|
||||
bool hasNormals = !!(geo->geoflags & 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
|
||||
bool isPrelit = !!(geo->geoflags & 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;
|
||||
header->attribDesc = new AttribDesc[header->numAttribs];
|
||||
memcpy(header->attribDesc, attribs,
|
||||
header->numAttribs*sizeof(AttribDesc));
|
||||
|
||||
//
|
||||
// Allocate and fill vertex buffer
|
||||
//
|
||||
uint8 *verts = new uint8[header->totalNumVertex*stride];
|
||||
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++)
|
||||
;
|
||||
instColor(VERT_RGBA, verts + a->offset,
|
||||
geo->colors,
|
||||
header->totalNumVertex, a->stride);
|
||||
}
|
||||
|
||||
// Texture coordinates
|
||||
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||
for(a = attribs; a->index != ATTRIB_TEXCOORDS0+n; a++)
|
||||
;
|
||||
instV2d(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;
|
||||
}
|
||||
|
||||
ObjPipeline*
|
||||
makeSkinPipeline(void)
|
||||
{
|
||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||
pipe->instanceCB = defaultInstanceCB;
|
||||
pipe->uninstanceCB = defaultUninstanceCB;
|
||||
pipe->renderCB = defaultRenderCB;
|
||||
pipe->pluginID = ID_SKIN;
|
||||
pipe->pluginData = 1;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
ObjPipeline*
|
||||
makeMatFXPipeline(void)
|
||||
{
|
||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||
pipe->instanceCB = defaultInstanceCB;
|
||||
pipe->uninstanceCB = defaultUninstanceCB;
|
||||
pipe->renderCB = defaultRenderCB;
|
||||
pipe->pluginID = ID_MATFX;
|
||||
pipe->pluginData = 0;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
132
src/gl/gl3raster.cpp
Normal file
132
src/gl/gl3raster.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#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"
|
||||
#include "../rwplugins.h"
|
||||
#ifdef RW_OPENGL
|
||||
#include <GL/glew.h>
|
||||
#endif
|
||||
#include "rwgl3.h"
|
||||
#include "rwgl3shader.h"
|
||||
|
||||
namespace rw {
|
||||
namespace gl3 {
|
||||
|
||||
int32 nativeRasterOffset;
|
||||
|
||||
static void
|
||||
rasterCreate(Raster *raster)
|
||||
{
|
||||
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
|
||||
if(raster->flags & Raster::DONTALLOCATE)
|
||||
return;
|
||||
|
||||
assert(raster->depth == 32);
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
glGenTextures(1, &natras->texid);
|
||||
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||
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, raster->width, raster->height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8*
|
||||
rasterLock(Raster*, int32 level)
|
||||
{
|
||||
printf("locking\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
rasterUnlock(Raster*, int32)
|
||||
{
|
||||
printf("unlocking\n");
|
||||
}
|
||||
|
||||
static int32
|
||||
rasterNumLevels(Raster*)
|
||||
{
|
||||
printf("numlevels\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rasterFromImage(Raster *raster, Image *image)
|
||||
{
|
||||
int32 format;
|
||||
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
|
||||
|
||||
format = Raster::C8888;
|
||||
format |= 4;
|
||||
|
||||
raster->type = format & 0x7;
|
||||
raster->flags = format & 0xF8;
|
||||
raster->format = format & 0xFF00;
|
||||
rasterCreate(raster);
|
||||
|
||||
assert(image->depth == 32);
|
||||
|
||||
natras->hasAlpha = image->hasAlpha();
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, raster->width, raster->height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void*
|
||||
createNativeRaster(void *object, int32 offset, int32)
|
||||
{
|
||||
Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset);
|
||||
ras->texid = 0;
|
||||
return object;
|
||||
}
|
||||
|
||||
static void*
|
||||
destroyNativeRaster(void *object, int32, int32)
|
||||
{
|
||||
//Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset);
|
||||
// TODO
|
||||
return object;
|
||||
}
|
||||
|
||||
static void*
|
||||
copyNativeRaster(void *dst, void *, int32 offset, int32)
|
||||
{
|
||||
Gl3Raster *d = PLUGINOFFSET(Gl3Raster, dst, offset);
|
||||
d->texid = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void
|
||||
registerNativeRaster(void)
|
||||
{
|
||||
nativeRasterOffset = Raster::registerPlugin(sizeof(Gl3Raster),
|
||||
0x12340000 | PLATFORM_GL3,
|
||||
createNativeRaster,
|
||||
destroyNativeRaster,
|
||||
copyNativeRaster);
|
||||
driver[PLATFORM_GL3].rasterNativeOffset = nativeRasterOffset;
|
||||
driver[PLATFORM_GL3].rasterCreate = rasterCreate;
|
||||
driver[PLATFORM_GL3].rasterLock = rasterLock;
|
||||
driver[PLATFORM_GL3].rasterUnlock = rasterUnlock;
|
||||
driver[PLATFORM_GL3].rasterNumLevels = rasterNumLevels;
|
||||
driver[PLATFORM_GL3].rasterFromImage = rasterFromImage;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
359
src/gl/gl3render.cpp
Normal file
359
src/gl/gl3render.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "../rwbase.h"
|
||||
#include "../rwerror.h"
|
||||
#include "../rwplg.h"
|
||||
#include "../rwpipeline.h"
|
||||
#include "../rwobjects.h"
|
||||
#include "../rwengine.h"
|
||||
#include "../rwplugins.h"
|
||||
#ifdef RW_OPENGL
|
||||
#include <GL/glew.h>
|
||||
#include "rwgl3.h"
|
||||
#include "rwgl3shader.h"
|
||||
|
||||
namespace rw {
|
||||
namespace gl3 {
|
||||
|
||||
struct UniformScene
|
||||
{
|
||||
float32 proj[16];
|
||||
float32 view[16];
|
||||
};
|
||||
|
||||
struct UniformLight
|
||||
{
|
||||
V3d position;
|
||||
float32 w;
|
||||
V3d direction;
|
||||
int32 pad1;
|
||||
RGBAf color;
|
||||
float32 radius;
|
||||
float32 minusCosAngle;
|
||||
int32 pad2[2];
|
||||
};
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
|
||||
struct UniformObject
|
||||
{
|
||||
Matrix world;
|
||||
RGBAf ambLight;
|
||||
int32 numLights;
|
||||
int32 pad[3];
|
||||
UniformLight lights[MAX_LIGHTS];
|
||||
};
|
||||
|
||||
GLuint vao;
|
||||
GLuint ubo_scene, ubo_object;
|
||||
GLuint whitetex;
|
||||
UniformScene uniformScene;
|
||||
UniformObject uniformObject;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
if(cam->projection == Camera::PERSPECTIVE){
|
||||
proj[8] = cam->viewOffset.x*invwx;
|
||||
proj[9] = cam->viewOffset.y*invwy;
|
||||
proj[10] = (cam->farPlane+cam->nearPlane)*invz;
|
||||
proj[11] = 1.0f;
|
||||
|
||||
proj[12] = 0.0f;
|
||||
proj[13] = 0.0f;
|
||||
proj[14] = -2.0f*cam->nearPlane*cam->farPlane*invz;
|
||||
proj[15] = 0.0f;
|
||||
}else{
|
||||
// TODO
|
||||
}
|
||||
setProjectionMatrix(proj);
|
||||
}
|
||||
|
||||
void
|
||||
initializeRender(void)
|
||||
{
|
||||
driver[PLATFORM_GL3].beginUpdate = beginUpdate;
|
||||
|
||||
glClearColor(0.25, 0.25, 0.25, 1.0);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
registerBlock("Scene");
|
||||
registerBlock("Object");
|
||||
registerUniform("u_matColor");
|
||||
registerUniform("u_surfaceProps");
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
setAttribPointers(InstanceDataHeader *header)
|
||||
{
|
||||
AttribDesc *a;
|
||||
for(a = header->attribDesc;
|
||||
a != &header->attribDesc[header->numAttribs];
|
||||
a++){
|
||||
glEnableVertexAttribArray(a->index);
|
||||
glVertexAttribPointer(a->index, a->size, a->type, a->normalized,
|
||||
a->stride, (void*)(uint64)a->offset);
|
||||
}
|
||||
}
|
||||
|
||||
static bool32 sceneDirty = 1;
|
||||
static bool32 objectDirty = 1;
|
||||
|
||||
void
|
||||
setWorldMatrix(Matrix *mat)
|
||||
{
|
||||
uniformObject.world = *mat;
|
||||
objectDirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
setAmbientLight(RGBAf *amb)
|
||||
{
|
||||
uniformObject.ambLight = *amb;
|
||||
objectDirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
setNumLights(int32 n)
|
||||
{
|
||||
uniformObject.numLights = n;
|
||||
objectDirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
setLight(int32 n, Light *light)
|
||||
{
|
||||
UniformLight *l;
|
||||
Frame *f;
|
||||
Matrix *m;
|
||||
|
||||
l = &uniformObject.lights[n];
|
||||
f = light->getFrame();
|
||||
if(f){
|
||||
m = f->getLTM();
|
||||
l->position = m->pos;
|
||||
l->direction = m->at;
|
||||
}
|
||||
// light has position
|
||||
l->w = light->getType() >= Light::POINT ? 1.0f : 0.0;
|
||||
l->color = light->color;
|
||||
l->radius = light->radius;
|
||||
l->minusCosAngle = light->minusCosAngle;
|
||||
objectDirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
setProjectionMatrix(float32 *mat)
|
||||
{
|
||||
memcpy(&uniformScene.proj, mat, 64);
|
||||
sceneDirty = 1;
|
||||
}
|
||||
|
||||
void
|
||||
setViewMatrix(float32 *mat)
|
||||
{
|
||||
memcpy(&uniformScene.view, mat, 64);
|
||||
sceneDirty = 1;
|
||||
}
|
||||
|
||||
static bool32 vertexAlpha;
|
||||
static bool32 textureAlpha;
|
||||
|
||||
void
|
||||
setTexture(int32 n, Texture *tex)
|
||||
{
|
||||
bool32 alpha;
|
||||
glActiveTexture(GL_TEXTURE0+n);
|
||||
if(tex == nil){
|
||||
glBindTexture(GL_TEXTURE_2D, whitetex);
|
||||
alpha = 0;
|
||||
}else{
|
||||
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, tex->raster,
|
||||
nativeRasterOffset);
|
||||
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||
alpha = natras->hasAlpha;
|
||||
}
|
||||
|
||||
if(textureAlpha == alpha)
|
||||
return;
|
||||
if(alpha)
|
||||
/*printf("enable\n"),*/ glEnable(GL_BLEND);
|
||||
else if(!vertexAlpha)
|
||||
/*printf("disable\n"),*/ glDisable(GL_BLEND);
|
||||
textureAlpha = alpha;
|
||||
}
|
||||
|
||||
void
|
||||
setVertexAlpha(bool32 alpha)
|
||||
{
|
||||
if(vertexAlpha == alpha)
|
||||
return;
|
||||
if(alpha)
|
||||
/*printf("enable\n"),*/ glEnable(GL_BLEND);
|
||||
else if(!textureAlpha)
|
||||
/*printf("disable\n"),*/ glDisable(GL_BLEND);
|
||||
vertexAlpha = alpha;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lightingCB(void)
|
||||
{
|
||||
World *world;
|
||||
RGBAf ambLight = (RGBAf){0.0, 0.0, 0.0, 1.0};
|
||||
int n = 0;
|
||||
|
||||
world = (World*)engine.currentWorld;
|
||||
// only unpositioned lights right now
|
||||
FORLIST(lnk, world->directionalLights){
|
||||
Light *l = Light::fromWorld(lnk);
|
||||
if(l->getType() == Light::DIRECTIONAL){
|
||||
if(n >= MAX_LIGHTS)
|
||||
continue;
|
||||
setLight(n++, l);
|
||||
}else if(l->getType() == Light::AMBIENT){
|
||||
ambLight.red += l->color.red;
|
||||
ambLight.green += l->color.green;
|
||||
ambLight.blue += l->color.blue;
|
||||
}
|
||||
}
|
||||
setNumLights(n);
|
||||
setAmbientLight(&ambLight);
|
||||
}
|
||||
|
||||
void
|
||||
defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
||||
{
|
||||
setWorldMatrix(atomic->getFrame()->getLTM());
|
||||
lightingCB();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
|
||||
setAttribPointers(header);
|
||||
|
||||
Material *m;
|
||||
RGBAf col;
|
||||
GLfloat surfProps[4];
|
||||
int id;
|
||||
InstanceData *inst = header->inst;
|
||||
int32 n = header->numMeshes;
|
||||
|
||||
while(n--){
|
||||
m = inst->material;
|
||||
|
||||
#define U(s) currentShader->uniformLocations[findUniform(s)]
|
||||
|
||||
convColor(&col, &m->color);
|
||||
glUniform4fv(U("u_matColor"), 1, (GLfloat*)&col);
|
||||
|
||||
surfProps[0] = m->surfaceProps.ambient;
|
||||
surfProps[1] = m->surfaceProps.specular;
|
||||
surfProps[2] = m->surfaceProps.diffuse;
|
||||
surfProps[3] = 0.0f;
|
||||
glUniform4fv(U("u_surfaceProps"), 1, surfProps);
|
||||
|
||||
setTexture(0, m->texture);
|
||||
|
||||
setVertexAlpha(inst->vertexAlpha || m->color.alpha != 0xFF);
|
||||
|
||||
flushCache();
|
||||
glDrawElements(header->primType, inst->numIndex,
|
||||
GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset);
|
||||
inst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
193
src/gl/gl3shader.cpp
Normal file
193
src/gl/gl3shader.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "../rwbase.h"
|
||||
#include "../rwerror.h"
|
||||
#include "../rwplg.h"
|
||||
#include "../rwpipeline.h"
|
||||
#include "../rwobjects.h"
|
||||
#include "../rwengine.h"
|
||||
#include "../rwplugins.h"
|
||||
#ifdef RW_OPENGL
|
||||
#include <GL/glew.h>
|
||||
#include "rwgl3.h"
|
||||
#include "rwgl3shader.h"
|
||||
|
||||
namespace rw {
|
||||
namespace gl3 {
|
||||
|
||||
UniformRegistry uniformRegistry;
|
||||
|
||||
int
|
||||
registerUniform(const char *name)
|
||||
{
|
||||
int i;
|
||||
i = findUniform(name);
|
||||
if(i >= 0) return i;
|
||||
uniformRegistry.uniformNames[uniformRegistry.numUniforms] = strdup(name);
|
||||
return uniformRegistry.numUniforms++;
|
||||
}
|
||||
|
||||
int
|
||||
findUniform(const char *name)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < uniformRegistry.numUniforms; i++)
|
||||
if(strcmp(name, uniformRegistry.uniformNames[i]) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
registerBlock(const char *name)
|
||||
{
|
||||
int i;
|
||||
i = findBlock(name);
|
||||
if(i >= 0) return i;
|
||||
uniformRegistry.blockNames[uniformRegistry.numBlocks] = strdup(name);
|
||||
return uniformRegistry.numBlocks++;
|
||||
}
|
||||
|
||||
int
|
||||
findBlock(const char *name)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < uniformRegistry.numBlocks; i++)
|
||||
if(strcmp(name, uniformRegistry.blockNames[i]) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Shader *currentShader;
|
||||
|
||||
// TODO: maybe make this public somewhere?
|
||||
static char*
|
||||
loadfile(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
long len;
|
||||
|
||||
if(f = fopen(path, "rb"), f == nil){
|
||||
fprintf(stderr, "Couldn't open file %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
buf = (char*)malloc(len+1);
|
||||
rewind(f);
|
||||
fread(buf, 1, len, f);
|
||||
buf[len] = '\0';
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
compileshader(GLenum type, const char *src, GLuint *shader)
|
||||
{
|
||||
GLint shdr, success;
|
||||
GLint len;
|
||||
char *log;
|
||||
|
||||
shdr = glCreateShader(type);
|
||||
glShaderSource(shdr, 1, &src, nil);
|
||||
glCompileShader(shdr);
|
||||
glGetShaderiv(shdr, GL_COMPILE_STATUS, &success);
|
||||
if(!success){
|
||||
fprintf(stderr, "Error in %s shader\n",
|
||||
type == GL_VERTEX_SHADER ? "vertex" : "fragment");
|
||||
glGetShaderiv(shdr, GL_INFO_LOG_LENGTH, &len);
|
||||
log = (char*)malloc(len);
|
||||
glGetShaderInfoLog(shdr, len, nil, log);
|
||||
fprintf(stderr, "%s\n", log);
|
||||
free(log);
|
||||
return 1;
|
||||
}
|
||||
*shader = shdr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
linkprogram(GLint vs, GLint fs, GLuint *program)
|
||||
{
|
||||
GLint prog, success;
|
||||
GLint len;
|
||||
char *log;
|
||||
|
||||
prog = glCreateProgram();
|
||||
|
||||
glAttachShader(prog, vs);
|
||||
glAttachShader(prog, fs);
|
||||
glLinkProgram(prog);
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &success);
|
||||
if(!success){
|
||||
fprintf(stderr, "Error in program\n");
|
||||
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
|
||||
log = (char*)malloc(len);
|
||||
glGetProgramInfoLog(prog, len, nil, log);
|
||||
fprintf(stderr, "%s\n", log);
|
||||
free(log);
|
||||
return 1;
|
||||
}
|
||||
*program = prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Shader*
|
||||
Shader::fromFiles(const char *vspath, const char *fspath)
|
||||
{
|
||||
GLuint vs, fs, program;
|
||||
int i;
|
||||
char *src;
|
||||
int fail;
|
||||
|
||||
src = loadfile(vspath);
|
||||
fail = compileshader(GL_VERTEX_SHADER, src, &vs);
|
||||
free(src);
|
||||
if(fail)
|
||||
return nil;
|
||||
|
||||
src = loadfile(fspath);
|
||||
fail = compileshader(GL_FRAGMENT_SHADER, src, &fs);
|
||||
free(src);
|
||||
if(fail)
|
||||
return nil;
|
||||
|
||||
fail = linkprogram(vs, fs, &program);
|
||||
if(fail)
|
||||
return nil;
|
||||
glDeleteProgram(vs);
|
||||
glDeleteProgram(fs);
|
||||
|
||||
Shader *sh = new Shader;
|
||||
|
||||
// set uniform block binding
|
||||
for(i = 0; i < uniformRegistry.numBlocks; i++){
|
||||
int idx = glGetUniformBlockIndex(program,
|
||||
uniformRegistry.blockNames[i]);
|
||||
if(idx >= 0)
|
||||
glUniformBlockBinding(program, idx, i);
|
||||
}
|
||||
|
||||
// query uniform locations
|
||||
sh->program = program;
|
||||
sh->uniformLocations = new GLint[uniformRegistry.numUniforms];
|
||||
for(i = 0; i < uniformRegistry.numUniforms; i++)
|
||||
sh->uniformLocations[i] = glGetUniformLocation(program,
|
||||
uniformRegistry.uniformNames[i]);
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
void
|
||||
Shader::use(void)
|
||||
{
|
||||
glUseProgram(this->program);
|
||||
currentShader = this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
108
src/gl/rwgl3.h
Normal file
108
src/gl/rwgl3.h
Normal file
@@ -0,0 +1,108 @@
|
||||
namespace rw {
|
||||
namespace gl3 {
|
||||
|
||||
void initializePlatform(void);
|
||||
void initializeRender(void);
|
||||
|
||||
// arguments to glVertexAttribPointer basically
|
||||
struct AttribDesc
|
||||
{
|
||||
uint32 index;
|
||||
int32 type;
|
||||
bool32 normalized;
|
||||
int32 size;
|
||||
uint32 stride;
|
||||
uint32 offset;
|
||||
};
|
||||
|
||||
enum AttribIndices
|
||||
{
|
||||
ATTRIB_POS = 0,
|
||||
ATTRIB_NORMAL,
|
||||
ATTRIB_COLOR,
|
||||
ATTRIB_TEXCOORDS0,
|
||||
ATTRIB_TEXCOORDS1,
|
||||
ATTRIB_TEXCOORDS2,
|
||||
ATTRIB_TEXCOORDS3,
|
||||
ATTRIB_TEXCOORDS4,
|
||||
ATTRIB_TEXCOORDS5,
|
||||
ATTRIB_TEXCOORDS6,
|
||||
ATTRIB_TEXCOORDS7,
|
||||
};
|
||||
|
||||
struct InstanceData
|
||||
{
|
||||
uint32 numIndex;
|
||||
uint32 minVert; // not used for rendering
|
||||
Material *material;
|
||||
bool32 vertexAlpha;
|
||||
uint32 program;
|
||||
uint32 offset;
|
||||
};
|
||||
|
||||
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||
{
|
||||
uint32 serialNumber; // not really needed right now
|
||||
uint32 numMeshes;
|
||||
uint16 *indexBuffer;
|
||||
uint32 primType;
|
||||
uint8 *vertexBuffer;
|
||||
int32 numAttribs;
|
||||
AttribDesc *attribDesc;
|
||||
uint32 totalNumIndex;
|
||||
uint32 totalNumVertex;
|
||||
|
||||
uint32 ibo;
|
||||
uint32 vbo; // or 2?
|
||||
|
||||
InstanceData *inst;
|
||||
};
|
||||
|
||||
void setAttribPointers(InstanceDataHeader *header);
|
||||
|
||||
// per Scene
|
||||
void setProjectionMatrix(float32*);
|
||||
void setViewMatrix(float32*);
|
||||
|
||||
// per Object
|
||||
void setWorldMatrix(Matrix*);
|
||||
void setAmbientLight(RGBAf*);
|
||||
void setNumLights(int32 n);
|
||||
void setLight(int32 n, Light*);
|
||||
|
||||
// per Mesh
|
||||
void setTexture(int32 n, Texture *tex);
|
||||
void setVertexAlpha(bool32 enable);
|
||||
|
||||
class ObjPipeline : public rw::ObjPipeline
|
||||
{
|
||||
public:
|
||||
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
|
||||
|
||||
ObjPipeline(uint32 platform);
|
||||
};
|
||||
|
||||
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||
void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||
void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header);
|
||||
|
||||
ObjPipeline *makeDefaultPipeline(void);
|
||||
ObjPipeline *makeSkinPipeline(void);
|
||||
ObjPipeline *makeMatFXPipeline(void);
|
||||
|
||||
// Native Texture and Raster
|
||||
|
||||
extern int32 nativeRasterOffset;
|
||||
|
||||
struct Gl3Raster
|
||||
{
|
||||
uint32 texid;
|
||||
bool32 hasAlpha;
|
||||
};
|
||||
|
||||
void registerNativeRaster(void);
|
||||
|
||||
}
|
||||
}
|
||||
44
src/gl/rwgl3shader.h
Normal file
44
src/gl/rwgl3shader.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifdef RW_OPENGL
|
||||
|
||||
namespace rw {
|
||||
namespace gl3 {
|
||||
|
||||
// TODO: make this dynamic
|
||||
enum {
|
||||
MAX_UNIFORMS = 20,
|
||||
MAX_BLOCKS = 20
|
||||
};
|
||||
|
||||
struct UniformRegistry
|
||||
{
|
||||
int numUniforms;
|
||||
char *uniformNames[MAX_UNIFORMS];
|
||||
|
||||
int numBlocks;
|
||||
char *blockNames[MAX_BLOCKS];
|
||||
};
|
||||
|
||||
int registerUniform(const char *name);
|
||||
int findUniform(const char *name);
|
||||
int registerBlock(const char *name);
|
||||
int findBlock(const char *name);
|
||||
|
||||
extern UniformRegistry uniformRegistry;
|
||||
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
GLuint program;
|
||||
// same number of elements as UniformRegistry::numUniforms
|
||||
GLint *uniformLocations;
|
||||
|
||||
static Shader *fromFiles(const char *vs, const char *fs);
|
||||
void use(void);
|
||||
};
|
||||
|
||||
extern Shader *currentShader;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
83
src/gl/rwwdgl.h
Normal file
83
src/gl/rwwdgl.h
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
namespace rw {
|
||||
namespace wdgl {
|
||||
|
||||
// NOTE: This is not really RW OpenGL! It's specific to WarDrum's GTA ports
|
||||
|
||||
void initializePlatform(void);
|
||||
|
||||
struct AttribDesc
|
||||
{
|
||||
// arguments to glVertexAttribPointer (should use OpenGL types here)
|
||||
// Vertex = 0, TexCoord, Normal, Color, Weight, Bone Index, Extra Color
|
||||
uint32 index;
|
||||
// float = 0, byte, ubyte, short, ushort
|
||||
int32 type;
|
||||
bool32 normalized;
|
||||
int32 size;
|
||||
uint32 stride;
|
||||
uint32 offset;
|
||||
};
|
||||
|
||||
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||
{
|
||||
int32 numAttribs;
|
||||
AttribDesc *attribs;
|
||||
uint32 dataSize;
|
||||
uint8 *data;
|
||||
|
||||
// needed for rendering
|
||||
uint32 vbo;
|
||||
uint32 ibo;
|
||||
};
|
||||
|
||||
// only RW_OPENGL
|
||||
void uploadGeo(Geometry *geo);
|
||||
void setAttribPointers(InstanceDataHeader *inst);
|
||||
|
||||
void packattrib(uint8 *dst, float32 *src, AttribDesc *a, float32 scale);
|
||||
void unpackattrib(float *dst, uint8 *src, AttribDesc *a, float32 scale);
|
||||
|
||||
void *destroyNativeData(void *object, int32, int32);
|
||||
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||
int32 getSizeNativeData(void *object, int32, int32);
|
||||
void registerNativeDataPlugin(void);
|
||||
|
||||
void printPipeinfo(Atomic *a);
|
||||
|
||||
class ObjPipeline : public rw::ObjPipeline
|
||||
{
|
||||
public:
|
||||
uint32 numCustomAttribs;
|
||||
uint32 (*instanceCB)(Geometry *g, int32 i, uint32 offset);
|
||||
void (*uninstanceCB)(Geometry *g);
|
||||
|
||||
ObjPipeline(uint32 platform);
|
||||
};
|
||||
|
||||
ObjPipeline *makeDefaultPipeline(void);
|
||||
|
||||
// Skin plugin
|
||||
|
||||
Stream *readNativeSkin(Stream *stream, int32, void *object, int32 offset);
|
||||
Stream *writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset);
|
||||
int32 getSizeNativeSkin(void *object, int32 offset);
|
||||
|
||||
ObjPipeline *makeSkinPipeline(void);
|
||||
|
||||
ObjPipeline *makeMatFXPipeline(void);
|
||||
|
||||
// Raster
|
||||
|
||||
struct Texture : rw::Texture
|
||||
{
|
||||
void upload(void);
|
||||
void bind(int n);
|
||||
};
|
||||
|
||||
extern int32 nativeRasterOffset;
|
||||
void registerNativeRaster(void);
|
||||
|
||||
}
|
||||
}
|
||||
793
src/gl/wdgl.cpp
Normal file
793
src/gl/wdgl.cpp
Normal file
@@ -0,0 +1,793 @@
|
||||
#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"
|
||||
#include "../rwplugins.h"
|
||||
#include "rwwdgl.h"
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
#include <GL/glew.h>
|
||||
#endif
|
||||
|
||||
#define PLUGIN_ID 2
|
||||
|
||||
namespace rw {
|
||||
namespace wdgl {
|
||||
|
||||
void
|
||||
initializePlatform(void)
|
||||
{
|
||||
driver[PLATFORM_WDGL].defaultPipeline = makeDefaultPipeline();
|
||||
}
|
||||
|
||||
|
||||
// VC
|
||||
// 8733 0 0 0 3
|
||||
// 45 1 0 0 2
|
||||
// 8657 1 3 0 2
|
||||
// 4610 2 1 1 3
|
||||
// 4185 3 2 1 4
|
||||
// 256 4 2 1 4
|
||||
// 201 4 4 1 4
|
||||
// 457 5 2 0 4
|
||||
|
||||
// SA
|
||||
// 20303 0 0 0 3 vertices: 3 floats
|
||||
// 53 1 0 0 2 texCoords: 2 floats
|
||||
// 20043 1 3 0 2 texCoords: 2 shorts
|
||||
// 6954 2 1 1 3 normal: 3 bytes normalized
|
||||
// 13527 3 2 1 4 color: 4 ubytes normalized
|
||||
// 196 4 2 1 4 weight: 4 ubytes normalized
|
||||
// 225 4 4 1 4 weight: 4 ushorts normalized
|
||||
// 421 5 2 0 4 indices: 4 ubytes
|
||||
// 12887 6 2 1 4 extracolor:4 ubytes normalized
|
||||
|
||||
/*
|
||||
static void
|
||||
printAttribInfo(AttribDesc *attribs, int n)
|
||||
{
|
||||
for(int i = 0; i < n; i++)
|
||||
printf("%x %x %x %x\n",
|
||||
attribs[i].index,
|
||||
attribs[i].type,
|
||||
attribs[i].normalized,
|
||||
attribs[i].size);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
void
|
||||
uploadGeo(Geometry *geo)
|
||||
{
|
||||
InstanceDataHeader *inst = (InstanceDataHeader*)geo->instData;
|
||||
MeshHeader *meshHeader = geo->meshHeader;
|
||||
|
||||
glGenBuffers(1, &inst->vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, inst->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, inst->dataSize,
|
||||
inst->data, GL_STATIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &inst->ibo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, inst->ibo);
|
||||
glBufferData(GL_ARRAY_BUFFER, meshHeader->totalIndices*2,
|
||||
0, GL_STATIC_DRAW);
|
||||
GLintptr offset = 0;
|
||||
for(uint32 i = 0; i < meshHeader->numMeshes; i++){
|
||||
Mesh *mesh = &meshHeader->mesh[i];
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offset, mesh->numIndices*2,
|
||||
mesh->indices);
|
||||
offset += mesh->numIndices*2;
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void
|
||||
setAttribPointers(InstanceDataHeader *inst)
|
||||
{
|
||||
static GLenum attribType[] = {
|
||||
GL_FLOAT,
|
||||
GL_BYTE, GL_UNSIGNED_BYTE,
|
||||
GL_SHORT, GL_UNSIGNED_SHORT
|
||||
};
|
||||
for(int32 i = 0; i < inst->numAttribs; i++){
|
||||
AttribDesc *a = &inst->attribs[i];
|
||||
glEnableVertexAttribArray(a->index);
|
||||
glVertexAttribPointer(a->index, a->size, attribType[a->type],
|
||||
a->normalized, a->stride,
|
||||
(void*)(uint64)a->offset);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
packattrib(uint8 *dst, float32 *src, AttribDesc *a, float32 scale=1.0f)
|
||||
{
|
||||
int8 *i8dst;
|
||||
uint16 *u16dst;
|
||||
int16 *i16dst;
|
||||
|
||||
switch(a->type){
|
||||
case 0: // float
|
||||
memcpy(dst, src, a->size*4);
|
||||
break;
|
||||
|
||||
// TODO: maybe have loop inside if?
|
||||
case 1: // byte
|
||||
i8dst = (int8*)dst;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
i8dst[i] = src[i]*scale;
|
||||
else
|
||||
i8dst[i] = src[i]*127.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // ubyte
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
dst[i] = src[i]*scale;
|
||||
else
|
||||
dst[i] = src[i]*255.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // short
|
||||
i16dst = (int16*)dst;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
i16dst[i] = src[i]*scale;
|
||||
else
|
||||
i16dst[i] = src[i]*32767.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // ushort
|
||||
u16dst = (uint16*)dst;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
u16dst[i] = src[i]*scale;
|
||||
else
|
||||
u16dst[i] = src[i]*65535.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unpackattrib(float *dst, uint8 *src, AttribDesc *a, float32 scale=1.0f)
|
||||
{
|
||||
int8 *i8src;
|
||||
uint16 *u16src;
|
||||
int16 *i16src;
|
||||
|
||||
switch(a->type){
|
||||
case 0: // float
|
||||
memcpy(dst, src, a->size*4);
|
||||
break;
|
||||
|
||||
// TODO: maybe have loop inside if?
|
||||
case 1: // byte
|
||||
i8src = (int8*)src;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
dst[i] = i8src[i]/scale;
|
||||
else
|
||||
dst[i] = i8src[i]/127.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // ubyte
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
dst[i] = src[i]/scale;
|
||||
else
|
||||
dst[i] = src[i]/255.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // short
|
||||
i16src = (int16*)src;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
dst[i] = i16src[i]/scale;
|
||||
else
|
||||
dst[i] = i16src[i]/32767.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // ushort
|
||||
u16src = (uint16*)src;
|
||||
for(int i = 0; i < a->size; i++){
|
||||
if(!a->normalized)
|
||||
dst[i] = u16src[i]/scale;
|
||||
else
|
||||
dst[i] = u16src[i]/65435.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
destroyNativeData(void *object, int32, int32)
|
||||
{
|
||||
Geometry *geometry = (Geometry*)object;
|
||||
if(geometry->instData == nil ||
|
||||
geometry->instData->platform != PLATFORM_WDGL)
|
||||
return object;
|
||||
InstanceDataHeader *header =
|
||||
(InstanceDataHeader*)geometry->instData;
|
||||
geometry->instData = nil;
|
||||
// TODO: delete ibo and vbo
|
||||
delete[] header->attribs;
|
||||
delete[] header->data;
|
||||
delete header;
|
||||
return object;
|
||||
}
|
||||
|
||||
Stream*
|
||||
readNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||
{
|
||||
Geometry *geometry = (Geometry*)object;
|
||||
InstanceDataHeader *header = new InstanceDataHeader;
|
||||
geometry->instData = header;
|
||||
header->platform = PLATFORM_WDGL;
|
||||
header->vbo = 0;
|
||||
header->ibo = 0;
|
||||
header->numAttribs = stream->readU32();
|
||||
header->attribs = new AttribDesc[header->numAttribs];
|
||||
stream->read(header->attribs,
|
||||
header->numAttribs*sizeof(AttribDesc));
|
||||
header->dataSize = header->attribs[0].stride*geometry->numVertices;
|
||||
header->data = new uint8[header->dataSize];
|
||||
stream->read(header->data, header->dataSize);
|
||||
return stream;
|
||||
}
|
||||
|
||||
Stream*
|
||||
writeNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||
{
|
||||
Geometry *geometry = (Geometry*)object;
|
||||
if(geometry->instData == nil ||
|
||||
geometry->instData->platform != PLATFORM_WDGL)
|
||||
return stream;
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||
stream->writeU32(header->numAttribs);
|
||||
stream->write(header->attribs, header->numAttribs*sizeof(AttribDesc));
|
||||
stream->write(header->data, header->dataSize);
|
||||
return stream;
|
||||
}
|
||||
|
||||
int32
|
||||
getSizeNativeData(void *object, int32, int32)
|
||||
{
|
||||
Geometry *geometry = (Geometry*)object;
|
||||
if(geometry->instData == nil ||
|
||||
geometry->instData->platform != PLATFORM_WDGL)
|
||||
return 0;
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||
return 4 + header->numAttribs*sizeof(AttribDesc) + header->dataSize;
|
||||
}
|
||||
|
||||
void
|
||||
registerNativeDataPlugin(void)
|
||||
{
|
||||
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
||||
nil, destroyNativeData, nil);
|
||||
Geometry::registerPluginStream(ID_NATIVEDATA,
|
||||
readNativeData,
|
||||
writeNativeData,
|
||||
getSizeNativeData);
|
||||
}
|
||||
|
||||
void
|
||||
printPipeinfo(Atomic *a)
|
||||
{
|
||||
Geometry *g = a->geometry;
|
||||
if(g->instData == nil || g->instData->platform != PLATFORM_WDGL)
|
||||
return;
|
||||
int32 plgid = 0;
|
||||
if(a->pipeline)
|
||||
plgid = a->pipeline->pluginID;
|
||||
printf("%s %x: ", debugFile, plgid);
|
||||
InstanceDataHeader *h = (InstanceDataHeader*)g->instData;
|
||||
for(int i = 0; i < h->numAttribs; i++)
|
||||
printf("%x(%x) ", h->attribs[i].index, h->attribs[i].type);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||
{
|
||||
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||
Geometry *geo = atomic->geometry;
|
||||
if(geo->geoflags & Geometry::NATIVE)
|
||||
return;
|
||||
InstanceDataHeader *header = new InstanceDataHeader;
|
||||
geo->instData = header;
|
||||
header->platform = PLATFORM_WDGL;
|
||||
header->vbo = 0;
|
||||
header->ibo = 0;
|
||||
header->numAttribs =
|
||||
pipe->numCustomAttribs + 1 + (geo->numTexCoordSets > 0);
|
||||
if(geo->geoflags & Geometry::PRELIT)
|
||||
header->numAttribs++;
|
||||
if(geo->geoflags & Geometry::NORMALS)
|
||||
header->numAttribs++;
|
||||
int32 offset = 0;
|
||||
header->attribs = new AttribDesc[header->numAttribs];
|
||||
|
||||
AttribDesc *a = header->attribs;
|
||||
// Vertices
|
||||
a->index = 0;
|
||||
a->type = 0;
|
||||
a->normalized = 0;
|
||||
a->size = 3;
|
||||
a->offset = offset;
|
||||
offset += 12;
|
||||
a++;
|
||||
int32 firstCustom = 1;
|
||||
|
||||
// texCoords, only one set here
|
||||
if(geo->numTexCoordSets){
|
||||
a->index = 1;
|
||||
a->type = 3;
|
||||
a->normalized = 0;
|
||||
a->size = 2;
|
||||
a->offset = offset;
|
||||
offset += 4;
|
||||
a++;
|
||||
firstCustom++;
|
||||
}
|
||||
|
||||
if(geo->geoflags & Geometry::NORMALS){
|
||||
a->index = 2;
|
||||
a->type = 1;
|
||||
a->normalized = 1;
|
||||
a->size = 3;
|
||||
a->offset = offset;
|
||||
offset += 4;
|
||||
a++;
|
||||
firstCustom++;
|
||||
}
|
||||
|
||||
if(geo->geoflags & Geometry::PRELIT){
|
||||
a->index = 3;
|
||||
a->type = 2;
|
||||
a->normalized = 1;
|
||||
a->size = 4;
|
||||
a->offset = offset;
|
||||
offset += 4;
|
||||
a++;
|
||||
firstCustom++;
|
||||
}
|
||||
|
||||
if(pipe->instanceCB)
|
||||
offset += pipe->instanceCB(geo, firstCustom, offset);
|
||||
else{
|
||||
header->dataSize = offset*geo->numVertices;
|
||||
header->data = new uint8[header->dataSize];
|
||||
}
|
||||
|
||||
a = header->attribs;
|
||||
for(int32 i = 0; i < header->numAttribs; i++)
|
||||
a[i].stride = offset;
|
||||
|
||||
uint8 *p = header->data + a->offset;
|
||||
float32 *vert = geo->morphTargets->vertices;
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
packattrib(p, vert, a);
|
||||
vert += 3;
|
||||
p += a->stride;
|
||||
}
|
||||
a++;
|
||||
|
||||
if(geo->numTexCoordSets){
|
||||
p = header->data + a->offset;
|
||||
float32 *texcoord = geo->texCoords[0];
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
packattrib(p, texcoord, a, 512.0f);
|
||||
texcoord += 2;
|
||||
p += a->stride;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
|
||||
if(geo->geoflags & Geometry::NORMALS){
|
||||
p = header->data + a->offset;
|
||||
float32 *norm = geo->morphTargets->normals;
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
packattrib(p, norm, a);
|
||||
norm += 3;
|
||||
p += a->stride;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
|
||||
if(geo->geoflags & Geometry::PRELIT){
|
||||
// TODO: this seems too complicated
|
||||
p = header->data + a->offset;
|
||||
uint8 *color = geo->colors;
|
||||
float32 f[4];
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
f[0] = color[0]/255.0f;
|
||||
f[1] = color[1]/255.0f;
|
||||
f[2] = color[2]/255.0f;
|
||||
f[3] = color[3]/255.0f;
|
||||
packattrib(p, f, a);
|
||||
color += 4;
|
||||
p += a->stride;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
geo->geoflags |= Geometry::NATIVE;
|
||||
}
|
||||
|
||||
static void
|
||||
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||
{
|
||||
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||
Geometry *geo = atomic->geometry;
|
||||
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||
return;
|
||||
assert(geo->instData != nil);
|
||||
assert(geo->instData->platform == PLATFORM_WDGL);
|
||||
geo->geoflags &= ~Geometry::NATIVE;
|
||||
geo->allocateData();
|
||||
|
||||
uint8 *p;
|
||||
float32 *texcoord = geo->texCoords[0];
|
||||
uint8 *color = geo->colors;
|
||||
float32 *vert = geo->morphTargets->vertices;
|
||||
float32 *norm = geo->morphTargets->normals;
|
||||
float32 f[4];
|
||||
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||
for(int i = 0; i < header->numAttribs; i++){
|
||||
AttribDesc *a = &header->attribs[i];
|
||||
p = header->data + a->offset;
|
||||
|
||||
switch(a->index){
|
||||
case 0: // Vertices
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
unpackattrib(vert, p, a);
|
||||
vert += 3;
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // texCoords
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
unpackattrib(texcoord, p, a, 512.0f);
|
||||
texcoord += 2;
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // normals
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
unpackattrib(norm, p, a);
|
||||
norm += 3;
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // colors
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
// TODO: this seems too complicated
|
||||
unpackattrib(f, p, a);
|
||||
color[0] = f[0]*255.0f;
|
||||
color[1] = f[1]*255.0f;
|
||||
color[2] = f[2]*255.0f;
|
||||
color[3] = f[3]*255.0f;
|
||||
color += 4;
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pipe->uninstanceCB)
|
||||
pipe->uninstanceCB(geo);
|
||||
|
||||
geo->generateTriangles();
|
||||
|
||||
destroyNativeData(geo, 0, 0);
|
||||
}
|
||||
|
||||
ObjPipeline::ObjPipeline(uint32 platform)
|
||||
: rw::ObjPipeline(platform)
|
||||
{
|
||||
this->numCustomAttribs = 0;
|
||||
this->impl.instance = wdgl::instance;
|
||||
this->impl.uninstance = wdgl::uninstance;
|
||||
this->instanceCB = nil;
|
||||
this->uninstanceCB = nil;
|
||||
}
|
||||
|
||||
ObjPipeline*
|
||||
makeDefaultPipeline(void)
|
||||
{
|
||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||
return pipe;
|
||||
}
|
||||
|
||||
// Skin
|
||||
|
||||
Stream*
|
||||
readNativeSkin(Stream *stream, int32, void *object, int32 offset)
|
||||
{
|
||||
Geometry *geometry = (Geometry*)object;
|
||||
uint32 platform;
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return nil;
|
||||
}
|
||||
platform = stream->readU32();
|
||||
if(platform != PLATFORM_GL){
|
||||
RWERROR((ERR_PLATFORM, platform));
|
||||
return nil;
|
||||
}
|
||||
Skin *skin = new Skin;
|
||||
*PLUGINOFFSET(Skin*, geometry, offset) = skin;
|
||||
|
||||
int32 numBones = stream->readI32();
|
||||
skin->init(numBones, 0, 0);
|
||||
stream->read(skin->inverseMatrices, skin->numBones*64);
|
||||
return stream;
|
||||
}
|
||||
|
||||
Stream*
|
||||
writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset)
|
||||
{
|
||||
writeChunkHeader(stream, ID_STRUCT, len-12);
|
||||
stream->writeU32(PLATFORM_WDGL);
|
||||
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||
stream->writeI32(skin->numBones);
|
||||
stream->write(skin->inverseMatrices, skin->numBones*64);
|
||||
return stream;
|
||||
}
|
||||
|
||||
int32
|
||||
getSizeNativeSkin(void *object, int32 offset)
|
||||
{
|
||||
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||
if(skin == nil)
|
||||
return -1;
|
||||
int32 size = 12 + 4 + 4 + skin->numBones*64;
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32
|
||||
skinInstanceCB(Geometry *g, int32 i, uint32 offset)
|
||||
{
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)g->instData;
|
||||
AttribDesc *a = &header->attribs[i];
|
||||
// weights
|
||||
a->index = 4;
|
||||
a->type = 2; /* but also short o_O */
|
||||
a->normalized = 1;
|
||||
a->size = 4;
|
||||
a->offset = offset;
|
||||
offset += 4;
|
||||
a++;
|
||||
|
||||
// indices
|
||||
a->index = 5;
|
||||
a->type = 2;
|
||||
a->normalized = 0;
|
||||
a->size = 4;
|
||||
a->offset = offset;
|
||||
offset += 4;
|
||||
|
||||
header->dataSize = offset*g->numVertices;
|
||||
header->data = new uint8[header->dataSize];
|
||||
|
||||
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
||||
if(skin == nil)
|
||||
return 8;
|
||||
|
||||
a = &header->attribs[i];
|
||||
uint8 *wgt = header->data + a[0].offset;
|
||||
uint8 *idx = header->data + a[1].offset;
|
||||
uint8 *indices = skin->indices;
|
||||
float32 *weights = skin->weights;
|
||||
for(int32 i = 0; i < g->numVertices; i++){
|
||||
packattrib(wgt, weights, a);
|
||||
weights += 4;
|
||||
wgt += offset;
|
||||
idx[0] = *indices++;
|
||||
idx[1] = *indices++;
|
||||
idx[2] = *indices++;
|
||||
idx[3] = *indices++;
|
||||
idx += offset;
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
void
|
||||
skinUninstanceCB(Geometry *geo)
|
||||
{
|
||||
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||
|
||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
||||
if(skin == nil)
|
||||
return;
|
||||
|
||||
uint8 *data = skin->data;
|
||||
float *invMats = skin->inverseMatrices;
|
||||
skin->init(skin->numBones, skin->numBones, geo->numVertices);
|
||||
memcpy(skin->inverseMatrices, invMats, skin->numBones*64);
|
||||
delete[] data;
|
||||
|
||||
uint8 *p;
|
||||
float *weights = skin->weights;
|
||||
uint8 *indices = skin->indices;
|
||||
for(int i = 0; i < header->numAttribs; i++){
|
||||
AttribDesc *a = &header->attribs[i];
|
||||
p = header->data + a->offset;
|
||||
|
||||
switch(a->index){
|
||||
case 4: // weights
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
unpackattrib(weights, p, a);
|
||||
weights += 4;
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // indices
|
||||
for(int32 i = 0; i < geo->numVertices; i++){
|
||||
*indices++ = p[0];
|
||||
*indices++ = p[1];
|
||||
*indices++ = p[2];
|
||||
*indices++ = p[3];
|
||||
p += a->stride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
skin->findNumWeights(geo->numVertices);
|
||||
skin->findUsedBones(geo->numVertices);
|
||||
}
|
||||
|
||||
ObjPipeline*
|
||||
makeSkinPipeline(void)
|
||||
{
|
||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||
pipe->pluginID = ID_SKIN;
|
||||
pipe->pluginData = 1;
|
||||
pipe->numCustomAttribs = 2;
|
||||
pipe->instanceCB = skinInstanceCB;
|
||||
pipe->uninstanceCB = skinUninstanceCB;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
ObjPipeline*
|
||||
makeMatFXPipeline(void)
|
||||
{
|
||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||
pipe->pluginID = ID_MATFX;
|
||||
pipe->pluginData = 0;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
// Raster
|
||||
|
||||
int32 nativeRasterOffset;
|
||||
|
||||
#ifdef RW_OPENGL
|
||||
struct GlRaster {
|
||||
GLuint id;
|
||||
};
|
||||
|
||||
static void*
|
||||
createNativeRaster(void *object, int32 offset, int32)
|
||||
{
|
||||
GlRaster *raster = PLUGINOFFSET(GlRaster, object, offset);
|
||||
raster->id = 0;
|
||||
return object;
|
||||
}
|
||||
|
||||
static void*
|
||||
destroyNativeRaster(void *object, int32 offset, int32)
|
||||
{
|
||||
// TODO:
|
||||
return object;
|
||||
}
|
||||
|
||||
static void*
|
||||
copyNativeRaster(void *dst, void *, int32 offset, int32)
|
||||
{
|
||||
GlRaster *raster = PLUGINOFFSET(GlRaster, dst, offset);
|
||||
raster->id = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void
|
||||
registerNativeRaster(void)
|
||||
{
|
||||
nativeRasterOffset = Raster::registerPlugin(sizeof(GlRaster),
|
||||
0x12340000 | PLATFORM_WDGL,
|
||||
createNativeRaster,
|
||||
destroyNativeRaster,
|
||||
copyNativeRaster);
|
||||
}
|
||||
|
||||
void
|
||||
Texture::upload(void)
|
||||
{
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
Raster *r = this->raster;
|
||||
if(r->palette){
|
||||
printf("can't upload paletted raster\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static GLenum filter[] = {
|
||||
0, GL_NEAREST, GL_LINEAR,
|
||||
GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
|
||||
GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR
|
||||
};
|
||||
static GLenum filternomip[] = {
|
||||
0, GL_NEAREST, GL_LINEAR,
|
||||
GL_NEAREST, GL_LINEAR,
|
||||
GL_NEAREST, GL_LINEAR
|
||||
};
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
filternomip[this->filterAddressing & 0xFF]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
filternomip[this->filterAddressing & 0xFF]);
|
||||
|
||||
static GLenum wrap[] = {
|
||||
0, GL_REPEAT, GL_MIRRORED_REPEAT,
|
||||
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
|
||||
};
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
wrap[(this->filterAddressing >> 8) & 0xF]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
wrap[(this->filterAddressing >> 12) & 0xF]);
|
||||
|
||||
switch(r->format & 0xF00){
|
||||
case Raster::C8888:
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, 4, r->width, r->height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, r->texels);
|
||||
break;
|
||||
default:
|
||||
printf("unsupported raster format: %x\n", r->format);
|
||||
break;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
GlRaster *glr = PLUGINOFFSET(GlRaster, r, nativeRasterOffset);
|
||||
glr->id = id;
|
||||
}
|
||||
|
||||
void
|
||||
Texture::bind(int n)
|
||||
{
|
||||
Raster *r = this->raster;
|
||||
GlRaster *glr = PLUGINOFFSET(GlRaster, r, nativeRasterOffset);
|
||||
glActiveTexture(GL_TEXTURE0+n);
|
||||
if(r){
|
||||
if(glr->id == 0)
|
||||
this->upload();
|
||||
glBindTexture(GL_TEXTURE_2D, glr->id);
|
||||
}else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user