mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-18 16:32:32 +02:00
Refactored rendering and frames
This commit is contained in:
parent
326fe4eeb3
commit
0773829dfc
@ -24,16 +24,12 @@ class Animator
|
||||
glm::vec3 lastRootPosition;
|
||||
glm::quat lastRootRotation;
|
||||
|
||||
std::vector<glm::mat4> matrices;
|
||||
std::map<int32_t, AnimationBone*> frameToBone;
|
||||
|
||||
float time;
|
||||
float serverTime;
|
||||
float lastServerTime;
|
||||
|
||||
bool repeat;
|
||||
|
||||
void updateFrameMapping();
|
||||
void reset();
|
||||
|
||||
public:
|
||||
|
@ -290,7 +290,7 @@ namespace RW
|
||||
return *reinterpret_cast<T*>(data+offset+sizeof(BSSectionHeader)*2);
|
||||
}
|
||||
|
||||
template<class T> T readSubStructure(size_t internalOffset)
|
||||
template<class T> T& readSubStructure(size_t internalOffset)
|
||||
{
|
||||
return *reinterpret_cast<T*>(data+offset+sizeof(BSSectionHeader)+internalOffset);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <render/ViewCamera.hpp>
|
||||
|
||||
class Model;
|
||||
class ModelFrame;
|
||||
class GameWorld;
|
||||
class GTAObject;
|
||||
class Animator;
|
||||
@ -25,6 +26,8 @@ class GTARenderer
|
||||
GTAObject* object;
|
||||
};
|
||||
|
||||
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GTAObject* object, bool queueTransparent = true);
|
||||
|
||||
// Internal method for processing sub-geometry
|
||||
bool renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, GTAObject* object, bool queueTransparent = true);
|
||||
|
||||
|
@ -1,14 +1,65 @@
|
||||
#pragma once
|
||||
#ifndef _MODEL_HPP_
|
||||
#define _MODEL_HPP_
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <loaders/rwbinarystream.h>
|
||||
|
||||
/**
|
||||
* Frame
|
||||
* => Atomic
|
||||
* => Geometry
|
||||
* - defaultRotation
|
||||
* - defaultTranslation
|
||||
*
|
||||
* + setTransform(mat)
|
||||
* + resetTransform()
|
||||
*/
|
||||
|
||||
class ModelFrame {
|
||||
glm::mat3 defaultRotation;
|
||||
glm::vec3 defaultTranslation;
|
||||
glm::mat4 matrix;
|
||||
ModelFrame* parentFrame;
|
||||
std::string name;
|
||||
std::vector<size_t> geometries;
|
||||
std::vector<ModelFrame*> childs;
|
||||
public:
|
||||
|
||||
ModelFrame(ModelFrame* parent, glm::mat3 dR, glm::vec3 dT);
|
||||
~ModelFrame();
|
||||
|
||||
void reset();
|
||||
void setTransform(const glm::mat4& m);
|
||||
|
||||
void setName(const std::string& fname)
|
||||
{ name = fname; }
|
||||
|
||||
void addGeometry(size_t idx);
|
||||
|
||||
glm::vec3 getDefaultTranslation() const
|
||||
{ return defaultTranslation; }
|
||||
|
||||
glm::mat3 getDefaultRotation() const
|
||||
{ return defaultRotation; }
|
||||
|
||||
glm::mat4 getMatrix() const
|
||||
{ return (parentFrame? parentFrame->getMatrix() : glm::mat4()) * matrix; }
|
||||
|
||||
const std::vector<ModelFrame*>& getChildren() const
|
||||
{ return childs; }
|
||||
|
||||
const std::string& getName() const
|
||||
{ return name; }
|
||||
|
||||
const std::vector<size_t>& getGeometries() const
|
||||
{ return geometries; }
|
||||
};
|
||||
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
@ -88,32 +139,15 @@ public:
|
||||
uint32_t frame;
|
||||
uint32_t geometry;
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
glm::mat4 matrix;
|
||||
glm::mat3 defaultRotation;
|
||||
glm::vec3 defaultTranslation;
|
||||
int32_t parentFrameIndex;
|
||||
};
|
||||
|
||||
std::vector<ModelFrame*> frames;
|
||||
|
||||
std::vector<std::string> frameNames;
|
||||
|
||||
std::vector<std::shared_ptr<Geometry>> geometries;
|
||||
std::vector<Atomic> atomics;
|
||||
std::vector<Frame> frames;
|
||||
|
||||
int32_t rootFrameIdx;
|
||||
|
||||
glm::mat4 getFrameMatrix(int32_t frameIndex)
|
||||
{
|
||||
Frame& frame = frames[frameIndex];
|
||||
if( frame.parentFrameIndex != -1 ) {
|
||||
return frame.matrix * getFrameMatrix(frame.parentFrameIndex);
|
||||
}
|
||||
else {
|
||||
return frame.matrix;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -9,40 +9,13 @@ Animator::Animator()
|
||||
|
||||
}
|
||||
|
||||
void Animator::updateFrameMapping()
|
||||
{
|
||||
if(! (animation && model) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
frameToBone.clear();
|
||||
|
||||
for( size_t f = 0; f < model->frames.size(); ++f ) {
|
||||
AnimationBone* bone = animation->bones[model->frameNames[f]];
|
||||
if(bone) {
|
||||
frameToBone.insert({f, bone});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::reset()
|
||||
{
|
||||
time = 0.f;
|
||||
lastServerTime= 0.f;
|
||||
|
||||
if(model && animation) {
|
||||
if(model->rootFrameIdx != -1) {
|
||||
auto it = frameToBone.find(model->rootFrameIdx);
|
||||
if( it != frameToBone.end() )
|
||||
{
|
||||
AnimationBone* b = it->second;
|
||||
AnimationKeyframe& KF = b->frames[0];
|
||||
if(b->type == AnimationBone::RT0 || b->type == AnimationBone::RTS) {
|
||||
lastRootPosition = KF.position;
|
||||
}
|
||||
lastRootRotation = KF.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,8 +27,7 @@ void Animator::setAnimation(Animation *animation, bool repeat)
|
||||
|
||||
this->animation = animation;
|
||||
this->repeat = repeat;
|
||||
|
||||
updateFrameMapping();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -65,13 +37,8 @@ void Animator::setModel(Model *model)
|
||||
return;
|
||||
}
|
||||
|
||||
this->model = model;
|
||||
this->model = model;
|
||||
|
||||
if(model != nullptr) {
|
||||
matrices.resize(model->frames.size());
|
||||
}
|
||||
|
||||
updateFrameMapping();
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -81,64 +48,9 @@ void Animator::tick(float dt)
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the root node movement.
|
||||
if( model->rootFrameIdx != -1 ) {
|
||||
auto it = frameToBone.find(model->rootFrameIdx);
|
||||
if( it != frameToBone.end() )
|
||||
{
|
||||
AnimationBone* boneanim = frameToBone[model->rootFrameIdx];
|
||||
if( boneanim->type != AnimationBone::R00 ) {
|
||||
auto keyframe = boneanim->getInterpolatedKeyframe(serverTime);
|
||||
lastRootPosition = keyframe.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastServerTime = serverTime;
|
||||
serverTime += dt;
|
||||
|
||||
for( size_t fi = 0; fi < model->frames.size(); ++fi ) {
|
||||
glm::mat4 fmat = glm::mat4(model->frames[fi].defaultRotation);
|
||||
fmat[3] = glm::vec4(model->frames[fi].defaultTranslation, 1.f);
|
||||
|
||||
if( animation && fi < model->frameNames.size() ) {
|
||||
if(repeat) {
|
||||
serverTime = fmod(serverTime, animation->duration);
|
||||
}
|
||||
else {
|
||||
serverTime = std::min(serverTime, animation->duration);
|
||||
}
|
||||
|
||||
if( lastServerTime > serverTime ) {
|
||||
lastRootPosition = glm::vec3(0.f);
|
||||
}
|
||||
|
||||
auto it = frameToBone.find(fi);
|
||||
if( it == frameToBone.end() ) continue;
|
||||
AnimationBone* boneanim = it->second;
|
||||
|
||||
if( boneanim && boneanim->frames.size() > 0 ) {
|
||||
auto keyframe = boneanim->getInterpolatedKeyframe(serverTime);
|
||||
fmat = glm::mat4(1.0f) * glm::mat4_cast(keyframe.rotation);
|
||||
|
||||
// Only add the translation back if is is not present.
|
||||
if( boneanim->type == AnimationBone::R00 ) {
|
||||
fmat[3] = glm::vec4(model->frames[fi].defaultTranslation, 1.f);
|
||||
}
|
||||
else {
|
||||
if( fi == model->rootFrameIdx ) {
|
||||
// Ignore root translation.
|
||||
fmat[3] = glm::vec4(model->frames[fi].defaultTranslation, 1.f);
|
||||
}
|
||||
else {
|
||||
fmat[3] = glm::vec4(keyframe.position, 1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrices[fi] = fmat;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::render(float dt)
|
||||
@ -149,16 +61,6 @@ void Animator::render(float dt)
|
||||
glm::vec3 Animator::getRootTranslation() const
|
||||
{
|
||||
if( model && model->rootFrameIdx != -1 ) {
|
||||
auto it = frameToBone.find(model->rootFrameIdx);
|
||||
if( it != frameToBone.end() )
|
||||
{
|
||||
AnimationBone* boneanim = it->second;
|
||||
|
||||
if( boneanim->type != AnimationBone::R00 ) {
|
||||
auto keyframe = boneanim->getInterpolatedKeyframe(serverTime);
|
||||
return keyframe.position - lastRootPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glm::vec3();
|
||||
@ -171,15 +73,6 @@ glm::quat Animator::getRootRotation() const
|
||||
|
||||
glm::mat4 Animator::getFrameMatrix(size_t frame) const
|
||||
{
|
||||
if( model ) {
|
||||
Model::Frame& f = model->frames[frame];
|
||||
if( f.parentFrameIndex == -1 ) {
|
||||
return matrices.at(frame);
|
||||
}
|
||||
else {
|
||||
return getFrameMatrix(f.parentFrameIndex) * matrices.at(frame);
|
||||
}
|
||||
}
|
||||
return glm::mat4();
|
||||
}
|
||||
|
||||
|
@ -245,11 +245,11 @@ GTAVehicle *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, co
|
||||
std::string& name = model->frameNames[f];
|
||||
|
||||
if( name.substr(0, 5) == "wheel" ) {
|
||||
auto frameTrans = model->getFrameMatrix(f);
|
||||
auto frameTrans = model->frames[f]->getMatrix();
|
||||
info->second.wheels.push_back({glm::vec3(frameTrans[3])});
|
||||
}
|
||||
if(name.substr(0, 3) == "ped" && name.substr(name.size()-4) == "seat") {
|
||||
auto p = model->frames[f].defaultTranslation;
|
||||
auto p = model->frames[f]->getDefaultTranslation();
|
||||
p.x = p.x * -1.f;
|
||||
info->second.seats.push_back({p});
|
||||
p.x = p.x * -1.f;
|
||||
|
@ -7,8 +7,6 @@
|
||||
#include <set>
|
||||
#include <cstring>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
Model* LoaderDFF::loadFromMemory(char *data, GameData *gameData)
|
||||
{
|
||||
auto model = new Model;
|
||||
@ -25,19 +23,21 @@ Model* LoaderDFF::loadFromMemory(char *data, GameData *gameData)
|
||||
auto list = sec.readStructure<RW::BSFrameList>();
|
||||
size_t fdataI = sizeof(RW::BSFrameList) + sizeof(RW::BSSectionHeader);
|
||||
|
||||
model->frames.reserve(list.numframes);
|
||||
|
||||
for(size_t f = 0; f < list.numframes; ++f) {
|
||||
auto rawframe = sec.readSubStructure<RW::BSFrameListFrame>(fdataI);
|
||||
RW::BSFrameListFrame& rawframe = sec.readSubStructure<RW::BSFrameListFrame>(fdataI);
|
||||
fdataI += sizeof(RW::BSFrameListFrame);
|
||||
|
||||
Model::Frame frame;
|
||||
frame.defaultRotation = rawframe.rotation;
|
||||
frame.defaultTranslation = rawframe.position;
|
||||
frame.parentFrameIndex = rawframe.index;
|
||||
|
||||
// Initilize the matrix with the correct values.
|
||||
frame.matrix = glm::translate(glm::mat4(frame.defaultRotation), frame.defaultTranslation);
|
||||
|
||||
model->frames.push_back(frame);
|
||||
ModelFrame* parent = nullptr;
|
||||
if(rawframe.index != -1) {
|
||||
parent = model->frames[rawframe.index];
|
||||
}
|
||||
else {
|
||||
model->rootFrameIdx = 0;
|
||||
}
|
||||
model->frames.push_back(
|
||||
new ModelFrame(parent, rawframe.rotation, rawframe.position)
|
||||
);
|
||||
}
|
||||
|
||||
size_t fldataI = 0;
|
||||
@ -47,6 +47,7 @@ Model* LoaderDFF::loadFromMemory(char *data, GameData *gameData)
|
||||
size_t extI = 0;
|
||||
while( listsec.hasMoreData(extI)) {
|
||||
auto extSec = listsec.getNextChildSection(extI);
|
||||
size_t fn = 0;
|
||||
if( extSec.header.id == RW::SID_NodeName) {
|
||||
std::string framename(extSec.raw(), extSec.header.size);
|
||||
std::transform(framename.begin(), framename.end(), framename.begin(), ::tolower );
|
||||
@ -55,8 +56,10 @@ Model* LoaderDFF::loadFromMemory(char *data, GameData *gameData)
|
||||
if(framename == "swaist") {
|
||||
model->rootFrameIdx = model->frameNames.size();
|
||||
}
|
||||
|
||||
model->frameNames.push_back(framename);
|
||||
|
||||
if( fn < model->frames.size() ) {
|
||||
model->frames[(fn++)]->setName(framename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -267,7 +270,9 @@ Model* LoaderDFF::loadFromMemory(char *data, GameData *gameData)
|
||||
break;
|
||||
}
|
||||
case RW::SID_Atomic: {
|
||||
model->atomics.push_back(sec.readStructure<Model::Atomic>());
|
||||
const Model::Atomic& at = sec.readStructure<Model::Atomic>();
|
||||
model->frames[at.frame]->addGeometry(at.geometry);
|
||||
model->atomics.push_back(at);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -447,6 +447,37 @@ void GTARenderer::renderGeometry(Model* model, size_t g, const glm::mat4& modelM
|
||||
}
|
||||
}
|
||||
|
||||
bool GTARenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GTAObject* object, bool queueTransparent)
|
||||
{
|
||||
auto localmatrix = matrix * f->getMatrix();
|
||||
for(size_t g : f->getGeometries()) {
|
||||
RW::BSGeometryBounds& bounds = m->geometries[g]->geometryBounds;
|
||||
if(! camera.frustum.intersects(bounds.center + glm::vec3(matrix[3]), bounds.radius)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if( object && object->type() == GTAObject::Vehicle ) {
|
||||
auto& name = f->getName();
|
||||
if( name.substr(name.size()-3) == "dam" || name.find("lo") != name.npos || name.find("dummy") != name.npos ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( (m->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) != RW::BSGeometry::ModuleMaterialColor) {
|
||||
glUniform4f(uniCol, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
renderGeometry(m,
|
||||
g, localmatrix,
|
||||
object);
|
||||
}
|
||||
|
||||
for(ModelFrame* c : f->getChildren()) {
|
||||
renderFrame(m, c, matrix, object, queueTransparent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static GLuint currentVBO = 0;
|
||||
|
||||
bool GTARenderer::renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, GTAObject* object, bool queueTransparent)
|
||||
@ -521,43 +552,7 @@ bool GTARenderer::renderSubgeometry(Model* model, size_t g, size_t sg, const glm
|
||||
|
||||
void GTARenderer::renderModel(Model* model, const glm::mat4& modelMatrix, GTAObject* object, Animator *animator)
|
||||
{
|
||||
for (size_t a = 0; a < model->atomics.size(); a++)
|
||||
{
|
||||
size_t g = model->atomics[a].geometry;
|
||||
RW::BSGeometryBounds& bounds = model->geometries[g]->geometryBounds;
|
||||
if(! camera.frustum.intersects(bounds.center + glm::vec3(modelMatrix[3]), bounds.radius)) {
|
||||
culled++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t fi = model->atomics[a].frame;
|
||||
if( object && object->type() == GTAObject::Vehicle ) {
|
||||
if(model->frameNames.size() > fi) {
|
||||
std::string& name = model->frameNames[fi];
|
||||
if( name.substr(name.size()-3) == "dam" || name.find("lo") != name.npos || name.find("dummy") != name.npos ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( (model->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) != RW::BSGeometry::ModuleMaterialColor) {
|
||||
glUniform4f(uniCol, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
// Determine which transformation to use (why is this neccasary)
|
||||
glm::mat4 localMatrix;
|
||||
if(animator) {
|
||||
localMatrix = animator->getFrameMatrix(model->atomics[a].frame);
|
||||
}
|
||||
else if(object&& object->type() == GTAObject::Vehicle)
|
||||
{
|
||||
localMatrix = model->getFrameMatrix(model->atomics[a].frame);
|
||||
}
|
||||
|
||||
renderGeometry(model,
|
||||
g, modelMatrix * localMatrix,
|
||||
object);
|
||||
}
|
||||
renderFrame(model, model->frames[model->rootFrameIdx], modelMatrix, object);
|
||||
}
|
||||
|
||||
void GTARenderer::renderPaths()
|
||||
|
@ -1,5 +1,9 @@
|
||||
#include "render/Model.hpp"
|
||||
#include <GL/glew.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
|
||||
Model::Geometry::Geometry()
|
||||
: VBO(0), EBO(0),
|
||||
@ -22,7 +26,6 @@ void Model::Geometry::generateNormals()
|
||||
{
|
||||
|
||||
}
|
||||
#include <iostream>
|
||||
|
||||
void Model::Geometry::buildBuffers()
|
||||
{
|
||||
@ -120,3 +123,22 @@ void Model::Geometry::buildBuffers()
|
||||
subgeom[i].indices);
|
||||
}
|
||||
}
|
||||
|
||||
ModelFrame::ModelFrame(ModelFrame* parent, glm::mat3 dR, glm::vec3 dT)
|
||||
: defaultRotation(dR), defaultTranslation(dT), parentFrame(parent)
|
||||
{
|
||||
if(parent != nullptr) {
|
||||
parent->childs.push_back(this);
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
void ModelFrame::reset()
|
||||
{
|
||||
matrix = glm::translate(glm::mat4(), defaultTranslation) * glm::mat4(defaultRotation);
|
||||
}
|
||||
|
||||
void ModelFrame::addGeometry(size_t idx)
|
||||
{
|
||||
geometries.push_back(idx);
|
||||
}
|
Loading…
Reference in New Issue
Block a user