// // RenderableParticleEffectEntityItem.cpp // interface/src // // Created by Jason Rickwald on 3/2/15. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include #include #include #include #include #include #include "EntitiesRendererLogging.h" #include "RenderableParticleEffectEntityItem.h" EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return EntityItemPointer(new RenderableParticleEffectEntityItem(entityID, properties)); } RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : ParticleEffectEntityItem(entityItemID, properties) { _cacheID = DependencyManager::get()->allocateID(); } void RenderableParticleEffectEntityItem::render(RenderArgs* args) { Q_ASSERT(getType() == EntityTypes::ParticleEffect); PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render"); if (_texturesChangedFlag) { if (_textures.isEmpty()) { _texture.clear(); } else { // for now use the textures string directly. // Eventually we'll want multiple textures in a map or array. _texture = DependencyManager::get()->getTexture(_textures); } _texturesChangedFlag = false; } bool textured = _texture && _texture->isLoaded(); updateQuads(args, textured); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; if (textured) { batch.setUniformTexture(0, _texture->getGPUTexture()); } batch.setModelTransform(getTransformToCenter()); DependencyManager::get()->bindSimpleProgram(batch, textured); DependencyManager::get()->renderVertices(batch, gpu::QUADS, _cacheID); }; static glm::vec3 zSortAxis; static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) { return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis); } void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool textured) { float particleRadius = getParticleRadius(); glm::vec4 particleColor(toGlm(getXColor()), getLocalRenderAlpha()); glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius; glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius; QVector vertices; QVector positions; QVector textureCoords; vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); if (textured) { textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); } positions.reserve(getLivingParticleCount()); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { positions.append(_particlePositions[i]); if (textured) { textureCoords.append(glm::vec2(0, 1)); textureCoords.append(glm::vec2(1, 1)); textureCoords.append(glm::vec2(1, 0)); textureCoords.append(glm::vec2(0, 0)); } } // sort particles back to front ::zSortAxis = args->_viewFrustum->getDirection(); qSort(positions.begin(), positions.end(), zSort); for (int i = 0; i < positions.size(); i++) { glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i]; // generate corners of quad aligned to face the camera. vertices.append(pos + rightOffset + upOffset); vertices.append(pos - rightOffset + upOffset); vertices.append(pos - rightOffset - upOffset); vertices.append(pos + rightOffset - upOffset); } if (textured) { DependencyManager::get()->updateVertices(_cacheID, vertices, textureCoords, particleColor); } else { DependencyManager::get()->updateVertices(_cacheID, vertices, particleColor); } }