STARK: Abstract out the actor rendering

This commit is contained in:
Bastien Bouclet 2015-02-21 09:11:35 +01:00
parent ca697468c2
commit e6d842e8a4
9 changed files with 326 additions and 218 deletions

View File

@ -29,6 +29,9 @@
#include "math/vector3d.h"
namespace Stark {
class VisualActor;
namespace Gfx {
class Texture;
@ -57,6 +60,14 @@ public:
*/
virtual Texture *createTexture(const Graphics::Surface *surface = nullptr, const byte *palette = nullptr) = 0;
/**
* Create a new actor renderer
*
* The caller is responsible for freeing it.
*
*/
virtual VisualActor *createActorRenderer() = 0;
/**
* Draw a 2D surface from the specified texture
*/

View File

@ -28,11 +28,12 @@
#include "math/matrix4.h"
#include "engines/stark/gfx/openglsactor.h"
#include "engines/stark/gfx/opengltexture.h"
#ifdef USE_OPENGL
#include "graphics/opengles2/shader.h"
#include "graphics/opengles2/system_headers.h"
namespace Stark {
namespace Gfx {
@ -84,6 +85,10 @@ Texture *OpenGLDriver::createTexture(const Graphics::Surface *surface, const byt
return texture;
}
VisualActor *OpenGLDriver::createActorRenderer() {
return new OpenGLSActorRenderer();
}
void OpenGLDriver::drawSurface(const Texture *texture, const Common::Point &dest) {
// Source texture rectangle
const float tLeft = 0.0;

View File

@ -49,6 +49,7 @@ public:
void flipBuffer();
Texture *createTexture(const Graphics::Surface *surface = nullptr, const byte *palette = nullptr) override;
VisualActor *createActorRenderer() override;
void drawSurface(const Texture *texture, const Common::Point &dest) override;

View File

@ -0,0 +1,235 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "engines/stark/gfx/openglsactor.h"
#include "engines/stark/actor.h"
#include "engines/stark/scene.h"
#include "engines/stark/services/services.h"
#include "engines/stark/skeleton.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/texture.h"
#include "common/archive.h"
#include "common/stream.h"
#include "graphics/opengles2/shader.h"
namespace Stark {
namespace Gfx {
OpenGLSActorRenderer::OpenGLSActorRenderer() :
VisualActor() {
static const char* attributes[] = { "position1", "position2", "bone1", "bone2", "boneWeight", "texcoord", NULL };
_shader = Graphics::Shader::fromFiles("stark_actor", attributes);
}
OpenGLSActorRenderer::~OpenGLSActorRenderer() {
clearVertices();
delete _shader;
}
Common::String OpenGLSActorRenderer::faceHash(const FaceNode *face) const {
return Common::String::format("%p", (const void *) face);
}
void OpenGLSActorRenderer::render(Gfx::Driver *gfx, const Math::Vector3d position, float direction) {
Scene *scene = StarkServices::instance().scene;
if (_meshIsDirty) {
// Update the OpenGL Buffer Objects if required
clearVertices();
uploadVertices();
_meshIsDirty = false;
}
_actor->getSkeleton()->animate(_time);
gfx->set3DMode();
Math::Matrix4 model = getModelMatrix(position, direction);
Math::Matrix4 view = scene->getViewMatrix();
Math::Matrix4 projection = scene->getProjectionMatrix();
Math::Matrix4 mvp = projection * view * model;
mvp.transpose();
_shader->use(true);
_shader->setUniform("mvp", mvp);
setBoneRotationArrayUniform("boneRotation");
setBonePositionArrayUniform("bonePosition");
Common::Array<MeshNode *> meshes = _actor->getMeshes();
Common::Array<MaterialNode *> mats = _actor->getMaterials();
const Gfx::TextureSet *texture = _actor->getTextureSet();
for (Common::Array<MeshNode *>::iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
for (Common::Array<FaceNode *>::iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
// For each face draw its vertices from the VBO, indexed by the EBO
const Gfx::Texture *tex = texture->getTexture(mats[(*face)->_matIdx]->_texName);
if (tex) {
tex->bind();
} else {
glBindTexture(GL_TEXTURE_2D, 0);
}
GLuint vbo = _faceVBO[faceHash(*face)];
GLuint ebo = _faceEBO[faceHash(*face)];
_shader->enableVertexAttribute("position1", vbo, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0);
_shader->enableVertexAttribute("position2", vbo, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 12);
_shader->enableIntegerVertexAttribute("bone1", vbo, 1, GL_INT, 11 * sizeof(float), 24);
_shader->enableIntegerVertexAttribute("bone2", vbo, 1, GL_INT, 11 * sizeof(float), 28);
_shader->enableVertexAttribute("boneWeight", vbo, 1, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 32);
_shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 36);
_shader->use(true);
_shader->setUniform("textured", tex != nullptr);
_shader->setUniform("color", Math::Vector3d(mats[(*face)->_matIdx]->_r, mats[(*face)->_matIdx]->_g, mats[(*face)->_matIdx]->_b));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glDrawElements(GL_TRIANGLES, 3 * (*face)->_tris.size(), GL_UNSIGNED_INT, 0);
glUseProgram(0);
}
}
}
void OpenGLSActorRenderer::clearVertices() {
for (Common::HashMap<Common::String, uint32>::iterator it = _faceVBO.begin(); it != _faceVBO.end(); ++it) {
Graphics::Shader::freeBuffer(it->_value);
}
for (Common::HashMap<Common::String, uint32>::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
Graphics::Shader::freeBuffer(it->_value);
}
_faceVBO.clear();
_faceEBO.clear();
}
void OpenGLSActorRenderer::uploadVertices() {
Common::Array<MeshNode *> meshes = _actor->getMeshes();
for (Common::Array<MeshNode *>::const_iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
for (Common::Array<FaceNode *>::const_iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
_faceVBO[faceHash(*face)] = createFaceVBO(*face);
_faceEBO[faceHash(*face)] = createFaceEBO(*face);
}
}
}
uint32 OpenGLSActorRenderer::createFaceVBO(const FaceNode *face) {
float *vertices = new float[11 * face->_verts.size()];
float *vertPtr = vertices;
// Build a vertex array
for (Common::Array<VertNode *>::const_iterator tri = face->_verts.begin(); tri != face->_verts.end(); ++tri) {
*vertPtr++ = (*tri)->_pos1.x();
*vertPtr++ = (*tri)->_pos1.y();
*vertPtr++ = (*tri)->_pos1.z();
*vertPtr++ = (*tri)->_pos2.x();
*vertPtr++ = (*tri)->_pos2.y();
*vertPtr++ = (*tri)->_pos2.z();
*(uint32 *)vertPtr++ = (*tri)->_bone1;
*(uint32 *)vertPtr++ = (*tri)->_bone2;
*vertPtr++ = (*tri)->_boneWeight;
*vertPtr++ = -(*tri)->_texS;
*vertPtr++ = (*tri)->_texT;
}
uint32 vbo = Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 11 * face->_verts.size(), vertices);
delete[] vertices;
return vbo;
}
uint32 OpenGLSActorRenderer::createFaceEBO(const FaceNode *face) {
uint32 *indices = new uint32[3 * face->_tris.size()];
uint32 *idxPtr = indices;
// Build a vertex indices array
for (Common::Array<TriNode *>::const_iterator tri = face->_tris.begin(); tri != face->_tris.end(); ++tri) {
for (int vert = 0; vert < 3; ++vert) {
if (vert == 0)
*idxPtr++ = (*tri)->_vert1;
else if (vert == 1)
*idxPtr++ = (*tri)->_vert2;
else
*idxPtr++ = (*tri)->_vert3;
}
}
uint32 ebo = Graphics::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * 3 * face->_tris.size(), indices);
delete[] indices;
return ebo;
}
void OpenGLSActorRenderer::setBonePositionArrayUniform(const char *uniform) {
const Common::Array<BoneNode *> bones = _actor->getSkeleton()->getBones();
GLint pos = _shader->getUniformLocation(uniform);
if (pos == -1) {
error("No uniform named '%s'", uniform);
}
float *positions = new float[3 * bones.size()];
float *positionsPtr = positions;
for (uint i = 0; i < bones.size(); i++) {
*positionsPtr++ = bones[i]->_animPos.x();
*positionsPtr++ = bones[i]->_animPos.y();
*positionsPtr++ = bones[i]->_animPos.z();
}
glUniform3fv(pos, bones.size(), positions);
delete[] positions;
}
void OpenGLSActorRenderer::setBoneRotationArrayUniform(const char *uniform) {
const Common::Array<BoneNode *> bones = _actor->getSkeleton()->getBones();
GLint rot = _shader->getUniformLocation(uniform);
if (rot == -1) {
error("No uniform named '%s'", uniform);
}
float *rotations = new float[4 * bones.size()];
float *rotationsPtr = rotations;
for (uint i = 0; i < bones.size(); i++) {
*rotationsPtr++ = bones[i]->_animRot.x();
*rotationsPtr++ = bones[i]->_animRot.y();
*rotationsPtr++ = bones[i]->_animRot.z();
*rotationsPtr++ = bones[i]->_animRot.w();
}
glUniform4fv(rot, bones.size(), rotations);
delete[] rotations;
}
} // End of namespace Gfx
} // End of namespace Stark

View File

@ -0,0 +1,63 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef STARK_GFX_OPENGL_S_ACTOR_H
#define STARK_GFX_OPENGL_S_ACTOR_H
#include "common/hash-str.h"
#include "common/str.h"
#include "engines/stark/visual/actor.h"
namespace Graphics {
class Shader;
}
namespace Stark {
namespace Gfx {
class OpenGLSActorRenderer : public VisualActor {
public:
OpenGLSActorRenderer();
virtual ~OpenGLSActorRenderer();
void render(Gfx::Driver *gfx, const Math::Vector3d position, float direction) override;
protected:
Graphics::Shader *_shader;
Common::HashMap<Common::String, uint32> _faceVBO;
Common::HashMap<Common::String, uint32> _faceEBO;
Common::String faceHash(const FaceNode *face) const;
void clearVertices();
void uploadVertices();
uint32 createFaceVBO(const FaceNode *face);
uint32 createFaceEBO(const FaceNode *face);
void setBonePositionArrayUniform(const char *uniform);
void setBoneRotationArrayUniform(const char *uniform);
};
} // End of namespace Gfx
} // End of namespace Stark
#endif // STARK_GFX_OPENGL_S_ACTOR_H

View File

@ -6,6 +6,7 @@ MODULE_OBJS := \
detection.o \
gfx/driver.o \
gfx/opengl.o \
gfx/openglsactor.o \
gfx/opengltexture.o \
gfx/renderentry.o \
gfx/texture.o \

View File

@ -23,6 +23,7 @@
#include "common/debug.h"
#include "engines/stark/formats/xrc.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/anim.h"
#include "engines/stark/resources/bonesmesh.h"
#include "engines/stark/resources/direction.h"
@ -249,7 +250,8 @@ AnimSkeleton::AnimSkeleton(Object *parent, byte subType, uint16 index, const Com
_seletonAnim(nullptr),
_currentTime(0),
_totalTime(0) {
_visual = new VisualActor();
Gfx::Driver *gfx = StarkServices::instance().gfx;
_visual = gfx->createActorRenderer();
}
void AnimSkeleton::applyToItem(Item *item) {

View File

@ -23,31 +23,20 @@
#include "engines/stark/visual/actor.h"
#include "engines/stark/actor.h"
#include "engines/stark/scene.h"
#include "engines/stark/services/services.h"
#include "engines/stark/skeleton.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/texture.h"
#include "common/archive.h"
#include "common/stream.h"
#include "graphics/opengles2/shader.h" // HACK: I just want to see something
namespace Stark {
VisualActor::VisualActor() :
Visual(TYPE),
_actor(nullptr),
_time(0) {
static const char* attributes[] = { "position1", "position2", "bone1", "bone2", "boneWeight", "texcoord", NULL };
_shader = Graphics::Shader::fromFiles("stark_actor", attributes);
_time(0),
_meshIsDirty(true) {
}
VisualActor::~VisualActor() {
clearVertices();
delete _shader;
}
void VisualActor::setMesh(Actor *mesh) {
@ -56,9 +45,7 @@ void VisualActor::setMesh(Actor *mesh) {
}
_actor = mesh;
clearVertices();
uploadVertices();
_meshIsDirty = true;
}
void VisualActor::setAnim(SkeletonAnim *anim) {
@ -73,10 +60,6 @@ void VisualActor::setTime(uint32 time) {
_time = time;
}
Common::String VisualActor::faceHash(const FaceNode *face) const {
return Common::String::format("%p", (const void *) face);
}
Math::Matrix4 VisualActor::getModelMatrix(const Math::Vector3d& position, float direction) {
Math::Matrix4 model;
@ -94,177 +77,4 @@ Math::Matrix4 VisualActor::getModelMatrix(const Math::Vector3d& position, float
return model;
}
void VisualActor::render(Gfx::Driver *gfx, const Math::Vector3d position, float direction) {
Scene *scene = StarkServices::instance().scene;
_actor->getSkeleton()->animate(_time);
// Prepare vertex list and push to gfx driver
// HACK: Purely because I just want to see something for now
gfx->set3DMode();
Math::Matrix4 model = getModelMatrix(position, direction);
Math::Matrix4 view = scene->getViewMatrix();
Math::Matrix4 projection = scene->getProjectionMatrix();
Math::Matrix4 mvp = projection * view * model;
mvp.transpose();
_shader->use(true);
_shader->setUniform("mvp", mvp);
setBoneRotationArrayUniform("boneRotation");
setBonePositionArrayUniform("bonePosition");
Common::Array<MeshNode *> meshes = _actor->getMeshes();
Common::Array<MaterialNode *> mats = _actor->getMaterials();
const Gfx::TextureSet *texture = _actor->getTextureSet();
for (Common::Array<MeshNode *>::iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
for (Common::Array<FaceNode *>::iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
// For each face draw its vertices from the VBO, indexed by the EBO
const Gfx::Texture *tex = texture->getTexture(mats[(*face)->_matIdx]->_texName);
if (tex) {
tex->bind();
} else {
glBindTexture(GL_TEXTURE_2D, 0);
}
GLuint vbo = _faceVBO[faceHash(*face)];
GLuint ebo = _faceEBO[faceHash(*face)];
_shader->enableVertexAttribute("position1", vbo, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0);
_shader->enableVertexAttribute("position2", vbo, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 12);
_shader->enableIntegerVertexAttribute("bone1", vbo, 1, GL_INT, 11 * sizeof(float), 24);
_shader->enableIntegerVertexAttribute("bone2", vbo, 1, GL_INT, 11 * sizeof(float), 28);
_shader->enableVertexAttribute("boneWeight", vbo, 1, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 32);
_shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 36);
_shader->use(true);
_shader->setUniform("textured", tex != nullptr);
_shader->setUniform("color", Math::Vector3d(mats[(*face)->_matIdx]->_r, mats[(*face)->_matIdx]->_g, mats[(*face)->_matIdx]->_b));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glDrawElements(GL_TRIANGLES, 3 * (*face)->_tris.size(), GL_UNSIGNED_INT, 0);
glUseProgram(0);
}
}
}
void VisualActor::clearVertices() {
for (Common::HashMap<Common::String, uint32>::iterator it = _faceVBO.begin(); it != _faceVBO.end(); ++it) {
Graphics::Shader::freeBuffer(it->_value);
}
for (Common::HashMap<Common::String, uint32>::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
Graphics::Shader::freeBuffer(it->_value);
}
_faceVBO.clear();
_faceEBO.clear();
}
void VisualActor::uploadVertices() {
Common::Array<MeshNode *> meshes = _actor->getMeshes();
for (Common::Array<MeshNode *>::const_iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
for (Common::Array<FaceNode *>::const_iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
_faceVBO[faceHash(*face)] = createFaceVBO(*face);
_faceEBO[faceHash(*face)] = createFaceEBO(*face);
}
}
}
uint32 VisualActor::createFaceVBO(const FaceNode *face) {
float *vertices = new float[11 * face->_verts.size()];
float *vertPtr = vertices;
// Build a vertex array
for (Common::Array<VertNode *>::const_iterator tri = face->_verts.begin(); tri != face->_verts.end(); ++tri) {
*vertPtr++ = (*tri)->_pos1.x();
*vertPtr++ = (*tri)->_pos1.y();
*vertPtr++ = (*tri)->_pos1.z();
*vertPtr++ = (*tri)->_pos2.x();
*vertPtr++ = (*tri)->_pos2.y();
*vertPtr++ = (*tri)->_pos2.z();
*(uint32 *)vertPtr++ = (*tri)->_bone1;
*(uint32 *)vertPtr++ = (*tri)->_bone2;
*vertPtr++ = (*tri)->_boneWeight;
*vertPtr++ = -(*tri)->_texS;
*vertPtr++ = (*tri)->_texT;
}
uint32 vbo = Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 11 * face->_verts.size(), vertices);
delete[] vertices;
return vbo;
}
uint32 VisualActor::createFaceEBO(const FaceNode *face) {
uint32 *indices = new uint32[3 * face->_tris.size()];
uint32 *idxPtr = indices;
// Build a vertex indices array
for (Common::Array<TriNode *>::const_iterator tri = face->_tris.begin(); tri != face->_tris.end(); ++tri) {
for (int vert = 0; vert < 3; ++vert) {
if (vert == 0)
*idxPtr++ = (*tri)->_vert1;
else if (vert == 1)
*idxPtr++ = (*tri)->_vert2;
else
*idxPtr++ = (*tri)->_vert3;
}
}
uint32 ebo = Graphics::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * 3 * face->_tris.size(), indices);
delete[] indices;
return ebo;
}
void VisualActor::setBonePositionArrayUniform(const char *uniform) {
const Common::Array<BoneNode *> bones = _actor->getSkeleton()->getBones();
GLint pos = _shader->getUniformLocation(uniform);
if (pos == -1) {
error("No uniform named '%s'", uniform);
}
float *positions = new float[3 * bones.size()];
float *positionsPtr = positions;
for (uint i = 0; i < bones.size(); i++) {
*positionsPtr++ = bones[i]->_animPos.x();
*positionsPtr++ = bones[i]->_animPos.y();
*positionsPtr++ = bones[i]->_animPos.z();
}
glUniform3fv(pos, bones.size(), positions);
delete[] positions;
}
void VisualActor::setBoneRotationArrayUniform(const char *uniform) {
const Common::Array<BoneNode *> bones = _actor->getSkeleton()->getBones();
GLint rot = _shader->getUniformLocation(uniform);
if (rot == -1) {
error("No uniform named '%s'", uniform);
}
float *rotations = new float[4 * bones.size()];
float *rotationsPtr = rotations;
for (uint i = 0; i < bones.size(); i++) {
*rotationsPtr++ = bones[i]->_animRot.x();
*rotationsPtr++ = bones[i]->_animRot.y();
*rotationsPtr++ = bones[i]->_animRot.z();
*rotationsPtr++ = bones[i]->_animRot.w();
}
glUniform4fv(rot, bones.size(), rotations);
delete[] rotations;
}
} // End of namespace Stark

View File

@ -23,7 +23,6 @@
#ifndef STARK_VISUAL_ACTOR_H
#define STARK_VISUAL_ACTOR_H
#include "common/hash-str.h"
#include "common/str.h"
#include "math/matrix4.h"
@ -31,14 +30,6 @@
#include "engines/stark/visual/visual.h"
namespace Common {
class Archive;
}
namespace Graphics {
class Shader;
}
namespace Stark {
namespace Gfx {
@ -62,25 +53,14 @@ public:
void setTexture(Gfx::TextureSet *texture);
void setTime(uint32 time);
void render(Gfx::Driver *gfx, const Math::Vector3d position, float direction);
virtual void render(Gfx::Driver *gfx, const Math::Vector3d position, float direction) = 0;
private:
protected:
Actor *_actor;
uint32 _time;
Graphics::Shader *_shader;
Common::HashMap<Common::String, uint32> _faceVBO;
Common::HashMap<Common::String, uint32> _faceEBO;
bool _meshIsDirty;
Math::Matrix4 getModelMatrix(const Math::Vector3d& position, float direction);
Common::String faceHash(const FaceNode *face) const;
void clearVertices();
void uploadVertices();
uint32 createFaceVBO(const FaceNode *face);
uint32 createFaceEBO(const FaceNode *face);
void setBonePositionArrayUniform(const char *uniform);
void setBoneRotationArrayUniform(const char *uniform);
};
} // End of namespace Stark