mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 11:48:09 +02:00
split out entity rendering into subclasses, improved rendering of models
This commit is contained in:
parent
ddae85ce4a
commit
ef86d86234
24 changed files with 886 additions and 466 deletions
|
@ -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 == "") {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
119
interface/src/entities/RenderableBoxEntityItem.cpp
Normal file
119
interface/src/entities/RenderableBoxEntityItem.cpp
Normal 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);
|
||||||
|
|
||||||
|
};
|
40
interface/src/entities/RenderableBoxEntityItem.h
Normal file
40
interface/src/entities/RenderableBoxEntityItem.h
Normal 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
|
241
interface/src/entities/RenderableModelEntityItem.cpp
Normal file
241
interface/src/entities/RenderableModelEntityItem.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
56
interface/src/entities/RenderableModelEntityItem.h
Normal file
56
interface/src/entities/RenderableModelEntityItem.h
Normal 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
|
50
interface/src/entities/RenderableSphereEntityItem.cpp
Normal file
50
interface/src/entities/RenderableSphereEntityItem.cpp
Normal 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();
|
||||||
|
};
|
40
interface/src/entities/RenderableSphereEntityItem.h
Normal file
40
interface/src/entities/RenderableSphereEntityItem.h
Normal 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
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
128
libraries/entities/src/SphereEntityItem.cpp
Normal file
128
libraries/entities/src/SphereEntityItem.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
57
libraries/entities/src/SphereEntityItem.h
Normal file
57
libraries/entities/src/SphereEntityItem.h
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue