mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-13 02:37:38 +02:00
more hacking on rendering of virtual entities
This commit is contained in:
parent
a194db837f
commit
e540bef672
8 changed files with 245 additions and 240 deletions
|
@ -14,9 +14,15 @@
|
|||
#include <FBXReader.h>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <ModelEntityItem.h>
|
||||
|
||||
|
||||
#include "Menu.h"
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
|
||||
|
||||
EntityTreeRenderer::EntityTreeRenderer() :
|
||||
OctreeRenderer() {
|
||||
}
|
||||
|
@ -45,36 +51,9 @@ void EntityTreeRenderer::clearModelsCache() {
|
|||
_unknownEntityItemModels.clear();
|
||||
}
|
||||
|
||||
class ModelEntityItemRenderer {
|
||||
public:
|
||||
static void render(EntityItem* entity) {
|
||||
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
|
||||
float radius = entity->getRadius() * (float)TREE_SCALE;
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
};
|
||||
|
||||
class BoxEntityItemRenderer {
|
||||
public:
|
||||
static void render(EntityItem* entity) {
|
||||
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
|
||||
float size = entity->getSize() * (float)TREE_SCALE;
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidCube(size);
|
||||
glPopMatrix();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void EntityTreeRenderer::init() {
|
||||
REGISTER_ENTITY_TYPE_RENDERER(Model)
|
||||
REGISTER_ENTITY_TYPE_RENDERER(Box)
|
||||
//REGISTER_ENTITY_TYPE_RENDERER(Model, this->renderEntityTypeModel);
|
||||
//REGISTER_ENTITY_TYPE_RENDERER(Box, this->renderEntityTypeBox);
|
||||
|
||||
OctreeRenderer::init();
|
||||
static_cast<EntityTree*>(_tree)->setFBXService(this);
|
||||
|
@ -272,125 +251,86 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
// render entityItem aspoints
|
||||
AACube entityCube = entityItem->getAACube();
|
||||
entityCube.scale(TREE_SCALE);
|
||||
|
||||
// TODO: some entity types (like lights) might want to be rendered even
|
||||
// when they are outside of the view frustum...
|
||||
if (args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) {
|
||||
glm::vec3 position = entityItem->getPosition() * (float)TREE_SCALE;
|
||||
float radius = entityItem->getRadius() * (float)TREE_SCALE;
|
||||
float size = entityItem->getSize() * (float)TREE_SCALE;
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
renderEntityTypeModel(entityItem, args);
|
||||
} else if (entityItem->getType() == EntityTypes::Box) {
|
||||
renderEntityTypeBox(entityItem, args);
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 //def HIDE_SUBCLASS_METHODS
|
||||
bool drawAsModel = entityItem->hasModel();
|
||||
#else
|
||||
bool drawAsModel = false;
|
||||
#endif
|
||||
void EntityTreeRenderer::renderEntityTypeModel(EntityItem* entity, RenderArgs* args) {
|
||||
assert(entity->getType() == EntityTypes::Model);
|
||||
|
||||
ModelEntityItem* entityItem = static_cast<ModelEntityItem*>(entity);
|
||||
bool drawAsModel = entityItem->hasModel();
|
||||
|
||||
args->_itemsRendered++;
|
||||
glm::vec3 position = entityItem->getPosition() * (float)TREE_SCALE;
|
||||
float radius = entityItem->getRadius() * (float)TREE_SCALE;
|
||||
float size = entity->getSize() * (float)TREE_SCALE;
|
||||
|
||||
if (drawAsModel) {
|
||||
glPushMatrix();
|
||||
{
|
||||
const float alpha = 1.0f;
|
||||
|
||||
Model* model = getModel(*entityItem);
|
||||
|
||||
if (model) {
|
||||
model->setScaleToFit(true, radius * 2.0f);
|
||||
model->setSnapModelToCenter(true);
|
||||
|
||||
// set the rotation
|
||||
glm::quat rotation = entityItem->getRotation();
|
||||
model->setRotation(rotation);
|
||||
|
||||
// set the position
|
||||
model->setTranslation(position);
|
||||
|
||||
// handle animations..
|
||||
if (entityItem->hasAnimation()) {
|
||||
if (!entityItem->jointsMapped()) {
|
||||
QStringList modelJointNames = model->getJointNames();
|
||||
entityItem->mapJoints(modelJointNames);
|
||||
}
|
||||
|
||||
if (drawAsModel) {
|
||||
#if 0 //def HIDE_SUBCLASS_METHODS
|
||||
glPushMatrix();
|
||||
{
|
||||
const float alpha = 1.0f;
|
||||
|
||||
Model* model = getModel(*entityItem);
|
||||
QVector<glm::quat> frameData = entityItem->getAnimationFrame();
|
||||
for (int i = 0; i < frameData.size(); i++) {
|
||||
model->setJointState(i, true, frameData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure to simulate so everything gets set up correctly for rendering
|
||||
model->simulate(0.0f);
|
||||
|
||||
// TODO: should we allow entityItems to have alpha on their models?
|
||||
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
|
||||
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
Glower glower(entityItem->getGlowLevel());
|
||||
|
||||
if (model) {
|
||||
model->setScaleToFit(true, radius * 2.0f);
|
||||
model->setSnapModelToCenter(true);
|
||||
|
||||
// set the rotation
|
||||
glm::quat rotation = entityItem->getRotation();
|
||||
model->setRotation(rotation);
|
||||
|
||||
// set the position
|
||||
model->setTranslation(position);
|
||||
|
||||
// handle animations..
|
||||
if (entityItem->hasAnimation()) {
|
||||
if (!entityItem->jointsMapped()) {
|
||||
QStringList modelJointNames = model->getJointNames();
|
||||
entityItem->mapJoints(modelJointNames);
|
||||
}
|
||||
|
||||
QVector<glm::quat> frameData = entityItem->getAnimationFrame();
|
||||
for (int i = 0; i < frameData.size(); i++) {
|
||||
model->setJointState(i, true, frameData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure to simulate so everything gets set up correctly for rendering
|
||||
model->simulate(0.0f);
|
||||
|
||||
// TODO: should we allow entityItems to have alpha on their models?
|
||||
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
|
||||
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
Glower glower(entityItem->getGlowLevel());
|
||||
|
||||
if (model->isActive()) {
|
||||
model->render(alpha, modelRenderMode);
|
||||
} else {
|
||||
// if we couldn't get a model, then just draw a sphere
|
||||
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
} else {
|
||||
if (model->isActive()) {
|
||||
model->render(alpha, modelRenderMode);
|
||||
} else {
|
||||
// if we couldn't get a model, then just draw a sphere
|
||||
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isShadowMode && displayModelBounds) {
|
||||
|
||||
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
|
||||
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
|
||||
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||
|
||||
float width = unRotatedExtents.x;
|
||||
float height = unRotatedExtents.y;
|
||||
float depth = unRotatedExtents.z;
|
||||
|
||||
Extents rotatedExtents = model->getUnscaledMeshExtents();
|
||||
calculateRotatedExtents(rotatedExtents, rotation);
|
||||
|
||||
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
|
||||
|
||||
const glm::vec3& modelScale = model->getScale();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
|
||||
// draw the orignal bounding cube
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
glutWireCube(size);
|
||||
|
||||
// draw the rotated bounding cube
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
|
||||
glutWireCube(1.0);
|
||||
glPopMatrix();
|
||||
|
||||
// draw the model relative bounding box
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glutWireCube(1.0);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
if (model->isActive()) {
|
||||
model->render(alpha, modelRenderMode);
|
||||
} else {
|
||||
// if we couldn't get a model, then just draw a sphere
|
||||
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
} else {
|
||||
if (model->isActive()) {
|
||||
model->render(alpha, modelRenderMode);
|
||||
} else {
|
||||
// if we couldn't get a model, then just draw a sphere
|
||||
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
|
||||
|
@ -400,17 +340,83 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
#endif
|
||||
|
||||
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
|
||||
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
|
||||
|
||||
if (!isShadowMode && displayModelBounds) {
|
||||
|
||||
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
|
||||
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
|
||||
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||
|
||||
float width = unRotatedExtents.x;
|
||||
float height = unRotatedExtents.y;
|
||||
float depth = unRotatedExtents.z;
|
||||
|
||||
Extents rotatedExtents = model->getUnscaledMeshExtents();
|
||||
calculateRotatedExtents(rotatedExtents, rotation);
|
||||
|
||||
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
|
||||
|
||||
const glm::vec3& modelScale = model->getScale();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
|
||||
// draw the orignal bounding cube
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
glutWireCube(size);
|
||||
|
||||
// draw the rotated bounding cube
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glPushMatrix();
|
||||
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
|
||||
glutWireCube(1.0);
|
||||
glPopMatrix();
|
||||
|
||||
// draw the model relative bounding box
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glutWireCube(1.0);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
} else {
|
||||
EntityTypes::renderEntityItem(entityItem);
|
||||
// if we couldn't get a model, then just draw a sphere
|
||||
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
glPopMatrix();
|
||||
} else {
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidSphere(radius, 15, 15);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::renderEntityTypeBox(EntityItem* entity, RenderArgs* args) {
|
||||
assert(entity->getType() == EntityTypes::Box);
|
||||
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
|
||||
float size = entity->getSize() * (float)TREE_SCALE;
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glutSolidCube(size);
|
||||
glPopMatrix();
|
||||
};
|
||||
|
||||
|
||||
float EntityTreeRenderer::getSizeScale() const {
|
||||
return Menu::getInstance()->getVoxelSizeScale();
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
|
||||
Q_INVOKABLE Model* getModel(const EntityItem& modelItem);
|
||||
|
||||
// renderers for various types of entities
|
||||
void renderEntityTypeBox(EntityItem* entity, RenderArgs* args);
|
||||
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
|
||||
|
||||
protected:
|
||||
void clearModelsCache();
|
||||
QMap<uint32_t, Model*> _knownEntityItemModels;
|
||||
|
|
|
@ -1085,84 +1085,6 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 //def HIDE_SUBCLASS_METHODS
|
||||
QMap<QString, AnimationPointer> EntityItem::_loadedAnimations; // TODO: improve cleanup by leveraging the AnimationPointer(s)
|
||||
AnimationCache EntityItem::_animationCache;
|
||||
|
||||
// This class/instance will cleanup the animations once unloaded.
|
||||
class EntityAnimationsBookkeeper {
|
||||
public:
|
||||
~EntityAnimationsBookkeeper() {
|
||||
EntityItem::cleanupLoadedAnimations();
|
||||
}
|
||||
};
|
||||
|
||||
EntityAnimationsBookkeeper modelAnimationsBookkeeperInstance;
|
||||
|
||||
void EntityItem::cleanupLoadedAnimations() {
|
||||
foreach(AnimationPointer animation, _loadedAnimations) {
|
||||
animation.clear();
|
||||
}
|
||||
_loadedAnimations.clear();
|
||||
}
|
||||
|
||||
Animation* EntityItem::getAnimation(const QString& url) {
|
||||
AnimationPointer animation;
|
||||
|
||||
// if we don't already have this model then create it and initialize it
|
||||
if (_loadedAnimations.find(url) == _loadedAnimations.end()) {
|
||||
animation = _animationCache.getAnimation(url);
|
||||
_loadedAnimations[url] = animation;
|
||||
} else {
|
||||
animation = _loadedAnimations[url];
|
||||
}
|
||||
return animation.data();
|
||||
}
|
||||
|
||||
void EntityItem::mapJoints(const QStringList& modelJointNames) {
|
||||
// if we don't have animation, or we're already joint mapped then bail early
|
||||
if (!hasAnimation() || _jointMappingCompleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
Animation* myAnimation = getAnimation(_animationURL);
|
||||
|
||||
if (!_jointMappingCompleted) {
|
||||
QStringList animationJointNames = myAnimation->getJointNames();
|
||||
|
||||
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
|
||||
_jointMapping.resize(modelJointNames.size());
|
||||
for (int i = 0; i < modelJointNames.size(); i++) {
|
||||
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
|
||||
}
|
||||
_jointMappingCompleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<glm::quat> EntityItem::getAnimationFrame() {
|
||||
QVector<glm::quat> frameData;
|
||||
if (hasAnimation() && _jointMappingCompleted) {
|
||||
Animation* myAnimation = getAnimation(_animationURL);
|
||||
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
|
||||
int frameCount = frames.size();
|
||||
|
||||
if (frameCount > 0) {
|
||||
int animationFrameIndex = (int)glm::floor(_animationFrameIndex) % frameCount;
|
||||
QVector<glm::quat> rotations = frames[animationFrameIndex].rotations;
|
||||
frameData.resize(_jointMapping.size());
|
||||
for (int j = 0; j < _jointMapping.size(); j++) {
|
||||
int rotationIndex = _jointMapping[j];
|
||||
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
|
||||
frameData[j] = rotations[rotationIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return frameData;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EntityItem::update(const quint64& updateTime) {
|
||||
_lastUpdated = updateTime;
|
||||
setShouldBeDeleted(getShouldBeDeleted());
|
||||
|
|
|
@ -97,8 +97,6 @@ public:
|
|||
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
|
||||
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0)
|
||||
|
||||
static void cleanupLoadedAnimations();
|
||||
|
||||
protected:
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
||||
|
|
|
@ -387,11 +387,11 @@ bool EntityTypes::registerEntityTypeRenderer(EntityType_t entityType, EntityType
|
|||
return true;
|
||||
}
|
||||
|
||||
void EntityTypes::renderEntityItem(EntityItem* entityItem) {
|
||||
void EntityTypes::renderEntityItem(EntityItem* entityItem, RenderArgs* args) {
|
||||
EntityType_t entityType = entityItem->getType();
|
||||
EntityTypeRenderer renderMethod = _renderers[entityType];
|
||||
if (renderMethod) {
|
||||
renderMethod(entityItem);
|
||||
renderMethod(entityItem, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
#include <OctreeRenderer.h> // for RenderArgs
|
||||
|
||||
class EntityItem;
|
||||
class EntityItemID;
|
||||
class EntityItemProperties;
|
||||
class ReadBitstreamToTreeParams;
|
||||
|
||||
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
typedef void (*EntityTypeRenderer)(EntityItem* entity);
|
||||
typedef void (*EntityTypeRenderer)(EntityItem* entity, RenderArgs* args);
|
||||
|
||||
class EntityTypes {
|
||||
public:
|
||||
|
@ -47,7 +49,7 @@ public:
|
|||
EntityItemID& entityID, EntityItemProperties& properties);
|
||||
|
||||
static bool registerEntityTypeRenderer(EntityType_t entityType, EntityTypeRenderer renderMethod);
|
||||
static void renderEntityItem(EntityItem* entityItem);
|
||||
static void renderEntityItem(EntityItem* entityItem, RenderArgs* args);
|
||||
|
||||
private:
|
||||
static QMap<EntityType_t, QString> _typeToNameMap;
|
||||
|
@ -65,10 +67,7 @@ private:
|
|||
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \
|
||||
EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory);
|
||||
|
||||
#define REGISTER_ENTITY_TYPE_RENDERER(x) static bool x##RendererRegistration = \
|
||||
EntityTypes::registerEntityTypeRenderer(EntityTypes::x, x##EntityItemRenderer::render); \
|
||||
x##RendererRegistration = x##RendererRegistration;
|
||||
|
||||
#define REGISTER_ENTITY_TYPE_RENDERER(x,y) EntityTypes::registerEntityTypeRenderer(EntityTypes::x, y);
|
||||
|
||||
|
||||
#endif // hifi_EntityTypes_h
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
#include "ModelEntityItem.h"
|
||||
|
||||
|
||||
//EntityTypes::registerEntityType(EntityTypes::Model, "Model", ModelEntityItem::factory);
|
||||
|
||||
|
||||
EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
qDebug() << "ModelEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
|
||||
return new ModelEntityItem(entityID, properties);
|
||||
|
@ -778,4 +775,81 @@ qDebug() << "ModelEntityItem::appendEntityData()... modelURL=" << getModelURL();
|
|||
}
|
||||
|
||||
return appendState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QMap<QString, AnimationPointer> ModelEntityItem::_loadedAnimations; // TODO: improve cleanup by leveraging the AnimationPointer(s)
|
||||
AnimationCache ModelEntityItem::_animationCache;
|
||||
|
||||
// This class/instance will cleanup the animations once unloaded.
|
||||
class EntityAnimationsBookkeeper {
|
||||
public:
|
||||
~EntityAnimationsBookkeeper() {
|
||||
ModelEntityItem::cleanupLoadedAnimations();
|
||||
}
|
||||
};
|
||||
|
||||
EntityAnimationsBookkeeper modelAnimationsBookkeeperInstance;
|
||||
|
||||
void ModelEntityItem::cleanupLoadedAnimations() {
|
||||
foreach(AnimationPointer animation, _loadedAnimations) {
|
||||
animation.clear();
|
||||
}
|
||||
_loadedAnimations.clear();
|
||||
}
|
||||
|
||||
Animation* ModelEntityItem::getAnimation(const QString& url) {
|
||||
AnimationPointer animation;
|
||||
|
||||
// if we don't already have this model then create it and initialize it
|
||||
if (_loadedAnimations.find(url) == _loadedAnimations.end()) {
|
||||
animation = _animationCache.getAnimation(url);
|
||||
_loadedAnimations[url] = animation;
|
||||
} else {
|
||||
animation = _loadedAnimations[url];
|
||||
}
|
||||
return animation.data();
|
||||
}
|
||||
|
||||
void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
||||
// if we don't have animation, or we're already joint mapped then bail early
|
||||
if (!hasAnimation() || _jointMappingCompleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
Animation* myAnimation = getAnimation(_animationURL);
|
||||
|
||||
if (!_jointMappingCompleted) {
|
||||
QStringList animationJointNames = myAnimation->getJointNames();
|
||||
|
||||
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
|
||||
_jointMapping.resize(modelJointNames.size());
|
||||
for (int i = 0; i < modelJointNames.size(); i++) {
|
||||
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
|
||||
}
|
||||
_jointMappingCompleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
|
||||
QVector<glm::quat> frameData;
|
||||
if (hasAnimation() && _jointMappingCompleted) {
|
||||
Animation* myAnimation = getAnimation(_animationURL);
|
||||
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
|
||||
int frameCount = frames.size();
|
||||
|
||||
if (frameCount > 0) {
|
||||
int animationFrameIndex = (int)glm::floor(_animationFrameIndex) % frameCount;
|
||||
QVector<glm::quat> rotations = frames[animationFrameIndex].rotations;
|
||||
frameData.resize(_jointMapping.size());
|
||||
for (int j = 0; j < _jointMapping.size(); j++) {
|
||||
int rotationIndex = _jointMapping[j];
|
||||
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
|
||||
frameData[j] = rotations[rotationIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return frameData;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ public:
|
|||
float getAnimationFrameIndex() const { return _animationFrameIndex; }
|
||||
float getAnimationFPS() const { return _animationFPS; }
|
||||
|
||||
static void cleanupLoadedAnimations();
|
||||
|
||||
protected:
|
||||
|
||||
rgbColor _color;
|
||||
|
|
Loading…
Reference in a new issue