split out entity rendering into subclasses, improved rendering of models

This commit is contained in:
ZappoMan 2014-08-20 15:49:50 -07:00
parent ddae85ce4a
commit ef86d86234
24 changed files with 886 additions and 466 deletions

View file

@ -1088,6 +1088,7 @@ var active;
var newModel; var newModel;
var browser; var browser;
var newBox; var newBox;
var newSphere;
function initToolBar() { function initToolBar() {
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
// New Model // New Model
@ -1118,6 +1119,14 @@ function initToolBar() {
visible: true, visible: true,
alpha: 0.9 alpha: 0.9
}); });
newSphere = toolBar.addTool({
imageURL: toolIconUrl + "add-model-tool.svg",
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
width: toolWidth, height: toolHeight,
visible: true,
alpha: 0.9
});
} }
function moveOverlays() { function moveOverlays() {
@ -1261,6 +1270,20 @@ function mousePressEvent(event) {
print("Can't create box: Box would be out of bounds."); print("Can't create box: Box would be out of bounds.");
} }
} else if (newSphere == toolBar.clicked(clickedOverlay)) {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
if (position.x > 0 && position.y > 0 && position.z > 0) {
Entities.addEntity({
type: "Sphere",
position: position,
radius: radiusDefault,
color: { red: 255, green: 0, blue: 0 }
});
} else {
print("Can't create box: Box would be out of bounds.");
}
} else if (browser == toolBar.clicked(clickedOverlay)) { } else if (browser == toolBar.clicked(clickedOverlay)) {
var url = Window.s3Browse(".*(fbx|FBX)"); var url = Window.s3Browse(".*(fbx|FBX)");
if (url == null || url == "") { if (url == null || url == "") {

View file

@ -2668,9 +2668,20 @@ void Application::updateShadowMap() {
glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
{
PerformanceTimer perfTimer("avatarManager");
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
}
{
PerformanceTimer perfTimer("particles");
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE); _particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
}
{
PerformanceTimer perfTimer("entities");
_entities.render(OctreeRenderer::SHADOW_RENDER_MODE); _entities.render(OctreeRenderer::SHADOW_RENDER_MODE);
}
glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_POLYGON_OFFSET_FILL);
@ -2867,9 +2878,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
// render models... // render models...
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
PerformanceTimer perfTimer("models"); PerformanceTimer perfTimer("entities");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... models..."); "Application::displaySide() ... entities...");
_entities.render(); _entities.render();
} }

View file

@ -15,17 +15,34 @@
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include <ModelEntityItem.h>
#include <BoxEntityItem.h> #include <BoxEntityItem.h>
#include <ModelEntityItem.h>
#include <PerfStat.h>
#include "Menu.h" #include "Menu.h"
#include "EntityTreeRenderer.h" #include "EntityTreeRenderer.h"
#include "RenderableBoxEntityItem.h"
#include "RenderableModelEntityItem.h"
#include "RenderableSphereEntityItem.h"
QThread* EntityTreeRenderer::getMainThread() {
return Application::getInstance()->getEntities()->thread();
}
EntityTreeRenderer::EntityTreeRenderer() : EntityTreeRenderer::EntityTreeRenderer() :
OctreeRenderer() { OctreeRenderer() {
qDebug() << "--- Overriding Entity Factories NOW ---";
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, RenderableBoxEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, RenderableSphereEntityItem::factory)
qDebug() << "--- DONE Overriding Entity Factories ---";
} }
EntityTreeRenderer::~EntityTreeRenderer() { EntityTreeRenderer::~EntityTreeRenderer() {
@ -40,6 +57,7 @@ void EntityTreeRenderer::clear() {
void EntityTreeRenderer::clearModelsCache() { void EntityTreeRenderer::clearModelsCache() {
qDebug() << "EntityTreeRenderer::clearModelsCache()..."; qDebug() << "EntityTreeRenderer::clearModelsCache()...";
/*
// delete the models in _knownEntityItemModels // delete the models in _knownEntityItemModels
foreach(Model* model, _knownEntityItemModels) { foreach(Model* model, _knownEntityItemModels) {
delete model; delete model;
@ -50,12 +68,15 @@ void EntityTreeRenderer::clearModelsCache() {
delete model; delete model;
} }
_unknownEntityItemModels.clear(); _unknownEntityItemModels.clear();
foreach(Model* model, _entityItemModels) {
delete model;
}
_entityItemModels.clear();
*/
} }
void EntityTreeRenderer::init() { void EntityTreeRenderer::init() {
//REGISTER_ENTITY_TYPE_RENDERER(Model, this->renderEntityTypeModel);
//REGISTER_ENTITY_TYPE_RENDERER(Box, this->renderEntityTypeBox);
OctreeRenderer::init(); OctreeRenderer::init();
static_cast<EntityTree*>(_tree)->setFBXService(this); static_cast<EntityTree*>(_tree)->setFBXService(this);
} }
@ -84,9 +105,10 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
const FBXGeometry* result = NULL; const FBXGeometry* result = NULL;
if (entityItem->getType() == EntityTypes::Model) { if (entityItem->getType() == EntityTypes::Model) {
const ModelEntityItem* modelEntityItem = static_cast<const ModelEntityItem*>(entityItem); const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
Model* model = getModel(modelEntityItem); assert(modelEntityItem); // we need this!!!
Model* model = modelEntityItem->getModel();
if (model) { if (model) {
result = &model->getGeometry()->getFBXGeometry(); result = &model->getGeometry()->getFBXGeometry();
} }
@ -97,73 +119,17 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityItem) { const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityItem) {
const Model* result = NULL; const Model* result = NULL;
if (entityItem->getType() == EntityTypes::Model) { if (entityItem->getType() == EntityTypes::Model) {
const ModelEntityItem* modelEntityItem = static_cast<const ModelEntityItem*>(entityItem); const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
assert(modelEntityItem); // we need this!!!
result = getModel(modelEntityItem); result = modelEntityItem->getModel();
} }
return result; return result;
} }
Model* EntityTreeRenderer::getModel(const ModelEntityItem* modelEntityItem) {
Model* model = NULL;
if (!modelEntityItem->getModelURL().isEmpty()) {
if (modelEntityItem->isKnownID()) {
if (_knownEntityItemModels.find(modelEntityItem->getID()) != _knownEntityItemModels.end()) {
model = _knownEntityItemModels[modelEntityItem->getID()];
if (QUrl(modelEntityItem->getModelURL()) != model->getURL()) {
delete model; // delete the old model...
model = NULL;
_knownEntityItemModels.remove(modelEntityItem->getID());
}
}
// if we don't have a model... but our item does have a model URL
if (!model) {
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
if (QThread::currentThread() != thread()) {
qDebug() << "about to call QMetaObject::invokeMethod(this, 'getModel', Qt::BlockingQueuedConnection,...";
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(Model*, model), Q_ARG(const ModelEntityItem*, modelEntityItem));
qDebug() << "got it... model=" << model;
return model;
}
model = new Model();
model->init();
model->setURL(QUrl(modelEntityItem->getModelURL()));
_knownEntityItemModels[modelEntityItem->getID()] = model;
}
} else {
if (_unknownEntityItemModels.find(modelEntityItem->getCreatorTokenID()) != _unknownEntityItemModels.end()) {
model = _unknownEntityItemModels[modelEntityItem->getCreatorTokenID()];
if (QUrl(modelEntityItem->getModelURL()) != model->getURL()) {
delete model; // delete the old model...
model = NULL;
_unknownEntityItemModels.remove(modelEntityItem->getCreatorTokenID());
}
}
if (!model) {
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(Model*, model), Q_ARG(const ModelEntityItem*, modelEntityItem));
return model;
}
model = new Model();
model->init();
model->setURL(QUrl(modelEntityItem->getModelURL()));
_unknownEntityItemModels[modelEntityItem->getCreatorTokenID()] = model;
}
}
}
return model;
}
void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
//PerformanceTimer perfTimer("renderElement");
args->_elementsTouched++; args->_elementsTouched++;
// actually render it here... // actually render it here...
// we need to iterate the actual entityItems of the element // we need to iterate the actual entityItems of the element
@ -271,13 +237,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
if (entityItem->getGlowLevel() > 0.0f) { if (entityItem->getGlowLevel() > 0.0f) {
glower = new Glower(entityItem->getGlowLevel()); glower = new Glower(entityItem->getGlowLevel());
} }
entityItem->render(args);
if (entityItem->getType() == EntityTypes::Model) {
renderEntityTypeModel(entityItem, args);
} else if (entityItem->getType() == EntityTypes::Box) {
renderEntityTypeBox(entityItem, args);
}
if (glower) { if (glower) {
delete glower; delete glower;
} }
@ -288,217 +248,6 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
} }
} }
void EntityTreeRenderer::renderEntityTypeModel(EntityItem* entity, RenderArgs* args) {
assert(entity->getType() == EntityTypes::Model);
ModelEntityItem* entityItem = static_cast<ModelEntityItem*>(entity);
bool drawAsModel = entityItem->hasModel();
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()) {
//qDebug() << "entityItem->hasAnimation()...";
if (!entityItem->jointsMapped()) {
QStringList modelJointNames = model->getJointNames();
entityItem->mapJoints(modelJointNames);
//qDebug() << "entityItem->mapJoints()...";
}
if (entityItem->jointsMapped()) {
//qDebug() << "model->setJointState()...";
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 (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();
}
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 {
// 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();
}
}
glPopMatrix();
} else {
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
}
// vertex array for glDrawElements() and glDrawRangeElement() =================
// Notice that the sizes of these arrays become samller than the arrays for
// glDrawArrays() because glDrawElements() uses an additional index array to
// choose designated vertices with the indices. The size of vertex array is now
// 24 instead of 36, but the index array size is 36, same as the number of
// vertices required to draw a cube.
GLfloat vertices2[] = { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
-1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1,v6,v7,v2 (left)
-1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7,v4,v3,v2 (bottom)
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back)
// normal array
GLfloat normals2[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1,v6,v7,v2 (left)
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7,v4,v3,v2 (bottom)
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v4,v7,v6,v5 (back)
// color array
GLfloat colors2[] = { 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // v0,v3,v4,v5 (right)
1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, // v0,v5,v6,v1 (top)
1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, // v1,v6,v7,v2 (left)
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // v7,v4,v3,v2 (bottom)
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1 }; // v4,v7,v6,v5 (back)
// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte indices[] = { 0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // right
8, 9,10, 10,11, 8, // top
12,13,14, 14,15,12, // left
16,17,18, 18,19,16, // bottom
20,21,22, 22,23,20 }; // back
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;
glm::quat rotation = entity->getRotation();
BoxEntityItem* boxEntityItem = static_cast<BoxEntityItem*>(entity);
/*
glColor3f(0.0f, 1.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glutSolidCube(size);
glPopMatrix();
*/
// enable and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals2);
//glColorPointer(3, GL_FLOAT, 0, colors2);
glVertexPointer(3, GL_FLOAT, 0, vertices2);
//glEnable(GL_BLEND);
glColor3ub(boxEntityItem->getColor()[RED_INDEX], boxEntityItem->getColor()[GREEN_INDEX], boxEntityItem->getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glScalef(size, size, size);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
//glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
};
float EntityTreeRenderer::getSizeScale() const { float EntityTreeRenderer::getSizeScale() const {
return Menu::getInstance()->getVoxelSizeScale(); return Menu::getInstance()->getVoxelSizeScale();
} }

View file

@ -25,8 +25,6 @@
#include "renderer/Model.h" #include "renderer/Model.h"
class ModelEntityItem;
// Generic client side Octree renderer class. // Generic client side Octree renderer class.
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService { class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService {
Q_OBJECT Q_OBJECT
@ -58,16 +56,19 @@ public:
/// clears the tree /// clears the tree
virtual void clear(); virtual void clear();
Q_INVOKABLE Model* getModel(const ModelEntityItem* modelEntityItem); //Q_INVOKABLE Model* getModel(const ModelEntityItem* modelEntityItem);
// renderers for various types of entities // renderers for various types of entities
void renderEntityTypeBox(EntityItem* entity, RenderArgs* args); void renderEntityTypeBox(EntityItem* entity, RenderArgs* args);
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args); void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
static QThread* getMainThread();
protected: protected:
void clearModelsCache(); void clearModelsCache();
QMap<QUuid, Model*> _knownEntityItemModels; //QMap<QUuid, Model*> _knownEntityItemModels;
QMap<uint32_t, Model*> _unknownEntityItemModels; //QMap<uint32_t, Model*> _unknownEntityItemModels;
//QMap<const ModelEntityItem*, Model*> _entityItemModels;
}; };
#endif // hifi_EntityTreeRenderer_h #endif // hifi_EntityTreeRenderer_h

View file

@ -0,0 +1,119 @@
//
// EntityTreeRenderer.cpp
// interface/src
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <glm/gtx/quaternion.hpp>
#include <FBXReader.h>
#include "InterfaceConfig.h"
#include <BoxEntityItem.h>
#include <ModelEntityItem.h>
#include <PerfStat.h>
#include "Menu.h"
#include "EntityTreeRenderer.h"
#include "RenderableBoxEntityItem.h"
// vertex array for glDrawElements() and glDrawRangeElement() =================
// Notice that the sizes of these arrays become samller than the arrays for
// glDrawArrays() because glDrawElements() uses an additional index array to
// choose designated vertices with the indices. The size of vertex array is now
// 24 instead of 36, but the index array size is 36, same as the number of
// vertices required to draw a cube.
GLfloat vertices2[] = { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
-1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1,v6,v7,v2 (left)
-1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7,v4,v3,v2 (bottom)
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back)
// normal array
GLfloat normals2[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1,v6,v7,v2 (left)
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7,v4,v3,v2 (bottom)
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v4,v7,v6,v5 (back)
// color array
GLfloat colors2[] = { 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // v0,v3,v4,v5 (right)
1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, // v0,v5,v6,v1 (top)
1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, // v1,v6,v7,v2 (left)
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // v7,v4,v3,v2 (bottom)
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1 }; // v4,v7,v6,v5 (back)
// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte indices[] = { 0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // right
8, 9,10, 10,11, 8, // top
12,13,14, 14,15,12, // left
16,17,18, 18,19,16, // bottom
20,21,22, 22,23,20 }; // back
EntityItem* RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
qDebug() << "RenderableBoxEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
return new RenderableBoxEntityItem(entityID, properties);
}
void RenderableBoxEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
assert(getType() == EntityTypes::Box);
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float size = getSize() * (float)TREE_SCALE;
glm::quat rotation = getRotation();
/*
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glutSolidCube(size);
glPopMatrix();
*/
// enable and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals2);
//glColorPointer(3, GL_FLOAT, 0, colors2);
glVertexPointer(3, GL_FLOAT, 0, vertices2);
//glEnable(GL_BLEND);
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
// we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1
float halfSize = size/2.0f;
glScalef(halfSize, halfSize, halfSize);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
//glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
};

View file

@ -0,0 +1,40 @@
//
// RenderableBoxEntityItem.h
// interface/src/entities
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RenderableBoxEntityItem_h
#define hifi_RenderableBoxEntityItem_h
#include <glm/glm.hpp>
#include <stdint.h>
#include <EntityTree.h>
#include <Octree.h>
#include <OctreePacketData.h>
#include <OctreeRenderer.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <ViewFrustum.h>
#include <BoxEntityItem.h>
class RenderableBoxEntityItem : public BoxEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableBoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
BoxEntityItem(entityItemID, properties)
{ };
virtual void render(RenderArgs* args);
};
#endif // hifi_RenderableBoxEntityItem_h

View file

@ -0,0 +1,241 @@
//
// EntityTreeRenderer.cpp
// interface/src
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <glm/gtx/quaternion.hpp>
#include <FBXReader.h>
#include "InterfaceConfig.h"
#include <BoxEntityItem.h>
#include <ModelEntityItem.h>
#include <PerfStat.h>
#include "Menu.h"
#include "EntityTreeRenderer.h"
#include "RenderableModelEntityItem.h"
EntityItem* RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
qDebug() << "RenderableModelEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
return new RenderableModelEntityItem(entityID, properties);
}
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
QString oldModelURL = getModelURL();
bool somethingChanged = ModelEntityItem::setProperties(properties, forceCopy);
if (somethingChanged && oldModelURL != getModelURL()) {
_needsModelReload = true;
}
return somethingChanged;
}
int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
QString oldModelURL = getModelURL();
int bytesRead = ModelEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
args, propertyFlags, overwriteLocalData);
if (oldModelURL != getModelURL()) {
_needsModelReload = true;
}
return bytesRead;
}
void RenderableModelEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableModelEntityItem::render");
assert(getType() == EntityTypes::Model);
bool drawAsModel = hasModel();
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float radius = getRadius() * (float)TREE_SCALE;
float size = getSize() * (float)TREE_SCALE;
if (drawAsModel) {
glPushMatrix();
{
const float alpha = 1.0f;
if (!_model || _needsModelReload) {
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
PerformanceTimer perfTimer("getModel");
getModel();
}
if (_model) {
// handle animations..
if (hasAnimation()) {
//qDebug() << "hasAnimation()...";
if (!jointsMapped()) {
QStringList modelJointNames = _model->getJointNames();
mapJoints(modelJointNames);
//qDebug() << "mapJoints()...";
}
if (jointsMapped()) {
//qDebug() << "_model->setJointState()...";
QVector<glm::quat> frameData = getAnimationFrame();
for (int i = 0; i < frameData.size(); i++) {
_model->setJointState(i, true, frameData[i]);
}
}
}
glm::quat rotation = getRotation();
if (_needsSimulation && _model->isActive()) {
_model->setScaleToFit(true, radius * 2.0f);
_model->setSnapModelToCenter(true);
_model->setRotation(rotation);
_model->setTranslation(position);
// make sure to simulate so everything gets set up correctly for rendering
{
// TODO: _model->simulate() appears to be about 28% of model render time.
// do we really need to call this every frame? I think not. Look into how to
// reduce calls to this.
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsSimulation = false;
}
// 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 (_model->isActive()) {
// TODO: this appears to be about 62% of model render time. Is there a way to call this that doesn't
// cost us as much? For example if the same model is used but rendered multiple places is it less
// expensive?
PerformanceTimer perfTimer("model->render");
_model->render(alpha, modelRenderMode);
} else {
// if we couldn't get a model, then just draw a sphere
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
if (!isShadowMode && displayModelBounds) {
PerformanceTimer perfTimer("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 {
// if we couldn't get a model, then just draw a sphere
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
}
glPopMatrix();
} else {
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
}
Model* RenderableModelEntityItem::getModel() {
_needsModelReload = false; // this is the reload
if (!getModelURL().isEmpty()) {
// double check our URLS match...
if (_model && QUrl(getModelURL()) != _model->getURL()) {
delete _model; // delete the old model...
_model = NULL;
_needsSimulation = true;
}
// if we don't have a model... but our item does have a model URL
if (!_model) {
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
if (QThread::currentThread() != EntityTreeRenderer::getMainThread()) {
// TODO: how do we better handle this??? we may need this for scripting...
// possible go back to a getModel() service on the TreeRenderer, but have it take a URL
// this would allow the entity items to use that service for loading, and since the
// EntityTreeRenderer is a Q_OBJECT it can call invokeMethod()
qDebug() << "can't call getModel() on thread other than rendering thread...";
//qDebug() << "about to call QMetaObject::invokeMethod(this, 'getModel', Qt::BlockingQueuedConnection,...";
//QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(Model*, _model));
//qDebug() << "got it... _model=" << _model;
return _model;
}
_model = new Model();
_model->init();
_model->setURL(QUrl(getModelURL()));
_needsSimulation = true;
}
} else {
// our URL is empty, we should clean up our old model
if (_model) {
delete _model; // delete the old model...
_model = NULL;
_needsSimulation = true;
}
}
return _model;
}

View file

@ -0,0 +1,56 @@
//
// RenderableModelEntityItem.h
// interface/src/entities
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RenderableModelEntityItem_h
#define hifi_RenderableModelEntityItem_h
#include <glm/glm.hpp>
#include <stdint.h>
#include <EntityTree.h>
#include <Octree.h>
#include <OctreePacketData.h>
#include <OctreeRenderer.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <ViewFrustum.h>
#include "renderer/Model.h"
#include <ModelEntityItem.h>
#include <BoxEntityItem.h>
class RenderableModelEntityItem : public ModelEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ModelEntityItem(entityItemID, properties),
_model(NULL),
_needsSimulation(true),
_needsModelReload(true) { };
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy);
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
virtual void somethingChangedNotification() { _needsSimulation = true; }
virtual void render(RenderArgs* args);
Model* getModel();
private:
Model* _model;
bool _needsSimulation;
bool _needsModelReload;
};
#endif // hifi_RenderableModelEntityItem_h

View file

@ -0,0 +1,50 @@
//
// RenderableSphereEntityItem.cpp
// interface/src
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <glm/gtx/quaternion.hpp>
#include <FBXReader.h>
#include "InterfaceConfig.h"
#include <PerfStat.h>
#include <SphereEntityItem.h>
#include "Menu.h"
#include "EntityTreeRenderer.h"
#include "RenderableSphereEntityItem.h"
EntityItem* RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
qDebug() << "RenderableSphereEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
return new RenderableSphereEntityItem(entityID, properties);
}
void RenderableSphereEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableSphereEntityItem::render");
assert(getType() == EntityTypes::Sphere);
glm::vec3 position = getPosition() * (float)TREE_SCALE;
float radius = getRadius() * (float)TREE_SCALE;
glm::quat rotation = getRotation();
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
// TODO: we can probably get rid of this rotation until we support different radius dimensions
//glm::vec3 axis = glm::axis(rotation);
//glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
};

View file

@ -0,0 +1,40 @@
//
// RenderableSphereEntityItem.h
// interface/src/entities
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RenderableSphereEntityItem_h
#define hifi_RenderableSphereEntityItem_h
#include <glm/glm.hpp>
#include <stdint.h>
#include <EntityTree.h>
#include <Octree.h>
#include <OctreePacketData.h>
#include <OctreeRenderer.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <ViewFrustum.h>
#include <SphereEntityItem.h>
class RenderableSphereEntityItem : public SphereEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableSphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
SphereEntityItem(entityItemID, properties)
{ };
virtual void render(RenderArgs* args);
};
#endif // hifi_RenderableSphereEntityItem_h

View file

@ -1242,8 +1242,6 @@ float Model::getLimbLength(int jointIndex) const {
return length; return length;
} }
const int BALL_SUBDIVISIONS = 10;
void Model::renderJointCollisionShapes(float alpha) { void Model::renderJointCollisionShapes(float alpha) {
// implement this when we have shapes for regular models // implement this when we have shapes for regular models
} }

View file

@ -56,12 +56,12 @@ EntityItemProperties BoxEntityItem::getProperties() const {
return properties; return properties;
} }
void BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
qDebug() << "BoxEntityItem::setProperties()..."; qDebug() << "BoxEntityItem::setProperties()...";
qDebug() << "BoxEntityItem::BoxEntityItem() properties.getModelURL()=" << properties.getModelURL(); qDebug() << "BoxEntityItem::BoxEntityItem() properties.getModelURL()=" << properties.getModelURL();
bool somethingChanged = false; bool somethingChanged = false;
EntityItem::setProperties(properties, forceCopy); // set the properties in our base class somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties._colorChanged || forceCopy) { if (properties._colorChanged || forceCopy) {
setColor(properties._color); setColor(properties._color);
@ -83,6 +83,7 @@ void BoxEntityItem::setProperties(const EntityItemProperties& properties, bool f
} }
setLastEdited(properties._lastEdited); setLastEdited(properties._lastEdited);
} }
return somethingChanged;
} }
int BoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, int BoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,

View file

@ -20,11 +20,11 @@ public:
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void somePureVirtualFunction() { }; // allow this class to be constructed ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity // methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const; virtual EntityItemProperties getProperties() const;
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false); virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time // TODO: eventually only include properties changed since the params.lastViewFrustumSent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;

View file

@ -421,7 +421,7 @@ int EntityItem::expectedBytes() {
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
bool wantDebug = true; bool wantDebug = false;
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
qDebug() << "EntityItem::readEntityDataFromBuffer()... ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU"; qDebug() << "EntityItem::readEntityDataFromBuffer()... ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
@ -499,6 +499,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
} }
_lastEdited = lastEditedFromBuffer; _lastEdited = lastEditedFromBuffer;
somethingChangedNotification(); // notify derived classes that something has changed
} }
// last updated is stored as ByteCountCoded delta from lastEdited // last updated is stored as ByteCountCoded delta from lastEdited
@ -828,7 +831,7 @@ EntityItemProperties EntityItem::getProperties() const {
return properties; return properties;
} }
void EntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool EntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
//qDebug() << "EntityItem::setProperties()... forceCopy=" << forceCopy; //qDebug() << "EntityItem::setProperties()... forceCopy=" << forceCopy;
//qDebug() << "EntityItem::setProperties() properties.getDamping()=" << properties.getDamping(); //qDebug() << "EntityItem::setProperties() properties.getDamping()=" << properties.getDamping();
//qDebug() << "EntityItem::setProperties() properties.getVelocity()=" << properties.getVelocity(); //qDebug() << "EntityItem::setProperties() properties.getVelocity()=" << properties.getVelocity();
@ -886,6 +889,7 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc
} }
if (somethingChanged) { if (somethingChanged) {
somethingChangedNotification(); // notify derived classes that something has changed
bool wantDebug = false; bool wantDebug = false;
if (wantDebug) { if (wantDebug) {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
@ -896,5 +900,6 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc
setLastEdited(properties._lastEdited); setLastEdited(properties._lastEdited);
} }
return somethingChanged;
} }

View file

@ -27,16 +27,22 @@
class EntityTreeElementExtraEncodeData; class EntityTreeElementExtraEncodeData;
/// EntityItem class - this is the actual model item class. #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
/// one directly, instead you must only construct one of it's derived classes with additional features.
class EntityItem { class EntityItem {
public: public:
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~EntityItem(); virtual ~EntityItem();
virtual void somePureVirtualFunction() = 0;
// ID and EntityItemID related methods // ID and EntityItemID related methods
QUuid getID() const { return _id; } QUuid getID() const { return _id; }
void setID(const QUuid& id) { _id = id; } void setID(const QUuid& id) { _id = id; }
@ -48,7 +54,13 @@ public:
// methods for getting/setting all properties of an entity // methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const; virtual EntityItemProperties getProperties() const;
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false);
/// returns true is something changed
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
/// override this in your derived class if you'd like to be informed when something about the state of the entity
/// has changed. This will be called with properties change or when new data is loaded from a stream
virtual void somethingChangedNotification() { }
quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs
quint64 getLastEdited() const { return _lastEdited; } /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } /// Last edited time of this entity universal usecs
@ -78,7 +90,9 @@ public:
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args, ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) EntityPropertyFlags& propertyFlags, bool overwriteLocalData)
{ return 0; }; { return 0; }
virtual void render(RenderArgs* args) { } // by default entity items don't know how to render
static int expectedBytes(); static int expectedBytes();
@ -188,52 +202,4 @@ protected:
QString _script; QString _script;
}; };
class SphereEntityItem : public EntityItem {
public:
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Sphere; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new SphereEntityItem(entityID, properties);
}
};
class PlaneEntityItem : public EntityItem {
public:
PlaneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Plane; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new PlaneEntityItem(entityID, properties);
}
};
class CylinderEntityItem : public EntityItem {
public:
CylinderEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Cylinder; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new CylinderEntityItem(entityID, properties);
}
};
class PyramidEntityItem : public EntityItem {
public:
PyramidEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) { _type = EntityTypes::Pyramid; }
virtual void somePureVirtualFunction() { }; // allow this class to be constructed
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new PyramidEntityItem(entityID, properties);
}
};
#endif // hifi_EntityItem_h #endif // hifi_EntityItem_h

View file

@ -180,6 +180,23 @@ public:
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties); EntityItemID& entityID, EntityItemProperties& properties);
bool positionChanged() const { return _positionChanged; }
bool radiusChanged() const { return _radiusChanged; }
bool rotationChanged() const { return _rotationChanged; }
bool massChanged() const { return _massChanged; }
bool velocityChanged() const { return _velocityChanged; }
bool gravityChanged() const { return _gravityChanged; }
bool dampingChanged() const { return _dampingChanged; }
bool lifetimeChanged() const { return _lifetimeChanged; }
bool scriptChanged() const { return _scriptChanged; }
bool colorChanged() const { return _colorChanged; }
bool modelURLChanged() const { return _modelURLChanged; }
bool animationURLChanged() const { return _animationURLChanged; }
bool animationIsPlayingChanged() const { return _animationIsPlayingChanged; }
bool animationFrameIndexChanged() const { return _animationFrameIndexChanged; }
bool animationFPSChanged() const { return _animationFPSChanged; }
bool glowLevelChanged() const { return _glowLevelChanged; }
private: private:
void setLastEdited(quint64 lastEdited) { _lastEdited = lastEdited; } void setLastEdited(quint64 lastEdited) { _lastEdited = lastEdited; }

View file

@ -20,23 +20,19 @@
#include "BoxEntityItem.h" #include "BoxEntityItem.h"
#include "ModelEntityItem.h" #include "ModelEntityItem.h"
#include "SphereEntityItem.h"
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap; QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap; QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
EntityTypeFactory EntityTypes::_factories[EntityTypes::LAST]; EntityTypeFactory EntityTypes::_factories[EntityTypes::LAST];
bool EntityTypes::_factoriesInitialized = false; bool EntityTypes::_factoriesInitialized = false;
EntityTypeRenderer EntityTypes::_renderers[EntityTypes::LAST];
bool EntityTypes::_renderersInitialized = false;
const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown"; const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown";
// Register Entity Types here... // Register Entity the default implementations of entity types here...
REGISTER_ENTITY_TYPE(Model) REGISTER_ENTITY_TYPE(Model)
REGISTER_ENTITY_TYPE(Box) REGISTER_ENTITY_TYPE(Box)
REGISTER_ENTITY_TYPE(Sphere) REGISTER_ENTITY_TYPE(Sphere)
REGISTER_ENTITY_TYPE(Plane)
REGISTER_ENTITY_TYPE(Cylinder)
REGISTER_ENTITY_TYPE(Pyramid)
const QString& EntityTypes::getEntityTypeName(EntityType entityType) { const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
@ -153,24 +149,3 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte
return NULL; return NULL;
} }
bool EntityTypes::registerEntityTypeRenderer(EntityType entityType, EntityTypeRenderer renderMethod) {
if (!_renderersInitialized) {
memset(&_renderers,0,sizeof(_renderers));
_renderersInitialized = true;
}
_renderers[entityType] = renderMethod;
return true;
}
void EntityTypes::renderEntityItem(EntityItem* entityItem, RenderArgs* args) {
EntityType entityType = entityItem->getType();
EntityTypeRenderer renderMethod = _renderers[entityType];
if (renderMethod) {
renderMethod(entityItem, args);
}
}

View file

@ -25,7 +25,6 @@ class EntityItemProperties;
class ReadBitstreamToTreeParams; class ReadBitstreamToTreeParams;
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties); typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
typedef void (*EntityTypeRenderer)(EntityItem* entity, RenderArgs* args);
class EntityTypes { class EntityTypes {
public: public:
@ -34,10 +33,7 @@ public:
Model, Model,
Box, Box,
Sphere, Sphere,
Plane, LAST = Sphere
Cylinder,
Pyramid,
LAST = Pyramid
} EntityType; } EntityType;
static const QString& getEntityTypeName(EntityType entityType); static const QString& getEntityTypeName(EntityType entityType);
@ -46,16 +42,11 @@ public:
static EntityItem* constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties); static EntityItem* constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args); static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args);
static bool registerEntityTypeRenderer(EntityType entityType, EntityTypeRenderer renderMethod);
static void renderEntityItem(EntityItem* entityItem, RenderArgs* args);
private: private:
static QMap<EntityType, QString> _typeToNameMap; static QMap<EntityType, QString> _typeToNameMap;
static QMap<QString, EntityTypes::EntityType> _nameToTypeMap; static QMap<QString, EntityTypes::EntityType> _nameToTypeMap;
static EntityTypeFactory _factories[LAST]; static EntityTypeFactory _factories[LAST];
static bool _factoriesInitialized; static bool _factoriesInitialized;
static EntityTypeRenderer _renderers[LAST];
static bool _renderersInitialized;
}; };
@ -66,7 +57,13 @@ private:
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \ #define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory); EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory);
#define REGISTER_ENTITY_TYPE_RENDERER(x,y) EntityTypes::registerEntityTypeRenderer(EntityTypes::x, y); /// Macro for registering entity types with an overloaded factory. Like using the REGISTER_ENTITY_TYPE macro: Make sure to add
/// an element to the EntityType enum with your name. But unlike REGISTER_ENTITY_TYPE, your class can be named anything
/// so long as you provide a static method passed to the macro, that takes an EnityItemID, and EntityItemProperties and
/// returns a newly constructed (heap allocated) instance of your type. e.g. The following prototype:
// static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
#define REGISTER_ENTITY_TYPE_WITH_FACTORY(x,y) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, y);
#endif // hifi_EntityTypes_h #endif // hifi_EntityTypes_h

View file

@ -63,11 +63,11 @@ EntityItemProperties ModelEntityItem::getProperties() const {
return properties; return properties;
} }
void ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
//qDebug() << "ModelEntityItem::setProperties()..."; //qDebug() << "ModelEntityItem::setProperties()...";
bool somethingChanged = false; bool somethingChanged = false;
EntityItem::setProperties(properties, forceCopy); // set the properties in our base class somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties._colorChanged || forceCopy) { if (properties._colorChanged || forceCopy) {
setColor(properties._color); setColor(properties._color);
@ -114,6 +114,8 @@ void ModelEntityItem::setProperties(const EntityItemProperties& properties, bool
} }
setLastEdited(properties._lastEdited); setLastEdited(properties._lastEdited);
} }
return somethingChanged;
} }

View file

@ -20,11 +20,11 @@ public:
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void somePureVirtualFunction() { }; // allow this class to be constructed ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity // methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const; virtual EntityItemProperties getProperties() const;
virtual void setProperties(const EntityItemProperties& properties, bool forceCopy = false); virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time // TODO: eventually only include properties changed since the params.lastViewFrustumSent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;

View file

@ -0,0 +1,128 @@
//
// SphereEntityItem.cpp
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QDebug>
#include <ByteCountCoding.h>
#include "EntityTree.h"
#include "EntityTreeElement.h"
#include "SphereEntityItem.h"
EntityItem* SphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
qDebug() << "SphereEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
return new SphereEntityItem(entityID, properties);
}
// our non-pure virtual subclass for now...
SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties)
{
_type = EntityTypes::Sphere;
setProperties(properties);
}
EntityItemProperties SphereEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
properties.setColor(getXColor());
properties.setGlowLevel(getGlowLevel());
return properties;
}
bool SphereEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
if (properties.colorChanged() || forceCopy) {
setColor(properties.getColor());
somethingChanged = true;
}
if (properties.glowLevelChanged() || forceCopy) {
setGlowLevel(properties.getGlowLevel());
somethingChanged = true;
}
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - _lastEdited;
qDebug() << "SphereEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " _lastEdited=" << _lastEdited;
}
setLastEdited(properties.getLastEdited());
}
return somethingChanged;
}
int SphereEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
int bytesRead = 0;
const unsigned char* dataAt = data;
// PROP_COLOR
if (propertyFlags.getHasProperty(PROP_COLOR)) {
rgbColor color;
if (overwriteLocalData) {
memcpy(_color, dataAt, sizeof(_color));
}
dataAt += sizeof(color);
bytesRead += sizeof(color);
}
return bytesRead;
}
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
EntityPropertyFlags SphereEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
return requestedProperties;
}
void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
// PROP_COLOR
if (requestedProperties.getHasProperty(PROP_COLOR)) {
//qDebug() << "PROP_COLOR requested...";
LevelDetails propertyLevel = packetData->startLevel();
successPropertyFits = packetData->appendColor(getColor());
if (successPropertyFits) {
propertyFlags |= PROP_COLOR;
propertiesDidntFit -= PROP_COLOR;
propertyCount++;
packetData->endLevel(propertyLevel);
} else {
//qDebug() << "PROP_COLOR didn't fit...";
packetData->discardLevel(propertyLevel);
appendState = OctreeElement::PARTIAL;
}
} else {
//qDebug() << "PROP_COLOR NOT requested...";
propertiesDidntFit -= PROP_COLOR;
}
}

View file

@ -0,0 +1,57 @@
//
// SphereEntityItem.h
// libraries/entities/src
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_SphereEntityItem_h
#define hifi_SphereEntityItem_h
#include "EntityItem.h"
class SphereEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
protected:
rgbColor _color;
};
#endif // hifi_SphereEntityItem_h

View file

@ -33,6 +33,12 @@ Model properties:
// //
// REQUIRED TO DO: // REQUIRED TO DO:
0) render performance of models...
a) make getModel() faster... consider storing the Model* in the actual EntityItem class
b) figure out how to only call simulate when needed:
if the properties change
when animated?
1) verify lots of models in single element works 1) verify lots of models in single element works
-- repro case - run editModelsExample.js -- create 10 models in the same octree element -- repro case - run editModelsExample.js -- create 10 models in the same octree element
@ -63,7 +69,6 @@ Model properties:
8) Test models -> attachments logic 8) Test models -> attachments logic
9) What happens if the edit properties don't fit in a single message MTU??? 9) What happens if the edit properties don't fit in a single message MTU???
10) animations not always working????? 10) animations not always working?????
11) EntityItemProperties::decodeEntityEditPacket() doesn't include PROP_SCRIPT 11) EntityItemProperties::decodeEntityEditPacket() doesn't include PROP_SCRIPT
@ -79,7 +84,6 @@ Model properties:
P) unit tests? P) unit tests?
Pa) OctreeTests::modelItemTests()...???? Pa) OctreeTests::modelItemTests()...????
G) why does is the Box entity not drawn in it's bounds
H) make the rotated model bounds work for other entity types? H) make the rotated model bounds work for other entity types?
I) maybe make "hasGeometry" be a property of EntityItem base class?? I) maybe make "hasGeometry" be a property of EntityItem base class??
@ -237,3 +241,4 @@ Model properties:
// maybe remember the extra state before removing it and if it fails, always re-add it // maybe remember the extra state before removing it and if it fails, always re-add it
// maybe add support for "reserving" bytes in the packet // maybe add support for "reserving" bytes in the packet
// SOLVED -- BROKEN File persistence... -- added chunking support in SVO file persistence. // SOLVED -- BROKEN File persistence... -- added chunking support in SVO file persistence.
// SOLVED -- G) why does is the Box entity not drawn in it's bounds

View file

@ -236,13 +236,6 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co
int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesLeftToRead, int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesLeftToRead,
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {
bool wantDebug = true;
if (wantDebug) {
qDebug() << "Octree::readElementData()";
qDebug() << " destinationElement->getAACube()=" << destinationElement->getAACube();
qDebug() << " bytesLeftToRead=" << bytesLeftToRead;
}
// give this destination element the child mask from the packet // give this destination element the child mask from the packet
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
unsigned char colorInPacketMask = *nodeData; unsigned char colorInPacketMask = *nodeData;
@ -287,8 +280,6 @@ if (wantDebug) {
int childIndex = 0; int childIndex = 0;
bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask); bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask);
//qDebug() << "Octree::readElementData()... childrenInTreeMask=" << childrenInTreeMask;
while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) { while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
// check the exists mask to see if we have a child to traverse into // check the exists mask to see if we have a child to traverse into
@ -324,33 +315,15 @@ if (wantDebug) {
// if this is the root, and there is more data to read, allow it to read it's element data... // if this is the root, and there is more data to read, allow it to read it's element data...
if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) { if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) {
// tell the element to read the subsequent data // tell the element to read the subsequent data
if (wantDebug) {
qDebug() << "Octree::readElementData().... reading element data for root element.....";
qDebug() << " bytesRead=" << bytesRead;
qDebug() << " bytesLeftToRead - bytesRead=" << bytesLeftToRead - bytesRead;
qDebug() << " READING ROOT DATA....";
}
bytesRead += _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args); bytesRead += _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args);
} }
if (wantDebug) {
qDebug() << "Octree::readElementData()";
qDebug() << " bytesRead=" << bytesLeftToRead;
}
return bytesRead; return bytesRead;
} }
void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes, void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes,
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {
bool wantDebug = true;
if (wantDebug) {
qDebug() << "Octree::readBitstreamToTree()";
qDebug() << " bufferSizeBytes=" << bufferSizeBytes;
}
int bytesRead = 0; int bytesRead = 0;
const unsigned char* bitstreamAt = bitstream; const unsigned char* bitstreamAt = bitstream;
@ -379,31 +352,15 @@ if (wantDebug) {
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt); int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
if (wantDebug) {
qDebug() << "Octree::readBitstreamToTree()";
qDebug() << " octalCodeBytes=" << octalCodeBytes;
}
int theseBytesRead = 0; int theseBytesRead = 0;
theseBytesRead += octalCodeBytes; theseBytesRead += octalCodeBytes;
if (wantDebug) {
qDebug() << " --- calling readElementData() bytes available=" << (bufferSizeBytes - (bytesRead + octalCodeBytes)) << "---";
}
theseBytesRead += readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes, theseBytesRead += readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes,
bufferSizeBytes - (bytesRead + octalCodeBytes), args); bufferSizeBytes - (bytesRead + octalCodeBytes), args);
if (wantDebug) {
qDebug() << " --- AFTER calling readElementData() ---";
qDebug() << " theseBytesRead=" << theseBytesRead;
}
// skip bitstream to new startPoint // skip bitstream to new startPoint
bitstreamAt += theseBytesRead; bitstreamAt += theseBytesRead;
bytesRead += theseBytesRead; bytesRead += theseBytesRead;
if (wantDebug) {
qDebug() << " bytesRead=" << bytesRead;
}
if (args.wantImportProgress) { if (args.wantImportProgress) {
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes); emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
} }
@ -1891,12 +1848,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
unsigned long headerLength = 0; // bytes in the header unsigned long headerLength = 0; // bytes in the header
bool wantDebug = true;
if (wantDebug) {
qDebug() << "Octree::readFromSVOFile()";
qDebug() << " fileLength=" << fileLength;
}
bool wantImportProgress = true; bool wantImportProgress = true;
// before reading the file, check to see if this version of the Octree supports file versions // before reading the file, check to see if this version of the Octree supports file versions
@ -1964,11 +1915,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
SharedNodePointer(), wantImportProgress, gotVersion); SharedNodePointer(), wantImportProgress, gotVersion);
if (wantDebug) {
qDebug() << " --- after reading header, type and version ---";
qDebug() << " dataLength=" << dataLength;
qDebug() << " --- calling readBitstreamToTree() ---";
}
readBitstreamToTree(dataAt, dataLength, args); readBitstreamToTree(dataAt, dataLength, args);
delete[] entireFileDataSection; delete[] entireFileDataSection;
@ -1985,8 +1931,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file
qDebug() << "read chunk size of:" << chunkLength;
remainingLength -= sizeof(chunkLength); remainingLength -= sizeof(chunkLength);
if (chunkLength > remainingLength) { if (chunkLength > remainingLength) {
@ -2011,9 +1955,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
SharedNodePointer(), wantImportProgress, gotVersion); SharedNodePointer(), wantImportProgress, gotVersion);
if (wantDebug) {
qDebug() << " --- calling readBitstreamToTree() dataLength:" << dataLength << "---";
}
readBitstreamToTree(dataAt, dataLength, args); readBitstreamToTree(dataAt, dataLength, args);
} }
@ -2084,7 +2025,6 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
if (hasBufferBreaks) { if (hasBufferBreaks) {
quint16 bufferSize = packetData.getFinalizedSize(); quint16 bufferSize = packetData.getFinalizedSize();
file.write((const char*)&bufferSize, sizeof(bufferSize)); file.write((const char*)&bufferSize, sizeof(bufferSize));
qDebug() << "wrote chunk size of:" << bufferSize << "---";
} }
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
lastPacketWritten = true; lastPacketWritten = true;
@ -2102,7 +2042,6 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
if (hasBufferBreaks) { if (hasBufferBreaks) {
quint16 bufferSize = packetData.getFinalizedSize(); quint16 bufferSize = packetData.getFinalizedSize();
file.write((const char*)&bufferSize, sizeof(bufferSize)); file.write((const char*)&bufferSize, sizeof(bufferSize));
qDebug() << "wrote FINAL chunk size of:" << bufferSize << "---";
} }
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
} }