Major graphics/model refactoring
- Decouple Model and ModelNode from MdlReader - Make Emitter a nested struct under ModelNode - Read all known controller types
This commit is contained in:
parent
277a94bec7
commit
366d8d739d
35 changed files with 1661 additions and 1721 deletions
|
@ -172,11 +172,8 @@ set(GRAPHICS_HEADERS
|
|||
src/engine/graphics/mesh/mesh.h
|
||||
src/engine/graphics/mesh/meshes.h
|
||||
src/engine/graphics/mesh/vertexattributes.h
|
||||
src/engine/graphics/model/aabbnode.h
|
||||
src/engine/graphics/model/animatedproperty.h
|
||||
src/engine/graphics/model/animation.h
|
||||
src/engine/graphics/model/emitter.h
|
||||
src/engine/graphics/model/lensflare.h
|
||||
src/engine/graphics/model/mdlreader.h
|
||||
src/engine/graphics/model/model.h
|
||||
src/engine/graphics/model/modelnode.h
|
||||
|
@ -217,6 +214,7 @@ set(GRAPHICS_SOURCES
|
|||
src/engine/graphics/mesh/meshes.cpp
|
||||
src/engine/graphics/model/animation.cpp
|
||||
src/engine/graphics/model/mdlreader.cpp
|
||||
src/engine/graphics/model/mdlreader_controllers.cpp
|
||||
src/engine/graphics/model/model.cpp
|
||||
src/engine/graphics/model/modelnode.cpp
|
||||
src/engine/graphics/model/models.cpp
|
||||
|
|
|
@ -256,7 +256,7 @@ glm::vec3 DialogGUI::getTalkPosition(const SpatialObject &object) const {
|
|||
if (model->getNodeAbsolutePosition("talkdummy", hookPosition)) {
|
||||
return object.position() + hookPosition;
|
||||
}
|
||||
return model->getCenterOfAABB();
|
||||
return model->getWorldCenterAABB();
|
||||
}
|
||||
|
||||
return object.position();
|
||||
|
|
|
@ -526,7 +526,7 @@ void Area::fill(SceneGraph &sceneGraph) {
|
|||
if (sceneNode) {
|
||||
sceneGraph.addRoot(sceneNode);
|
||||
}
|
||||
shared_ptr<ModelNode> aabbNode(sceneNode->model()->findAABBNode());
|
||||
shared_ptr<ModelNode> aabbNode(sceneNode->model()->getAABBNode());
|
||||
if (aabbNode && _grass.texture) {
|
||||
glm::mat4 aabbTransform(glm::translate(aabbNode->absoluteTransform(), room.second->position()));
|
||||
auto grass = make_shared<GrassSceneNode>(&sceneGraph, glm::vec2(_grass.quadSize), _grass.texture, aabbNode->mesh()->lightmap);
|
||||
|
|
|
@ -418,7 +418,7 @@ glm::vec3 Creature::getSelectablePosition() const {
|
|||
shared_ptr<ModelSceneNode> model(getModelSceneNode());
|
||||
if (!model) return _position;
|
||||
|
||||
if (_dead) return model->getCenterOfAABB();
|
||||
if (_dead) return model->getWorldCenterAABB();
|
||||
|
||||
glm::vec3 position;
|
||||
|
||||
|
@ -426,7 +426,7 @@ glm::vec3 Creature::getSelectablePosition() const {
|
|||
return model->absoluteTransform() * glm::vec4(position, 1.0f);
|
||||
}
|
||||
|
||||
return model->getCenterOfAABB();
|
||||
return model->getWorldCenterAABB();
|
||||
}
|
||||
|
||||
float Creature::getAttackRange() const {
|
||||
|
|
|
@ -226,7 +226,7 @@ shared_ptr<Walkmesh> SpatialObject::getWalkmesh() const {
|
|||
|
||||
glm::vec3 SpatialObject::getSelectablePosition() const {
|
||||
auto model = getModelSceneNode();
|
||||
return model ? model->getCenterOfAABB() : _position;
|
||||
return model ? model->getWorldCenterAABB() : _position;
|
||||
}
|
||||
|
||||
void SpatialObject::setRoom(Room *room) {
|
||||
|
|
|
@ -29,7 +29,7 @@ LipAnimation::LipAnimation(float length, vector<Keyframe> keyframes) :
|
|||
_length(length), _keyframes(move(keyframes)) {
|
||||
}
|
||||
|
||||
bool LipAnimation::getKeyframes(float time, uint8_t &leftShape, uint8_t &rightShape, float &interpolant) const {
|
||||
bool LipAnimation::getKeyframes(float time, uint8_t &leftShape, uint8_t &rightShape, float &factor) const {
|
||||
if (_keyframes.empty()) return false;
|
||||
|
||||
const Keyframe *left = &_keyframes[0];
|
||||
|
@ -49,9 +49,9 @@ bool LipAnimation::getKeyframes(float time, uint8_t &leftShape, uint8_t &rightSh
|
|||
rightShape = right->shape;
|
||||
|
||||
if (&left == &right) {
|
||||
interpolant = 0.0f;
|
||||
factor = 0.0f;
|
||||
} else {
|
||||
interpolant = (time - left->time) / (right->time - left->time);
|
||||
factor = (time - left->time) / (right->time - left->time);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
LipAnimation(float length, std::vector<Keyframe> keyframes);
|
||||
|
||||
bool getKeyframes(float time, uint8_t &leftShape, uint8_t &rightShape, float &interpolant) const;
|
||||
bool getKeyframes(float time, uint8_t &leftShape, uint8_t &rightShape, float &factor) const;
|
||||
|
||||
float length() const { return _length; }
|
||||
const std::vector<Keyframe> &keyframes() const { return _keyframes; }
|
||||
|
|
|
@ -36,7 +36,8 @@ Materials &Materials::instance() {
|
|||
}
|
||||
|
||||
void Materials::init() {
|
||||
if (!_inited) {
|
||||
if (_inited) return;
|
||||
|
||||
shared_ptr<TwoDA> materials(Resources::instance().get2DA("material", false));
|
||||
if (materials) {
|
||||
for (int row = 0; row < materials->getRowCount(); ++row) {
|
||||
|
@ -58,8 +59,8 @@ void Materials::init() {
|
|||
_materials.insert(make_pair(tex, move(material)));
|
||||
}
|
||||
}
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
Materials::~Materials() {
|
||||
|
|
|
@ -76,7 +76,6 @@ public:
|
|||
const std::vector<float> &vertices() const { return _vertices; }
|
||||
const std::vector<uint16_t> &indices() const { return _indices; }
|
||||
const VertexAttributes &attributes() const { return _attributes; }
|
||||
VertexAttributes &attributes() { return _attributes; }
|
||||
const AABB &aabb() const { return _aabb; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../aabb.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
struct AABBNode {
|
||||
enum class Plane {
|
||||
None = 0,
|
||||
PositiveX = 1,
|
||||
PositiveY = 2,
|
||||
PositiveZ = 4
|
||||
};
|
||||
|
||||
int faceIndex { 0 };
|
||||
Plane mostSignificantPlane { Plane::None };
|
||||
AABB aabb;
|
||||
std::shared_ptr<AABBNode> leftChild;
|
||||
std::shared_ptr<AABBNode> rightChild;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
} // namespace reone
|
|
@ -40,22 +40,22 @@ struct SlerpInterpolator {
|
|||
}
|
||||
};
|
||||
|
||||
template <class V, class Interpolator = MixInterpolator<V>>
|
||||
template <class V, class Inter = MixInterpolator<V>>
|
||||
class AnimatedProperty {
|
||||
public:
|
||||
int getNumKeyframes() const {
|
||||
return static_cast<int>(_keyframes.size());
|
||||
int getNumFrames() const {
|
||||
return static_cast<int>(_frames.size());
|
||||
}
|
||||
|
||||
bool getByTime(float time, V &value) const {
|
||||
if (_keyframes.empty()) return false;
|
||||
if (_frames.empty()) return false;
|
||||
|
||||
const std::pair<float, V> *frame1 = &_keyframes[0];
|
||||
const std::pair<float, V> *frame2 = &_keyframes[0];
|
||||
for (auto it = _keyframes.begin(); it != _keyframes.end(); ++it) {
|
||||
const std::pair<float, V> *frame1 = &_frames[0];
|
||||
const std::pair<float, V> *frame2 = &_frames[0];
|
||||
for (auto it = _frames.begin(); it != _frames.end(); ++it) {
|
||||
if (it->first >= time) {
|
||||
frame2 = &*it;
|
||||
if (it != _keyframes.begin()) {
|
||||
if (it != _frames.begin()) {
|
||||
frame1 = &*(it - 1);
|
||||
}
|
||||
break;
|
||||
|
@ -69,33 +69,33 @@ public:
|
|||
factor = (time - frame1->first) / (frame2->first - frame1->first);
|
||||
}
|
||||
|
||||
value = Interpolator::interpolate(frame1->second, frame2->second, factor);
|
||||
value = Inter::interpolate(frame1->second, frame2->second, factor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V getByKeyframe(int frame) const {
|
||||
return _keyframes[frame].second;
|
||||
V getByFrame(int frame) const {
|
||||
return _frames[frame].second;
|
||||
}
|
||||
|
||||
V getByKeyframeOrElse(int frame, V defaultValue) const {
|
||||
return frame < static_cast<int>(_keyframes.size()) ?
|
||||
getByKeyframe(frame) :
|
||||
V getByFrameOrElse(int frame, V defaultValue) const {
|
||||
return frame < static_cast<int>(_frames.size()) ?
|
||||
getByFrame(frame) :
|
||||
std::move(defaultValue);
|
||||
}
|
||||
|
||||
void addKeyframe(float time, V value) {
|
||||
_keyframes.push_back(std::make_pair(time, value));
|
||||
void addFrame(float time, V value) {
|
||||
_frames.push_back(std::make_pair(time, std::move(value)));
|
||||
}
|
||||
|
||||
void update() {
|
||||
std::sort(_keyframes.begin(), _keyframes.end(), [](auto &left, auto &right) {
|
||||
std::sort(_frames.begin(), _frames.end(), [](auto &left, auto &right) {
|
||||
return left.first < right.first;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<float, V>> _keyframes;
|
||||
std::vector<std::pair<float, V>> _frames;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include <queue>
|
||||
|
||||
#include "../../common/collectionutil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace reone {
|
||||
|
@ -26,22 +28,22 @@ namespace reone {
|
|||
namespace graphics {
|
||||
|
||||
Animation::Animation(
|
||||
const string &name,
|
||||
string name,
|
||||
float length,
|
||||
float transitionTime,
|
||||
vector<Event> &&events,
|
||||
const shared_ptr<ModelNode> &rootNode
|
||||
shared_ptr<ModelNode> rootNode,
|
||||
vector<Event> &&events
|
||||
) :
|
||||
_name(name),
|
||||
_name(move(name)),
|
||||
_length(length),
|
||||
_transitionTime(transitionTime),
|
||||
_events(move(events)),
|
||||
_rootNode(rootNode) {
|
||||
_rootNode(move(rootNode)),
|
||||
_events(move(events)) {
|
||||
|
||||
initNodeByName();
|
||||
fillNodeByName();
|
||||
}
|
||||
|
||||
void Animation::initNodeByName() {
|
||||
void Animation::fillNodeByName() {
|
||||
queue<shared_ptr<ModelNode>> nodes;
|
||||
nodes.push(_rootNode);
|
||||
|
||||
|
@ -51,20 +53,14 @@ void Animation::initNodeByName() {
|
|||
|
||||
_nodeByName.insert(make_pair(node->name(), node));
|
||||
|
||||
const vector<shared_ptr<ModelNode>> &children = node->children();
|
||||
for (auto &child : children) {
|
||||
for (auto &child : node->children()) {
|
||||
nodes.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode> Animation::findNode(const string &name) const {
|
||||
auto it = _nodeByName.find(name);
|
||||
return it != _nodeByName.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
void Animation::setName(string name) {
|
||||
_name = move(name);
|
||||
shared_ptr<ModelNode> Animation::getNodeByName(const string &name) const {
|
||||
return getFromLookupOrNull(_nodeByName, name);
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
@ -37,13 +37,13 @@ public:
|
|||
};
|
||||
|
||||
Animation(
|
||||
const std::string &name,
|
||||
std::string name,
|
||||
float length,
|
||||
float transitionTime,
|
||||
std::vector<Event> &&events,
|
||||
const std::shared_ptr<ModelNode> &rootNode);
|
||||
std::shared_ptr<ModelNode> rootNode,
|
||||
std::vector<Event> &&events);
|
||||
|
||||
std::shared_ptr<ModelNode> findNode(const std::string &name) const;
|
||||
std::shared_ptr<ModelNode> getNodeByName(const std::string &name) const;
|
||||
|
||||
const std::string &name() const { return _name; }
|
||||
float length() const { return _length; }
|
||||
|
@ -51,20 +51,16 @@ public:
|
|||
std::shared_ptr<ModelNode> rootNode() const { return _rootNode; }
|
||||
const std::vector<Event> &events() const { return _events; }
|
||||
|
||||
void setName(std::string name);
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
float _length { 0.0f };
|
||||
float _transitionTime { 0.0f };
|
||||
std::vector<Event> _events;
|
||||
std::shared_ptr<ModelNode> _rootNode;
|
||||
std::vector<Event> _events;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<ModelNode>> _nodeByName;
|
||||
|
||||
void initNodeByName();
|
||||
|
||||
friend class MdlReader;
|
||||
void fillNodeByName();
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "glm/vec2.hpp"
|
||||
|
||||
#include "../texture/texture.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
class Emitter {
|
||||
public:
|
||||
enum class UpdateMode {
|
||||
Invalid,
|
||||
Fountain,
|
||||
Single,
|
||||
Explosion
|
||||
};
|
||||
|
||||
enum class RenderMode {
|
||||
Invalid = 0,
|
||||
Normal = 1,
|
||||
BillboardToWorldZ = 2,
|
||||
MotionBlur = 3,
|
||||
BillboardToLocalZ = 4,
|
||||
AlignedToParticleDir = 5
|
||||
};
|
||||
|
||||
enum class BlendMode {
|
||||
Invalid,
|
||||
Normal,
|
||||
Punch,
|
||||
Lighten
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Constraints {
|
||||
T start;
|
||||
T mid;
|
||||
T end;
|
||||
};
|
||||
|
||||
UpdateMode updateMode() const { return _updateMode; }
|
||||
RenderMode renderMode() const { return _renderMode; }
|
||||
BlendMode blendMode() const { return _blendMode; }
|
||||
int renderOrder() const { return _renderOrder; }
|
||||
|
||||
std::shared_ptr<Texture> texture() const { return _texture; }
|
||||
int gridWidth() const { return _gridWidth; }
|
||||
int gridHeight() const { return _gridHeight; }
|
||||
int frameStart() const { return _frameStart; }
|
||||
int frameEnd() const { return _frameEnd; }
|
||||
|
||||
glm::vec2 &size() { return _size; }
|
||||
const glm::vec2 &size() const { return _size; }
|
||||
Constraints<float> &particleSize() { return _particleSize; }
|
||||
const Constraints<float> &particleSize() const { return _particleSize; }
|
||||
Constraints<glm::vec3> &color() { return _color; }
|
||||
const Constraints<glm::vec3> &color() const { return _color; }
|
||||
Constraints<float> &alpha() { return _alpha; }
|
||||
const Constraints<float> &alpha() const { return _alpha; }
|
||||
int birthrate() const { return _birthrate; }
|
||||
int lifeExpectancy() const { return _lifeExpectancy; }
|
||||
float velocity() const { return _velocity; }
|
||||
float randomVelocity() const { return _randomVelocity; }
|
||||
float spread() const { return _spread; }
|
||||
bool loop() const { return _loop; }
|
||||
int fps() const { return _fps; }
|
||||
|
||||
void setFrameStart(int value) { _frameStart = value; }
|
||||
void setFrameEnd(int value) { _frameEnd = value; }
|
||||
void setBirthrate(int value) { _birthrate = value; }
|
||||
void setLifeExpectancy(int value) { _lifeExpectancy = value; }
|
||||
void setVelocity(float value) { _velocity = value; }
|
||||
void setRandomVelocity(float value) { _randomVelocity = value; }
|
||||
void setSpread(float value) { _spread = value; }
|
||||
void setLoop(bool value) { _loop = value; }
|
||||
void setFPS(int value) { _fps = value; }
|
||||
|
||||
private:
|
||||
UpdateMode _updateMode { UpdateMode::Invalid };
|
||||
RenderMode _renderMode { RenderMode::Invalid };
|
||||
BlendMode _blendMode { BlendMode::Invalid };
|
||||
int _renderOrder { 0 };
|
||||
|
||||
std::shared_ptr<Texture> _texture;
|
||||
int _gridWidth { 0 };
|
||||
int _gridHeight { 0 };
|
||||
int _frameStart { 0 };
|
||||
int _frameEnd { 0 };
|
||||
|
||||
glm::vec2 _size { 0.0f };
|
||||
int _birthrate { 0 }; /**< rate of particle birth per second */
|
||||
int _lifeExpectancy { 0 }; /**< life of each particle in seconds */
|
||||
float _velocity { 0.0f };
|
||||
float _randomVelocity { 0.0f };
|
||||
float _spread { 0.0f };
|
||||
bool _loop { false };
|
||||
int _fps { 0 };
|
||||
|
||||
Constraints<float> _particleSize;
|
||||
Constraints<glm::vec3> _color;
|
||||
Constraints<float> _alpha;
|
||||
|
||||
friend class MdlReader;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
} // namespace reone
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "glm/vec3.hpp"
|
||||
|
||||
#include "../texture/texture.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
struct LensFlare {
|
||||
std::shared_ptr<Texture> texture;
|
||||
glm::vec3 colorShift { 0.0f };
|
||||
float position { 0.0f };
|
||||
float size { 0.0f };
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
} // namespace reone
|
File diff suppressed because it is too large
Load diff
|
@ -17,9 +17,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../resource/format/binreader.h"
|
||||
|
||||
#include "aabbnode.h"
|
||||
#include "model.h"
|
||||
|
||||
namespace reone {
|
||||
|
@ -35,76 +38,133 @@ public:
|
|||
std::shared_ptr<graphics::Model> model() const { return _model; }
|
||||
|
||||
private:
|
||||
struct NodeFlags {
|
||||
static constexpr int header = 1;
|
||||
static constexpr int light = 2;
|
||||
static constexpr int emitter = 4;
|
||||
static constexpr int camera = 8;
|
||||
static constexpr int reference = 0x10;
|
||||
static constexpr int mesh = 0x20;
|
||||
static constexpr int skin = 0x40;
|
||||
static constexpr int anim = 0x80;
|
||||
static constexpr int dangly = 0x100;
|
||||
static constexpr int aabb = 0x200;
|
||||
static constexpr int saber = 0x800;
|
||||
};
|
||||
|
||||
struct ArrayDefinition {
|
||||
uint32_t offset { 0 };
|
||||
uint32_t count { 0 };
|
||||
uint32_t count2 { 0 };
|
||||
};
|
||||
|
||||
struct MeshHeader {
|
||||
// Material
|
||||
glm::vec3 ambient { 0.0f };
|
||||
glm::vec3 diffuse { 0.0f };
|
||||
std::string texture1;
|
||||
std::string texture2;
|
||||
bool render { false };
|
||||
bool shadow { false };
|
||||
bool backgroundGeometry { false };
|
||||
int transparencyHint { 0 };
|
||||
|
||||
// Geometry
|
||||
int numVertices { 0 };
|
||||
int numFaces { 0 };
|
||||
uint32_t offFaces { 0 };
|
||||
uint32_t offOffIndices { 0 };
|
||||
|
||||
// MDX
|
||||
int mdxVertexSize { 0 };
|
||||
int offMdxVertices { 0 };
|
||||
int offMdxNormals { 0 };
|
||||
int offMdxTexCoords1 { 0 };
|
||||
int offMdxTexCoords2 { 0 };
|
||||
int offMdxTanSpace { 0 };
|
||||
|
||||
// UV animation
|
||||
bool animateUV { false };
|
||||
float uvDirectionX { 0.0f };
|
||||
float uvDirectionY { 0.0f };
|
||||
struct ControllerKey {
|
||||
uint32_t type { 0 };
|
||||
uint16_t numRows { 0 };
|
||||
uint16_t timeIndex { 0 };
|
||||
uint16_t dataIndex { 0 };
|
||||
uint8_t numColumns { 0 };
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32_t, std::vector<uint32_t>> MaterialMap;
|
||||
typedef std::function<void(const ControllerKey &, const std::vector<float> &, ModelNode &)> ControllerFn;
|
||||
|
||||
std::unordered_map<uint32_t, ControllerFn> _genericControllers;
|
||||
std::unordered_map<uint32_t, ControllerFn> _meshControllers;
|
||||
std::unordered_map<uint32_t, ControllerFn> _lightControllers;
|
||||
std::unordered_map<uint32_t, ControllerFn> _emitterControllers;
|
||||
|
||||
std::unique_ptr<StreamReader> _mdxReader;
|
||||
|
||||
bool _tsl { false }; /**< is this a TSL model? */
|
||||
int _nodeIndex { 0 };
|
||||
std::vector<std::string> _nodeNames;
|
||||
std::unordered_map<uint32_t, int> _nodeFlags;
|
||||
bool _readingAnimations { false };
|
||||
|
||||
std::map<uint16_t, uint16_t> _nodeFlags;
|
||||
std::shared_ptr<graphics::Model> _model;
|
||||
|
||||
void doLoad() override;
|
||||
|
||||
ArrayDefinition readArrayDefinition();
|
||||
void readNodeNames(const std::vector<uint32_t> &offsets);
|
||||
std::unique_ptr<graphics::ModelNode> readNode(uint32_t offset, graphics::ModelNode *parent);
|
||||
std::unique_ptr<graphics::ModelNode> readNode(uint32_t offset, const ModelNode *parent, bool anim = false);
|
||||
std::vector<std::shared_ptr<graphics::Animation>> readAnimations(const std::vector<uint32_t> &offsets);
|
||||
std::unique_ptr<graphics::Animation> readAnimation(uint32_t offset);
|
||||
void readControllers(bool anim, uint32_t keyOffset, uint32_t keyCount, const std::vector<float> &data, graphics::ModelNode &node);
|
||||
|
||||
void readControllers(int nodeFlags, uint32_t keyOffset, uint32_t keyCount, const std::vector<float> &data, graphics::ModelNode &node);
|
||||
void readLight(graphics::ModelNode &node);
|
||||
void readEmitter(graphics::ModelNode &node);
|
||||
void readReference(graphics::ModelNode &node);
|
||||
void readMesh(graphics::ModelNode &node);
|
||||
void readSkin(graphics::ModelNode &node);
|
||||
void readDanglymesh(graphics::ModelNode &node);
|
||||
void readAABB(graphics::ModelNode &node);
|
||||
void readSaber(graphics::ModelNode &node);
|
||||
std::shared_ptr<ModelNode::Reference> readReference();
|
||||
std::shared_ptr<ModelNode::Light> readLight();
|
||||
std::shared_ptr<ModelNode::Emitter> readEmitter();
|
||||
std::shared_ptr<ModelNode::TriangleMesh> readMesh(int flags);
|
||||
|
||||
void loadMesh(const MeshHeader &header, std::vector<float> &&vertices, std::vector<uint16_t> &&indices, VertexAttributes &&attributes, MaterialMap &&materialFaces, graphics::ModelNode &node);
|
||||
MeshHeader readMeshHeader();
|
||||
std::shared_ptr<AABBNode> readAABBNode(uint32_t offset);
|
||||
std::shared_ptr<ModelNode::AABBTree> readAABBTree(uint32_t offset);
|
||||
|
||||
// Controllers
|
||||
|
||||
void initControllerFn();
|
||||
|
||||
ControllerFn getControllerFn(uint32_t type, int nodeFlags);
|
||||
|
||||
static void readPositionController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readOrientationController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readScaleController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readAlphaController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSelfIllumColorController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readColorController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readRadiusController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readShadowRadiusController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readVerticalDisplacementController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readMultiplierController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readAlphaEndController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readAlphaStartController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readBirthrateController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readBounceCoController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readCombineTimeController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readDragController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readFPSController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readFrameEndController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readFrameStartController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readGravController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLifeExpController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readMassController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readP2PBezier2Controller(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readP2PBezier3Controller(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readParticleRotController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readRandVelController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeStartController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeEndController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeStartYController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeEndYController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSpreadController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readThresholdController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readVelocityController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readXSizeController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readYSizeController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readBlurLengthController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLightingDelayController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLightingRadiusController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLightingScaleController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLightingSubDivController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readLightingZigZagController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readAlphaMidController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readPercentStartController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readPercentMidController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readPercentEndController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeMidController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readSizeMidYController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readRandomBirthRateController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readTargetSizeController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readNumControlPtsController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readControlPtRadiusController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readControlPtDelayController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readTangentSpreadController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readTangentLengthController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readColorMidController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readColorEndController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readColorStartController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
static void readDetonateController(const ControllerKey &key, const std::vector<float> &data, ModelNode &node);
|
||||
|
||||
static void readFloatController(const ControllerKey &key, const std::vector<float> &data, AnimatedProperty<float> &prop);
|
||||
static void readVectorController(const ControllerKey &key, const std::vector<float> &data, AnimatedProperty<glm::vec3> &prop);
|
||||
|
||||
// END Controllers
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
443
src/engine/graphics/model/mdlreader_controllers.cpp
Normal file
443
src/engine/graphics/model/mdlreader_controllers.cpp
Normal file
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mdlreader.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "glm/ext.hpp"
|
||||
|
||||
#include "../../common/collectionutil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::resource;
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
static constexpr int kFlagBezier = 16;
|
||||
|
||||
void MdlReader::initControllerFn() {
|
||||
_genericControllers = unordered_map<uint32_t, ControllerFn> {
|
||||
{ 8, &readPositionController },
|
||||
{ 20, &readOrientationController },
|
||||
{ 36, &readScaleController }
|
||||
};
|
||||
_meshControllers = unordered_map<uint32_t, ControllerFn> {
|
||||
{ 100, &readSelfIllumColorController },
|
||||
{ 132, &readAlphaController }
|
||||
};
|
||||
_lightControllers = unordered_map<uint32_t, ControllerFn> {
|
||||
{ 76, &readColorController },
|
||||
{ 88, &readRadiusController },
|
||||
{ 96, &readShadowRadiusController },
|
||||
{ 100, &readVerticalDisplacementController },
|
||||
{ 140, &readMultiplierController }
|
||||
};
|
||||
_emitterControllers = unordered_map<uint32_t, ControllerFn> {
|
||||
{ 80, &readAlphaEndController },
|
||||
{ 84, &readAlphaStartController },
|
||||
{ 88, &readBirthrateController },
|
||||
{ 92, &readBounceCoController },
|
||||
{ 96, &readCombineTimeController },
|
||||
{ 100, &readDragController },
|
||||
{ 104, &readFPSController },
|
||||
{ 108, &readFrameEndController },
|
||||
{ 112, &readFrameStartController },
|
||||
{ 116, &readGravController },
|
||||
{ 120, &readLifeExpController },
|
||||
{ 124, &readMassController },
|
||||
{ 128, &readP2PBezier2Controller },
|
||||
{ 132, &readP2PBezier3Controller },
|
||||
{ 136, &readParticleRotController },
|
||||
{ 140, &readRandVelController },
|
||||
{ 144, &readSizeStartController },
|
||||
{ 148, &readSizeEndController },
|
||||
{ 152, &readSizeStartYController },
|
||||
{ 156, &readSizeEndYController },
|
||||
{ 160, &readSpreadController },
|
||||
{ 164, &readThresholdController },
|
||||
{ 168, &readVelocityController },
|
||||
{ 172, &readXSizeController },
|
||||
{ 176, &readYSizeController },
|
||||
{ 180, &readBlurLengthController },
|
||||
{ 184, &readLightingDelayController },
|
||||
{ 188, &readLightingRadiusController },
|
||||
{ 192, &readLightingScaleController },
|
||||
{ 196, &readLightingSubDivController },
|
||||
{ 200, &readLightingZigZagController },
|
||||
{ 216, &readAlphaMidController },
|
||||
{ 220, &readPercentStartController },
|
||||
{ 224, &readPercentMidController },
|
||||
{ 228, &readPercentEndController },
|
||||
{ 232, &readSizeMidController },
|
||||
{ 236, &readSizeMidYController },
|
||||
{ 240, &readRandomBirthRateController },
|
||||
{ 252, &readTargetSizeController },
|
||||
{ 256, &readNumControlPtsController },
|
||||
{ 260, &readControlPtRadiusController },
|
||||
{ 264, &readControlPtDelayController },
|
||||
{ 268, &readTangentSpreadController },
|
||||
{ 272, &readTangentLengthController },
|
||||
{ 284, &readColorMidController },
|
||||
{ 380, &readColorEndController },
|
||||
{ 392, &readColorStartController },
|
||||
{ 502, &readDetonateController }
|
||||
};
|
||||
}
|
||||
|
||||
MdlReader::ControllerFn MdlReader::getControllerFn(uint32_t type, int nodeFlags) {
|
||||
ControllerFn fn;
|
||||
if (nodeFlags & NodeFlags::mesh) {
|
||||
fn = getFromLookupOrNull(_meshControllers, type);
|
||||
} else if (nodeFlags & NodeFlags::light) {
|
||||
fn = getFromLookupOrNull(_lightControllers, type);
|
||||
} else if (nodeFlags & NodeFlags::emitter) {
|
||||
fn = getFromLookupOrNull(_emitterControllers, type);
|
||||
}
|
||||
if (!fn) {
|
||||
fn = getFromLookupOrNull(_genericControllers, type);
|
||||
}
|
||||
return move(fn);
|
||||
}
|
||||
|
||||
static inline void ensureNumColumnsEquals(int type, int expected, int actual) {
|
||||
if (actual != expected) {
|
||||
throw runtime_error(str(boost::format("Controller %d: number of columns is %d, expected %d") % type % actual % expected));
|
||||
}
|
||||
}
|
||||
|
||||
void MdlReader::readPositionController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
bool bezier = key.numColumns & kFlagBezier;
|
||||
int numColumns = key.numColumns & ~kFlagBezier;
|
||||
ensureNumColumnsEquals(key.type, 3, numColumns);
|
||||
|
||||
for (uint16_t i = 0; i < key.numRows; ++i) {
|
||||
int rowTimeIdx = key.timeIndex + i;
|
||||
int rowDataIdx = key.dataIndex + (bezier ? 9 : 3) * i;
|
||||
float time = data[rowTimeIdx];
|
||||
glm::vec3 position(glm::make_vec3(&data[rowDataIdx]));
|
||||
node.position().addFrame(time, move(position));
|
||||
}
|
||||
node.position().update();
|
||||
}
|
||||
|
||||
void MdlReader::readOrientationController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
switch (key.numColumns) {
|
||||
case 2:
|
||||
for (uint16_t i = 0; i < key.numRows; ++i) {
|
||||
int rowTimeIdx = key.timeIndex + i;
|
||||
int rowDataIdx = key.dataIndex + i;
|
||||
|
||||
uint32_t temp = *reinterpret_cast<const uint32_t *>(&data[rowDataIdx]);
|
||||
float x = 1.0f - static_cast<float>(temp & 0x7ff) / 1023.0f;
|
||||
float y = 1.0f - static_cast<float>((temp >> 11) & 0x7ff) / 1023.0f;
|
||||
float z = 1.0f - static_cast<float>(temp >> 22) / 511.0f;
|
||||
float dot = x * x + y * y + z * z;
|
||||
float w;
|
||||
|
||||
if (dot >= 1.0f) {
|
||||
float len = glm::sqrt(dot);
|
||||
x /= len;
|
||||
y /= len;
|
||||
z /= len;
|
||||
w = 0.0f;
|
||||
} else {
|
||||
w = -glm::sqrt(1.0f - dot);
|
||||
}
|
||||
|
||||
float time = data[rowTimeIdx];
|
||||
glm::quat orientation(w, x, y, z);
|
||||
node.orientation().addFrame(time, move(orientation));
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (uint16_t i = 0; i < key.numRows; ++i) {
|
||||
int rowTimeIdx = key.timeIndex + i;
|
||||
int rowDataIdx = key.dataIndex + 4 * i;
|
||||
|
||||
float time = data[rowTimeIdx];
|
||||
|
||||
float x = data[rowDataIdx + 0];
|
||||
float y = data[rowDataIdx + 1];
|
||||
float z = data[rowDataIdx + 2];
|
||||
float w = data[rowDataIdx + 3];
|
||||
glm::quat orientation(w, x, y, z);
|
||||
|
||||
node.orientation().addFrame(time, move(orientation));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("Unexpected number of columns: " + to_string(key.numColumns));
|
||||
}
|
||||
|
||||
node.orientation().update();
|
||||
}
|
||||
|
||||
void MdlReader::readFloatController(const ControllerKey &key, const vector<float> &data, AnimatedProperty<float> &prop) {
|
||||
ensureNumColumnsEquals(key.type, 1, key.numColumns);
|
||||
for (uint16_t i = 0; i < key.numRows; ++i) {
|
||||
float time = data[key.timeIndex + i];
|
||||
float value = data[key.dataIndex + i];
|
||||
prop.addFrame(time, value);
|
||||
}
|
||||
prop.update();
|
||||
}
|
||||
|
||||
void MdlReader::readVectorController(const ControllerKey &key, const vector<float> &data, AnimatedProperty<glm::vec3> &prop) {
|
||||
bool bezier = key.numColumns & kFlagBezier;
|
||||
int numColumns = key.numColumns & ~kFlagBezier;
|
||||
ensureNumColumnsEquals(key.type, 3, numColumns);
|
||||
|
||||
for (uint16_t i = 0; i < key.numRows; ++i) {
|
||||
float time = data[key.timeIndex + i];
|
||||
glm::vec3 value(glm::make_vec3(&data[key.dataIndex + (bezier ? 9 : 3) * i]));
|
||||
prop.addFrame(time, value);
|
||||
}
|
||||
prop.update();
|
||||
}
|
||||
|
||||
void MdlReader::readScaleController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.scale());
|
||||
}
|
||||
|
||||
void MdlReader::readSelfIllumColorController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readVectorController(key, data, node.selfIllumColor());
|
||||
}
|
||||
|
||||
void MdlReader::readAlphaController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.alpha());
|
||||
}
|
||||
|
||||
void MdlReader::readColorController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readVectorController(key, data, node.color());
|
||||
}
|
||||
|
||||
void MdlReader::readRadiusController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.radius());
|
||||
}
|
||||
|
||||
void MdlReader::readShadowRadiusController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.shadowRadius());
|
||||
}
|
||||
|
||||
void MdlReader::readVerticalDisplacementController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.verticalDisplacement());
|
||||
}
|
||||
|
||||
void MdlReader::readMultiplierController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.multiplier());
|
||||
}
|
||||
|
||||
void MdlReader::readAlphaEndController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.alphaEnd());
|
||||
}
|
||||
|
||||
void MdlReader::readAlphaStartController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.alphaStart());
|
||||
}
|
||||
|
||||
void MdlReader::readBirthrateController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.birthrate());
|
||||
}
|
||||
|
||||
void MdlReader::readBounceCoController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.bounceCo());
|
||||
}
|
||||
|
||||
void MdlReader::readCombineTimeController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.combineTime());
|
||||
}
|
||||
|
||||
void MdlReader::readDragController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.drag());
|
||||
}
|
||||
|
||||
void MdlReader::readFPSController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.fps());
|
||||
}
|
||||
|
||||
void MdlReader::readFrameEndController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.frameEnd());
|
||||
}
|
||||
|
||||
void MdlReader::readFrameStartController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.frameStart());
|
||||
}
|
||||
|
||||
void MdlReader::readGravController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.grav());
|
||||
}
|
||||
|
||||
void MdlReader::readLifeExpController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lifeExp());
|
||||
}
|
||||
|
||||
void MdlReader::readMassController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.mass());
|
||||
}
|
||||
|
||||
void MdlReader::readP2PBezier2Controller(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.p2pBezier2());
|
||||
}
|
||||
|
||||
void MdlReader::readP2PBezier3Controller(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.p2pBezier3());
|
||||
}
|
||||
|
||||
void MdlReader::readParticleRotController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.particleRot());
|
||||
}
|
||||
|
||||
void MdlReader::readRandVelController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.randVel());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeStartController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeStart());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeEndController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeEnd());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeStartYController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeStartY());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeEndYController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeEndY());
|
||||
}
|
||||
|
||||
void MdlReader::readSpreadController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.spread());
|
||||
}
|
||||
|
||||
void MdlReader::readThresholdController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.threshold());
|
||||
}
|
||||
|
||||
void MdlReader::readVelocityController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.velocity());
|
||||
}
|
||||
|
||||
void MdlReader::readXSizeController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.xSize());
|
||||
}
|
||||
|
||||
void MdlReader::readYSizeController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.ySize());
|
||||
}
|
||||
|
||||
void MdlReader::readBlurLengthController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.blurLength());
|
||||
}
|
||||
|
||||
void MdlReader::readLightingDelayController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lightingDelay());
|
||||
}
|
||||
|
||||
void MdlReader::readLightingRadiusController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lightingRadius());
|
||||
}
|
||||
|
||||
void MdlReader::readLightingScaleController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lightingScale());
|
||||
}
|
||||
|
||||
void MdlReader::readLightingSubDivController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lightingSubDiv());
|
||||
}
|
||||
|
||||
void MdlReader::readLightingZigZagController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.lightingZigZag());
|
||||
}
|
||||
|
||||
void MdlReader::readAlphaMidController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.alphaMid());
|
||||
}
|
||||
|
||||
void MdlReader::readPercentStartController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.percentStart());
|
||||
}
|
||||
|
||||
void MdlReader::readPercentMidController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.percentMid());
|
||||
}
|
||||
|
||||
void MdlReader::readPercentEndController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.percentEnd());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeMidController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeMid());
|
||||
}
|
||||
|
||||
void MdlReader::readSizeMidYController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.sizeMidY());
|
||||
}
|
||||
|
||||
void MdlReader::readRandomBirthRateController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.randomBirthRate());
|
||||
}
|
||||
|
||||
void MdlReader::readTargetSizeController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.targetSize());
|
||||
}
|
||||
|
||||
void MdlReader::readNumControlPtsController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.numControlPts());
|
||||
}
|
||||
|
||||
void MdlReader::readControlPtRadiusController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.controlPtRadius());
|
||||
}
|
||||
|
||||
void MdlReader::readControlPtDelayController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.controlPtDelay());
|
||||
}
|
||||
|
||||
void MdlReader::readTangentSpreadController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.tangentSpread());
|
||||
}
|
||||
|
||||
void MdlReader::readTangentLengthController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.tangentLength());
|
||||
}
|
||||
|
||||
void MdlReader::readColorMidController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readVectorController(key, data, node.colorMid());
|
||||
}
|
||||
|
||||
void MdlReader::readColorEndController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readVectorController(key, data, node.colorEnd());
|
||||
}
|
||||
|
||||
void MdlReader::readColorStartController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readVectorController(key, data, node.colorStart());
|
||||
}
|
||||
|
||||
void MdlReader::readDetonateController(const ControllerKey &key, const vector<float> &data, ModelNode &node) {
|
||||
readFloatController(key, data, node.detonate());
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
} // namespace reone
|
|
@ -31,37 +31,64 @@ namespace graphics {
|
|||
Model::Model(
|
||||
string name,
|
||||
Classification classification,
|
||||
float animationScale,
|
||||
shared_ptr<Model> superModel,
|
||||
shared_ptr<ModelNode> rootNode,
|
||||
vector<shared_ptr<Animation>> animations,
|
||||
shared_ptr<Model> superModel
|
||||
float animationScale
|
||||
) :
|
||||
_name(move(name)),
|
||||
_classification(classification),
|
||||
_animationScale(animationScale),
|
||||
_superModel(move(superModel)),
|
||||
_rootNode(rootNode),
|
||||
_superModel(move(superModel)) {
|
||||
_animationScale(animationScale) {
|
||||
|
||||
if (!rootNode) {
|
||||
throw invalid_argument("rootNode must not be null");
|
||||
}
|
||||
for (auto &anim : animations) {
|
||||
_animations.insert(make_pair(anim->name(), move(anim)));
|
||||
}
|
||||
initInternal(_rootNode);
|
||||
|
||||
fillNodeLookups(_rootNode);
|
||||
fillBoneNodeId();
|
||||
computeAABB();
|
||||
}
|
||||
|
||||
void Model::initInternal(const shared_ptr<ModelNode> &node) {
|
||||
_nodeByNumber.insert(make_pair(node->nodeNumber(), node));
|
||||
void Model::fillNodeLookups(const shared_ptr<ModelNode> &node) {
|
||||
_nodes.push_back(node);
|
||||
_nodeById.insert(make_pair(node->id(), node));
|
||||
_nodeByName.insert(make_pair(node->name(), node));
|
||||
|
||||
shared_ptr<ModelNode::Trimesh> mesh(node->mesh());
|
||||
if (mesh) {
|
||||
_aabb.expand(mesh->mesh->aabb() * node->absoluteTransform());
|
||||
}
|
||||
|
||||
for (auto &child : node->children()) {
|
||||
initInternal(child);
|
||||
fillNodeLookups(child);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::fillBoneNodeId() {
|
||||
// In MDL files, bones reference node serial numbers (DFS ordering).
|
||||
// We want them to reference node identifiers, for simplicity.
|
||||
|
||||
for (auto &node : _nodes) {
|
||||
if (!node->isSkinMesh()) continue;
|
||||
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(node->mesh());
|
||||
mesh->skin->boneNodeId.resize(mesh->skin->boneNodeSerial.size());
|
||||
|
||||
for (size_t i = 0; i < mesh->skin->boneNodeSerial.size(); ++i) {
|
||||
uint16_t nodeSerial = mesh->skin->boneNodeSerial[i];
|
||||
if (nodeSerial < static_cast<int>(_nodes.size())) {
|
||||
mesh->skin->boneNodeId[i] = _nodes[nodeSerial]->id();
|
||||
} else {
|
||||
mesh->skin->boneNodeId[i] = 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::computeAABB() {
|
||||
_aabb.reset();
|
||||
|
||||
for (auto &node : _nodeById) {
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(node.second->mesh());
|
||||
if (mesh) {
|
||||
_aabb.expand(mesh->mesh->aabb() * node.second->absoluteTransform());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +96,10 @@ void Model::init() {
|
|||
_rootNode->init();
|
||||
}
|
||||
|
||||
void Model::addAnimation(shared_ptr<Animation> animation) {
|
||||
_animations.insert(make_pair(animation->name(), move(animation)));
|
||||
}
|
||||
|
||||
vector<string> Model::getAnimationNames() const {
|
||||
vector<string> result;
|
||||
|
||||
|
@ -100,17 +131,13 @@ shared_ptr<Animation> Model::getAnimation(const string &name) const {
|
|||
return move(anim);
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode> Model::findNodeByNumber(uint16_t number) const {
|
||||
return getFromLookupOrNull(_nodeByNumber, number);
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode> Model::findNodeByName(const string &name) const {
|
||||
shared_ptr<ModelNode> Model::getNodeByName(const string &name) const {
|
||||
return getFromLookupOrNull(_nodeByName, name);
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode> Model::findAABBNode() const {
|
||||
for (auto &node : _nodeByNumber) {
|
||||
if (node.second->isAABB()) return node.second;
|
||||
shared_ptr<ModelNode> Model::getAABBNode() const {
|
||||
for (auto &node : _nodeById) {
|
||||
if (node.second->isAABBMesh()) return node.second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -32,11 +32,10 @@ namespace reone {
|
|||
namespace graphics {
|
||||
|
||||
/**
|
||||
* Tree-like data structure, representing a 3D model. Contains model nodes
|
||||
* and animations. Models are cached and reused between model scene nodes.
|
||||
* 3D model, a tree-like data structure. Contains model nodes and animations.
|
||||
*
|
||||
* @see reone::graphics::ModelNode
|
||||
* @see reone::graphics::Animation
|
||||
* @see ModelNode
|
||||
* @see Animation
|
||||
*/
|
||||
class Model : boost::noncopyable {
|
||||
public:
|
||||
|
@ -54,20 +53,20 @@ public:
|
|||
Model(
|
||||
std::string name,
|
||||
Classification classification,
|
||||
float animationScale,
|
||||
std::shared_ptr<Model> superModel,
|
||||
std::shared_ptr<ModelNode> rootNode,
|
||||
std::vector<std::shared_ptr<Animation>> animations,
|
||||
std::shared_ptr<Model> superModel = nullptr);
|
||||
float animationScale);
|
||||
|
||||
void init();
|
||||
|
||||
void addAnimation(std::shared_ptr<Animation> animation);
|
||||
|
||||
bool isAffectedByFog() const { return _affectedByFog; }
|
||||
|
||||
std::vector<std::string> getAnimationNames() const;
|
||||
std::shared_ptr<Animation> getAnimation(const std::string &name) const;
|
||||
std::shared_ptr<ModelNode> findNodeByNumber(uint16_t number) const;
|
||||
std::shared_ptr<ModelNode> findNodeByName(const std::string &name) const;
|
||||
std::shared_ptr<ModelNode> findAABBNode() const;
|
||||
std::shared_ptr<ModelNode> getNodeByName(const std::string &name) const;
|
||||
std::shared_ptr<ModelNode> getAABBNode() const;
|
||||
|
||||
const std::string &name() const { return _name; }
|
||||
Classification classification() const { return _classification; }
|
||||
|
@ -81,19 +80,20 @@ public:
|
|||
private:
|
||||
std::string _name;
|
||||
Classification _classification;
|
||||
float _animationScale;
|
||||
std::shared_ptr<Model> _superModel;
|
||||
std::shared_ptr<ModelNode> _rootNode;
|
||||
std::unordered_map<std::string, std::shared_ptr<Animation>> _animations;
|
||||
std::shared_ptr<Model> _superModel;
|
||||
float _animationScale;
|
||||
bool _affectedByFog;
|
||||
|
||||
std::unordered_map<uint16_t, std::shared_ptr<ModelNode>> _nodeByNumber;
|
||||
std::vector<std::shared_ptr<ModelNode>> _nodes;
|
||||
std::unordered_map<uint16_t, std::shared_ptr<ModelNode>> _nodeById;
|
||||
std::unordered_map<std::string, std::shared_ptr<ModelNode>> _nodeByName;
|
||||
AABB _aabb;
|
||||
bool _affectedByFog { false };
|
||||
|
||||
void initInternal(const std::shared_ptr<ModelNode> &node);
|
||||
|
||||
friend class MdlReader;
|
||||
void fillNodeLookups(const std::shared_ptr<ModelNode> &node);
|
||||
void fillBoneNodeId();
|
||||
void computeAABB();
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
@ -17,17 +17,46 @@
|
|||
|
||||
#include "modelnode.h"
|
||||
|
||||
#include "glm/gtx/matrix_decompose.hpp"
|
||||
|
||||
#include "../../common/log.h"
|
||||
|
||||
#include "glm/gtx/transform.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
ModelNode::ModelNode(int index, const ModelNode *parent) : _index(index), _parent(parent) {
|
||||
ModelNode::ModelNode(
|
||||
uint16_t id,
|
||||
string name,
|
||||
glm::vec3 restPosition,
|
||||
glm::quat restOrientation,
|
||||
const ModelNode *parent
|
||||
) :
|
||||
_id(id),
|
||||
_name(move(name)),
|
||||
_restPosition(move(restPosition)),
|
||||
_restOrientation(move(restOrientation)),
|
||||
_parent(parent) {
|
||||
|
||||
computeLocalTransform();
|
||||
computeAbsoluteTransform();
|
||||
}
|
||||
|
||||
void ModelNode::computeLocalTransform() {
|
||||
_localTransform = glm::mat4(1.0f);
|
||||
_localTransform *= glm::translate(_restPosition);
|
||||
_localTransform *= glm::mat4_cast(_restOrientation);
|
||||
}
|
||||
|
||||
void ModelNode::computeAbsoluteTransform() {
|
||||
if (_parent) {
|
||||
_absTransform = _parent->_absTransform * _localTransform;
|
||||
} else {
|
||||
_absTransform = _localTransform;
|
||||
}
|
||||
_absTransformInv = glm::inverse(_absTransform);
|
||||
}
|
||||
|
||||
void ModelNode::init() {
|
||||
|
@ -39,95 +68,58 @@ void ModelNode::init() {
|
|||
}
|
||||
}
|
||||
|
||||
void ModelNode::addChild(shared_ptr<ModelNode> child) {
|
||||
child->_parent = this;
|
||||
void ModelNode::addChild(std::shared_ptr<ModelNode> child) {
|
||||
_children.push_back(move(child));
|
||||
}
|
||||
|
||||
void ModelNode::computeLocalTransforms() {
|
||||
if (_parent) {
|
||||
_localTransform = glm::inverse(_parent->_absTransform) * _absTransform;
|
||||
_absTransform = _parent->_absTransform * _localTransform;
|
||||
_absTransformInv = glm::inverse(_absTransform);
|
||||
|
||||
// Extract position and orientation for use in animations.
|
||||
glm::vec3 scale, skew;
|
||||
glm::vec4 perspective;
|
||||
glm::decompose(_localTransform, scale, _orientation, _position, skew, perspective);
|
||||
|
||||
} else {
|
||||
_localTransform = _absTransform;
|
||||
}
|
||||
|
||||
_absTransform = _parent ? _parent->_absTransform * _localTransform : _localTransform;
|
||||
_absTransformInv = glm::inverse(_absTransform);
|
||||
|
||||
for (auto &child : _children) {
|
||||
child->computeLocalTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelNode::computeAbsoluteTransforms() {
|
||||
_absTransform = _parent ? _parent->_absTransform * _localTransform : _localTransform;
|
||||
_absTransformInv = glm::inverse(_absTransform);
|
||||
|
||||
for (auto &child : _children) {
|
||||
child->computeAbsoluteTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelNode::getPosition(int leftFrameIdx, int rightFrameIdx, float factor, glm::vec3 &position) const {
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_positions.getNumKeyframes()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_positions.getNumKeyframes())) return false;
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_position.getNumFrames()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_position.getNumFrames())) return false;
|
||||
|
||||
if (leftFrameIdx == rightFrameIdx) {
|
||||
position = _positions.getByKeyframe(leftFrameIdx);
|
||||
position = _position.getByFrame(leftFrameIdx);
|
||||
} else {
|
||||
position = glm::mix(
|
||||
_positions.getByKeyframe(leftFrameIdx),
|
||||
_positions.getByKeyframe(rightFrameIdx),
|
||||
_position.getByFrame(leftFrameIdx),
|
||||
_position.getByFrame(rightFrameIdx),
|
||||
factor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModelNode::getOrientation(int leftFrameIdx, int rightFrameIdx, float interpolant, glm::quat &orientation) const {
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_orientations.getNumKeyframes()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_orientations.getNumKeyframes())) return false;
|
||||
bool ModelNode::getOrientation(int leftFrameIdx, int rightFrameIdx, float factor, glm::quat &orientation) const {
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_orientation.getNumFrames()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_orientation.getNumFrames())) return false;
|
||||
|
||||
if (leftFrameIdx == rightFrameIdx) {
|
||||
orientation = _orientations.getByKeyframe(leftFrameIdx);
|
||||
orientation = _orientation.getByFrame(leftFrameIdx);
|
||||
} else {
|
||||
orientation = glm::slerp(
|
||||
_orientations.getByKeyframe(leftFrameIdx),
|
||||
_orientations.getByKeyframe(rightFrameIdx),
|
||||
interpolant);
|
||||
_orientation.getByFrame(leftFrameIdx),
|
||||
_orientation.getByFrame(rightFrameIdx),
|
||||
factor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModelNode::getScale(int leftFrameIdx, int rightFrameIdx, float interpolant, float &scale) const {
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_scales.getNumKeyframes()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_scales.getNumKeyframes())) return false;
|
||||
bool ModelNode::getScale(int leftFrameIdx, int rightFrameIdx, float factor, float &scale) const {
|
||||
if (leftFrameIdx < 0 || leftFrameIdx >= static_cast<int>(_scale.getNumFrames()) ||
|
||||
rightFrameIdx < 0 || rightFrameIdx >= static_cast<int>(_scale.getNumFrames())) return false;
|
||||
|
||||
if (leftFrameIdx == rightFrameIdx) {
|
||||
scale = _scales.getByKeyframe(leftFrameIdx);
|
||||
scale = _scale.getByFrame(leftFrameIdx);
|
||||
} else {
|
||||
scale = glm::mix(
|
||||
_scales.getByKeyframe(leftFrameIdx),
|
||||
_scales.getByKeyframe(rightFrameIdx),
|
||||
interpolant);
|
||||
_scale.getByFrame(leftFrameIdx),
|
||||
_scale.getByFrame(rightFrameIdx),
|
||||
factor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const glm::vec3 &ModelNode::getCenterOfAABB() const {
|
||||
return _mesh->mesh->aabb().center();
|
||||
}
|
||||
|
||||
vector<uint32_t> ModelNode::getFacesByMaterial(uint32_t material) const {
|
||||
if (!_mesh || _mesh->materialFaces.count(material) == 0) return vector<uint32_t>();
|
||||
|
||||
|
|
|
@ -25,34 +25,102 @@
|
|||
#include "glm/gtx/quaternion.hpp"
|
||||
|
||||
#include "../mesh/mesh.h"
|
||||
#include "../texture/texture.h"
|
||||
|
||||
#include "aabbnode.h"
|
||||
#include "animatedproperty.h"
|
||||
#include "emitter.h"
|
||||
#include "lensflare.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace graphics {
|
||||
|
||||
#define DECL_ANIM_PROP(a, b, c) \
|
||||
const AnimatedProperty<a> &b() const { return c; }; \
|
||||
AnimatedProperty<a> &b() { return c; };
|
||||
|
||||
class Model;
|
||||
|
||||
/**
|
||||
* Node of a 3D model or an animation, which are tree-like data structures.
|
||||
* Model nodes have spatial properties and can have an arbitary number of
|
||||
* children.
|
||||
*
|
||||
* When part of an animation, certain properties of a model node can be
|
||||
* animated. These are position, orientation, scale, alpha and self-illumination
|
||||
* color.
|
||||
*
|
||||
* Model nodes can be specialized to represent meshes, lights, emitters, etc.
|
||||
*
|
||||
* @see reone::graphics::Model
|
||||
* @see reone::graphics::Animation
|
||||
* Model or animation node. Can be specialized to represent a triangle mesh, a light, an emitter and etc.
|
||||
*/
|
||||
class ModelNode : boost::noncopyable {
|
||||
public:
|
||||
struct Skin {
|
||||
std::vector<uint16_t> boneNodeSerial; /**< temporary, used to fill boneNodeId below */
|
||||
std::vector<uint16_t> boneNodeId; /**< used in skeletal animation */
|
||||
};
|
||||
|
||||
struct UVAnimation {
|
||||
glm::vec2 dir { 0.0f };
|
||||
};
|
||||
|
||||
struct DanglyMeshConstraint {
|
||||
float multiplier { 0.0f };
|
||||
glm::vec3 position { 0.0f };
|
||||
};
|
||||
|
||||
struct DanglyMesh {
|
||||
float displacement { 0.0f };
|
||||
float tightness { 0.0f };
|
||||
float period { 0.0f };
|
||||
std::vector<DanglyMeshConstraint> constraints;
|
||||
};
|
||||
|
||||
struct AABBTree {
|
||||
enum class Plane {
|
||||
None = 0,
|
||||
PositiveX = 1,
|
||||
PositiveY = 2,
|
||||
PositiveZ = 4
|
||||
};
|
||||
|
||||
int faceIndex { 0 };
|
||||
Plane mostSignificantPlane { Plane::None };
|
||||
AABB aabb;
|
||||
std::shared_ptr<AABBTree> left;
|
||||
std::shared_ptr<AABBTree> right;
|
||||
};
|
||||
|
||||
struct TriangleMesh {
|
||||
std::shared_ptr<Mesh> mesh;
|
||||
std::unordered_map<uint32_t, std::vector<uint32_t>> materialFaces;
|
||||
UVAnimation uvAnimation;
|
||||
glm::vec3 diffuse { 1.0f };
|
||||
glm::vec3 ambient { 1.0f };
|
||||
int transparency { 0 };
|
||||
|
||||
// Flags
|
||||
|
||||
bool render { false };
|
||||
bool shadow { false };
|
||||
bool backgroundGeometry { false };
|
||||
|
||||
// END Flags
|
||||
|
||||
// Textures
|
||||
|
||||
std::shared_ptr<Texture> diffuseMap;
|
||||
std::shared_ptr<Texture> lightmap;
|
||||
std::shared_ptr<Texture> bumpmap;
|
||||
|
||||
// END Textures
|
||||
|
||||
// Specialization
|
||||
|
||||
std::shared_ptr<Skin> skin;
|
||||
std::shared_ptr<DanglyMesh> danglyMesh;
|
||||
std::shared_ptr<AABBTree> aabbTree;
|
||||
bool saber { false };
|
||||
|
||||
// END Specialization
|
||||
};
|
||||
|
||||
struct LensFlare {
|
||||
std::shared_ptr<Texture> texture;
|
||||
glm::vec3 colorShift { 0.0f };
|
||||
float position { 0.0f };
|
||||
float size { 0.0f };
|
||||
};
|
||||
|
||||
struct Light {
|
||||
int priority { 0 };
|
||||
int dynamicType { 0 };
|
||||
|
@ -63,181 +131,284 @@ public:
|
|||
std::vector<LensFlare> flares;
|
||||
};
|
||||
|
||||
struct Emitter {
|
||||
enum class UpdateMode {
|
||||
Invalid,
|
||||
Fountain,
|
||||
Single,
|
||||
Explosion
|
||||
};
|
||||
|
||||
enum class RenderMode {
|
||||
Invalid = 0,
|
||||
Normal = 1,
|
||||
BillboardToWorldZ = 2,
|
||||
MotionBlur = 3,
|
||||
BillboardToLocalZ = 4,
|
||||
AlignedToParticleDir = 5
|
||||
};
|
||||
|
||||
enum class BlendMode {
|
||||
Invalid,
|
||||
Normal,
|
||||
Punch,
|
||||
Lighten
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Constraints {
|
||||
T start;
|
||||
T mid;
|
||||
T end;
|
||||
};
|
||||
|
||||
UpdateMode updateMode { UpdateMode::Invalid };
|
||||
RenderMode renderMode { RenderMode::Invalid };
|
||||
BlendMode blendMode { BlendMode::Invalid };
|
||||
int renderOrder { 0 };
|
||||
|
||||
std::shared_ptr<Texture> texture;
|
||||
int gridWidth { 0 };
|
||||
int gridHeight { 0 };
|
||||
int frameStart { 0 };
|
||||
int frameEnd { 0 };
|
||||
|
||||
glm::vec2 size { 0.0f };
|
||||
float birthrate { 0.0f }; /**< rate of particle birth per second */
|
||||
float lifeExpectancy { 0.0f }; /**< life of each particle in seconds */
|
||||
float velocity { 0.0f };
|
||||
float randomVelocity { 0.0f };
|
||||
float spread { 0.0f };
|
||||
bool loop { false };
|
||||
float fps { 0.0f };
|
||||
|
||||
Constraints<float> particleSize;
|
||||
Constraints<glm::vec3> color;
|
||||
Constraints<float> alpha;
|
||||
};
|
||||
|
||||
struct Reference {
|
||||
std::shared_ptr<Model> model;
|
||||
bool reattachable { false };
|
||||
};
|
||||
|
||||
struct Skin {
|
||||
std::unordered_map<uint16_t, uint16_t> nodeIdxByBoneIdx;
|
||||
};
|
||||
|
||||
struct DanglymeshConstraint {
|
||||
float multiplier { 0.0f };
|
||||
glm::vec3 position { 0.0f };
|
||||
};
|
||||
|
||||
struct Danglymesh {
|
||||
float displacement { 0.0f };
|
||||
float tightness { 0.0f };
|
||||
float period { 0.0f };
|
||||
std::vector<DanglymeshConstraint> constraints;
|
||||
};
|
||||
|
||||
struct UVAnimation {
|
||||
bool animated { false };
|
||||
float directionX { 0.0f };
|
||||
float directionY { 0.0f };
|
||||
};
|
||||
|
||||
struct Trimesh {
|
||||
std::shared_ptr<Mesh> mesh;
|
||||
std::unordered_map<uint32_t, std::vector<uint32_t>> materialFaces;
|
||||
UVAnimation uvAnimation;
|
||||
|
||||
int transparency { 0 };
|
||||
glm::vec3 ambientColor { 1.0f };
|
||||
glm::vec3 diffuseColor { 0.0f };
|
||||
|
||||
bool render { false };
|
||||
bool shadow { false };
|
||||
bool backgroundGeometry { false };
|
||||
bool bumpmapSwizzled { false };
|
||||
|
||||
std::shared_ptr<Texture> diffuse;
|
||||
std::shared_ptr<Texture> lightmap;
|
||||
std::shared_ptr<Texture> bumpmap;
|
||||
};
|
||||
|
||||
ModelNode(int index, const ModelNode *parent = nullptr);
|
||||
ModelNode(
|
||||
uint16_t id,
|
||||
std::string name,
|
||||
glm::vec3 restPosition,
|
||||
glm::quat restOrientation,
|
||||
const ModelNode *parent = nullptr);
|
||||
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Adds the specified node to the list of this nodes children. Also sets the
|
||||
* specified nodes parent pointer to this node.
|
||||
*/
|
||||
void addChild(std::shared_ptr<ModelNode> node);
|
||||
void addChild(std::shared_ptr<ModelNode> child);
|
||||
|
||||
/**
|
||||
* Recursively computes the local transform, position and orientation of
|
||||
* this node and its children. Absolute transform must be set prior to
|
||||
* calling this method.
|
||||
*/
|
||||
void computeLocalTransforms();
|
||||
std::vector<uint32_t> getFacesByMaterial(uint32_t material) const;
|
||||
|
||||
/**
|
||||
* Recursively computes the absolute transform of this node and its
|
||||
* children. Local transform must be set prior to calling this method.
|
||||
*/
|
||||
void computeAbsoluteTransforms();
|
||||
uint16_t id() const { return _id; }
|
||||
const std::string &name() const { return _name; }
|
||||
uint16_t flags() const { return _flags; }
|
||||
const ModelNode *parent() const { return _parent; }
|
||||
const std::vector<std::shared_ptr<ModelNode>> &children() const { return _children; }
|
||||
|
||||
bool isAABB() const { return static_cast<bool>(_aabb); }
|
||||
bool isSaber() const { return _saber; }
|
||||
void setFlags(uint16_t flags) { _flags = flags; }
|
||||
|
||||
// Transformations
|
||||
|
||||
const glm::vec3 &restPosition() const { return _restPosition; }
|
||||
const glm::quat &restOrientation() const { return _restOrientation; }
|
||||
const glm::mat4 &localTransform() const { return _localTransform; }
|
||||
const glm::mat4 &absoluteTransform() const { return _absTransform; }
|
||||
const glm::mat4 &absoluteTransformInverse() const { return _absTransformInv; }
|
||||
|
||||
// END Transformations
|
||||
|
||||
// Specialization
|
||||
|
||||
bool isSkinMesh() const { return _mesh && _mesh->skin; }
|
||||
bool isDanglyMesh() const { return _mesh && _mesh->danglyMesh; }
|
||||
bool isAABBMesh() const { return _mesh && _mesh->aabbTree; }
|
||||
bool isSaberMesh() const { return _mesh && _mesh->saber; }
|
||||
|
||||
std::shared_ptr<TriangleMesh> mesh() const { return _mesh; }
|
||||
std::shared_ptr<Light> light() const { return _light; }
|
||||
std::shared_ptr<Emitter> emitter() const { return _emitter; }
|
||||
std::shared_ptr<Reference> reference() const { return _reference; }
|
||||
|
||||
void setMesh(std::shared_ptr<TriangleMesh> mesh) { _mesh = std::move(mesh); }
|
||||
void setLight(std::shared_ptr<Light> light) { _light = std::move(light); }
|
||||
void setEmitter(std::shared_ptr<Emitter> emitter) { _emitter = std::move(emitter); }
|
||||
void setReference(std::shared_ptr<Reference> reference) { _reference = std::move(reference); }
|
||||
|
||||
// END Specialization
|
||||
|
||||
// Keyframes
|
||||
|
||||
bool getPosition(int leftFrameIdx, int rightFrameIdx, float factor, glm::vec3 &position) const;
|
||||
bool getOrientation(int leftFrameIdx, int rightFrameIdx, float factor, glm::quat &orientation) const;
|
||||
bool getScale(int leftFrameIx, int rightFrameIdx, float factor, float &scale) const;
|
||||
|
||||
const glm::vec3 &getCenterOfAABB() const;
|
||||
const AnimatedProperty<glm::quat, SlerpInterpolator> &orientation() const { return _orientation; }
|
||||
AnimatedProperty<glm::quat, SlerpInterpolator> &orientation() { return _orientation; }
|
||||
|
||||
std::vector<uint32_t> getFacesByMaterial(uint32_t material) const;
|
||||
DECL_ANIM_PROP(glm::vec3, position, _position)
|
||||
DECL_ANIM_PROP(float, scale, _scale)
|
||||
|
||||
int index() const { return _index; }
|
||||
const ModelNode *parent() const { return _parent; }
|
||||
uint16_t nodeNumber() const { return _nodeNumber; }
|
||||
const std::string &name() const { return _name; }
|
||||
const std::vector<std::shared_ptr<ModelNode>> &children() const { return _children; }
|
||||
DECL_ANIM_PROP(glm::vec3, selfIllumColor, _selfIllumColor)
|
||||
DECL_ANIM_PROP(float, alpha, _alpha)
|
||||
|
||||
// Transformation
|
||||
DECL_ANIM_PROP(glm::vec3, color, _color)
|
||||
DECL_ANIM_PROP(float, radius, _radius)
|
||||
DECL_ANIM_PROP(float, shadowRadius, _shadowRadius)
|
||||
DECL_ANIM_PROP(float, verticalDisplacement, _verticalDisplacement)
|
||||
DECL_ANIM_PROP(float, multiplier, _multiplier)
|
||||
|
||||
const glm::vec3 &position() const { return _position; }
|
||||
const glm::quat &orientation() const { return _orientation; }
|
||||
const glm::mat4 &localTransform() const { return _localTransform; }
|
||||
const glm::mat4 &absoluteTransform() const { return _absTransform; }
|
||||
const glm::mat4 &absoluteTransformInverse() const { return _absTransformInv; }
|
||||
DECL_ANIM_PROP(float, alphaEnd, _alphaEnd)
|
||||
DECL_ANIM_PROP(float, alphaStart, _alphaStart)
|
||||
DECL_ANIM_PROP(float, birthrate, _birthrate)
|
||||
DECL_ANIM_PROP(float, bounceCo, _bounceCo)
|
||||
DECL_ANIM_PROP(float, combineTime, _combineTime)
|
||||
DECL_ANIM_PROP(float, drag, _drag)
|
||||
DECL_ANIM_PROP(float, fps, _fps)
|
||||
DECL_ANIM_PROP(float, frameEnd, _frameEnd)
|
||||
DECL_ANIM_PROP(float, frameStart, _frameStart)
|
||||
DECL_ANIM_PROP(float, grav, _grav)
|
||||
DECL_ANIM_PROP(float, lifeExp, _lifeExp)
|
||||
DECL_ANIM_PROP(float, mass, _mass)
|
||||
DECL_ANIM_PROP(float, p2pBezier2, _p2pBezier2)
|
||||
DECL_ANIM_PROP(float, p2pBezier3, _p2pBezier3)
|
||||
DECL_ANIM_PROP(float, particleRot, _particleRot)
|
||||
DECL_ANIM_PROP(float, randVel, _randVel)
|
||||
DECL_ANIM_PROP(float, sizeStart, _sizeStart)
|
||||
DECL_ANIM_PROP(float, sizeEnd, _sizeEnd)
|
||||
DECL_ANIM_PROP(float, sizeStartY, _sizeStartY)
|
||||
DECL_ANIM_PROP(float, sizeEndY, _sizeEndY)
|
||||
DECL_ANIM_PROP(float, spread, _spread)
|
||||
DECL_ANIM_PROP(float, threshold, _threshold)
|
||||
DECL_ANIM_PROP(float, velocity, _velocity)
|
||||
DECL_ANIM_PROP(float, xSize, _xSize)
|
||||
DECL_ANIM_PROP(float, ySize, _ySize)
|
||||
DECL_ANIM_PROP(float, blurLength, _blurLength)
|
||||
DECL_ANIM_PROP(float, lightingDelay, _lightingDelay)
|
||||
DECL_ANIM_PROP(float, lightingRadius, _lightingRadius)
|
||||
DECL_ANIM_PROP(float, lightingScale, _lightingScale)
|
||||
DECL_ANIM_PROP(float, lightingSubDiv, _lightingSubDiv)
|
||||
DECL_ANIM_PROP(float, lightingZigZag, _lightingZigZag)
|
||||
DECL_ANIM_PROP(float, alphaMid, _alphaMid)
|
||||
DECL_ANIM_PROP(float, percentStart, _percentStart)
|
||||
DECL_ANIM_PROP(float, percentMid, _percentMid)
|
||||
DECL_ANIM_PROP(float, percentEnd, _percentEnd)
|
||||
DECL_ANIM_PROP(float, sizeMid, _sizeMid)
|
||||
DECL_ANIM_PROP(float, sizeMidY, _sizeMidY)
|
||||
DECL_ANIM_PROP(float, randomBirthRate, _randomBirthRate)
|
||||
DECL_ANIM_PROP(float, targetSize, _targetSize)
|
||||
DECL_ANIM_PROP(float, numControlPts, _numControlPts)
|
||||
DECL_ANIM_PROP(float, controlPtRadius, _controlPtRadius)
|
||||
DECL_ANIM_PROP(float, controlPtDelay, _controlPtDelay)
|
||||
DECL_ANIM_PROP(float, tangentSpread, _tangentSpread)
|
||||
DECL_ANIM_PROP(float, tangentLength, _tangentLength)
|
||||
DECL_ANIM_PROP(glm::vec3, colorMid, _colorMid)
|
||||
DECL_ANIM_PROP(glm::vec3, colorEnd, _colorEnd)
|
||||
DECL_ANIM_PROP(glm::vec3, colorStart, _colorStart)
|
||||
DECL_ANIM_PROP(float, detonate, _detonate)
|
||||
|
||||
// END Transformation
|
||||
|
||||
// Components
|
||||
|
||||
std::shared_ptr<Light> light() const { return _light; }
|
||||
std::shared_ptr<Emitter> emitter() const { return _emitter; }
|
||||
std::shared_ptr<Reference> reference() const { return _reference; }
|
||||
std::shared_ptr<Trimesh> mesh() const { return _mesh; }
|
||||
std::shared_ptr<Skin> skin() const { return _skin; }
|
||||
std::shared_ptr<Danglymesh> danglymesh() const { return _danglymesh; }
|
||||
std::shared_ptr<AABBNode> aabb() const { return _aabb; }
|
||||
|
||||
// END Components
|
||||
|
||||
// Animation
|
||||
|
||||
const AnimatedProperty<glm::vec3> &positions() const { return _positions; }
|
||||
AnimatedProperty<glm::vec3> &positions() { return _positions; }
|
||||
const AnimatedProperty<glm::quat, SlerpInterpolator> &orientations() const { return _orientations; }
|
||||
AnimatedProperty<glm::quat, SlerpInterpolator> &orientations() { return _orientations; }
|
||||
const AnimatedProperty<float> &scales() const { return _scales; }
|
||||
AnimatedProperty<float> &scales() { return _scales; }
|
||||
const AnimatedProperty<float> &alphas() const { return _alphas; }
|
||||
AnimatedProperty<float> &alphas() { return _alphas; }
|
||||
const AnimatedProperty<glm::vec3> &selfIllumColors() const { return _selfIllumColors; }
|
||||
AnimatedProperty<glm::vec3> &selfIllumColors() { return _selfIllumColors; }
|
||||
const AnimatedProperty<glm::vec3> &lightColors() const { return _lightColors; }
|
||||
AnimatedProperty<glm::vec3> &lightColors() { return _lightColors; }
|
||||
const AnimatedProperty<float> &lightMultipliers() const { return _lightMultipliers; }
|
||||
AnimatedProperty<float> &lightMultipliers() { return _lightMultipliers; }
|
||||
const AnimatedProperty<float> &lightRadii() const { return _lightRadii; }
|
||||
AnimatedProperty<float> &lightRadii() { return _lightRadii; }
|
||||
|
||||
// END Animation
|
||||
// END Keyframes
|
||||
|
||||
private:
|
||||
int _index;
|
||||
uint16_t _id; /**< node identifier, matches id within supermodel */
|
||||
std::string _name;
|
||||
const ModelNode *_parent;
|
||||
|
||||
uint16_t _flags { 0 };
|
||||
uint16_t _nodeNumber { 0 };
|
||||
std::string _name;
|
||||
std::vector<std::shared_ptr<ModelNode>> _children;
|
||||
|
||||
// Transformation
|
||||
// Transformations
|
||||
|
||||
glm::vec3 _position { 0.0f };
|
||||
glm::quat _orientation { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 _restPosition { 0.0f };
|
||||
glm::quat _restOrientation { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
glm::mat4 _localTransform { 1.0f };
|
||||
glm::mat4 _absTransform { 1.0f };
|
||||
glm::mat4 _absTransformInv { 1.0f };
|
||||
|
||||
// END Transformation
|
||||
// END Transformations
|
||||
|
||||
// Components
|
||||
// Specialization
|
||||
|
||||
std::shared_ptr<TriangleMesh> _mesh;
|
||||
std::shared_ptr<Light> _light;
|
||||
std::shared_ptr<Emitter> _emitter;
|
||||
std::shared_ptr<Reference> _reference;
|
||||
std::shared_ptr<Trimesh> _mesh;
|
||||
std::shared_ptr<Skin> _skin;
|
||||
std::shared_ptr<Danglymesh> _danglymesh;
|
||||
std::shared_ptr<AABBNode> _aabb;
|
||||
bool _saber { false };
|
||||
|
||||
// END Components
|
||||
// END Specialization
|
||||
|
||||
// Animation
|
||||
// Keyframes
|
||||
|
||||
AnimatedProperty<glm::vec3> _positions;
|
||||
AnimatedProperty<glm::quat, SlerpInterpolator> _orientations;
|
||||
AnimatedProperty<float> _scales;
|
||||
AnimatedProperty<float> _alphas;
|
||||
AnimatedProperty<glm::vec3> _selfIllumColors;
|
||||
AnimatedProperty<glm::vec3> _lightColors;
|
||||
AnimatedProperty<float> _lightMultipliers;
|
||||
AnimatedProperty<float> _lightRadii;
|
||||
AnimatedProperty<glm::vec3> _position;
|
||||
AnimatedProperty<glm::quat, SlerpInterpolator> _orientation;
|
||||
AnimatedProperty<float> _scale;
|
||||
|
||||
// END Animation
|
||||
AnimatedProperty<glm::vec3> _selfIllumColor;
|
||||
AnimatedProperty<float> _alpha;
|
||||
|
||||
friend class MdlReader;
|
||||
AnimatedProperty<glm::vec3> _color;
|
||||
AnimatedProperty<float> _radius;
|
||||
AnimatedProperty<float> _shadowRadius;
|
||||
AnimatedProperty<float> _verticalDisplacement;
|
||||
AnimatedProperty<float> _multiplier;
|
||||
|
||||
AnimatedProperty<float> _alphaEnd;
|
||||
AnimatedProperty<float> _alphaStart;
|
||||
AnimatedProperty<float> _birthrate;
|
||||
AnimatedProperty<float> _bounceCo;
|
||||
AnimatedProperty<float> _combineTime;
|
||||
AnimatedProperty<float> _drag;
|
||||
AnimatedProperty<float> _fps;
|
||||
AnimatedProperty<float> _frameEnd;
|
||||
AnimatedProperty<float> _frameStart;
|
||||
AnimatedProperty<float> _grav;
|
||||
AnimatedProperty<float> _lifeExp;
|
||||
AnimatedProperty<float> _mass;
|
||||
AnimatedProperty<float> _p2pBezier2;
|
||||
AnimatedProperty<float> _p2pBezier3;
|
||||
AnimatedProperty<float> _particleRot;
|
||||
AnimatedProperty<float> _randVel;
|
||||
AnimatedProperty<float> _sizeStart;
|
||||
AnimatedProperty<float> _sizeEnd;
|
||||
AnimatedProperty<float> _sizeStartY;
|
||||
AnimatedProperty<float> _sizeEndY;
|
||||
AnimatedProperty<float> _spread;
|
||||
AnimatedProperty<float> _threshold;
|
||||
AnimatedProperty<float> _velocity;
|
||||
AnimatedProperty<float> _xSize;
|
||||
AnimatedProperty<float> _ySize;
|
||||
AnimatedProperty<float> _blurLength;
|
||||
AnimatedProperty<float> _lightingDelay;
|
||||
AnimatedProperty<float> _lightingRadius;
|
||||
AnimatedProperty<float> _lightingScale;
|
||||
AnimatedProperty<float> _lightingSubDiv;
|
||||
AnimatedProperty<float> _lightingZigZag;
|
||||
AnimatedProperty<float> _alphaMid;
|
||||
AnimatedProperty<float> _percentStart;
|
||||
AnimatedProperty<float> _percentMid;
|
||||
AnimatedProperty<float> _percentEnd;
|
||||
AnimatedProperty<float> _sizeMid;
|
||||
AnimatedProperty<float> _sizeMidY;
|
||||
AnimatedProperty<float> _randomBirthRate;
|
||||
AnimatedProperty<float> _targetSize;
|
||||
AnimatedProperty<float> _numControlPts;
|
||||
AnimatedProperty<float> _controlPtRadius;
|
||||
AnimatedProperty<float> _controlPtDelay;
|
||||
AnimatedProperty<float> _tangentSpread;
|
||||
AnimatedProperty<float> _tangentLength;
|
||||
AnimatedProperty<glm::vec3> _colorMid;
|
||||
AnimatedProperty<glm::vec3> _colorEnd;
|
||||
AnimatedProperty<glm::vec3> _colorStart;
|
||||
AnimatedProperty<float> _detonate;
|
||||
|
||||
// END Keyframes
|
||||
|
||||
void computeLocalTransform();
|
||||
void computeAbsoluteTransform();
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
@ -235,7 +235,7 @@ vec3 getNormalFromBumpmap(vec2 uv) {
|
|||
if (uBumpmaps.swizzled) {
|
||||
result = vec3(bumpmapSample.a, bumpmapSample.g, 1.0);
|
||||
} else {
|
||||
result = vec3(bumpmapSample.r, bumpmapSample.g, bumpmapSample.b);
|
||||
result = bumpmapSample.rgb;
|
||||
}
|
||||
result = normalize(result * 2.0 - 1.0);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ void AnimationChannel::update(float dt, bool visible) {
|
|||
}
|
||||
|
||||
if (visible) {
|
||||
_stateByNumber.clear();
|
||||
_stateById.clear();
|
||||
computeSceneNodeStates(*_animation->rootNode());
|
||||
}
|
||||
|
||||
|
@ -108,42 +108,42 @@ void AnimationChannel::computeSceneNodeStates(const ModelNode &animNode) {
|
|||
const ModelNode *modelNode = modelNodeSceneNode->modelNode();
|
||||
bool transformChanged = false;
|
||||
float scale = 1.0f;
|
||||
glm::vec3 position(modelNode->position());
|
||||
glm::quat orientation(modelNode->orientation());
|
||||
glm::vec3 position(modelNode->restPosition());
|
||||
glm::quat orientation(modelNode->restOrientation());
|
||||
|
||||
if (_properties.flags & AnimationFlags::syncLipAnim) {
|
||||
uint8_t leftFrameIdx, rightFrameIdx;
|
||||
float interpolant;
|
||||
if (_lipAnimation->getKeyframes(_time, leftFrameIdx, rightFrameIdx, interpolant)) {
|
||||
float factor;
|
||||
if (_lipAnimation->getKeyframes(_time, leftFrameIdx, rightFrameIdx, factor)) {
|
||||
float animScale;
|
||||
if (animNode.getScale(leftFrameIdx, rightFrameIdx, interpolant, animScale)) {
|
||||
if (animNode.getScale(leftFrameIdx, rightFrameIdx, factor, animScale)) {
|
||||
scale = animScale;
|
||||
transformChanged = true;
|
||||
}
|
||||
glm::vec3 animPosiiton;
|
||||
if (animNode.getPosition(leftFrameIdx, rightFrameIdx, interpolant, animPosiiton)) {
|
||||
if (animNode.getPosition(leftFrameIdx, rightFrameIdx, factor, animPosiiton)) {
|
||||
position += _properties.scale * animPosiiton;
|
||||
transformChanged = true;
|
||||
}
|
||||
glm::quat animOrientation;
|
||||
if (animNode.getOrientation(leftFrameIdx, rightFrameIdx, interpolant, animOrientation)) {
|
||||
if (animNode.getOrientation(leftFrameIdx, rightFrameIdx, factor, animOrientation)) {
|
||||
orientation = move(animOrientation);
|
||||
transformChanged = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float animScale;
|
||||
if (animNode.scales().getByTime(_time, animScale)) {
|
||||
if (animNode.scale().getByTime(_time, animScale)) {
|
||||
scale = animScale;
|
||||
transformChanged = true;
|
||||
}
|
||||
glm::vec3 animPosition;
|
||||
if (animNode.positions().getByTime(_time, animPosition)) {
|
||||
if (animNode.position().getByTime(_time, animPosition)) {
|
||||
position += _properties.scale * animPosition;
|
||||
transformChanged = true;
|
||||
}
|
||||
glm::quat animOrientation;
|
||||
if (animNode.orientations().getByTime(_time, animOrientation)) {
|
||||
if (animNode.orientation().getByTime(_time, animOrientation)) {
|
||||
orientation = move(animOrientation);
|
||||
transformChanged = true;
|
||||
}
|
||||
|
@ -151,27 +151,27 @@ void AnimationChannel::computeSceneNodeStates(const ModelNode &animNode) {
|
|||
|
||||
SceneNodeState state;
|
||||
float alpha;
|
||||
if (animNode.alphas().getByTime(_time, alpha)) {
|
||||
if (animNode.alpha().getByTime(_time, alpha)) {
|
||||
state.flags |= SceneNodeStateFlags::alpha;
|
||||
state.alpha = alpha;
|
||||
}
|
||||
glm::vec3 selfIllumColor;
|
||||
if (animNode.selfIllumColors().getByTime(_time, selfIllumColor)) {
|
||||
if (animNode.selfIllumColor().getByTime(_time, selfIllumColor)) {
|
||||
state.flags |= SceneNodeStateFlags::selfIllum;
|
||||
state.selfIllumColor = move(selfIllumColor);
|
||||
}
|
||||
glm::vec3 lightColor;
|
||||
if (animNode.lightColors().getByTime(_time, lightColor)) {
|
||||
if (animNode.color().getByTime(_time, lightColor)) {
|
||||
state.flags |= SceneNodeStateFlags::lightColor;
|
||||
state.lightColor = move(lightColor);
|
||||
}
|
||||
float lightMultiplier;
|
||||
if (animNode.lightMultipliers().getByTime(_time, lightMultiplier)) {
|
||||
if (animNode.multiplier().getByTime(_time, lightMultiplier)) {
|
||||
state.flags |= SceneNodeStateFlags::lightMultiplier;
|
||||
state.lightMultiplier = lightMultiplier;
|
||||
}
|
||||
float lightRadius;
|
||||
if (animNode.lightRadii().getByTime(_time, lightRadius)) {
|
||||
if (animNode.radius().getByTime(_time, lightRadius)) {
|
||||
state.flags |= SceneNodeStateFlags::lightRadius;
|
||||
state.lightRadius = lightRadius;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ void AnimationChannel::computeSceneNodeStates(const ModelNode &animNode) {
|
|||
state.flags |= SceneNodeStateFlags::transform;
|
||||
state.transform = move(transform);
|
||||
}
|
||||
_stateByNumber.insert(make_pair(modelNode->nodeNumber(), move(state)));
|
||||
_stateById.insert(make_pair(modelNode->id(), move(state)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,9 +216,9 @@ float AnimationChannel::getTransitionTime() const {
|
|||
return _animation ? _animation->transitionTime() : 0.0f;
|
||||
}
|
||||
|
||||
bool AnimationChannel::getSceneNodeStateByNumber(uint16_t nodeNumber, SceneNodeState &state) const {
|
||||
auto maybeState = _stateByNumber.find(nodeNumber);
|
||||
if (maybeState != _stateByNumber.end()) {
|
||||
bool AnimationChannel::getSceneNodeStateById(uint16_t nodeId, SceneNodeState &state) const {
|
||||
auto maybeState = _stateById.find(nodeId);
|
||||
if (maybeState != _stateById.end()) {
|
||||
state = maybeState->second;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
bool isFinished() const;
|
||||
|
||||
float getTransitionTime() const;
|
||||
bool getSceneNodeStateByNumber(uint16_t nodeNumber, SceneNodeState &state) const;
|
||||
bool getSceneNodeStateById(uint16_t nodeId, SceneNodeState &state) const;
|
||||
std::string getAnimationName() const;
|
||||
|
||||
float time() const { return _time; }
|
||||
|
@ -97,7 +97,7 @@ private:
|
|||
float _time { 0.0f };
|
||||
bool _freeze { false };
|
||||
bool _finished { false };
|
||||
std::unordered_map<uint16_t, SceneNodeState> _stateByNumber;
|
||||
std::unordered_map<uint16_t, SceneNodeState> _stateById;
|
||||
|
||||
void computeSceneNodeStates(const graphics::ModelNode &animNode);
|
||||
};
|
||||
|
|
|
@ -68,7 +68,7 @@ void SceneNodeAnimator::update(float dt, bool visible) {
|
|||
|
||||
if (visible) {
|
||||
// Compute and apply node states to the managed model
|
||||
_stateByNumber.clear();
|
||||
_stateById.clear();
|
||||
computeSceneNodeStates(*_sceneNode->model()->rootNode());
|
||||
applySceneNodeStates(*_sceneNode->model()->rootNode());
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ bool SceneNodeAnimator::isInTransition() const {
|
|||
}
|
||||
|
||||
void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 parentTransform) {
|
||||
if (modelNode.skin()) return;
|
||||
if (modelNode.isSkinMesh()) return;
|
||||
|
||||
SceneNodeState state;
|
||||
state.flags |= SceneNodeStateFlags::transform;
|
||||
|
@ -97,8 +97,8 @@ void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 p
|
|||
|
||||
// In the Blend mode, blend animations on the first two channels (only transforms)
|
||||
SceneNodeState channel0State, channel1State;
|
||||
bool hasChannel0State = _channels[0].getSceneNodeStateByNumber(modelNode.nodeNumber(), channel0State);
|
||||
bool hasChannel1State = _channels[1].getSceneNodeStateByNumber(modelNode.nodeNumber(), channel1State);
|
||||
bool hasChannel0State = _channels[0].getSceneNodeStateById(modelNode.id(), channel0State);
|
||||
bool hasChannel1State = _channels[1].getSceneNodeStateById(modelNode.id(), channel1State);
|
||||
if (hasChannel0State && (channel0State.flags & SceneNodeStateFlags::transform) &&
|
||||
hasChannel1State && (channel1State.flags & SceneNodeStateFlags::transform)) {
|
||||
|
||||
|
@ -140,7 +140,7 @@ void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 p
|
|||
int componentsLeft = SceneNodeStateFlags::all;
|
||||
for (int i = kChannelCount - 1; i >= 0; --i) {
|
||||
SceneNodeState channelState;
|
||||
if (_channels[i].isActive() && _channels[i].getSceneNodeStateByNumber(modelNode.nodeNumber(), channelState)) {
|
||||
if (_channels[i].isActive() && _channels[i].getSceneNodeStateById(modelNode.id(), channelState)) {
|
||||
if ((channelState.flags & SceneNodeStateFlags::transform) && (componentsLeft & SceneNodeStateFlags::transform)) {
|
||||
localTransform = move(channelState.transform);
|
||||
componentsLeft &= ~SceneNodeStateFlags::transform;
|
||||
|
@ -175,7 +175,7 @@ void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 p
|
|||
} else {
|
||||
// Otherwise, select animation on the first channel
|
||||
SceneNodeState channelState;
|
||||
if (_channels[0].getSceneNodeStateByNumber(modelNode.nodeNumber(), channelState)) {
|
||||
if (_channels[0].getSceneNodeStateById(modelNode.id(), channelState)) {
|
||||
if (channelState.flags & SceneNodeStateFlags::transform) {
|
||||
localTransform = move(channelState.transform);
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 p
|
|||
|
||||
glm::mat4 absTransform(parentTransform * localTransform);
|
||||
state.transform = absTransform;
|
||||
_stateByNumber.insert(make_pair(modelNode.nodeNumber(), move(state)));
|
||||
_stateById.insert(make_pair(modelNode.id(), move(state)));
|
||||
|
||||
for (auto &child : modelNode.children()) {
|
||||
computeSceneNodeStates(*child, absTransform);
|
||||
|
@ -213,12 +213,12 @@ void SceneNodeAnimator::computeSceneNodeStates(ModelNode &modelNode, glm::mat4 p
|
|||
|
||||
void SceneNodeAnimator::applySceneNodeStates(ModelNode &modelNode) {
|
||||
// Do not apply transforms to skinned model nodes
|
||||
if (modelNode.skin()) return;
|
||||
if (modelNode.isSkinMesh()) return;
|
||||
|
||||
auto maybeState = _stateByNumber.find(modelNode.nodeNumber());
|
||||
if (maybeState != _stateByNumber.end()) {
|
||||
auto maybeState = _stateById.find(modelNode.id());
|
||||
if (maybeState != _stateById.end()) {
|
||||
const SceneNodeState &state = maybeState->second;
|
||||
ModelNodeSceneNode *sceneNode = _sceneNode->getModelNodeByIndex(modelNode.index());
|
||||
ModelNodeSceneNode *sceneNode = _sceneNode->getModelNodeById(modelNode.id());
|
||||
if (state.flags & SceneNodeStateFlags::transform) {
|
||||
sceneNode->setLocalTransform(state.transform);
|
||||
sceneNode->setBoneTransform(state.transform * modelNode.absoluteTransformInverse());
|
||||
|
@ -229,7 +229,7 @@ void SceneNodeAnimator::applySceneNodeStates(ModelNode &modelNode) {
|
|||
if (state.flags & SceneNodeStateFlags::selfIllum) {
|
||||
sceneNode->setSelfIllumColor(state.selfIllumColor);
|
||||
}
|
||||
LightSceneNode *light = _sceneNode->getLightNodeByNumber(modelNode.nodeNumber());
|
||||
LightSceneNode *light = _sceneNode->getLightNodeById(modelNode.id());
|
||||
if (light) {
|
||||
if (state.flags & SceneNodeStateFlags::lightColor) {
|
||||
light->setColor(state.lightColor);
|
||||
|
|
|
@ -86,7 +86,7 @@ private:
|
|||
|
||||
CompositionMode _compositionMode { CompositionMode::Overlay };
|
||||
bool _transition { false }; /**< is there an animation transition going on? */
|
||||
std::unordered_map<uint16_t, SceneNodeState> _stateByNumber;
|
||||
std::unordered_map<uint16_t, SceneNodeState> _stateById;
|
||||
|
||||
std::string _defaultAnimName;
|
||||
AnimationProperties _defaultAnimProperties;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace scene {
|
|||
|
||||
static constexpr float kMotionBlurStrength = 0.25f;
|
||||
|
||||
EmitterSceneNode::EmitterSceneNode(const ModelSceneNode *modelSceneNode, const shared_ptr<Emitter> &emitter, SceneGraph *sceneGraph) :
|
||||
EmitterSceneNode::EmitterSceneNode(const ModelSceneNode *modelSceneNode, const shared_ptr<ModelNode::Emitter> &emitter, SceneGraph *sceneGraph) :
|
||||
SceneNode(SceneNodeType::Emitter, sceneGraph),
|
||||
_modelSceneNode(modelSceneNode),
|
||||
_emitter(emitter) {
|
||||
|
@ -59,8 +59,8 @@ EmitterSceneNode::EmitterSceneNode(const ModelSceneNode *modelSceneNode, const s
|
|||
}
|
||||
|
||||
void EmitterSceneNode::init() {
|
||||
if (_emitter->birthrate() != 0) {
|
||||
_birthInterval = 1.0f / static_cast<float>(_emitter->birthrate());
|
||||
if (_emitter->birthrate != 0) {
|
||||
_birthInterval = 1.0f / static_cast<float>(_emitter->birthrate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,9 +88,9 @@ void EmitterSceneNode::removeExpiredParticles(float dt) {
|
|||
}
|
||||
|
||||
void EmitterSceneNode::spawnParticles(float dt) {
|
||||
switch (_emitter->updateMode()) {
|
||||
case Emitter::UpdateMode::Fountain:
|
||||
if (_emitter->birthrate() != 0.0f) {
|
||||
switch (_emitter->updateMode) {
|
||||
case ModelNode::Emitter::UpdateMode::Fountain:
|
||||
if (_emitter->birthrate != 0.0f) {
|
||||
if (_birthTimer.advance(dt)) {
|
||||
if (_particles.size() < kMaxParticles) {
|
||||
doSpawnParticle();
|
||||
|
@ -99,8 +99,8 @@ void EmitterSceneNode::spawnParticles(float dt) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case Emitter::UpdateMode::Single:
|
||||
if (!_spawned || (_particles.empty() && _emitter->loop())) {
|
||||
case ModelNode::Emitter::UpdateMode::Single:
|
||||
if (!_spawned || (_particles.empty() && _emitter->loop)) {
|
||||
doSpawnParticle();
|
||||
_spawned = true;
|
||||
}
|
||||
|
@ -111,17 +111,17 @@ void EmitterSceneNode::spawnParticles(float dt) {
|
|||
}
|
||||
|
||||
void EmitterSceneNode::doSpawnParticle() {
|
||||
float halfW = 0.005f * _emitter->size().x;
|
||||
float halfH = 0.005f * _emitter->size().y;
|
||||
float halfW = 0.005f * _emitter->size.x;
|
||||
float halfH = 0.005f * _emitter->size.y;
|
||||
glm::vec3 position(random(-halfW, halfW), random(-halfH, halfH), 0.0f);
|
||||
|
||||
float sign;
|
||||
if (_emitter->spread() > glm::pi<float>() && random(0, 1) != 0) {
|
||||
if (_emitter->spread > glm::pi<float>() && random(0, 1) != 0) {
|
||||
sign = -1.0f;
|
||||
} else {
|
||||
sign = 1.0f;
|
||||
}
|
||||
float velocity = sign * (_emitter->velocity() + random(0.0f, _emitter->randomVelocity()));
|
||||
float velocity = sign * (_emitter->velocity + random(0.0f, _emitter->randomVelocity));
|
||||
|
||||
auto particle = make_shared<Particle>(position, velocity, this);
|
||||
_particles.push_back(particle);
|
||||
|
@ -130,20 +130,20 @@ void EmitterSceneNode::doSpawnParticle() {
|
|||
void EmitterSceneNode::drawParticles(const vector<Particle *> &particles) {
|
||||
if (particles.empty()) return;
|
||||
|
||||
shared_ptr<Texture> texture(_emitter->texture());
|
||||
shared_ptr<Texture> texture(_emitter->texture);
|
||||
if (!texture) return;
|
||||
|
||||
ShaderUniforms uniforms(_sceneGraph->uniformsPrototype());
|
||||
uniforms.combined.featureMask |= UniformFeatureFlags::particles;
|
||||
uniforms.particles->gridSize = glm::vec2(_emitter->gridWidth(), _emitter->gridHeight());
|
||||
uniforms.particles->render = static_cast<int>(_emitter->renderMode());
|
||||
uniforms.particles->gridSize = glm::vec2(_emitter->gridWidth, _emitter->gridHeight);
|
||||
uniforms.particles->render = static_cast<int>(_emitter->renderMode);
|
||||
|
||||
for (size_t i = 0; i < particles.size(); ++i) {
|
||||
const Particle &particle = *particles[i];
|
||||
|
||||
glm::mat4 transform(_absoluteTransform);
|
||||
transform = glm::translate(transform, particles[i]->position());
|
||||
if (_emitter->renderMode() == Emitter::RenderMode::MotionBlur) {
|
||||
if (_emitter->renderMode == ModelNode::Emitter::RenderMode::MotionBlur) {
|
||||
transform = glm::scale(transform, glm::vec3((1.0f + kMotionBlurStrength * _modelSceneNode->projectileSpeed()) * particle.size(), particle.size(), particle.size()));
|
||||
} else {
|
||||
transform = glm::scale(transform, glm::vec3(particle.size()));
|
||||
|
@ -161,7 +161,7 @@ void EmitterSceneNode::drawParticles(const vector<Particle *> &particles) {
|
|||
StateManager::instance().setActiveTextureUnit(TextureUnits::diffuse);
|
||||
texture->bind();
|
||||
|
||||
bool lighten = _emitter->blendMode() == Emitter::BlendMode::Lighten;
|
||||
bool lighten = _emitter->blendMode == ModelNode::Emitter::BlendMode::Lighten;
|
||||
if (lighten) {
|
||||
StateManager::instance().withLightenBlending([&particles]() {
|
||||
Meshes::instance().getBillboard()->drawInstanced(static_cast<int>(particles.size()));
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "glm/vec3.hpp"
|
||||
|
||||
#include "../../common/timer.h"
|
||||
#include "../../graphics/model/emitter.h"
|
||||
#include "../../graphics/model/modelnode.h"
|
||||
|
||||
#include "../particle.h"
|
||||
|
||||
|
@ -36,7 +36,7 @@ class ModelSceneNode;
|
|||
|
||||
class EmitterSceneNode : public SceneNode {
|
||||
public:
|
||||
EmitterSceneNode(const ModelSceneNode *modelSceneNode, const std::shared_ptr<graphics::Emitter> &emitter, SceneGraph *sceneGraph);
|
||||
EmitterSceneNode(const ModelSceneNode *modelSceneNode, const std::shared_ptr<graphics::ModelNode::Emitter> &emitter, SceneGraph *sceneGraph);
|
||||
|
||||
void update(float dt) override;
|
||||
|
||||
|
@ -49,12 +49,12 @@ public:
|
|||
|
||||
void detonate();
|
||||
|
||||
std::shared_ptr<graphics::Emitter> emitter() const { return _emitter; }
|
||||
std::shared_ptr<graphics::ModelNode::Emitter> emitter() const { return _emitter; }
|
||||
const std::vector<std::shared_ptr<Particle>> &particles() const { return _particles; }
|
||||
|
||||
private:
|
||||
const ModelSceneNode *_modelSceneNode;
|
||||
std::shared_ptr<graphics::Emitter> _emitter;
|
||||
std::shared_ptr<graphics::ModelNode::Emitter> _emitter;
|
||||
|
||||
float _birthInterval { 0.0f };
|
||||
Timer _birthTimer;
|
||||
|
|
|
@ -41,7 +41,7 @@ LightSceneNode::LightSceneNode(int priority, SceneGraph *sceneGraph) :
|
|||
_priority(priority) {
|
||||
}
|
||||
|
||||
void LightSceneNode::drawLensFlares(const LensFlare &flare) {
|
||||
void LightSceneNode::drawLensFlares(const ModelNode::LensFlare &flare) {
|
||||
shared_ptr<CameraSceneNode> camera(_sceneGraph->activeCamera());
|
||||
if (!camera) return;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "../types.h"
|
||||
|
||||
#include "../../graphics/model/lensflare.h"
|
||||
#include "../../graphics/model/modelnode.h"
|
||||
|
||||
#include "scenenode.h"
|
||||
|
||||
|
@ -31,7 +31,7 @@ class LightSceneNode : public SceneNode {
|
|||
public:
|
||||
LightSceneNode(int priority, SceneGraph *sceneGraph);
|
||||
|
||||
void drawLensFlares(const graphics::LensFlare &flare);
|
||||
void drawLensFlares(const graphics::ModelNode::LensFlare &flare);
|
||||
|
||||
bool isShadow() const { return _shadow; }
|
||||
bool isAmbientOnly() const { return _ambientOnly; }
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
float multiplier() const { return _multiplier; }
|
||||
float radius() const { return _radius; }
|
||||
float flareRadius() const { return _flareRadius; }
|
||||
const std::vector<graphics::LensFlare> &flares() const { return _flares; }
|
||||
const std::vector<graphics::ModelNode::LensFlare> &flares() const { return _flares; }
|
||||
|
||||
void setColor(glm::vec3 color) { _color = std::move(color); }
|
||||
void setMultiplier(float multiplier) { _multiplier = multiplier; }
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
void setAmbientOnly(bool ambientOnly) { _ambientOnly = ambientOnly; }
|
||||
void setDirectional(bool directional) { _directional = directional; }
|
||||
void setFlareRadius(float radius) { _flareRadius = radius; }
|
||||
void setFlares(std::vector<graphics::LensFlare> flares) { _flares = std::move(flares); }
|
||||
void setFlares(std::vector<graphics::ModelNode::LensFlare> flares) { _flares = std::move(flares); }
|
||||
|
||||
private:
|
||||
int _priority;
|
||||
|
@ -66,7 +66,7 @@ private:
|
|||
// Light flares
|
||||
|
||||
float _flareRadius { 0.0f };
|
||||
std::vector<graphics::LensFlare> _flares;
|
||||
std::vector<graphics::ModelNode::LensFlare> _flares;
|
||||
|
||||
// END Light flares
|
||||
};
|
||||
|
|
|
@ -60,20 +60,20 @@ ModelNodeSceneNode::ModelNodeSceneNode(SceneGraph *sceneGraph, const ModelSceneN
|
|||
if (!modelNode) {
|
||||
throw invalid_argument("modelNode must not be null");
|
||||
}
|
||||
if (_modelNode->alphas().getNumKeyframes() > 0) {
|
||||
_alpha = _modelNode->alphas().getByKeyframe(0);
|
||||
if (_modelNode->alpha().getNumFrames() > 0) {
|
||||
_alpha = _modelNode->alpha().getByFrame(0);
|
||||
}
|
||||
if (_modelNode->selfIllumColors().getNumKeyframes() > 0) {
|
||||
_selfIllumColor = _modelNode->selfIllumColors().getByKeyframe(0);
|
||||
if (_modelNode->selfIllumColor().getNumFrames() > 0) {
|
||||
_selfIllumColor = _modelNode->selfIllumColor().getByFrame(0);
|
||||
}
|
||||
initTextures();
|
||||
}
|
||||
|
||||
void ModelNodeSceneNode::initTextures() {
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh) return;
|
||||
|
||||
_textures.diffuse = mesh->diffuse;
|
||||
_textures.diffuse = mesh->diffuseMap;
|
||||
_textures.lightmap = mesh->lightmap;
|
||||
_textures.bumpmap = mesh->bumpmap;
|
||||
|
||||
|
@ -105,13 +105,11 @@ void ModelNodeSceneNode::refreshAdditionalTextures() {
|
|||
}
|
||||
|
||||
void ModelNodeSceneNode::update(float dt) {
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (mesh) {
|
||||
// UV animation
|
||||
const ModelNode::UVAnimation &uvAnimation = mesh->uvAnimation;
|
||||
if (uvAnimation.animated) {
|
||||
glm::vec2 dir(uvAnimation.directionX, uvAnimation.directionY);
|
||||
_uvOffset += kUvAnimationSpeed * dir * dt;
|
||||
if (mesh->uvAnimation.dir.x != 0.0f || mesh->uvAnimation.dir.y != 0.0f) {
|
||||
_uvOffset += kUvAnimationSpeed * mesh->uvAnimation.dir * dt;
|
||||
_uvOffset -= glm::floor(_uvOffset);
|
||||
}
|
||||
|
||||
|
@ -130,20 +128,20 @@ void ModelNodeSceneNode::update(float dt) {
|
|||
}
|
||||
|
||||
// Danglymesh animation
|
||||
shared_ptr<ModelNode::Danglymesh> danglymesh(_modelNode->danglymesh());
|
||||
if (danglymesh) {
|
||||
shared_ptr<ModelNode::DanglyMesh> danglyMesh(mesh->danglyMesh);
|
||||
if (danglyMesh) {
|
||||
bool forceApplied = glm::length2(_danglymeshAnimation.force) > 0.0f;
|
||||
if (forceApplied) {
|
||||
// When force is applied, stride in the opposite direction from the applied force
|
||||
glm::vec3 strideDir(-_danglymeshAnimation.force);
|
||||
glm::vec3 maxStride(danglymesh->displacement);
|
||||
_danglymeshAnimation.stride = glm::clamp(_danglymeshAnimation.stride + danglymesh->period * strideDir * dt, -maxStride, maxStride);
|
||||
glm::vec3 maxStride(danglyMesh->displacement);
|
||||
_danglymeshAnimation.stride = glm::clamp(_danglymeshAnimation.stride + danglyMesh->period * strideDir * dt, -maxStride, maxStride);
|
||||
} else {
|
||||
// When force is not applied, gradually nullify stride
|
||||
float strideMag2 = glm::length2(_danglymeshAnimation.stride);
|
||||
if (strideMag2 > 0.0f) {
|
||||
glm::vec3 strideDir(-_danglymeshAnimation.stride);
|
||||
_danglymeshAnimation.stride += danglymesh->period * strideDir * dt;
|
||||
_danglymeshAnimation.stride += danglyMesh->period * strideDir * dt;
|
||||
if ((strideDir.x > 0.0f && _danglymeshAnimation.stride.x > 0.0f) || (strideDir.x < 0.0f && _danglymeshAnimation.stride.x < 0.0f)) {
|
||||
_danglymeshAnimation.stride.x = 0.0f;
|
||||
}
|
||||
|
@ -162,27 +160,27 @@ void ModelNodeSceneNode::update(float dt) {
|
|||
}
|
||||
|
||||
bool ModelNodeSceneNode::shouldRender() const {
|
||||
if (g_debugWalkmesh) return _modelNode->isAABB();
|
||||
if (g_debugWalkmesh) return _modelNode->isAABBMesh();
|
||||
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
if (!mesh || !mesh->render || _modelNode->alphas().getByKeyframeOrElse(0, 1.0f) == 0.0f) return false;
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh || !mesh->render || _modelNode->alpha().getByFrameOrElse(0, 1.0f) == 0.0f) return false;
|
||||
|
||||
return !_modelNode->isAABB();
|
||||
return !_modelNode->isAABBMesh();
|
||||
}
|
||||
|
||||
bool ModelNodeSceneNode::shouldCastShadows() const {
|
||||
// Skin nodes must not cast shadows
|
||||
if (static_cast<bool>(_modelNode->skin())) return false;
|
||||
if (_modelNode->isSkinMesh()) return false;
|
||||
|
||||
// Meshless nodes must not cast shadows
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh) return false;
|
||||
|
||||
return mesh->shadow;
|
||||
}
|
||||
|
||||
bool ModelNodeSceneNode::isTransparent() const {
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh) return false; // Meshless nodes are opaque
|
||||
|
||||
// Character models are opaque
|
||||
|
@ -195,7 +193,7 @@ bool ModelNodeSceneNode::isTransparent() const {
|
|||
if (!_textures.diffuse) return false;
|
||||
|
||||
// Model nodes with transparency hint greater than 0 are transparent
|
||||
if (mesh->transparency> 0) return true;
|
||||
if (mesh->transparency > 0) return true;
|
||||
|
||||
// Model nodes with additive diffuse texture are opaque
|
||||
if (_textures.diffuse->isAdditive()) return true;
|
||||
|
@ -226,7 +224,7 @@ static bool isReceivingShadows(const ModelSceneNode &model, const ModelNodeScene
|
|||
}
|
||||
|
||||
void ModelNodeSceneNode::drawSingle(bool shadowPass) {
|
||||
shared_ptr<ModelNode::Trimesh> mesh(_modelNode->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh) return;
|
||||
|
||||
// Setup shaders
|
||||
|
@ -285,20 +283,20 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) {
|
|||
uniforms.combined.featureMask |= UniformFeatureFlags::shadows;
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode::Skin> skin(_modelNode->skin());
|
||||
if (skin) {
|
||||
if (mesh->skin) {
|
||||
uniforms.combined.featureMask |= UniformFeatureFlags::skeletal;
|
||||
|
||||
for (int i = 0; i < kMaxBones; ++i) {
|
||||
uniforms.skeletal->bones[i] = glm::mat4(1.0f);
|
||||
}
|
||||
for (auto &pair : skin->nodeIdxByBoneIdx) {
|
||||
uint16_t boneIdx = pair.first;
|
||||
uint16_t nodeIdx = pair.second;
|
||||
|
||||
ModelNodeSceneNode *bone = _modelSceneNode->getModelNodeByIndex(nodeIdx);
|
||||
if (i < static_cast<int>(mesh->skin->boneNodeId.size())) {
|
||||
uint16_t nodeId = mesh->skin->boneNodeId[i];
|
||||
if (nodeId != 0xffff) {
|
||||
ModelNodeSceneNode *bone = _modelSceneNode->getModelNodeById(nodeId);
|
||||
if (bone) {
|
||||
uniforms.skeletal->bones[boneIdx] = _modelNode->absoluteTransformInverse() * bone->boneTransform() * _modelNode->absoluteTransform();
|
||||
uniforms.skeletal->bones[i] = _modelNode->absoluteTransformInverse() * bone->boneTransform() * _modelNode->absoluteTransform();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uniforms.skeletal->bones[i] = glm::mat4(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,8 +309,8 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) {
|
|||
const vector<LightSceneNode *> &lights = _sceneGraph->closestLights();
|
||||
|
||||
uniforms.combined.featureMask |= UniformFeatureFlags::lighting;
|
||||
uniforms.combined.material.ambient = glm::vec4(mesh->ambientColor, 1.0f);
|
||||
uniforms.combined.material.diffuse = glm::vec4(mesh->diffuseColor, 1.0f);
|
||||
uniforms.combined.material.ambient = glm::vec4(mesh->ambient, 1.0f);
|
||||
uniforms.combined.material.diffuse = glm::vec4(mesh->diffuse, 1.0f);
|
||||
uniforms.combined.material.shininess = _material.shininess;
|
||||
uniforms.combined.material.metallic = _material.metallic;
|
||||
uniforms.combined.material.roughness = _material.roughness;
|
||||
|
@ -347,14 +345,14 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) {
|
|||
uniforms.combined.general.fogColor = glm::vec4(_sceneGraph->fogColor(), 1.0f);
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode::Danglymesh> danglymesh(_modelNode->danglymesh());
|
||||
if (danglymesh) {
|
||||
shared_ptr<ModelNode::DanglyMesh> danglyMesh(mesh->danglyMesh);
|
||||
if (danglyMesh) {
|
||||
uniforms.combined.featureMask |= UniformFeatureFlags::danglymesh;
|
||||
uniforms.danglymesh->stride = glm::vec4(_danglymeshAnimation.stride, 0.0f);
|
||||
uniforms.danglymesh->displacement = danglymesh->displacement;
|
||||
uniforms.danglymesh->displacement = danglyMesh->displacement;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < danglymesh->constraints.size(); ++i) {
|
||||
uniforms.danglymesh->constraints[i / 4][i % 4] = danglymesh->constraints[i].multiplier;
|
||||
for (i = 0; i < danglyMesh->constraints.size(); ++i) {
|
||||
uniforms.danglymesh->constraints[i / 4][i % 4] = danglyMesh->constraints[i].multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,14 +416,14 @@ bool ModelNodeSceneNode::isLightingEnabled() const {
|
|||
}
|
||||
|
||||
void ModelNodeSceneNode::setAppliedForce(glm::vec3 force) {
|
||||
if (_modelNode->danglymesh()) {
|
||||
if (_modelNode->isDanglyMesh()) {
|
||||
// Convert force from world to object space
|
||||
_danglymeshAnimation.force = _absoluteTransformInv * glm::vec4(force, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 ModelNodeSceneNode::getOrigin() const {
|
||||
return _absoluteTransform * glm::vec4(_modelNode->getCenterOfAABB(), 1.0f);
|
||||
return _absoluteTransform * glm::vec4(_modelNode->mesh()->mesh->aabb().center(), 1.0f);
|
||||
}
|
||||
|
||||
void ModelNodeSceneNode::setBoneTransform(const glm::mat4 &transform) {
|
||||
|
|
|
@ -65,35 +65,35 @@ ModelSceneNode::ModelSceneNode(
|
|||
_volumetric = true;
|
||||
}
|
||||
|
||||
static bool validateEmitter(const Emitter &emitter) {
|
||||
switch (emitter.updateMode()) {
|
||||
case Emitter::UpdateMode::Fountain:
|
||||
case Emitter::UpdateMode::Single:
|
||||
case Emitter::UpdateMode::Explosion:
|
||||
static bool validateEmitter(const ModelNode::Emitter &emitter) {
|
||||
switch (emitter.updateMode) {
|
||||
case ModelNode::Emitter::UpdateMode::Fountain:
|
||||
case ModelNode::Emitter::UpdateMode::Single:
|
||||
case ModelNode::Emitter::UpdateMode::Explosion:
|
||||
break;
|
||||
default:
|
||||
warn("validateEmitter: unsupported update mode: " + to_string(static_cast<int>(emitter.updateMode())));
|
||||
warn("validateEmitter: unsupported update mode: " + to_string(static_cast<int>(emitter.updateMode)));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (emitter.renderMode()) {
|
||||
case Emitter::RenderMode::Normal:
|
||||
case Emitter::RenderMode::BillboardToWorldZ:
|
||||
case Emitter::RenderMode::MotionBlur:
|
||||
case Emitter::RenderMode::BillboardToLocalZ:
|
||||
case Emitter::RenderMode::AlignedToParticleDir:
|
||||
switch (emitter.renderMode) {
|
||||
case ModelNode::Emitter::RenderMode::Normal:
|
||||
case ModelNode::Emitter::RenderMode::BillboardToWorldZ:
|
||||
case ModelNode::Emitter::RenderMode::MotionBlur:
|
||||
case ModelNode::Emitter::RenderMode::BillboardToLocalZ:
|
||||
case ModelNode::Emitter::RenderMode::AlignedToParticleDir:
|
||||
break;
|
||||
default:
|
||||
warn("validateEmitter: unsupported render mode: " + to_string(static_cast<int>(emitter.renderMode())));
|
||||
warn("validateEmitter: unsupported render mode: " + to_string(static_cast<int>(emitter.renderMode)));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (emitter.blendMode()) {
|
||||
case Emitter::BlendMode::Normal:
|
||||
case Emitter::BlendMode::Lighten:
|
||||
switch (emitter.blendMode) {
|
||||
case ModelNode::Emitter::BlendMode::Normal:
|
||||
case ModelNode::Emitter::BlendMode::Lighten:
|
||||
break;
|
||||
default:
|
||||
warn("validateEmitter: unsupported blend mode: " + to_string(static_cast<int>(emitter.blendMode())));
|
||||
warn("validateEmitter: unsupported blend mode: " + to_string(static_cast<int>(emitter.blendMode)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,7 @@ void ModelSceneNode::initModelNodes() {
|
|||
nodes.pop();
|
||||
|
||||
const ModelNode *modelNode = sceneNode->modelNode();
|
||||
_modelNodeByIndex.insert(make_pair(modelNode->index(), sceneNode));
|
||||
_modelNodeByNumber.insert(make_pair(modelNode->nodeNumber(), sceneNode));
|
||||
_modelNodeById.insert(make_pair(modelNode->id(), sceneNode));
|
||||
|
||||
for (auto &child : modelNode->children()) {
|
||||
shared_ptr<ModelNodeSceneNode> childNode(getModelNodeSceneNode(*child));
|
||||
|
@ -123,12 +122,12 @@ void ModelSceneNode::initModelNodes() {
|
|||
shared_ptr<ModelNode::Light> light(child->light());
|
||||
if (light) {
|
||||
// Light is considered directional if its radius exceeds a certain threshold
|
||||
float radius = child->lightRadii().getByKeyframeOrElse(0, 1.0f);
|
||||
float radius = child->radius().getByFrameOrElse(0, 1.0f);
|
||||
bool directional = radius >= kMinDirectionalLightRadius;
|
||||
|
||||
auto lightNode = make_shared<LightSceneNode>(light->priority, _sceneGraph);
|
||||
lightNode->setColor(child->lightColors().getByKeyframeOrElse(0, glm::vec3(1.0f)));
|
||||
lightNode->setMultiplier(child->lightMultipliers().getByKeyframeOrElse(0, 1.0f));
|
||||
lightNode->setColor(child->color().getByFrameOrElse(0, glm::vec3(1.0f)));
|
||||
lightNode->setMultiplier(child->multiplier().getByFrameOrElse(0, 1.0f));
|
||||
lightNode->setRadius(radius);
|
||||
lightNode->setShadow(light->shadow);
|
||||
lightNode->setAmbientOnly(light->ambientOnly);
|
||||
|
@ -137,10 +136,10 @@ void ModelSceneNode::initModelNodes() {
|
|||
lightNode->setFlares(light->flares);
|
||||
|
||||
childNode->addChild(lightNode);
|
||||
_lightNodeByNumber.insert(make_pair(modelNode->nodeNumber(), lightNode.get()));
|
||||
_lightNodeById.insert(make_pair(modelNode->id(), lightNode.get()));
|
||||
}
|
||||
|
||||
shared_ptr<Emitter> emitter(child->emitter());
|
||||
shared_ptr<ModelNode::Emitter> emitter(child->emitter());
|
||||
if (emitter && validateEmitter(*emitter)) {
|
||||
auto emitterNode = make_shared<EmitterSceneNode>(this, emitter, _sceneGraph);
|
||||
childNode->addChild(emitterNode);
|
||||
|
@ -155,7 +154,7 @@ void ModelSceneNode::initModelNodes() {
|
|||
}
|
||||
}
|
||||
|
||||
refreshAABB();
|
||||
computeAABB();
|
||||
}
|
||||
|
||||
unique_ptr<ModelNodeSceneNode> ModelSceneNode::getModelNodeSceneNode(ModelNode &node) const {
|
||||
|
@ -188,9 +187,9 @@ shared_ptr<ModelSceneNode> ModelSceneNode::attach(const string &parent, const sh
|
|||
|
||||
shared_ptr<ModelSceneNode> ModelSceneNode::attach(ModelNodeSceneNode &parent, const shared_ptr<Model> &model, ModelUsage usage) {
|
||||
const ModelNode *parentModelNode = parent.modelNode();
|
||||
uint16_t parentNumber = parentModelNode->nodeNumber();
|
||||
uint16_t parentId = parentModelNode->id();
|
||||
|
||||
auto maybeAttached = _attachedModels.find(parentNumber);
|
||||
auto maybeAttached = _attachedModels.find(parentId);
|
||||
if (maybeAttached != _attachedModels.end()) {
|
||||
parent.removeChild(*maybeAttached->second);
|
||||
_attachedModels.erase(maybeAttached);
|
||||
|
@ -203,7 +202,7 @@ shared_ptr<ModelSceneNode> ModelSceneNode::attach(ModelNodeSceneNode &parent, co
|
|||
auto modelNode = make_shared<ModelSceneNode>(usage, model, _sceneGraph, ignoreNodes);
|
||||
parent.addChild(modelNode);
|
||||
|
||||
return _attachedModels.insert(make_pair(parentNumber, move(modelNode))).first->second;
|
||||
return _attachedModels.insert(make_pair(parentId, move(modelNode))).first->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -211,47 +210,47 @@ shared_ptr<ModelSceneNode> ModelSceneNode::attach(ModelNodeSceneNode &parent, co
|
|||
}
|
||||
|
||||
ModelNodeSceneNode *ModelSceneNode::getModelNode(const string &name) const {
|
||||
shared_ptr<ModelNode> modelNode(_model->findNodeByName(name));
|
||||
shared_ptr<ModelNode> modelNode(_model->getNodeByName(name));
|
||||
if (!modelNode) return nullptr;
|
||||
|
||||
return getFromLookupOrNull(_modelNodeByNumber, modelNode->nodeNumber());
|
||||
return getFromLookupOrNull(_modelNodeById, modelNode->id());
|
||||
}
|
||||
|
||||
ModelNodeSceneNode *ModelSceneNode::getModelNodeByIndex(int index) const {
|
||||
return getFromLookupOrNull(_modelNodeByIndex, static_cast<uint16_t>(index));
|
||||
ModelNodeSceneNode *ModelSceneNode::getModelNodeById(uint16_t nodeId) const {
|
||||
return getFromLookupOrNull(_modelNodeById, nodeId);
|
||||
}
|
||||
|
||||
LightSceneNode *ModelSceneNode::getLightNodeByNumber(uint16_t nodeNumber) const {
|
||||
return getFromLookupOrNull(_lightNodeByNumber, nodeNumber);
|
||||
LightSceneNode *ModelSceneNode::getLightNodeById(uint16_t nodeId) const {
|
||||
return getFromLookupOrNull(_lightNodeById, nodeId);
|
||||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> ModelSceneNode::getAttachedModel(const string &parent) const {
|
||||
shared_ptr<ModelNode> parentModelNode(_model->findNodeByName(parent));
|
||||
shared_ptr<ModelNode> parentModelNode(_model->getNodeByName(parent));
|
||||
if (!parentModelNode) return nullptr;
|
||||
|
||||
return getFromLookupOrNull(_attachedModels, parentModelNode->nodeNumber());
|
||||
return getFromLookupOrNull(_attachedModels, parentModelNode->id());
|
||||
}
|
||||
|
||||
void ModelSceneNode::attach(const string &parent, const shared_ptr<SceneNode> &node) {
|
||||
shared_ptr<ModelNode> parentModelNode(_model->findNodeByName(parent));
|
||||
shared_ptr<ModelNode> parentModelNode(_model->getNodeByName(parent));
|
||||
if (!parentModelNode) {
|
||||
warn(boost::format("Scene node %s: model node not found: %s") % _model->name() % parent);
|
||||
return;
|
||||
}
|
||||
uint16_t parentNumber = parentModelNode->nodeNumber();
|
||||
uint16_t parentId = parentModelNode->id();
|
||||
|
||||
auto maybeNode = _modelNodeByNumber.find(parentNumber);
|
||||
if (maybeNode != _modelNodeByNumber.end()) {
|
||||
auto maybeNode = _modelNodeById.find(parentId);
|
||||
if (maybeNode != _modelNodeById.end()) {
|
||||
maybeNode->second->addChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelSceneNode::getNodeAbsolutePosition(const string &name, glm::vec3 &position) const {
|
||||
shared_ptr<ModelNode> node(_model->findNodeByName(name));
|
||||
shared_ptr<ModelNode> node(_model->getNodeByName(name));
|
||||
if (!node) {
|
||||
shared_ptr<Model> superModel(_model->superModel());
|
||||
if (superModel) {
|
||||
node = superModel->findNodeByName(name);
|
||||
node = superModel->getNodeByName(name);
|
||||
}
|
||||
}
|
||||
if (!node) return false;
|
||||
|
@ -261,7 +260,7 @@ bool ModelSceneNode::getNodeAbsolutePosition(const string &name, glm::vec3 &posi
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::vec3 ModelSceneNode::getCenterOfAABB() const {
|
||||
glm::vec3 ModelSceneNode::getWorldCenterAABB() const {
|
||||
return _absoluteTransform * glm::vec4(_aabb.center(), 1.0f);
|
||||
}
|
||||
|
||||
|
@ -295,15 +294,7 @@ void ModelSceneNode::setAlpha(float alpha) {
|
|||
}
|
||||
}
|
||||
|
||||
void ModelSceneNode::setProjectileSpeed(float speed) {
|
||||
_projectileSpeed = speed;
|
||||
}
|
||||
|
||||
void ModelSceneNode::setWalkmesh(shared_ptr<Walkmesh> walkmesh) {
|
||||
_walkmesh = move(walkmesh);
|
||||
}
|
||||
|
||||
void ModelSceneNode::refreshAABB() {
|
||||
void ModelSceneNode::computeAABB() {
|
||||
_aabb.reset();
|
||||
|
||||
stack<SceneNode *> nodes;
|
||||
|
@ -315,7 +306,7 @@ void ModelSceneNode::refreshAABB() {
|
|||
|
||||
if (node->type() == SceneNodeType::ModelNode) {
|
||||
auto modelNode = static_cast<ModelNodeSceneNode *>(node);
|
||||
shared_ptr<ModelNode::Trimesh> mesh(modelNode->modelNode()->mesh());
|
||||
shared_ptr<ModelNode::TriangleMesh> mesh(modelNode->modelNode()->mesh());
|
||||
if (mesh) {
|
||||
_aabb.expand(mesh->mesh->aabb() * node->localTransform());
|
||||
}
|
||||
|
@ -340,7 +331,7 @@ void ModelSceneNode::signalEvent(const string &name) {
|
|||
}
|
||||
|
||||
void ModelSceneNode::setAppliedForce(glm::vec3 force) {
|
||||
for (auto &nodePair : _modelNodeByIndex) {
|
||||
for (auto &nodePair : _modelNodeById) {
|
||||
nodePair.second->setAppliedForce(force);
|
||||
}
|
||||
for (auto &attached : _attachedModels) {
|
||||
|
|
|
@ -50,16 +50,16 @@ public:
|
|||
void update(float dt) override;
|
||||
void draw() override;
|
||||
|
||||
void refreshAABB();
|
||||
void computeAABB();
|
||||
void signalEvent(const std::string &name);
|
||||
void setAppliedForce(glm::vec3 force);
|
||||
|
||||
ModelNodeSceneNode *getModelNode(const std::string &name) const;
|
||||
ModelNodeSceneNode *getModelNodeByIndex(int index) const;
|
||||
LightSceneNode *getLightNodeByNumber(uint16_t nodeNumber) const;
|
||||
ModelNodeSceneNode *getModelNodeById(uint16_t nodeId) const;
|
||||
LightSceneNode *getLightNodeById(uint16_t nodeId) const;
|
||||
std::shared_ptr<ModelSceneNode> getAttachedModel(const std::string &parent) const;
|
||||
bool getNodeAbsolutePosition(const std::string &name, glm::vec3 &position) const;
|
||||
glm::vec3 getCenterOfAABB() const;
|
||||
glm::vec3 getWorldCenterAABB() const;
|
||||
const std::string &getName() const;
|
||||
|
||||
ModelUsage usage() const { return _usage; }
|
||||
|
@ -72,8 +72,8 @@ public:
|
|||
void setVisible(bool visible) override;
|
||||
void setDiffuseTexture(const std::shared_ptr<graphics::Texture> &texture);
|
||||
void setAlpha(float alpha);
|
||||
void setProjectileSpeed(float speed);
|
||||
void setWalkmesh(std::shared_ptr<graphics::Walkmesh> walkmesh);
|
||||
void setProjectileSpeed(float speed) { _projectileSpeed = speed; }
|
||||
void setWalkmesh(std::shared_ptr<graphics::Walkmesh> walkmesh) { _walkmesh = std::move(walkmesh); }
|
||||
|
||||
// Attachments
|
||||
|
||||
|
@ -91,9 +91,8 @@ private:
|
|||
std::shared_ptr<graphics::Walkmesh> _walkmesh;
|
||||
SceneNodeAnimator _animator;
|
||||
|
||||
std::unordered_map<uint16_t, ModelNodeSceneNode *> _modelNodeByIndex;
|
||||
std::unordered_map<uint16_t, ModelNodeSceneNode *> _modelNodeByNumber;
|
||||
std::unordered_map<uint16_t, LightSceneNode *> _lightNodeByNumber;
|
||||
std::unordered_map<uint16_t, ModelNodeSceneNode *> _modelNodeById;
|
||||
std::unordered_map<uint16_t, LightSceneNode *> _lightNodeById;
|
||||
std::vector<std::shared_ptr<EmitterSceneNode>> _emitters;
|
||||
std::unordered_map<uint16_t, std::shared_ptr<ModelSceneNode>> _attachedModels;
|
||||
bool _visible { true };
|
||||
|
|
|
@ -42,21 +42,21 @@ Particle::Particle(glm::vec3 position, float velocity, EmitterSceneNode *emitter
|
|||
}
|
||||
|
||||
void Particle::init() {
|
||||
shared_ptr<Emitter> emitter(_emitter->emitter());
|
||||
shared_ptr<ModelNode::Emitter> emitter(_emitter->emitter());
|
||||
|
||||
if (emitter->fps() > 0) {
|
||||
_animLength = (emitter->frameEnd() - emitter->frameStart() + 1) / static_cast<float>(emitter->fps());
|
||||
if (emitter->fps > 0) {
|
||||
_animLength = (emitter->frameEnd - emitter->frameStart + 1) / static_cast<float>(emitter->fps);
|
||||
}
|
||||
|
||||
_renderOrder = emitter->renderOrder();
|
||||
_frame = emitter->frameStart();
|
||||
_renderOrder = emitter->renderOrder;
|
||||
_frame = emitter->frameStart;
|
||||
}
|
||||
|
||||
void Particle::update(float dt) {
|
||||
shared_ptr<Emitter> emitter(_emitter->emitter());
|
||||
shared_ptr<ModelNode::Emitter> emitter(_emitter->emitter());
|
||||
|
||||
if (emitter->lifeExpectancy() != -1) {
|
||||
_lifetime = glm::min(_lifetime + dt, static_cast<float>(emitter->lifeExpectancy()));
|
||||
if (emitter->lifeExpectancy != -1) {
|
||||
_lifetime = glm::min(_lifetime + dt, static_cast<float>(emitter->lifeExpectancy));
|
||||
} else if (_lifetime == _animLength) {
|
||||
_lifetime = 0.0f;
|
||||
} else {
|
||||
|
@ -70,7 +70,7 @@ void Particle::update(float dt) {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
static T interpolateConstraints(const Emitter::Constraints<T> &constraints, float t) {
|
||||
static T interpolateConstraints(const ModelNode::Emitter::Constraints<T> &constraints, float t) {
|
||||
T result;
|
||||
if (t < 0.5f) {
|
||||
float tt = 2.0f * t;
|
||||
|
@ -83,26 +83,26 @@ static T interpolateConstraints(const Emitter::Constraints<T> &constraints, floa
|
|||
}
|
||||
|
||||
void Particle::updateAnimation(float dt) {
|
||||
shared_ptr<Emitter> emitter(_emitter->emitter());
|
||||
shared_ptr<ModelNode::Emitter> emitter(_emitter->emitter());
|
||||
|
||||
float maturity;
|
||||
if (emitter->lifeExpectancy() != -1) {
|
||||
maturity = _lifetime / static_cast<float>(emitter->lifeExpectancy());
|
||||
if (emitter->lifeExpectancy != -1) {
|
||||
maturity = _lifetime / static_cast<float>(emitter->lifeExpectancy);
|
||||
} else if (_animLength > 0.0f) {
|
||||
maturity = _lifetime / _animLength;
|
||||
} else {
|
||||
maturity = 0.0f;
|
||||
}
|
||||
|
||||
_frame = static_cast<int>(glm::ceil(emitter->frameStart() + maturity * (emitter->frameEnd() - emitter->frameStart())));
|
||||
_size = interpolateConstraints(emitter->particleSize(), maturity);
|
||||
_color = interpolateConstraints(emitter->color(), maturity);
|
||||
_alpha = interpolateConstraints(emitter->alpha(), maturity);
|
||||
_frame = static_cast<int>(glm::ceil(emitter->frameStart + maturity * (emitter->frameEnd - emitter->frameStart)));
|
||||
_size = interpolateConstraints(emitter->particleSize, maturity);
|
||||
_color = interpolateConstraints(emitter->color, maturity);
|
||||
_alpha = interpolateConstraints(emitter->alpha, maturity);
|
||||
}
|
||||
|
||||
bool Particle::isExpired() const {
|
||||
shared_ptr<Emitter> emitter(_emitter->emitter());
|
||||
return emitter->lifeExpectancy() != -1 && _lifetime >= emitter->lifeExpectancy();
|
||||
shared_ptr<ModelNode::Emitter> emitter(_emitter->emitter());
|
||||
return emitter->lifeExpectancy != -1 && _lifetime >= emitter->lifeExpectancy;
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
|
|
Loading…
Reference in a new issue