Interview project updates.

Tried to address all of Brad's notes, most of which were related to
matching the coding style for the project.  Also used GeometryCache
instead of making direct calls to OpenGL to do drawing, took a different
approach to seeding rand(), updated the packet version, and fixed a bug
that I noticed in the setting of the dimensions for the particle effect
entity.
This commit is contained in:
Jason 2015-03-06 15:52:21 -08:00
parent 3522357c8c
commit 7a5669f14e
8 changed files with 581 additions and 585 deletions

View file

@ -15,11 +15,17 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include <DeferredLightingEffect.h> #include <DeferredLightingEffect.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <GeometryCache.h>
#include "RenderableParticleEffectEntityItem.h" #include "RenderableParticleEffectEntityItem.h"
EntityItem* RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableParticleEffectEntityItem(entityID, properties); return new RenderableParticleEffectEntityItem(entityID, properties);
}
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties) {
_cacheID = DependencyManager::get<GeometryCache>()->allocateID();
} }
void RenderableParticleEffectEntityItem::render(RenderArgs* args) { void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
@ -28,11 +34,45 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
glm::vec3 position = getPositionInMeters(); glm::vec3 position = getPositionInMeters();
glm::vec3 center = getCenterInMeters(); glm::vec3 center = getCenterInMeters();
glm::quat rotation = getRotation(); glm::quat rotation = getRotation();
float pa_rad = getParticleRadius(); float pa_rad = getParticleRadius();
const float MAX_COLOR = 255.0f; const float MAX_COLOR = 255.0f;
glm::vec4 sphereColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR, glm::vec4 paColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha()); getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
// Right now we're just iterating over particles and rendering as a cross of four quads.
// This is pretty dumb, it was quick enough to code up. Really, there should be many
// rendering modes, including the all-important textured billboards.
QVector<glm::vec3>* pointVec = new QVector<glm::vec3>(_paCount * VERTS_PER_PARTICLE);
quint32 paIter = _paHead;
while (_paLife[paIter] > 0.0f) {
int j = paIter * XYZ_STRIDE;
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
paIter = (paIter + 1) % _maxParticles;
}
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, *pointVec, paColor);
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
@ -44,45 +84,9 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
glm::vec3 positionToCenter = center - position; glm::vec3 positionToCenter = center - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
const int SLICES = 8; DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
const int STACKS = 5;
glBegin(GL_QUADS);
glColor4f(sphereColor.r, sphereColor.g, sphereColor.b, sphereColor.a);
// Right now we're just iterating over particles and rendering as a cross of four quads.
// This is pretty dumb, it was quick enough to code up. Really, there should be many
// rendering modes, including the all-important textured billboards.
quint32 paiter = pa_head;
while (pa_life[paiter] > 0.0f)
{
int j = paiter * 3;
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] + pa_rad);
paiter = (paiter + 1) % _maxParticles;
}
glEnd();
glPopMatrix(); glPopMatrix();
glPopMatrix(); glPopMatrix();
delete pointVec;
}; };

View file

@ -16,13 +16,12 @@
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
public: public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties)
{ }
virtual void render(RenderArgs* args); virtual void render(RenderArgs* args);
protected:
int _cacheID;
const int VERTS_PER_PARTICLE = 16;
}; };

View file

@ -67,13 +67,13 @@ EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR), CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR), CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR),
CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE), CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE),
CONSTRUCT_PROPERTY(maxParticles, ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES), CONSTRUCT_PROPERTY(maxParticles, ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES),
CONSTRUCT_PROPERTY(lifespan, ParticleEffectEntityItem::DEFAULT_LIFESPAN), CONSTRUCT_PROPERTY(lifespan, ParticleEffectEntityItem::DEFAULT_LIFESPAN),
CONSTRUCT_PROPERTY(emitRate, ParticleEffectEntityItem::DEFAULT_EMIT_RATE), CONSTRUCT_PROPERTY(emitRate, ParticleEffectEntityItem::DEFAULT_EMIT_RATE),
CONSTRUCT_PROPERTY(emitDirection, ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION), CONSTRUCT_PROPERTY(emitDirection, ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION),
CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH), CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH),
CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY), CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY),
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
_id(UNKNOWN_ENTITY_ID), _id(UNKNOWN_ENTITY_ID),
_idSet(false), _idSet(false),
@ -246,13 +246,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor); CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor); CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor);
CHECK_PROPERTY_CHANGE(PROP_SHAPE_TYPE, shapeType); CHECK_PROPERTY_CHANGE(PROP_SHAPE_TYPE, shapeType);
CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles); CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles);
CHECK_PROPERTY_CHANGE(PROP_LIFESPAN, lifespan); CHECK_PROPERTY_CHANGE(PROP_LIFESPAN, lifespan);
CHECK_PROPERTY_CHANGE(PROP_EMIT_RATE, emitRate); CHECK_PROPERTY_CHANGE(PROP_EMIT_RATE, emitRate);
CHECK_PROPERTY_CHANGE(PROP_EMIT_DIRECTION, emitDirection); CHECK_PROPERTY_CHANGE(PROP_EMIT_DIRECTION, emitDirection);
CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength); CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity); CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity);
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
return changedProperties; return changedProperties;
} }
@ -312,13 +312,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(textColor, getTextColor()); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(textColor, getTextColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(backgroundColor, getBackgroundColor()); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(backgroundColor, getBackgroundColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles); COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan); COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate); COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(emitDirection); COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(emitDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength); COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength);
COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity); COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
// Sitting properties support // Sitting properties support
QScriptValue sittingPoints = engine->newObject(); QScriptValue sittingPoints = engine->newObject();
@ -397,13 +397,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(textColor, setTextColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(textColor, setTextColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(backgroundColor, setBackgroundColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(backgroundColor, setBackgroundColor);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType); COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(maxParticles, setMaxParticles); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(maxParticles, setMaxParticles);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifespan, setLifespan); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifespan, setLifespan);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitRate, setEmitRate); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitRate, setEmitRate);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(emitDirection, setEmitDirection); COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(emitDirection, setEmitDirection);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius);
_lastEdited = usecTimestampNow(); _lastEdited = usecTimestampNow();
} }
@ -582,15 +582,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff()); APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff());
} }
if (properties.getType() == EntityTypes::ParticleEffect) { if (properties.getType() == EntityTypes::ParticleEffect) {
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, properties.getMaxParticles()); APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, properties.getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, properties.getLifespan()); APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, properties.getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, properties.getEmitRate()); APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, properties.getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, properties.getEmitDirection()); APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, properties.getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, properties.getEmitStrength()); APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, properties.getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity()); APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius());
} }
} }
if (propertyCount > 0) { if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset(); int endOfEntityItemData = packetData->getUncompressedByteOffset();
@ -814,15 +814,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
} }
if (properties.getType() == EntityTypes::ParticleEffect) { if (properties.getType() == EntityTypes::ParticleEffect) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_STRENGTH, float, setEmitStrength); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_STRENGTH, float, setEmitStrength);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
} }
return valid; return valid;
} }
@ -901,13 +901,13 @@ void EntityItemProperties::markAllChanged() {
_backgroundColorChanged = true; _backgroundColorChanged = true;
_shapeTypeChanged = true; _shapeTypeChanged = true;
_maxParticlesChanged = true; _maxParticlesChanged = true;
_lifespanChanged = true; _lifespanChanged = true;
_emitRateChanged = true; _emitRateChanged = true;
_emitDirectionChanged = true; _emitDirectionChanged = true;
_emitStrengthChanged = true; _emitStrengthChanged = true;
_localGravityChanged = true; _localGravityChanged = true;
_particleRadiusChanged = true; _particleRadiusChanged = true;
} }
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const { AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {

View file

@ -84,14 +84,14 @@ enum EntityPropertyList {
PROP_USER_DATA, PROP_USER_DATA,
PROP_SHAPE_TYPE, PROP_SHAPE_TYPE,
// used by ParticleEffect entities // used by ParticleEffect entities
PROP_MAX_PARTICLES, PROP_MAX_PARTICLES,
PROP_LIFESPAN, PROP_LIFESPAN,
PROP_EMIT_RATE, PROP_EMIT_RATE,
PROP_EMIT_DIRECTION, PROP_EMIT_DIRECTION,
PROP_EMIT_STRENGTH, PROP_EMIT_STRENGTH,
PROP_LOCAL_GRAVITY, PROP_LOCAL_GRAVITY,
PROP_PARTICLE_RADIUS, PROP_PARTICLE_RADIUS,
// NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below // NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below
PROP_LAST_ITEM = PROP_PARTICLE_RADIUS, PROP_LAST_ITEM = PROP_PARTICLE_RADIUS,
@ -119,7 +119,7 @@ class EntityItemProperties {
friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods
public: public:
EntityItemProperties(); EntityItemProperties();
virtual ~EntityItemProperties(); virtual ~EntityItemProperties();
@ -192,13 +192,13 @@ public:
DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor); DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor);
DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor); DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor);
DEFINE_PROPERTY_REF_ENUM(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); DEFINE_PROPERTY_REF_ENUM(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType);
DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32); DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32);
DEFINE_PROPERTY(PROP_LIFESPAN, Lifespan, lifespan, float); DEFINE_PROPERTY(PROP_LIFESPAN, Lifespan, lifespan, float);
DEFINE_PROPERTY(PROP_EMIT_RATE, EmitRate, emitRate, float); DEFINE_PROPERTY(PROP_EMIT_RATE, EmitRate, emitRate, float);
DEFINE_PROPERTY_REF(PROP_EMIT_DIRECTION, EmitDirection, emitDirection, glm::vec3); DEFINE_PROPERTY_REF(PROP_EMIT_DIRECTION, EmitDirection, emitDirection, glm::vec3);
DEFINE_PROPERTY(PROP_EMIT_STRENGTH, EmitStrength, emitStrength, float); DEFINE_PROPERTY(PROP_EMIT_STRENGTH, EmitStrength, emitStrength, float);
DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float); DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float);
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
public: public:
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
@ -321,13 +321,13 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, TextColor, textColor, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, TextColor, textColor, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundColor, backgroundColor, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundColor, backgroundColor, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ShapeType, shapeType, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ShapeType, shapeType, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MaxParticles, maxParticles, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, MaxParticles, maxParticles, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifespan, lifespan, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifespan, lifespan, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitRate, emitRate, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitRate, emitRate, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitDirection, emitDirection, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitDirection, emitDirection, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
debug << " last edited:" << properties.getLastEdited() << "\n"; debug << " last edited:" << properties.getLastEdited() << "\n";
debug << " edited ago:" << properties.getEditedAgo() << "\n"; debug << " edited ago:" << properties.getEditedAgo() << "\n";

View file

@ -57,466 +57,456 @@ const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new ParticleEffectEntityItem(entityID, properties); return new ParticleEffectEntityItem(entityID, properties);
} }
// our non-pure virtual subclass for now... // our non-pure virtual subclass for now...
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) EntityItem(entityItemID, properties) {
{ _type = EntityTypes::ParticleEffect;
_type = EntityTypes::ParticleEffect; _maxParticles = DEFAULT_MAX_PARTICLES;
_maxParticles = DEFAULT_MAX_PARTICLES; _lifespan = DEFAULT_LIFESPAN;
_lifespan = DEFAULT_LIFESPAN; _emitRate = DEFAULT_EMIT_RATE;
_emitRate = DEFAULT_EMIT_RATE; _emitDirection = DEFAULT_EMIT_DIRECTION;
_emitDirection = DEFAULT_EMIT_DIRECTION; _emitStrength = DEFAULT_EMIT_STRENGTH;
_emitStrength = DEFAULT_EMIT_STRENGTH; _localGravity = DEFAULT_LOCAL_GRAVITY;
_localGravity = DEFAULT_LOCAL_GRAVITY; _particleRadius = DEFAULT_PARTICLE_RADIUS;
_particleRadius = DEFAULT_PARTICLE_RADIUS; setProperties(properties);
setProperties(properties); // this is a pretty dumb thing to do, and it should probably be changed to use a more dynamic
// this is a pretty dumb thing to do, and it should probably be changed to use a more dynamic // data structure in the future. I'm just trying to get some code out the door for now (and it's
// data structure in the future. I'm just trying to get some code out the door for now (and it's // at least time efficient (though not space efficient).
// at least time efficient (though not space efficient). // Also, this being a real-time application, it's doubtful we'll ever have millions of particles
// Also, this being a real-time application, it's doubtful we'll ever have millions of particles // to keep track of, so this really isn't all that bad.
// to keep track of, so this really isn't all that bad. _paLife = new float[_maxParticles];
pa_life = (float*) malloc(sizeof(float) * _maxParticles); _paPosition = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
pa_position = (float*)malloc(sizeof(float) * _maxParticles * 3); // x,y,z _paVelocity = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
pa_velocity = (float*)malloc(sizeof(float) * _maxParticles * 3); // x,y,z _paXmax = _paYmax = _paZmax = 1.0f;
pa_xmax = pa_ymax = pa_zmax = 1.0f; _paXmin = _paYmin = _paZmin = -1.0f;
pa_xmin = pa_ymin = pa_zmin = -1.0f; _randSeed = (unsigned int) glm::abs(_lifespan + _emitRate + _localGravity + getPosition().x + getPosition().y + getPosition().z);
resetSim(); resetSimulation();
_lastAnimated = usecTimestampNow(); _lastAnimated = usecTimestampNow();
} }
ParticleEffectEntityItem::~ParticleEffectEntityItem() ParticleEffectEntityItem::~ParticleEffectEntityItem() {
{ delete [] _paLife;
free(pa_life); delete [] _paPosition;
free(pa_position); delete [] _paVelocity;
free(pa_velocity);
} }
EntityItemProperties ParticleEffectEntityItem::getProperties() const { EntityItemProperties ParticleEffectEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationSettings, getAnimationSettings); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationSettings, getAnimationSettings);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles); COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitDirection, getEmitDirection); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitDirection, getEmitDirection);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitStrength, getEmitStrength); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitStrength, getEmitStrength);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localGravity, getLocalGravity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(localGravity, getLocalGravity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius); COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
return properties; return properties;
} }
bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& properties) { bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationSettings, setAnimationSettings); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationSettings, setAnimationSettings);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles); SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitDirection, setEmitDirection); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitDirection, setEmitDirection);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitStrength, setEmitStrength); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitStrength, setEmitStrength);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localGravity, setLocalGravity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localGravity, setLocalGravity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius); SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
if (somethingChanged) { if (somethingChanged) {
bool wantDebug = false; bool wantDebug = false;
if (wantDebug) { if (wantDebug) {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
int elapsed = now - getLastEdited(); int elapsed = now - getLastEdited();
qDebug() << "ParticleEffectEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << qDebug() << "ParticleEffectEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " getLastEdited()=" << getLastEdited(); "now=" << now << " getLastEdited()=" << getLastEdited();
} }
setLastEdited(properties.getLastEdited()); setLastEdited(properties.getLastEdited());
} }
return somethingChanged; return somethingChanged;
} }
int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args, ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
int bytesRead = 0; int bytesRead = 0;
const unsigned char* dataAt = data; const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
// Because we're using AnimationLoop which will reset the frame index if you change it's running state // Because we're using AnimationLoop which will reset the frame index if you change it's running state
// we want to read these values in the order they appear in the buffer, but call our setters in an // we want to read these values in the order they appear in the buffer, but call our setters in an
// order that allows AnimationLoop to preserve the correct frame rate. // order that allows AnimationLoop to preserve the correct frame rate.
float animationFPS = getAnimationFPS(); float animationFPS = getAnimationFPS();
float animationFrameIndex = getAnimationFrameIndex(); float animationFrameIndex = getAnimationFrameIndex();
bool animationIsPlaying = getAnimationIsPlaying(); bool animationIsPlaying = getAnimationIsPlaying();
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying);
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) { if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
if (animationIsPlaying != getAnimationIsPlaying()) { if (animationIsPlaying != getAnimationIsPlaying()) {
setAnimationIsPlaying(animationIsPlaying); setAnimationIsPlaying(animationIsPlaying);
} }
} }
if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) { if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) {
setAnimationFPS(animationFPS); setAnimationFPS(animationFPS);
} }
if (propertyFlags.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) { if (propertyFlags.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) {
setAnimationFrameIndex(animationFrameIndex); setAnimationFrameIndex(animationFrameIndex);
} }
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings); READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings);
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType); READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, _maxParticles); READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, _maxParticles);
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, _lifespan); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, _lifespan);
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, _emitRate); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, _emitRate);
READ_ENTITY_PROPERTY_SETTER(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection); READ_ENTITY_PROPERTY_SETTER(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection);
READ_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, float, _emitStrength); READ_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, float, _emitStrength);
READ_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, float, _localGravity); READ_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, float, _localGravity);
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, _particleRadius); READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, _particleRadius);
return bytesRead; return bytesRead;
} }
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time // TODO: eventually only include properties changed since the params.lastViewFrustumSent time
EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR; requestedProperties += PROP_COLOR;
requestedProperties += PROP_ANIMATION_FPS; requestedProperties += PROP_ANIMATION_FPS;
requestedProperties += PROP_ANIMATION_FRAME_INDEX; requestedProperties += PROP_ANIMATION_FRAME_INDEX;
requestedProperties += PROP_ANIMATION_PLAYING; requestedProperties += PROP_ANIMATION_PLAYING;
requestedProperties += PROP_ANIMATION_SETTINGS; requestedProperties += PROP_ANIMATION_SETTINGS;
requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_SHAPE_TYPE;
requestedProperties += PROP_MAX_PARTICLES; requestedProperties += PROP_MAX_PARTICLES;
requestedProperties += PROP_LIFESPAN; requestedProperties += PROP_LIFESPAN;
requestedProperties += PROP_EMIT_RATE; requestedProperties += PROP_EMIT_RATE;
requestedProperties += PROP_EMIT_DIRECTION; requestedProperties += PROP_EMIT_DIRECTION;
requestedProperties += PROP_EMIT_STRENGTH; requestedProperties += PROP_EMIT_STRENGTH;
requestedProperties += PROP_LOCAL_GRAVITY; requestedProperties += PROP_LOCAL_GRAVITY;
requestedProperties += PROP_PARTICLE_RADIUS; requestedProperties += PROP_PARTICLE_RADIUS;
return requestedProperties; return requestedProperties;
} }
void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties, EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit, EntityPropertyFlags& propertiesDidntFit,
int& propertyCount, int& propertyCount,
OctreeElement::AppendState& appendState) const { OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true; bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, getMaxParticles()); APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, getLifespan()); APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, getEmitRate()); APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, getEmitDirection()); APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, getEmitStrength()); APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, getLocalGravity()); APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius());
} }
bool ParticleEffectEntityItem::isAnimatingSomething() const { bool ParticleEffectEntityItem::isAnimatingSomething() const {
return getAnimationIsPlaying() && return getAnimationIsPlaying() &&
getAnimationFPS() != 0.0f; getAnimationFPS() != 0.0f;
} }
bool ParticleEffectEntityItem::needsToCallUpdate() const { bool ParticleEffectEntityItem::needsToCallUpdate() const {
return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate(); return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate();
} }
void ParticleEffectEntityItem::update(const quint64& now) { void ParticleEffectEntityItem::update(const quint64& now) {
// only advance the frame index if we're playing // only advance the frame index if we're playing
if (getAnimationIsPlaying()) { if (getAnimationIsPlaying()) {
float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND; float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND;
_lastAnimated = now; _lastAnimated = now;
float lastFrame = _animationLoop.getFrameIndex(); float lastFrame = _animationLoop.getFrameIndex();
_animationLoop.simulate(deltaTime); _animationLoop.simulate(deltaTime);
float curFrame = _animationLoop.getFrameIndex(); float curFrame = _animationLoop.getFrameIndex();
if (curFrame > lastFrame) if (curFrame > lastFrame) {
{ stepSimulation(deltaTime);
stepSim(deltaTime); }
} else if (curFrame < lastFrame) {
else if (curFrame < lastFrame) // we looped around, so restart the sim and only sim up to the point
{ // since the beginning of the frame range.
// we looped around, so restart the sim and only sim up to the point resetSimulation();
// since the beginning of the frame range. stepSimulation((curFrame - _animationLoop.getFirstFrame()) / _animationLoop.getFPS());
resetSim(); }
stepSim((curFrame - _animationLoop.getFirstFrame()) / _animationLoop.getFPS()); }
} else {
} _lastAnimated = now;
else { }
_lastAnimated = now;
}
// update the dimensions // update the dimensions
glm::vec3 dims; glm::vec3 dims;
dims.x = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax)); dims.x = glm::max(glm::abs(_paXmin), glm::abs(_paXmax)) * 2.0;
dims.y = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax)); dims.y = glm::max(glm::abs(_paYmin), glm::abs(_paYmax)) * 2.0;
dims.z = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax)); dims.z = glm::max(glm::abs(_paZmin), glm::abs(_paZmax)) * 2.0;
setDimensionsInMeters(dims); setDimensionsInMeters(dims);
EntityItem::update(now); // let our base class handle it's updates... EntityItem::update(now); // let our base class handle it's updates...
} }
void ParticleEffectEntityItem::debugDump() const { void ParticleEffectEntityItem::debugDump() const {
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
qDebug() << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qDebug() << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qDebug() << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qDebug() << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
qDebug() << " position:" << debugTreeVector(_position); qDebug() << " position:" << debugTreeVector(_position);
qDebug() << " dimensions:" << debugTreeVector(_dimensions); qDebug() << " dimensions:" << debugTreeVector(_dimensions);
qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now);
} }
void ParticleEffectEntityItem::updateShapeType(ShapeType type) { void ParticleEffectEntityItem::updateShapeType(ShapeType type) {
if (type != _shapeType) { if (type != _shapeType) {
_shapeType = type; _shapeType = type;
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
} }
} }
void ParticleEffectEntityItem::setAnimationFrameIndex(float value) { void ParticleEffectEntityItem::setAnimationFrameIndex(float value) {
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
if (isAnimatingSomething()) { if (isAnimatingSomething()) {
qDebug() << "ParticleEffectEntityItem::setAnimationFrameIndex()"; qDebug() << "ParticleEffectEntityItem::setAnimationFrameIndex()";
qDebug() << " value:" << value; qDebug() << " value:" << value;
qDebug() << " was:" << _animationLoop.getFrameIndex(); qDebug() << " was:" << _animationLoop.getFrameIndex();
} }
#endif #endif
_animationLoop.setFrameIndex(value); _animationLoop.setFrameIndex(value);
} }
void ParticleEffectEntityItem::setAnimationSettings(const QString& value) { void ParticleEffectEntityItem::setAnimationSettings(const QString& value) {
// the animations setting is a JSON string that may contain various animation settings. // the animations setting is a JSON string that may contain various animation settings.
// if it includes fps, frameIndex, or running, those values will be parsed out and // if it includes fps, frameIndex, or running, those values will be parsed out and
// will over ride the regular animation settings // will over ride the regular animation settings
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object(); QJsonObject settingsAsJsonObject = settingsAsJson.object();
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
if (settingsMap.contains("fps")) { if (settingsMap.contains("fps")) {
float fps = settingsMap["fps"].toFloat(); float fps = settingsMap["fps"].toFloat();
setAnimationFPS(fps); setAnimationFPS(fps);
} }
if (settingsMap.contains("frameIndex")) { if (settingsMap.contains("frameIndex")) {
float frameIndex = settingsMap["frameIndex"].toFloat(); float frameIndex = settingsMap["frameIndex"].toFloat();
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
if (isAnimatingSomething()) { if (isAnimatingSomething()) {
qDebug() << "ParticleEffectEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; qDebug() << "ParticleEffectEntityItem::setAnimationSettings() calling setAnimationFrameIndex()...";
qDebug() << " settings:" << value; qDebug() << " settings:" << value;
qDebug() << " settingsMap[frameIndex]:" << settingsMap["frameIndex"]; qDebug() << " settingsMap[frameIndex]:" << settingsMap["frameIndex"];
qDebug(" frameIndex: %20.5f", frameIndex); qDebug(" frameIndex: %20.5f", frameIndex);
} }
#endif #endif
setAnimationFrameIndex(frameIndex); setAnimationFrameIndex(frameIndex);
} }
if (settingsMap.contains("running")) { if (settingsMap.contains("running")) {
bool running = settingsMap["running"].toBool(); bool running = settingsMap["running"].toBool();
if (running != getAnimationIsPlaying()) { if (running != getAnimationIsPlaying()) {
setAnimationIsPlaying(running); setAnimationIsPlaying(running);
} }
} }
if (settingsMap.contains("firstFrame")) { if (settingsMap.contains("firstFrame")) {
float firstFrame = settingsMap["firstFrame"].toFloat(); float firstFrame = settingsMap["firstFrame"].toFloat();
setAnimationFirstFrame(firstFrame); setAnimationFirstFrame(firstFrame);
} }
if (settingsMap.contains("lastFrame")) { if (settingsMap.contains("lastFrame")) {
float lastFrame = settingsMap["lastFrame"].toFloat(); float lastFrame = settingsMap["lastFrame"].toFloat();
setAnimationLastFrame(lastFrame); setAnimationLastFrame(lastFrame);
} }
if (settingsMap.contains("loop")) { if (settingsMap.contains("loop")) {
bool loop = settingsMap["loop"].toBool(); bool loop = settingsMap["loop"].toBool();
setAnimationLoop(loop); setAnimationLoop(loop);
} }
if (settingsMap.contains("hold")) { if (settingsMap.contains("hold")) {
bool hold = settingsMap["hold"].toBool(); bool hold = settingsMap["hold"].toBool();
setAnimationHold(hold); setAnimationHold(hold);
} }
if (settingsMap.contains("startAutomatically")) { if (settingsMap.contains("startAutomatically")) {
bool startAutomatically = settingsMap["startAutomatically"].toBool(); bool startAutomatically = settingsMap["startAutomatically"].toBool();
setAnimationStartAutomatically(startAutomatically); setAnimationStartAutomatically(startAutomatically);
} }
_animationSettings = value; _animationSettings = value;
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
} }
void ParticleEffectEntityItem::setAnimationIsPlaying(bool value) { void ParticleEffectEntityItem::setAnimationIsPlaying(bool value) {
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
_animationLoop.setRunning(value); _animationLoop.setRunning(value);
} }
void ParticleEffectEntityItem::setAnimationFPS(float value) { void ParticleEffectEntityItem::setAnimationFPS(float value) {
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
_animationLoop.setFPS(value); _animationLoop.setFPS(value);
} }
QString ParticleEffectEntityItem::getAnimationSettings() const { QString ParticleEffectEntityItem::getAnimationSettings() const {
// the animations setting is a JSON string that may contain various animation settings. // the animations setting is a JSON string that may contain various animation settings.
// if it includes fps, frameIndex, or running, those values will be parsed out and // if it includes fps, frameIndex, or running, those values will be parsed out and
// will over ride the regular animation settings // will over ride the regular animation settings
QString value = _animationSettings; QString value = _animationSettings;
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object(); QJsonObject settingsAsJsonObject = settingsAsJson.object();
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
QVariant fpsValue(getAnimationFPS()); QVariant fpsValue(getAnimationFPS());
settingsMap["fps"] = fpsValue; settingsMap["fps"] = fpsValue;
QVariant frameIndexValue(getAnimationFrameIndex()); QVariant frameIndexValue(getAnimationFrameIndex());
settingsMap["frameIndex"] = frameIndexValue; settingsMap["frameIndex"] = frameIndexValue;
QVariant runningValue(getAnimationIsPlaying()); QVariant runningValue(getAnimationIsPlaying());
settingsMap["running"] = runningValue; settingsMap["running"] = runningValue;
QVariant firstFrameValue(getAnimationFirstFrame()); QVariant firstFrameValue(getAnimationFirstFrame());
settingsMap["firstFrame"] = firstFrameValue; settingsMap["firstFrame"] = firstFrameValue;
QVariant lastFrameValue(getAnimationLastFrame()); QVariant lastFrameValue(getAnimationLastFrame());
settingsMap["lastFrame"] = lastFrameValue; settingsMap["lastFrame"] = lastFrameValue;
QVariant loopValue(getAnimationLoop()); QVariant loopValue(getAnimationLoop());
settingsMap["loop"] = loopValue; settingsMap["loop"] = loopValue;
QVariant holdValue(getAnimationHold()); QVariant holdValue(getAnimationHold());
settingsMap["hold"] = holdValue; settingsMap["hold"] = holdValue;
QVariant startAutomaticallyValue(getAnimationStartAutomatically()); QVariant startAutomaticallyValue(getAnimationStartAutomatically());
settingsMap["startAutomatically"] = startAutomaticallyValue; settingsMap["startAutomatically"] = startAutomaticallyValue;
settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap); settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap);
QJsonDocument newDocument(settingsAsJsonObject); QJsonDocument newDocument(settingsAsJsonObject);
QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact); QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact);
QString jsonByteString(jsonByteArray); QString jsonByteString(jsonByteArray);
return jsonByteString; return jsonByteString;
} }
void ParticleEffectEntityItem::stepSim(float deltaTime) void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
{ _paXmin = _paYmin = _paZmin = -1.0;
pa_xmin = pa_ymin = pa_zmin = -1.0; _paXmax = _paYmax = _paZmax = 1.0;
pa_xmax = pa_ymax = pa_zmax = 1.0;
// update particles // update particles
quint32 updateIter = pa_head; quint32 updateIter = _paHead;
while (pa_life[updateIter] > 0.0f) while (_paLife[updateIter] > 0.0f) {
{ _paLife[updateIter] -= deltaTime;
pa_life[updateIter] -= deltaTime; if (_paLife[updateIter] <= 0.0f) {
if (pa_life[updateIter] <= 0.0f) _paLife[updateIter] = -1.0f;
{ _paHead = (_paHead + 1) % _maxParticles;
pa_life[updateIter] = -1.0f; _paCount--;
pa_head = (pa_head + 1) % _maxParticles; }
pa_count--; else {
} // DUMB FORWARD EULER just to get it done
else int j = updateIter * XYZ_STRIDE;
{ _paPosition[j] += _paVelocity[j] * deltaTime;
// DUMB FORWARD EULER just to get it done _paPosition[j+1] += _paVelocity[j+1] * deltaTime;
int j = updateIter * 3; _paPosition[j+2] += _paVelocity[j+2] * deltaTime;
pa_position[j] += pa_velocity[j] * deltaTime;
pa_position[j+1] += pa_velocity[j+1] * deltaTime;
pa_position[j+2] += pa_velocity[j+2] * deltaTime;
pa_xmin = glm::min(pa_xmin, pa_position[j]); _paXmin = glm::min(_paXmin, _paPosition[j]);
pa_ymin = glm::min(pa_ymin, pa_position[j+1]); _paYmin = glm::min(_paYmin, _paPosition[j+1]);
pa_zmin = glm::min(pa_zmin, pa_position[j+2]); _paZmin = glm::min(_paZmin, _paPosition[j+2]);
pa_xmax = glm::max(pa_xmax, pa_position[j]); _paXmax = glm::max(_paXmax, _paPosition[j]);
pa_ymax = glm::max(pa_ymax, pa_position[j + 1]); _paYmax = glm::max(_paYmax, _paPosition[j + 1]);
pa_zmax = glm::max(pa_zmax, pa_position[j + 2]); _paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// massless particles // massless particles
pa_velocity[j + 1] += deltaTime * _localGravity; _paVelocity[j + 1] += deltaTime * _localGravity;
} }
updateIter = (updateIter + 1) % _maxParticles; updateIter = (updateIter + 1) % _maxParticles;
} }
// emit new particles // emit new particles
quint32 pa_emit_idx = updateIter; quint32 emitIdx = updateIter;
partial_emit += ((float)_emitRate) * deltaTime; _partialEmit += ((float)_emitRate) * deltaTime;
quint32 birthed = (quint32)partial_emit; quint32 birthed = (quint32)_partialEmit;
partial_emit -= (float)birthed; _partialEmit -= (float)birthed;
glm::vec3 randOffset; glm::vec3 randOffset;
for (quint32 i = 0; i < birthed; i++) for (quint32 i = 0; i < birthed; i++) {
{ if (_paLife[emitIdx] < 0.0f) {
if (pa_life[pa_emit_idx] < 0.0f) int j = emitIdx * XYZ_STRIDE;
{ _paLife[emitIdx] = _lifespan;
int j = pa_emit_idx * 3; randOffset.x = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
pa_life[pa_emit_idx] = _lifespan; randOffset.y = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.x = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength; randOffset.z = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.y = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength; _paVelocity[j] = (_emitDirection.x * _emitStrength) + randOffset.x;
randOffset.z = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength; _paVelocity[j + 1] = (_emitDirection.y * _emitStrength) + randOffset.y;
pa_velocity[j] = (_emitDirection.x * _emitStrength) + randOffset.x; _paVelocity[j + 2] = (_emitDirection.z * _emitStrength) + randOffset.z;
pa_velocity[j + 1] = (_emitDirection.y * _emitStrength) + randOffset.y;
pa_velocity[j + 2] = (_emitDirection.z * _emitStrength) + randOffset.z;
// DUMB FORWARD EULER just to get it done // DUMB FORWARD EULER just to get it done
pa_position[j] += pa_velocity[j] * deltaTime; _paPosition[j] += _paVelocity[j] * deltaTime;
pa_position[j + 1] += pa_velocity[j + 1] * deltaTime; _paPosition[j + 1] += _paVelocity[j + 1] * deltaTime;
pa_position[j + 2] += pa_velocity[j + 2] * deltaTime; _paPosition[j + 2] += _paVelocity[j + 2] * deltaTime;
pa_xmin = glm::min(pa_xmin, pa_position[j]); _paXmin = glm::min(_paXmin, _paPosition[j]);
pa_ymin = glm::min(pa_ymin, pa_position[j + 1]); _paYmin = glm::min(_paYmin, _paPosition[j + 1]);
pa_zmin = glm::min(pa_zmin, pa_position[j + 2]); _paZmin = glm::min(_paZmin, _paPosition[j + 2]);
pa_xmax = glm::max(pa_xmax, pa_position[j]); _paXmax = glm::max(_paXmax, _paPosition[j]);
pa_ymax = glm::max(pa_ymax, pa_position[j + 1]); _paYmax = glm::max(_paYmax, _paPosition[j + 1]);
pa_zmax = glm::max(pa_zmax, pa_position[j + 2]); _paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// massless particles // massless particles
pa_velocity[j + 1] += deltaTime * _localGravity; // and simple gravity down
_paVelocity[j + 1] += deltaTime * _localGravity;
pa_emit_idx = (pa_emit_idx + 1) % _maxParticles; emitIdx = (emitIdx + 1) % _maxParticles;
pa_count++; _paCount++;
} }
else else
break; break;
} }
} }
void ParticleEffectEntityItem::resetSim() void ParticleEffectEntityItem::resetSimulation() {
{ for (int i = 0; i < _maxParticles; i++) {
for (int i = 0; i < _maxParticles; i++) int j = i * XYZ_STRIDE;
{ _paLife[i] = -1.0f;
int j = i * 3; _paPosition[j] = 0.0f;
pa_life[i] = -1.0f; _paPosition[j+1] = 0.0f;
pa_position[j] = 0.0f; _paPosition[j+2] = 0.0f;
pa_position[j+1] = 0.0f; _paVelocity[j] = 0.0f;
pa_position[j+2] = 0.0f; _paVelocity[j+1] = 0.0f;
pa_velocity[j] = 0.0f; _paVelocity[j+2] = 0.0f;
pa_velocity[j+1] = 0.0f; }
pa_velocity[j+2] = 0.0f; _paCount = 0;
} _paHead = 0;
pa_count = 0; _partialEmit = 0.0f;
pa_head = 0;
partial_emit = 0.0f;
srand((unsigned int) this); srand(_randSeed);
} }

View file

@ -39,141 +39,143 @@
class ParticleEffectEntityItem : public EntityItem { class ParticleEffectEntityItem : public EntityItem {
public: public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~ParticleEffectEntityItem(); virtual ~ParticleEffectEntityItem();
ALLOW_INSTANTIATION // This class can be instantiated ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of this entity // methods for getting/setting all properties of this entity
virtual EntityItemProperties getProperties() const; virtual EntityItemProperties getProperties() const;
virtual bool setProperties(const EntityItemProperties& properties); virtual bool setProperties(const EntityItemProperties& properties);
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties, EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit, EntityPropertyFlags& propertiesDidntFit,
int& propertyCount, int& propertyCount,
OctreeElement::AppendState& appendState) const; OctreeElement::AppendState& appendState) const;
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);
virtual void update(const quint64& now); virtual void update(const quint64& now);
virtual bool needsToCallUpdate() const; virtual bool needsToCallUpdate() const;
const rgbColor& getColor() const { return _color; } const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; 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 rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) { void setColor(const xColor& value) {
_color[RED_INDEX] = value.red; _color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green; _color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue; _color[BLUE_INDEX] = value.blue;
} }
void updateShapeType(ShapeType type); void updateShapeType(ShapeType type);
virtual ShapeType getShapeType() const { return _shapeType; } virtual ShapeType getShapeType() const { return _shapeType; }
virtual void debugDump() const; virtual void debugDump() const;
static const float DEFAULT_ANIMATION_FRAME_INDEX; static const float DEFAULT_ANIMATION_FRAME_INDEX;
void setAnimationFrameIndex(float value); void setAnimationFrameIndex(float value);
void setAnimationSettings(const QString& value); void setAnimationSettings(const QString& value);
static const bool DEFAULT_ANIMATION_IS_PLAYING; static const bool DEFAULT_ANIMATION_IS_PLAYING;
void setAnimationIsPlaying(bool value); void setAnimationIsPlaying(bool value);
static const float DEFAULT_ANIMATION_FPS; static const float DEFAULT_ANIMATION_FPS;
void setAnimationFPS(float value); void setAnimationFPS(float value);
void setAnimationLoop(bool loop) { _animationLoop.setLoop(loop); } void setAnimationLoop(bool loop) { _animationLoop.setLoop(loop); }
bool getAnimationLoop() const { return _animationLoop.getLoop(); } bool getAnimationLoop() const { return _animationLoop.getLoop(); }
void setAnimationHold(bool hold) { _animationLoop.setHold(hold); } void setAnimationHold(bool hold) { _animationLoop.setHold(hold); }
bool getAnimationHold() const { return _animationLoop.getHold(); } bool getAnimationHold() const { return _animationLoop.getHold(); }
void setAnimationStartAutomatically(bool startAutomatically) { _animationLoop.setStartAutomatically(startAutomatically); } void setAnimationStartAutomatically(bool startAutomatically) { _animationLoop.setStartAutomatically(startAutomatically); }
bool getAnimationStartAutomatically() const { return _animationLoop.getStartAutomatically(); } bool getAnimationStartAutomatically() const { return _animationLoop.getStartAutomatically(); }
void setAnimationFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); } void setAnimationFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); }
float getAnimationFirstFrame() const { return _animationLoop.getFirstFrame(); } float getAnimationFirstFrame() const { return _animationLoop.getFirstFrame(); }
void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); } void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); }
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
static const quint32 DEFAULT_MAX_PARTICLES; static const quint32 DEFAULT_MAX_PARTICLES;
void setMaxParticles(quint32 maxParticles) { _maxParticles = maxParticles; } void setMaxParticles(quint32 maxParticles) { _maxParticles = maxParticles; }
quint32 getMaxParticles() const { return _maxParticles; } quint32 getMaxParticles() const { return _maxParticles; }
static const float DEFAULT_LIFESPAN; static const float DEFAULT_LIFESPAN;
void setLifespan(float lifespan) { _lifespan = lifespan; } void setLifespan(float lifespan) { _lifespan = lifespan; }
float getLifespan() const { return _lifespan; } float getLifespan() const { return _lifespan; }
static const float DEFAULT_EMIT_RATE; static const float DEFAULT_EMIT_RATE;
void setEmitRate(float emitRate) { _emitRate = emitRate; } void setEmitRate(float emitRate) { _emitRate = emitRate; }
float getEmitRate() const { return _emitRate; } float getEmitRate() const { return _emitRate; }
static const glm::vec3 DEFAULT_EMIT_DIRECTION; static const glm::vec3 DEFAULT_EMIT_DIRECTION;
void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = emitDirection; } void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = emitDirection; }
const glm::vec3& getEmitDirection() const { return _emitDirection; } const glm::vec3& getEmitDirection() const { return _emitDirection; }
static const float DEFAULT_EMIT_STRENGTH; static const float DEFAULT_EMIT_STRENGTH;
void setEmitStrength(float emitStrength) { _emitStrength = emitStrength; } void setEmitStrength(float emitStrength) { _emitStrength = emitStrength; }
float getEmitStrength() const { return _emitStrength; } float getEmitStrength() const { return _emitStrength; }
static const float DEFAULT_LOCAL_GRAVITY; static const float DEFAULT_LOCAL_GRAVITY;
void setLocalGravity(float localGravity) { _localGravity = localGravity; } void setLocalGravity(float localGravity) { _localGravity = localGravity; }
float getLocalGravity() const { return _localGravity; } float getLocalGravity() const { return _localGravity; }
static const float DEFAULT_PARTICLE_RADIUS; static const float DEFAULT_PARTICLE_RADIUS;
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
float getParticleRadius() const { return _particleRadius; } float getParticleRadius() const { return _particleRadius; }
bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); }
float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); } float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); }
float getAnimationFPS() const { return _animationLoop.getFPS(); } float getAnimationFPS() const { return _animationLoop.getFPS(); }
QString getAnimationSettings() const; QString getAnimationSettings() const;
protected: protected:
bool isAnimatingSomething() const; bool isAnimatingSomething() const;
void stepSim(float deltaTime); void stepSimulation(float deltaTime);
void resetSim(); void resetSimulation();
// the properties of this entity // the properties of this entity
rgbColor _color; rgbColor _color;
quint32 _maxParticles; quint32 _maxParticles;
float _lifespan; float _lifespan;
float _emitRate; float _emitRate;
glm::vec3 _emitDirection; glm::vec3 _emitDirection;
float _emitStrength; float _emitStrength;
float _localGravity; float _localGravity;
float _particleRadius; float _particleRadius;
quint64 _lastAnimated; quint64 _lastAnimated;
AnimationLoop _animationLoop; AnimationLoop _animationLoop;
QString _animationSettings; QString _animationSettings;
ShapeType _shapeType = SHAPE_TYPE_NONE; ShapeType _shapeType = SHAPE_TYPE_NONE;
// all the internals of running the particle sim // all the internals of running the particle sim
float* pa_life; const quint32 XYZ_STRIDE = 3;
float* pa_position; float* _paLife;
float* pa_velocity; float* _paPosition;
float partial_emit; float* _paVelocity;
quint32 pa_count; float _partialEmit;
quint32 pa_head; quint32 _paCount;
float pa_xmin; quint32 _paHead;
float pa_xmax; float _paXmin;
float pa_ymin; float _paXmax;
float pa_ymax; float _paYmin;
float pa_zmin; float _paYmax;
float pa_zmax; float _paZmin;
float _paZmax;
unsigned int _randSeed;
}; };

View file

@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1; return 1;
case PacketTypeEntityAddOrEdit: case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData: case PacketTypeEntityData:
return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE; return VERSION_ENTITIES_HAS_PARTICLES;
case PacketTypeEntityErase: case PacketTypeEntityErase:
return 2; return 2;
case PacketTypeAudioStreamStats: case PacketTypeAudioStreamStats:

View file

@ -129,5 +129,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8; const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
#endif // hifi_PacketHeaders_h #endif // hifi_PacketHeaders_h