void RenderableZoneEntityItem::render(RenderArgs* args) {
    Q_ASSERT(getType() == EntityTypes::Zone);
    
    if (_drawZoneBoundaries) {
        switch (getShapeType()) {
            case SHAPE_TYPE_COMPOUND: {
                PerformanceTimer perfTimer("zone->renderCompound");
                updateGeometry();
                if (_model && _model->needsFixupInScene()) {
                    // check to see if when we added our models to the scene they were ready, if they were not ready, then
                    // fix them up in the scene
                    render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
                    render::PendingChanges pendingChanges;
                    _model->removeFromScene(scene, pendingChanges);
                    _model->addToScene(scene, pendingChanges);
                    
                    scene->enqueuePendingChanges(pendingChanges);
                    
                    _model->setVisibleInScene(getVisible(), scene);
                }
                break;
            }
            case SHAPE_TYPE_BOX:
            case SHAPE_TYPE_SPHERE: {
                PerformanceTimer perfTimer("zone->renderPrimitive");
                glm::vec4 DEFAULT_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
                
                Q_ASSERT(args->_batch);
                gpu::Batch& batch = *args->_batch;
                batch.setModelTransform(getTransformToCenter());
                
                auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
                
                if (getShapeType() == SHAPE_TYPE_SPHERE) {
                    const int SLICES = 15, STACKS = 15;
                    deferredLightingEffect->renderWireSphere(batch, 0.5f, SLICES, STACKS, DEFAULT_COLOR);
                } else {
                    deferredLightingEffect->renderWireCube(batch, 1.0f, DEFAULT_COLOR);
                }
                break;
            }
            default:
                // Not handled
                break;
        }
    }
    
    if ((!_drawZoneBoundaries || getShapeType() != SHAPE_TYPE_COMPOUND) &&
        _model && !_model->needsFixupInScene()) {
        // If the model is in the scene but doesn't need to be, remove it.
        render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
        render::PendingChanges pendingChanges;
        _model->removeFromScene(scene, pendingChanges);
        scene->enqueuePendingChanges(pendingChanges);
    }
}
void RenderableZoneEntityItem::render(RenderArgs* args) {
    if (_drawZoneBoundaries) {
        switch (getShapeType()) {
            case SHAPE_TYPE_COMPOUND: {
                updateGeometry();
                
                if (_model && _model->isActive()) {
                    PerformanceTimer perfTimer("zone->renderCompound");
                    glPushMatrix();
                    _model->renderInScene(getLocalRenderAlpha(), args);
                    glPopMatrix();
                }
                break;
            }
            case SHAPE_TYPE_BOX:
            case SHAPE_TYPE_SPHERE: {
                PerformanceTimer perfTimer("zone->renderPrimitive");
                glm::vec3 position = getPosition();
                glm::vec3 center = getCenter();
                glm::vec3 dimensions = getDimensions();
                glm::quat rotation = getRotation();
                
                glm::vec4 DEFAULT_COLOR(1.0f, 1.0f, 1.0f, getLocalRenderAlpha());
                
                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);
                    glPushMatrix(); {
                        glm::vec3 positionToCenter = center - position;
                        glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
                        glScalef(dimensions.x, dimensions.y, dimensions.z);
                        
                        auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
                        
                        if (getShapeType() == SHAPE_TYPE_SPHERE) {
                            const int SLICES = 15;
                            const int STACKS = 15;
                            deferredLightingEffect->renderWireSphere(0.5f, SLICES, STACKS, DEFAULT_COLOR);
                        } else {
                            deferredLightingEffect->renderWireCube(1.0f, DEFAULT_COLOR);
                        }
                    } glPopMatrix();
                } glPopMatrix();
                break;
            }
            default:
                // Not handled
                break;
        }
    }
}
Example #3
0
void PhysicsRigidBody::transformChanged(Transform* transform, long cookie)
{
    if (getShapeType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
    {
        GP_ASSERT(_collisionShape && _collisionShape->_shapeData.heightfieldData);

        // Dirty the heightfield's inverse kmMat4 (used to compute height values from world-space coordinates)
        _collisionShape->_shapeData.heightfieldData->inverseIsDirty = true;

        // Update local scaling for the heightfield.
        kmVec3 scale = vec3Zero;
        //_node->getWorldMatrix().getScale(&scale);
		kmMat4Decompose(&_node->getWorldMatrix(), &scale, NULL, NULL);

        // If the node has a terrain attached, factor in the terrain local scaling as well for the collision shape
        Terrain* terrain = dynamic_cast<Terrain*>(_node->getDrawable());
        if (terrain)
        {
            const kmVec3& tScale = terrain->_localScale;
			scale = { scale.x * tScale.x, scale.y * tScale.y, scale.z * tScale.z };
        }

        _collisionShape->_shape->setLocalScaling(BV(scale));

        // Update center of mass offset
        float minHeight = _collisionShape->_shapeData.heightfieldData->minHeight;
        float maxHeight = _collisionShape->_shapeData.heightfieldData->maxHeight;
		_motionState->setCenterOfMassOffset({ 0, -(minHeight + (maxHeight - minHeight)*0.5f) * scale.y, 0 });
    }
}
Example #4
0
void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, 
                                    EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData,
                                    EntityPropertyFlags& requestedProperties,
                                    EntityPropertyFlags& propertyFlags,
                                    EntityPropertyFlags& propertiesDidntFit,
                                    int& propertyCount, 
                                    OctreeElement::AppendState& appendState) const { 

    bool successPropertyFits = true;

    _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
                                         propertyFlags, propertiesDidntFit, propertyCount, appendState);

    _stageProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
                                    propertyFlags, propertiesDidntFit, propertyCount, appendState);


    APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
    APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
    APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)getBackgroundMode()); // could this be a uint16??

    _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
                                    propertyFlags, propertiesDidntFit, propertyCount, appendState);

    APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
    APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
    APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
}
bool RenderableModelEntityItem::isReadyToComputeShape() {
    ShapeType type = getShapeType();
    if (type == SHAPE_TYPE_COMPOUND) {

        if (!_model) {
            return false; // hmm...
        }

        if (_needsInitialSimulation) {
            // the _model's offset will be wrong until _needsInitialSimulation is false
            return false;
        }

        assert(!_model->getCollisionURL().isEmpty());
    
        if (_model->getURL().isEmpty()) {
            // we need a render geometry with a scale to proceed, so give up.
            return false;
        }
    
        const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
        const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
    
        if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
            (renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
            // we have both URLs AND both geometries AND they are both fully loaded.
            return true;
        }

        // the model is still being downloaded.
        return false;
    }
    return true;
}
void PhysicsRigidBody::transformChanged(Transform* transform, long cookie)
{
    if (getShapeType() == PhysicsCollisionShape::SHAPE_HEIGHTFIELD)
    {
        GP_ASSERT(_collisionShape && _collisionShape->_shapeData.heightfieldData);
        _collisionShape->_shapeData.heightfieldData->inverseIsDirty = true;
    }
}
Example #7
0
gep::CollisionMesh* gep::CollisionMeshFileLoader::loadResource(CollisionMesh* pInPlace)
{
    CollisionMesh* result = nullptr;
    bool isInPlace = true;
    if (pInPlace == nullptr)
    {
        result = new CollisionMesh();
        isInPlace = false;
    }
    auto* havokLoader = g_resourceManager.getHavokResourceLoader();
    auto* container = havokLoader->load(m_path.c_str());
    GEP_ASSERT(container != nullptr, "Could not load asset! %s", m_path.c_str());

    if (container)
    {
        auto* physicsData = reinterpret_cast<hkpPhysicsData*>(container->findObjectByType(hkpPhysicsDataClass.getName()));
        GEP_ASSERT(physicsData != nullptr, "Unable to load physics data!");

        if (physicsData)
        {
            const auto& physicsSystems = physicsData->getPhysicsSystems();
            GEP_ASSERT(physicsSystems.getSize() == 1, "Wrong number of physics systems!");
            auto body = physicsSystems[0]->getRigidBodies()[0];
            auto hkShape = body->getCollidable()->getShape();

            auto shape = conversion::hk::from(const_cast<hkpShape*>(hkShape));

            auto type = shape->getShapeType();
            if ( type == hkcdShapeType::BV_COMPRESSED_MESH ||
                 type == hkcdShapeType::CONVEX_VERTICES )
            {
                hkTransform transform = body->getTransform();
                transform.getRotation().setAxisAngle(hkVector4(0.0f, 0.0f, 1.0f), GetPi<float>::value());

                auto hkTransformShape = new hkpTransformShape(hkShape, transform);
                hkTransformShape->addReference();
                shape = GEP_NEW(m_pAllocator, HavokShape_Transform)(hkTransformShape);
                //auto meshShape = static_cast<HavokMeshShape*>(shape);
                //Transform* tempTrans = new Transform();
                //conversion::hk::from(transform, *tempTrans);
                //
                //// Since havok content tools are buggy (?) and no custom transformation can be applied,
                //// we have to convert into our engine's space by hand.
                //// TODO: Ensure, that this transformation is correct in every case
                //tempTrans->setRotation(tempTrans->getRotation() * Quaternion(vec3(1,0,0),180));
                //meshShape->setTransform(tempTrans);
            }


            result->setShape(shape);
            
        }

    }
    return result;
}
Example #8
0
dReal ODE_Particle::getRadius()
{
    if (getShapeType() == dSphereClass)
    {
        return dGeomSphereGetRadius(geom);
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Requesting radius for non spherical object");
        exit(0);
    }
}
bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
    if (getShapeType() != SHAPE_TYPE_COMPOUND) {
        return EntityItem::contains(point);
    }
    const_cast<RenderableZoneEntityItem*>(this)->updateGeometry();
    
    if (_model && _model->isActive() && EntityItem::contains(point)) {
        return _model->convexHullContains(point);
    }
    
    return false;
}
Example #10
0
void ShapeEntityItem::debugDump() const {
    quint64 now = usecTimestampNow();
    qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
    qCDebug(entities) << "               name:" << _name;
    qCDebug(entities) << "              shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )";
    qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType());
    qCDebug(entities) << "              color:" << _color[0] << "," << _color[1] << "," << _color[2];
    qCDebug(entities) << "           position:" << debugTreeVector(getWorldPosition());
    qCDebug(entities) << "         dimensions:" << debugTreeVector(getScaledDimensions());
    qCDebug(entities) << "      getLastEdited:" << debugTime(getLastEdited(), now);
    qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
}
Example #11
0
void ODE_Particle::getLengths(dVector3 &sides)
{
    if (getShapeType() == dBoxClass)
    {                
        dGeomBoxGetLengths (geom,sides);
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Requesting dimensions for non box object");
        exit(0);
    }
}
Example #12
0
//set mass and radius by available total mass
void Particle::setMassTotal(dReal total_mass, dReal rad)
{    
    if (getShapeType() == dSphereClass)
    {
        radius=rad;
        mass=total_mass;
        inv_mass=1/mass;        
    }
    else
    {
        printf("ERROR in Particle.cpp: Setting totalMass for non spherical object");
        exit(0);
    }
}
Example #13
0
void Particle::getLengths(dVector3 &s)
{
    if (getShapeType() == dBoxClass)
    {                
        s[0]=sides[0];
        s[1]=sides[1];
        s[2]=sides[2];
    }
    else
    {
        printf("ERROR in Particle.cpp: Requesting dimensions for non box object");
        exit(0);
    }
}
Example #14
0
void Particle::getLengths(dReal &r0,dReal &r1,dReal &r2)
{
    if (getShapeType() == dBoxClass)
    {
        r0=sides[0];
        r1=sides[1];
        r2=sides[2];
    }
    else
    {
        printf("ERROR in Particle.cpp: Requesting dimensions for non box object");
        exit(0);
    }
}
Example #15
0
//set mass by radius and density
void Particle::setMass(dReal density, dReal rad)
{
    if (getShapeType() == dSphereClass)
    {        
        radius=rad;                
        mass=4.18879*radius*radius*radius*density;  // 4/3*PI=4.18879
        inv_mass=1/mass;   
    }
    else
    {
        printf("ERROR in Particle.cpp: Setting Mass using density for non spherical object");
        exit(0);
    }
}
Example #16
0
GUIGLObjectPopupMenu*
GNEPOI::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
    GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, *this);
    buildPopupHeader(ret, app);
    buildCenterPopupEntry(ret);
    buildNameCopyPopupEntry(ret);
    // build selection and show parameters menu
    myNet->getViewNet()->buildSelectionACPopupEntry(ret, this);
    buildShowParamsPopupEntry(ret);
    if (getLaneParents().size() > 0) {
        // build shape header
        buildShapePopupOptions(app, ret, getShapeType());
        // add option for convert to GNEPOI
        new FXMenuCommand(ret, ("Release from " + toString(SUMO_TAG_LANE)).c_str(), GUIIconSubSys::getIcon(ICON_LANE), &parent, MID_GNE_POI_TRANSFORM);
        return ret;
    } else {
        // build shape header
        buildShapePopupOptions(app, ret, getShapeType());
        // add option for convert to GNEPOI
        new FXMenuCommand(ret, ("Attach to nearest " + toString(SUMO_TAG_LANE)).c_str(), GUIIconSubSys::getIcon(ICON_LANE), &parent, MID_GNE_POI_TRANSFORM);
    }
    return ret;
}
Example #17
0
std::string
GNEPOI::getAttribute(SumoXMLAttr key) const {
    switch (key) {
        case SUMO_ATTR_ID:
            return myID;
        case SUMO_ATTR_COLOR:
            return toString(getShapeColor());
        case SUMO_ATTR_LANE:
            return myLane;
        case SUMO_ATTR_POSITION:
            if (getLaneParents().size() > 0) {
                return toString(myPosOverLane);
            } else {
                return toString(*this);
            }
        case SUMO_ATTR_POSITION_LAT:
            return toString(myPosLat);
        case SUMO_ATTR_GEOPOSITION:
            return toString(myGEOPosition, gPrecisionGeo);
        case SUMO_ATTR_GEO:
            return toString(myGeo);
        case SUMO_ATTR_TYPE:
            return getShapeType();
        case SUMO_ATTR_LAYER:
            if (getShapeLayer() == Shape::DEFAULT_LAYER_POI) {
                return "default";
            } else {
                return toString(getShapeLayer());
            }
        case SUMO_ATTR_IMGFILE:
            return getShapeImgFile();
        case SUMO_ATTR_RELATIVEPATH:
            return toString(getShapeRelativePath());
        case SUMO_ATTR_WIDTH:
            return toString(getWidth());
        case SUMO_ATTR_HEIGHT:
            return toString(getHeight());
        case SUMO_ATTR_ANGLE:
            return toString(getShapeNaviDegree());
        case GNE_ATTR_BLOCK_MOVEMENT:
            return toString(myBlockMovement);
        case GNE_ATTR_SELECTED:
            return toString(isAttributeCarrierSelected());
        case GNE_ATTR_GENERIC:
            return getGenericParametersStr();
        default:
            throw InvalidArgument(getTagStr() + " attribute '" + toString(key) + "' not allowed");
    }
}
Example #18
0
void basicShape::buildBasicMenu(){
	// build custom UI
	
	basicShapeGui.clear();
	basicShapeGui.setup( getShapeType() );
	basicShapeGui.setShowHeader(true);
	
	basicShapeGui.add( (new ofxIntSlider( groupID )) );
	
	basicShapeGui.add( (new ofxLabel( shapeName )) );
	
	shapeGui.setup();
	shapeGui.add( &basicShapeGui );
	//shapeGui->setShowHeader(false);
}
Example #19
0
// writes the shape data to XML. xml's cursor is already pushed into the right <shape> tag.
// return success state
bool basicShape::saveToXML(ofxXmlSettings &xml){
	
	// create position tag
	xml.addTag("position");
	xml.pushTag("position");
	xml.addValue("X", getPositionUnaltered()->x);
	xml.addValue("Y", getPositionUnaltered()->y);
	xml.popTag();
	
	xml.addValue("shapeType", getShapeType() );
	xml.addValue("groupID", getGroupID() );
	xml.addValue("shapeName", shapeName );
	
	return true;
}
Example #20
0
//set mass and sides by available dimensions for box objects
void ODE_Particle::setMassTotal(dReal total_mass, dReal side1,dReal side2,dReal side3)
{
    dMass m;
    dMassSetZero(&m);       
    if (getShapeType() == dBoxClass)
    {
        dMassSetBoxTotal(&m,total_mass,side1,side2,side3);
        dBodySetMass(body,&m);
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Setting Mass using total mass for non box object");
        exit(0);
    }
}
Example #21
0
void ODE_Particle::getLengths(dReal &r0,dReal &r1,dReal &r2)
{
    if (getShapeType() == dBoxClass)
    {
        dVector3 sides;
        dGeomBoxGetLengths (geom,sides);
        r0=sides[0];
        r1=sides[1];
        r2=sides[2];
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Requesting dimensions for non box object");
        exit(0);
    }
}
Example #22
0
//set mass by sides and density for box objects
void Particle::setMass(dReal density, dReal side1,dReal side2,dReal side3)
{    
    if (getShapeType() == dBoxClass)
    {
        mass=density*side1*side2*side3;
        inv_mass=1/mass;    
        sides[0]=side1;
        sides[1]=side2;
        sides[2]=side3;
    }
    else
    {
        printf("ERROR in Particle.cpp: Setting Mass using density for non box object");
        exit(0);
    }    
}
Example #23
0
//set mass by sides and density for box objects
void ODE_Particle::setMass(dReal density, dReal side1,dReal side2,dReal side3)
{
    dMass m;
    dMassSetZero(&m);
    
    if (getShapeType() == dBoxClass)
    {
        dMassSetBox (&m,density,side1,side2,side3);
        dBodySetMass(body,&m);   
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Setting Mass using density for non box object");
        exit(0);
    }
}
Example #24
0
//set mass and sides by available dimensions for box objects
void Particle::setMassTotal(dReal total_mass, dReal side1,dReal side2,dReal side3)
{
    if (getShapeType() == dBoxClass)
    {
        mass=total_mass;
        inv_mass=1/mass;    
        sides[0]=side1;
        sides[1]=side2;
        sides[2]=side3;
    }
    else
    {
        printf("ERROR in Particle.cpp: Setting Mass using total mass for non box object");
        exit(0);
    }
}
Example #25
0
//set mass and radius by available total mass
void ODE_Particle::setMassTotal(dReal total_mass, dReal rad)
{
    dMass m;
    dMassSetZero(&m);
    
    if (getShapeType() == dSphereClass)
    {
        dMassSetSphereTotal(&m,total_mass,rad);    // set a given mass to sphere       
        dBodySetMass(body,&m);        
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Setting totalMass for non spherical object");
        exit(0);
    }
}
Example #26
0
//set mass by radius and density
void ODE_Particle::setMass(dReal density, dReal rad)
{
    dMass m;
    dMassSetZero(&m);   
        
    if (getShapeType() == dSphereClass)
    {
        dMassSetSphere (&m,density,rad);    // calculate a mass for a sphere        
        dBodySetMass(body,&m); 
    }
    else
    {
        printf("ERROR in ODE_Particle.cpp: Setting Mass using density for non spherical object");
        exit(0);
    }
}
Example #27
0
void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
                                EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
                                EntityPropertyFlags& requestedProperties,
                                EntityPropertyFlags& propertyFlags,
                                EntityPropertyFlags& propertiesDidntFit,
                                int& propertyCount, OctreeElement::AppendState& appendState) const {

    bool successPropertyFits = true;

    APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
    APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL());
    APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
    APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());

    _animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
        propertyFlags, propertiesDidntFit, propertyCount, appendState);

    APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
}
Example #28
0
void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
                                EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
                                EntityPropertyFlags& requestedProperties,
                                EntityPropertyFlags& propertyFlags,
                                EntityPropertyFlags& propertiesDidntFit,
                                int& propertyCount, OctreeElement::AppendState& appendState) const {

    bool successPropertyFits = true;

    APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
    APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL());
    APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
    APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getAnimationURL());
    APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getAnimationFPS());
    APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getAnimationFrameIndex());
    APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getAnimationIsPlaying());
    APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
    APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, getAnimationSettings());
    APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
}
void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
                                                  EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData,
                                                  EntityPropertyFlags& requestedProperties,
                                                  EntityPropertyFlags& propertyFlags,
                                                  EntityPropertyFlags& propertiesDidntFit,
                                                  int& propertyCount,
                                                  OctreeElement::AppendState& appendState) const {

    bool successPropertyFits = true;
    APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
    APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting());
    APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
    APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles());
    APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, getLifespan());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, getEmitRate());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, getEmitAcceleration());
    APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, getAccelerationSpread());
    APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
    APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
    APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread());
    APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart());
    APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish());
    APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread());
    APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart());
    APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish());
    APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
    APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread());
    APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart());
    APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, getEmitSpeed());
    APPEND_ENTITY_PROPERTY(PROP_SPEED_SPREAD, getSpeedSpread());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, getEmitOrientation());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, getEmitDimensions());
    APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, getEmitRadiusStart());
    APPEND_ENTITY_PROPERTY(PROP_POLAR_START, getPolarStart());
    APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish());
    APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart());
    APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish());
    APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail());
}
bool RenderableModelEntityItem::isReadyToComputeShape() {
    ShapeType type = getShapeType();

    if (type == SHAPE_TYPE_COMPOUND) {
        if (!_model || _model->getCollisionURL().isEmpty()) {
            EntityTreePointer tree = getTree();
            if (tree) {
                QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
            }
            return false;
        }

        if (_model->getURL().isEmpty()) {
            // we need a render geometry with a scale to proceed, so give up.
            return false;
        }

        const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
        const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();

        if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
            (renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
            // we have both URLs AND both geometries AND they are both fully loaded.

            if (_needsInitialSimulation) {
                // the _model's offset will be wrong until _needsInitialSimulation is false
                PerformanceTimer perfTimer("_model->simulate");
                _model->simulate(0.0f);
                _needsInitialSimulation = false;
            }

            return true;
        }

        // the model is still being downloaded.
        return false;
    }
    return true;
}