void Emitter::setTank(int minTank,int maxTank) { SPK_ASSERT(minTank >= 0 == maxTank >= 0,"Emitter::setTank(int,int) : min and max tank values must be of the same sign"); if (minTank < 0 || maxTank < 0) minTank = maxTank = -1; if (minTank > maxTank) { SPK_LOG_WARNING("Emitter::setTank(int,int) : min tank is greater than max tank. Values are swapped"); std::swap(minTank,maxTank); } this->minTank = minTank; this->maxTank = maxTank; resetTank(); SPK_ASSERT(flow >= 0.0f || currentTank >= 0,"Emitter::setTank(int,int) : the flow and tank of an emitter cannot be both negative"); }
void Group::reallocate(size_t capacity) { SPK_ASSERT(capacity != 0,"Group::reallocate(size_t) - Group capacity must not be 0"); if (isInitialized() && (!particleData.initialized || capacity != particleData.maxParticles)) { destroyAllAdditionnalData(); size_t copySize = particleData.nbParticles; if (capacity < copySize) copySize = capacity; reallocateArray(particleData.positions,capacity,copySize); reallocateArray(particleData.velocities,capacity,copySize); reallocateArray(particleData.oldPositions,capacity,copySize); reallocateArray(particleData.ages,capacity,copySize); reallocateArray(particleData.lifeTimes,capacity,copySize); reallocateArray(particleData.energies,capacity,copySize); reallocateArray(particleData.sqrDists,capacity,copySize); reallocateArray(particleData.colors,capacity,copySize); for (size_t i = 0; i < nbEnabledParameters; ++i) reallocateArray(particleData.parameters[enabledParamIndices[i]],capacity,copySize); particleData.initialized = true; } particleData.maxParticles = capacity; }
DX9Buffer::DX9Buffer(BufferInfo &info) : nbVertices(info.nbVertices), nbIndices(info.nbIndices), nbTexCoords(info.nbTexCoords), currentVertexIndex(0), currentColorIndex(0), currentTexCoordIndex(0), currentLock(NO_LOCK), vertexBuffer(NULL), colorBuffer(NULL), texCoordBuffer(NULL), indexBuffer(NULL), ptrVertexBuffer(NULL), ptrColorBuffer(NULL), ptrTexCoordBuffer(NULL), ptrIndexBuffer(NULL) { SPK_ASSERT(nbVertices > 0,"DX9Buffer::DX9Buffer(BufferInfo) - The number of vertices cannot be 0"); DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DXVECTOR3), D3DUSAGE_DYNAMIC, D3DFVF_XYZ, D3DPOOL_DEFAULT, &vertexBuffer, NULL); DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DCOLOR), D3DUSAGE_DYNAMIC, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &colorBuffer, NULL); // TODO : gérer les indices 32bit if( nbIndices > 0 ) { DX9Info::getDevice()->CreateIndexBuffer(nbIndices*sizeof(short), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, 0); unsigned int offsetIndex = 0; lock(INDEX_LOCK); // initialisation de l'index buffer for(size_t i = 0; i < nbIndices/6; i++) { //#ifdef _DX9QUADRENDERER_CLOCKWISE_ *(ptrIndexBuffer++) = 0 + offsetIndex; *(ptrIndexBuffer++) = 1 + offsetIndex; *(ptrIndexBuffer++) = 2 + offsetIndex; *(ptrIndexBuffer++) = 0 + offsetIndex; *(ptrIndexBuffer++) = 2 + offsetIndex; *(ptrIndexBuffer++) = 3 + offsetIndex; // TODO handle counter clockwise //#else // *(ptrIndexBuffer++) = 0 + offsetIndex; // *(ptrIndexBuffer++) = 2 + offsetIndex; // *(ptrIndexBuffer++) = 1 + offsetIndex; // *(ptrIndexBuffer++) = 0 + offsetIndex; // *(ptrIndexBuffer++) = 3 + offsetIndex; // *(ptrIndexBuffer++) = 2 + offsetIndex; //#endif offsetIndex += 4; } unlock(); } // TODO : gérer autre chose que les textures 2D if(nbTexCoords > 0) DX9Info::getDevice()->CreateVertexBuffer(nbVertices*sizeof(D3DXVECTOR2), D3DUSAGE_DYNAMIC, D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE1(nbTexCoords), D3DPOOL_DEFAULT, &texCoordBuffer, NULL); }
void Group::setLifeTime(float minLifeTime,float maxLifeTime) { SPK_ASSERT(minLifeTime > 0.0f && maxLifeTime > 0.0f,"Group::setLifeTime(float,float) - Life times must not be set to negative values"); if (minLifeTime <= maxLifeTime) { this->minLifeTime = minLifeTime; this->maxLifeTime = maxLifeTime; } else { SPK_LOG_WARNING("Group::setEnergy(float,float) - minEnergy is higher than maxEnergy - Values are swapped"); this->minLifeTime = maxLifeTime; this->maxLifeTime = minLifeTime; } }
void DX9LineRenderer::render(const Group& group,const DataSet* dataSet,RenderBuffer* renderBuffer) const { SPK_ASSERT(renderBuffer != NULL,"DX9LinesRenderer::render(const Group&,const DataSet*,RenderBuffer*) - renderBuffer must not be NULL"); DX9Buffer& buffer = static_cast<DX9Buffer&>(*renderBuffer); buffer.positionAtStart(); initBlending(); initRenderingOptions(); DX9Info::getDevice()->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); for (ConstGroupIterator particleIt(group); !particleIt.end(); ++particleIt) { const Particle& particle = *particleIt; buffer.setNextVertex(particle.position()); buffer.setNextVertex(particle.position() + particle.velocity() * length); buffer.setNextColor(particle.getColor()); buffer.setNextColor(particle.getColor()); } buffer.render(D3DPT_LINELIST, group.getNbParticles()); }
void Collider::modify(Group& group,DataSet* dataSet,float deltaTime) const { float groupSqrRadius = group.getPhysicalRadius() * group.getPhysicalRadius(); SPK_ASSERT(group.getOctree() != NULL,"GLQuadRenderer::render(const Group&,const DataSet*,RenderBuffer*) - renderBuffer must not be NULL"); const Octree& octree = *group.getOctree(); for (GroupIterator particleIt0(group); !particleIt0.end(); ++particleIt0) { Particle& particle0 = *particleIt0; float radius0 = particle0.getParam(PARAM_SCALE); float m0 = particle0.getParam(PARAM_MASS); size_t index0 = particle0.getIndex(); const Octree::Array<size_t>& neighborCells = octree.getNeighborCells(index0); size_t nbCells = neighborCells.size(); for (size_t i = 0; i < nbCells; ++i) // For each neighboring cell in the octree { const Octree::Cell& cell = octree.getCell(neighborCells[i]); size_t nbParticleInCells = cell.particles.size(); for (size_t j = 0; j < nbParticleInCells; ++j) // for each particles in the cell { size_t index1 = cell.particles[j]; if (index1 >= index0) break; // as particle are ordered Particle particle1 = group.getParticle(index1); float radius1 = particle1.getParam(PARAM_SCALE); float sqrRadius = radius0 + radius1; sqrRadius *= sqrRadius * groupSqrRadius; // Gets the normal of the collision plane Vector3D normal = particle0.position() - particle1.position(); float sqrDist = normal.getSqrNorm(); if (sqrDist < sqrRadius) // particles are intersecting each other { Vector3D delta = particle0.velocity() - particle1.velocity(); if (dotProduct(normal,delta) < 0.0f) // particles are moving towards each other { float oldSqrDist = getSqrDist(particle0.oldPosition(),particle1.oldPosition()); if (oldSqrDist > sqrDist) { // Disables the move from this frame particle0.position() = particle0.oldPosition(); particle1.position() = particle1.oldPosition(); normal = particle0.position() - particle1.position(); if (dotProduct(normal,delta) >= 0.0f) continue; } normal.normalize(); // Gets the normal components of the velocities Vector3D normal0 = normal * dotProduct(normal,particle0.velocity()); Vector3D normal1 = normal * dotProduct(normal,particle1.velocity()); // Resolves collision float m1 = particle1.getParam(PARAM_MASS); if (oldSqrDist < sqrRadius && sqrDist < sqrRadius) { // Tweak to separate particles that intersects at both t - deltaTime and t // In that case the collision is no more considered as punctual if (dotProduct(normal,normal0) < 0.0f) { particle0.velocity() -= normal0; particle1.velocity() += normal0; } if (dotProduct(normal,normal1) > 0.0f) { particle1.velocity() -= normal1; particle0.velocity() += normal1; } } else { // Else classic collision equations are applied // Tangent components of the velocities are left untouched float elasticityM0 = elasticity * m0; float elasticityM1 = elasticity * m1; float invM01 = 1 / (m0 + m1); particle0.velocity() -= (1.0f + (elasticityM1 - m0) * invM01) * normal0; particle1.velocity() -= (1.0f + (elasticityM0 - m1) * invM01) * normal1; normal0 *= (elasticityM0 + m0) * invM01; normal1 *= (elasticityM1 + m0) * invM01; particle0.velocity() += normal1; particle1.velocity() += normal0; } } } } } } }
void Emitter::setFlow(float flow) { SPK_ASSERT(flow >= 0.0f || currentTank >= 0,"Emitter::setFlow(float) : the flow and tank of an emitter cannot be both negative"); this->flow = flow; }
void GLQuadRenderer::render(const Group& group,const DataSet* dataSet,RenderBuffer* renderBuffer) const { SPK_ASSERT(renderBuffer != NULL,"GLQuadRenderer::render(const Group&,const DataSet*,RenderBuffer*) - renderBuffer must not be NULL"); GLBuffer& buffer = static_cast<GLBuffer&>(*renderBuffer); buffer.positionAtStart(); // Repositions all the buffers at the start float oldModelView[16]; for (int i = 0; i < 16; ++i) oldModelView[i] = modelView[i]; glGetFloatv(GL_MODELVIEW_MATRIX,modelView); for (int i = 0; i < 16; ++i) if (oldModelView[i] != modelView[i]) { invertModelView(); break; } initBlending(); initRenderingOptions(); glShadeModel(GL_FLAT); switch(texturingMode) { case TEXTURE_MODE_2D : // Creates and inits the 2D TexCoord buffer if necessary if (buffer.getNbTexCoords() != 2) { buffer.setNbTexCoords(2); if (!group.isEnabled(PARAM_TEXTURE_INDEX)) { float t[8] = {1.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f}; for (size_t i = 0; i < group.getCapacity() << 3; ++i) buffer.setNextTexCoord(t[i & 7]); } } // Binds the texture #ifndef SPK_GL_NO_EXT if (SPK_GL_CHECK_EXTENSION(SPK_GL_TEXTURE_3D_EXT)) glDisable(GL_TEXTURE_3D_EXT); #endif glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,textureIndex); // Selects the correct function if (!group.isEnabled(PARAM_TEXTURE_INDEX)) { if (!group.isEnabled(PARAM_ANGLE)) renderParticle = &GLQuadRenderer::render2D; else renderParticle = &GLQuadRenderer::render2DRot; } else { if (!group.isEnabled(PARAM_ANGLE)) renderParticle = &GLQuadRenderer::render2DAtlas; else renderParticle = &GLQuadRenderer::render2DAtlasRot; } break; case TEXTURE_MODE_3D : // Creates and inits the 3D TexCoord buffer if necessery if (buffer.getNbTexCoords() != 3) { buffer.setNbTexCoords(3); float t[12] = {1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f}; for (size_t i = 0; i < group.getCapacity() * 12; ++i) buffer.setNextTexCoord(t[i % 12]); } // Binds the texture glDisable(GL_TEXTURE_2D); #ifndef SPK_GL_NO_EXT glEnable(GL_TEXTURE_3D_EXT); glBindTexture(GL_TEXTURE_3D_EXT,textureIndex); #endif // Selects the correct function if (!group.isEnabled(PARAM_ANGLE)) renderParticle = &GLQuadRenderer::render3D; else renderParticle = &GLQuadRenderer::render3DRot; break; case TEXTURE_MODE_NONE : if (buffer.getNbTexCoords() != 0) buffer.setNbTexCoords(0); glDisable(GL_TEXTURE_2D); // Selects the correct function #ifndef SPK_GL_NO_EXT if (SPK_GL_CHECK_EXTENSION(SPK_GL_TEXTURE_3D_EXT)) glDisable(GL_TEXTURE_3D_EXT); #endif if (!group.isEnabled(PARAM_ANGLE)) renderParticle = &GLQuadRenderer::render2D; else renderParticle = &GLQuadRenderer::render2DRot; break; } bool globalOrientation = precomputeOrientation3D( group, Vector3D(-invModelView[8],-invModelView[9],-invModelView[10]), Vector3D(invModelView[4],invModelView[5],invModelView[6]), Vector3D(invModelView[12],invModelView[13],invModelView[14])); // Fills the buffers if (globalOrientation) { computeGlobalOrientation3D(group); for (ConstGroupIterator particleIt(group); !particleIt.end(); ++particleIt) (this->*renderParticle)(*particleIt,buffer); } else { for (ConstGroupIterator particleIt(group); !particleIt.end(); ++particleIt) { computeSingleOrientation3D(*particleIt); (this->*renderParticle)(*particleIt,buffer); } } buffer.render(GL_QUADS,group.getNbParticles() << 2); }
const Particle Group::getParticle(size_t index) const { SPK_ASSERT(index < particleData.nbParticles,"Group::getParticle(size_t) - Particle index is out of bounds : " << index); return Particle(const_cast<Group&>(*this),index); }
const Ref<Action>& ActionSet::getAction(size_t index) const { SPK_ASSERT(index <= getNbActions(),"ActionSet::getAction(size_t) - Action index is out of bounds : " << index); return actions[index]; }