mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 16:13:28 +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 browser;
|
||||
var newBox;
|
||||
var newSphere;
|
||||
function initToolBar() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
|
||||
// New Model
|
||||
|
@ -1118,6 +1119,14 @@ function initToolBar() {
|
|||
visible: true,
|
||||
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() {
|
||||
|
@ -1261,6 +1270,20 @@ function mousePressEvent(event) {
|
|||
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)) {
|
||||
var url = Window.s3Browse(".*(fbx|FBX)");
|
||||
if (url == null || url == "") {
|
||||
|
|
|
@ -2668,9 +2668,20 @@ void Application::updateShadowMap() {
|
|||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
_entities.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
{
|
||||
PerformanceTimer perfTimer("avatarManager");
|
||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("particles");
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("entities");
|
||||
_entities.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
}
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
|
@ -2867,9 +2878,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// render models...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
|
||||
PerformanceTimer perfTimer("models");
|
||||
PerformanceTimer perfTimer("entities");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... models...");
|
||||
"Application::displaySide() ... entities...");
|
||||
_entities.render();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,17 +15,34 @@
|
|||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <ModelEntityItem.h>
|
||||
#include <BoxEntityItem.h>
|
||||
#include <ModelEntityItem.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
|
||||
#include "Menu.h"
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
#include "RenderableBoxEntityItem.h"
|
||||
#include "RenderableModelEntityItem.h"
|
||||
#include "RenderableSphereEntityItem.h"
|
||||
|
||||
|
||||
QThread* EntityTreeRenderer::getMainThread() {
|
||||
return Application::getInstance()->getEntities()->thread();
|
||||
}
|
||||
|
||||
|
||||
|
||||
EntityTreeRenderer::EntityTreeRenderer() :
|
||||
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() {
|
||||
|
@ -40,6 +57,7 @@ void EntityTreeRenderer::clear() {
|
|||
void EntityTreeRenderer::clearModelsCache() {
|
||||
qDebug() << "EntityTreeRenderer::clearModelsCache()...";
|
||||
|
||||
/*
|
||||
// delete the models in _knownEntityItemModels
|
||||
foreach(Model* model, _knownEntityItemModels) {
|
||||
delete model;
|
||||
|
@ -50,12 +68,15 @@ void EntityTreeRenderer::clearModelsCache() {
|
|||
delete model;
|
||||
}
|
||||
_unknownEntityItemModels.clear();
|
||||
|
||||
foreach(Model* model, _entityItemModels) {
|
||||
delete model;
|
||||
}
|
||||
_entityItemModels.clear();
|
||||
*/
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::init() {
|
||||
//REGISTER_ENTITY_TYPE_RENDERER(Model, this->renderEntityTypeModel);
|
||||
//REGISTER_ENTITY_TYPE_RENDERER(Box, this->renderEntityTypeBox);
|
||||
|
||||
OctreeRenderer::init();
|
||||
static_cast<EntityTree*>(_tree)->setFBXService(this);
|
||||
}
|
||||
|
@ -84,9 +105,10 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
|
|||
const FBXGeometry* result = NULL;
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
const ModelEntityItem* modelEntityItem = static_cast<const ModelEntityItem*>(entityItem);
|
||||
|
||||
Model* model = getModel(modelEntityItem);
|
||||
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
|
||||
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
||||
assert(modelEntityItem); // we need this!!!
|
||||
Model* model = modelEntityItem->getModel();
|
||||
if (model) {
|
||||
result = &model->getGeometry()->getFBXGeometry();
|
||||
}
|
||||
|
@ -97,73 +119,17 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
|
|||
const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityItem) {
|
||||
const Model* result = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
//PerformanceTimer perfTimer("renderElement");
|
||||
args->_elementsTouched++;
|
||||
// actually render it here...
|
||||
// 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) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
}
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
renderEntityTypeModel(entityItem, args);
|
||||
} else if (entityItem->getType() == EntityTypes::Box) {
|
||||
renderEntityTypeBox(entityItem, args);
|
||||
}
|
||||
|
||||
entityItem->render(args);
|
||||
if (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 {
|
||||
return Menu::getInstance()->getVoxelSizeScale();
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
#include "renderer/Model.h"
|
||||
|
||||
class ModelEntityItem;
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService {
|
||||
Q_OBJECT
|
||||
|
@ -58,16 +56,19 @@ public:
|
|||
/// clears the tree
|
||||
virtual void clear();
|
||||
|
||||
Q_INVOKABLE Model* getModel(const ModelEntityItem* modelEntityItem);
|
||||
//Q_INVOKABLE Model* getModel(const ModelEntityItem* modelEntityItem);
|
||||
|
||||
// renderers for various types of entities
|
||||
void renderEntityTypeBox(EntityItem* entity, RenderArgs* args);
|
||||
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
|
||||
|
||||
static QThread* getMainThread();
|
||||
|
||||
protected:
|
||||
void clearModelsCache();
|
||||
QMap<QUuid, Model*> _knownEntityItemModels;
|
||||
QMap<uint32_t, Model*> _unknownEntityItemModels;
|
||||
//QMap<QUuid, Model*> _knownEntityItemModels;
|
||||
//QMap<uint32_t, Model*> _unknownEntityItemModels;
|
||||
//QMap<const ModelEntityItem*, Model*> _entityItemModels;
|
||||
};
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
const int BALL_SUBDIVISIONS = 10;
|
||||
|
||||
void Model::renderJointCollisionShapes(float alpha) {
|
||||
// implement this when we have shapes for regular models
|
||||
}
|
||||
|
|
|
@ -56,12 +56,12 @@ EntityItemProperties BoxEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
void BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
qDebug() << "BoxEntityItem::setProperties()...";
|
||||
qDebug() << "BoxEntityItem::BoxEntityItem() properties.getModelURL()=" << properties.getModelURL();
|
||||
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) {
|
||||
setColor(properties._color);
|
||||
|
@ -83,6 +83,7 @@ void BoxEntityItem::setProperties(const EntityItemProperties& properties, bool f
|
|||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
}
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
int BoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
|
|
|
@ -19,12 +19,12 @@ public:
|
|||
static EntityItem* factory(const EntityItemID& entityID, 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
|
||||
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
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
|
|
@ -421,7 +421,7 @@ int EntityItem::expectedBytes() {
|
|||
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
somethingChangedNotification(); // notify derived classes that something has changed
|
||||
|
||||
}
|
||||
|
||||
// last updated is stored as ByteCountCoded delta from lastEdited
|
||||
|
@ -828,7 +831,7 @@ EntityItemProperties EntityItem::getProperties() const {
|
|||
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() properties.getDamping()=" << properties.getDamping();
|
||||
//qDebug() << "EntityItem::setProperties() properties.getVelocity()=" << properties.getVelocity();
|
||||
|
@ -886,6 +889,7 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc
|
|||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
somethingChangedNotification(); // notify derived classes that something has changed
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
|
@ -895,6 +899,7 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc
|
|||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
}
|
||||
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,15 +27,21 @@
|
|||
|
||||
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 {
|
||||
|
||||
public:
|
||||
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
|
||||
|
||||
EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
|
||||
virtual ~EntityItem();
|
||||
|
||||
virtual void somePureVirtualFunction() = 0;
|
||||
|
||||
// ID and EntityItemID related methods
|
||||
QUuid getID() const { return _id; }
|
||||
|
@ -48,7 +54,13 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
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 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,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
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();
|
||||
|
||||
|
@ -164,7 +178,7 @@ public:
|
|||
static const QString DEFAULT_SCRIPT;
|
||||
const QString& getScript() const { return _script; }
|
||||
void setScript(const QString& value) { _script = value; }
|
||||
|
||||
|
||||
protected:
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
||||
|
@ -188,52 +202,4 @@ protected:
|
|||
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
|
||||
|
|
|
@ -180,6 +180,23 @@ public:
|
|||
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||
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:
|
||||
void setLastEdited(quint64 lastEdited) { _lastEdited = lastEdited; }
|
||||
|
||||
|
|
|
@ -20,23 +20,19 @@
|
|||
|
||||
#include "BoxEntityItem.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "SphereEntityItem.h"
|
||||
|
||||
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
||||
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
||||
EntityTypeFactory EntityTypes::_factories[EntityTypes::LAST];
|
||||
bool EntityTypes::_factoriesInitialized = false;
|
||||
EntityTypeRenderer EntityTypes::_renderers[EntityTypes::LAST];
|
||||
bool EntityTypes::_renderersInitialized = false;
|
||||
|
||||
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(Box)
|
||||
REGISTER_ENTITY_TYPE(Sphere)
|
||||
REGISTER_ENTITY_TYPE(Plane)
|
||||
REGISTER_ENTITY_TYPE(Cylinder)
|
||||
REGISTER_ENTITY_TYPE(Pyramid)
|
||||
|
||||
|
||||
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
||||
|
@ -153,24 +149,3 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte
|
|||
|
||||
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;
|
||||
|
||||
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
typedef void (*EntityTypeRenderer)(EntityItem* entity, RenderArgs* args);
|
||||
|
||||
class EntityTypes {
|
||||
public:
|
||||
|
@ -34,10 +33,7 @@ public:
|
|||
Model,
|
||||
Box,
|
||||
Sphere,
|
||||
Plane,
|
||||
Cylinder,
|
||||
Pyramid,
|
||||
LAST = Pyramid
|
||||
LAST = Sphere
|
||||
} 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(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args);
|
||||
|
||||
static bool registerEntityTypeRenderer(EntityType entityType, EntityTypeRenderer renderMethod);
|
||||
static void renderEntityItem(EntityItem* entityItem, RenderArgs* args);
|
||||
|
||||
private:
|
||||
static QMap<EntityType, QString> _typeToNameMap;
|
||||
static QMap<QString, EntityTypes::EntityType> _nameToTypeMap;
|
||||
static EntityTypeFactory _factories[LAST];
|
||||
static bool _factoriesInitialized;
|
||||
static EntityTypeRenderer _renderers[LAST];
|
||||
static bool _renderersInitialized;
|
||||
};
|
||||
|
||||
|
||||
|
@ -66,7 +57,13 @@ private:
|
|||
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \
|
||||
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
|
||||
|
|
|
@ -63,11 +63,11 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
void ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
//qDebug() << "ModelEntityItem::setProperties()...";
|
||||
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) {
|
||||
setColor(properties._color);
|
||||
|
@ -114,6 +114,8 @@ void ModelEntityItem::setProperties(const EntityItemProperties& properties, bool
|
|||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
}
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@ public:
|
|||
|
||||
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
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
-- repro case - run editModelsExample.js -- create 10 models in the same octree element
|
||||
|
||||
|
@ -62,7 +68,6 @@ Model properties:
|
|||
7) Handle the ID -> UUID swap in old files to new files
|
||||
|
||||
8) Test models -> attachments logic
|
||||
|
||||
|
||||
9) What happens if the edit properties don't fit in a single message MTU???
|
||||
10) animations not always working?????
|
||||
|
@ -79,7 +84,6 @@ Model properties:
|
|||
P) unit tests?
|
||||
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?
|
||||
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 add support for "reserving" bytes in the packet
|
||||
// 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,
|
||||
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
|
||||
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
|
||||
unsigned char colorInPacketMask = *nodeData;
|
||||
|
@ -287,8 +280,6 @@ if (wantDebug) {
|
|||
int childIndex = 0;
|
||||
bytesRead += args.includeExistsBits ? sizeof(childrenInTreeMask) + sizeof(childMask) : sizeof(childMask);
|
||||
|
||||
//qDebug() << "Octree::readElementData()... childrenInTreeMask=" << childrenInTreeMask;
|
||||
|
||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
|
||||
// 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 (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "Octree::readElementData()";
|
||||
qDebug() << " bytesRead=" << bytesLeftToRead;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes,
|
||||
ReadBitstreamToTreeParams& args) {
|
||||
|
||||
bool wantDebug = true;
|
||||
if (wantDebug) {
|
||||
qDebug() << "Octree::readBitstreamToTree()";
|
||||
qDebug() << " bufferSizeBytes=" << bufferSizeBytes;
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
const unsigned char* bitstreamAt = bitstream;
|
||||
|
||||
|
@ -379,31 +352,15 @@ if (wantDebug) {
|
|||
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "Octree::readBitstreamToTree()";
|
||||
qDebug() << " octalCodeBytes=" << octalCodeBytes;
|
||||
}
|
||||
|
||||
int theseBytesRead = 0;
|
||||
theseBytesRead += octalCodeBytes;
|
||||
if (wantDebug) {
|
||||
qDebug() << " --- calling readElementData() bytes available=" << (bufferSizeBytes - (bytesRead + octalCodeBytes)) << "---";
|
||||
}
|
||||
theseBytesRead += readElementData(bitstreamRootElement, bitstreamAt + octalCodeBytes,
|
||||
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
||||
if (wantDebug) {
|
||||
qDebug() << " --- AFTER calling readElementData() ---";
|
||||
qDebug() << " theseBytesRead=" << theseBytesRead;
|
||||
}
|
||||
|
||||
// skip bitstream to new startPoint
|
||||
bitstreamAt += theseBytesRead;
|
||||
bytesRead += theseBytesRead;
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " bytesRead=" << bytesRead;
|
||||
}
|
||||
|
||||
if (args.wantImportProgress) {
|
||||
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
|
||||
}
|
||||
|
@ -1891,12 +1848,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
|||
|
||||
unsigned long headerLength = 0; // bytes in the header
|
||||
|
||||
bool wantDebug = true;
|
||||
if (wantDebug) {
|
||||
qDebug() << "Octree::readFromSVOFile()";
|
||||
qDebug() << " fileLength=" << fileLength;
|
||||
}
|
||||
|
||||
bool wantImportProgress = true;
|
||||
|
||||
// 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,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " --- after reading header, type and version ---";
|
||||
qDebug() << " dataLength=" << dataLength;
|
||||
qDebug() << " --- calling readBitstreamToTree() ---";
|
||||
}
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
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
|
||||
|
||||
qDebug() << "read chunk size of:" << chunkLength;
|
||||
|
||||
remainingLength -= sizeof(chunkLength);
|
||||
|
||||
if (chunkLength > remainingLength) {
|
||||
|
@ -2011,9 +1955,6 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
|||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " --- calling readBitstreamToTree() dataLength:" << dataLength << "---";
|
||||
}
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
}
|
||||
|
||||
|
@ -2084,7 +2025,6 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
|
|||
if (hasBufferBreaks) {
|
||||
quint16 bufferSize = packetData.getFinalizedSize();
|
||||
file.write((const char*)&bufferSize, sizeof(bufferSize));
|
||||
qDebug() << "wrote chunk size of:" << bufferSize << "---";
|
||||
}
|
||||
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
|
||||
lastPacketWritten = true;
|
||||
|
@ -2102,7 +2042,6 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) {
|
|||
if (hasBufferBreaks) {
|
||||
quint16 bufferSize = packetData.getFinalizedSize();
|
||||
file.write((const char*)&bufferSize, sizeof(bufferSize));
|
||||
qDebug() << "wrote FINAL chunk size of:" << bufferSize << "---";
|
||||
}
|
||||
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue