// // ParticleSystemRenderer.cpp // cocos2d_libs // // Created by 徐俊杰 on 2020/4/24. // #include "rparticle/ParticleSystemRenderer.h" #include "rparticle/ParticleSystemParticle.h" #include "rparticle/Utilities/StrideIterator.h" #include "rparticle/Macros/RParticleGlobalStuff.h" #include "rparticle/Utilities/Transform.h" #include "2d/CCCamera.h" #include "base/ccMacros.h" #include "renderer/ccGLStateCache.h" #include "renderer/CCGLProgram.h" #include "renderer/CCRenderer.h" #include #include "rparticle/Serialize/TransferFunctions/SerializeTransfer.h" using namespace cocos2d; NS_RRP_BEGIN //PROFILER_INFORMATION(gParticlesSort, "ParticleSystem.Sort", kProfilerParticles) //PROFILER_INFORMATION(gParticlesSingleProfile, "ParticleSystem.RenderSingle", kProfilerParticles) //PROFILER_INFORMATION(gParticlesBatchProfile, "ParticleSystem.RenderBatch", kProfilerParticles) //PROFILER_INFORMATION(gSubmitVBOParticleProfile, "Mesh.SubmitVBO", kProfilerRender) enum { kMaxQuads = 65536/4 - 4 }; // so we fit into 16 bit indices, minus some more just in case #define DEBUG_PARTICLE_SORTING (0) #if UNITY_WII #define kMaxNumParticlesPerBatch (65536/6) #else #define kMaxNumParticlesPerBatch (std::min(kDynamicBatchingIndicesThreshold/6, kMaxQuads)) #endif //struct ParticleSystemVertex //{ // Vector3f vert; // Vector3f normal; // ColorRGBAf color; // Vector2f uv; // Vector4f tangent; // Here, we put 2nd uv + blend factor //}; struct ParticleSystemGeomConstInputData { Matrix4x4f m_ViewMatrix; Vector3f m_CameraVelocity; //Object* m_Renderer; UInt16 const* m_MeshIndexBuffer[ParticleSystemRendererData::kMaxNumParticleMeshes]; int m_MeshIndexCount[ParticleSystemRendererData::kMaxNumParticleMeshes]; int m_NumTilesX; int m_NumTilesY; float maxPlaneScale; float maxOrthoSize; float numUVFrame; float animUScale; float animVScale; Vector3f xSpan; Vector3f ySpan; bool usesSheetIndex; int uvModuleMode; float bentNormalFactor; Vector3f bentNormalVector; bool isSpriteFrame; RRP_PARTICLEQUAD_VERTEX_INFO* vertexInfo; Vector3f globalScale; }; inline void ScaleMatrix(Matrix4x4f& matrix, float scale) { matrix.m[0] *= scale; matrix.m[1] *= scale; matrix.m[2] *= scale; matrix.m[4] *= scale; matrix.m[5] *= scale; matrix.m[6] *= scale; matrix.m[8] *= scale; matrix.m[9] *= scale; matrix.m[10] *= scale; } static ParticleSystemVertex* _vbPtr = nullptr; struct ParticleSort { inline static void SetValues(ParticleSort& sort, UInt32 inIndex, int inIntValue) { sort.index = inIndex; sort.intValue = inIntValue; } inline static bool CompareValue (const ParticleSort& left, const ParticleSort& right) { return (left.intValue < right.intValue); } inline static void Swap(ParticleSort* oneOfThem, ParticleSort* theOtherOne) { ParticleSort temp = *oneOfThem; *oneOfThem = *theOtherOne; *theOtherOne = temp; } UInt32 index; int intValue; }; //bool ParticleSystemRenderer::init(){ // //if(!Node::init()){ // // return false; // //} // //this->setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR)); // return true; //} //ParticleSystemRenderer* ParticleSystemRenderer::create() { // ParticleSystemRenderer * ret = new (std::nothrow) ParticleSystemRenderer(); // if (ret && ret->init()) { // //ret->autorelease(); // } else { // CC_SAFE_DELETE(ret); // } // return ret; //} void GenerateSortIndices(ParticleSort* indices, const Vector3f& distFactor, const ParticleSystemParticles& ps, ParticleSystemSortMode sortMode) { const size_t particleCount = ps.array_size(); if(sortMode == kSSMByDistance) for(int i = 0; i < particleCount; i++) ParticleSort::SetValues(indices[i], i, (int)(Dot (distFactor, ps.position[i]) * 40000.0f)); else if(sortMode == kSSMOldestFirst) for(int i = 0; i < particleCount; i++) ParticleSort::SetValues(indices[i], i, (int)((ps.startLifetime[i]- ps.lifetime[i]) * -40000.0f)); else if(sortMode == kSSMYoungestFirst) for(int i = 0; i < particleCount; i++) ParticleSort::SetValues(indices[i], i, (int)((ps.startLifetime[i]- ps.lifetime[i]) * 40000.0f)); } template void ApplySortRemap(ParticleSort* particleSortIndexBuffer, ParticleSystemParticlesTempData* tempData, ParticleSystemParticles& ps) { const size_t count = ps.array_size(); for(int i = 0; i < count; i++) { int dst = particleSortIndexBuffer[i].intValue; while(i != dst) { ParticleSort::Swap(&particleSortIndexBuffer[i], &particleSortIndexBuffer[dst]); ps.element_swap(i, dst); if(sortTempData) tempData->element_swap(i, dst); dst = particleSortIndexBuffer[i].intValue; } } } void Sort (const Matrix4x4f& matrix, ParticleSystemParticles& ps, ParticleSystemSortMode mode, ParticleSystemParticlesTempData* tempData, bool sortTempData) { //PROFILER_AUTO_GFX(gParticlesSort, 0); DebugAssert(mode != kSSMNone); const Vector3f distFactor = Vector3f (matrix.Get (2, 0), matrix.Get (2, 1), + matrix.Get (2, 2)); const size_t count = ps.array_size(); ParticleSort* particleSortIndexBuffer; //ALLOC_TEMP(particleSortIndexBuffer, ParticleSort, count); particleSortIndexBuffer = (ParticleSort*)malloc(sizeof(ParticleSort) * count); GenerateSortIndices(&particleSortIndexBuffer[0], distFactor, ps, mode); // Sort std::sort(&particleSortIndexBuffer[0], &particleSortIndexBuffer[0] + count, ParticleSort::CompareValue); // Create inverse mapping for(int i = 0; i < count; i++) particleSortIndexBuffer[particleSortIndexBuffer[i].index].intValue = i; if(sortTempData) ApplySortRemap(particleSortIndexBuffer, tempData, ps); else ApplySortRemap(particleSortIndexBuffer, tempData, ps); free(particleSortIndexBuffer); } struct ParticleMeshData { int vertexCount; StrideIterator positions; StrideIterator normals; StrideIterator tangents; StrideIterator colors; StrideIterator texCoords; int indexCount; const UInt16* indexBuffer; }; template void TransformParticleMesh(const ParticleMeshData& src, ColorRGBA32 particleColor, const Matrix4x4f& xform, const Matrix4x4f& xformNoScale, UInt8** dest) { for(int vertex = 0; vertex < src.vertexCount; vertex++) { // Vertex format is position, color, uv, and optional normals and tangents xform.MultiplyPoint3(src.positions[vertex], *reinterpret_cast(*dest)); *dest += sizeof(Vector3f); if (hasNormals) { xformNoScale.MultiplyVector3(src.normals[vertex], *reinterpret_cast(*dest)); *dest += sizeof(Vector3f); } auto tempColor = particleColor; tempColor *= src.colors[vertex]; *reinterpret_cast(*dest) = tempColor; *dest += sizeof(ColorRGBA32); *reinterpret_cast(*dest) = src.texCoords[vertex]; *dest += sizeof(Vector2f); // Tangent is last in vertex format if (hasTangents) { Vector3f newTangent = xformNoScale.MultiplyVector3((const Vector3f&)src.tangents[vertex]); //*reinterpret_cast(*dest) = Vector4f(newTangent, src.tangents[vertex].w); *reinterpret_cast(*dest) = Vector4f(newTangent.x, newTangent.y, newTangent.z, src.tangents[vertex].w); *dest += sizeof(Vector4f); } } } ParticleSystemRenderer::ParticleSystemRenderer (/*MemLabelId label, ObjectCreationMode mode*/) //: Super(kRendererParticleSystem, label, mode) : m_LocalSpaceAABB (Vector3f::ZERO, Vector3f::ZERO) { //setName(COMPONENT_PS_RENDERER); //SetVisible (false); //for (int i = 0; i < ParticleSystemRendererData::kMaxNumParticleMeshes; ++i) // m_Data.cachedMeshUserNode[i].SetData (this); #if UNITY_EDITOR m_EditorEnabled = true; #endif } ParticleSystemRenderer::~ParticleSystemRenderer () { } //void ParticleSystemRenderer::InitializeClass () //{ // REGISTER_MESSAGE_PTR (ParticleSystemRenderer, kDidDeleteMesh, OnDidDeleteMesh, Mesh); //} //void ParticleSystemRenderer::AwakeFromLoad (AwakeFromLoadMode awakeMode) //{ // Super::AwakeFromLoad (awakeMode); // UpdateCachedMesh (); //} //void ParticleSystemRenderer::UpdateCachedMesh () //{ // int dst = 0; // for(int src = 0; src < ParticleSystemRendererData::kMaxNumParticleMeshes; src++) // { // m_Data.cachedMesh[src] = NULL; // m_Data.cachedMeshUserNode[src].RemoveFromList (); // // Mesh* mesh = m_Mesh[src]; // if (mesh) // { // if (mesh->GetSubMeshCount() == 1) // { // m_Data.cachedMesh[dst] = mesh; // const SubMesh& sm = mesh->GetSubMeshFast(0); // const UInt16* buffer = mesh->GetSubMeshBuffer16(0); // // if (sm.topology == kPrimitiveTriangleStripDeprecated) // { // const int capacity = CountTrianglesInStrip(buffer, sm.indexCount) * 3; // m_CachedIndexBuffer[dst].resize_uninitialized(capacity); // Destripify(buffer, sm.indexCount, m_CachedIndexBuffer[dst].begin(), capacity); // } // else if (sm.topology == kPrimitiveTriangles) // { // const int capacity = sm.indexCount; // m_CachedIndexBuffer[dst].resize_uninitialized(capacity); // memcpy(m_CachedIndexBuffer[dst].begin(), buffer, capacity*kVBOIndexSize); // } // else // { // m_CachedIndexBuffer[dst].resize_uninitialized(0); // } // // // Hook into mesh's user notifications. // mesh->AddObjectUser (m_Data.cachedMeshUserNode[dst]); // // dst++; // } // else // { // m_Data.cachedMesh[src] = NULL; // m_CachedIndexBuffer[src].resize_uninitialized(0); // AssertString ("Particle system meshes will only work with exactly one (1) sub mesh"); // } // } // } //} //void ParticleSystemRenderer::OnDidDeleteMesh (Mesh* mesh) //{ // // Clear out cached pointer to mesh. // for (int i = 0; i < ParticleSystemRendererData::kMaxNumParticleMeshes; ++i) // { // if (m_Data.cachedMesh[i] != mesh) // continue; // // m_Data.cachedMesh[i] = NULL; // m_Data.cachedMeshUserNode[i].RemoveFromList (); // } //} //void ParticleSystemRenderer::GetLocalAABB (AABB& result) //{ // result = m_LocalSpaceAABB; //} //void ParticleSystemRenderer::GetWorldAABB (AABB& result) //{ // TransformAABB (m_LocalSpaceAABB, GetTransform ().GetPosition (), GetTransform ().GetRotation (), result); //} float ParticleSystemRenderer::GetSortingFudge () const { return m_Data.sortingFudge; } //void ParticleSystemRenderer::CheckConsistency () //{ // Super::CheckConsistency (); // m_Data.maxParticleSize = std::max (0.0F, m_Data.maxParticleSize); // m_Data.normalDirection = clamp(m_Data.normalDirection, 0.0f, 1.0f); //} void ParticleSystemRenderer::Reset () { //Super::Reset (); m_Data.orthographic = false; m_Data.scale = 1.0F; m_Data.renderMode = kSRMBillboard; m_Data.lengthScale = 2.0F; m_Data.velocityScale = 0.0F; m_Data.cameraVelocityScale = 0.0F; m_Data.maxParticleSize = 0.5F; m_Data.sortingFudge = 0.0F; m_Data.sortMode = kSSMNone; m_Data.normalDirection = 1.0f; //for(int i = 0; i < ParticleSystemRendererData::kMaxNumParticleMeshes; i++) // m_Mesh[i] = NULL; //m_LocalSpaceAABB.SetCenterAndExtent (Vector3f::ZERO, Vector3f::ZERO); m_LocalSpaceAABB.set(Vector3f::ZERO, Vector3f::ZERO); #if UNITY_EDITOR m_EditorEnabled = true; #endif } //void ParticleSystemRenderer::UpdateRenderer () //{ // ParticleSystem* system = QueryComponent(ParticleSystem); // if (system) // { // SetVisible (true); // BoundsChanged(); // } // else // { // UpdateManagerState (false); // } // // Super::UpdateRenderer (); //} //void ParticleSystemRenderer::Update (const AABB& aabb) //{ // m_LocalSpaceAABB = aabb; // UpdateManagerState (true); //} void ParticleSystemRenderer::RendererBecameVisible() { //Super::RendererBecameVisible(); //ParticleSystem* system = QueryComponent(ParticleSystem); //if(system) // system->RendererBecameVisible(); } void ParticleSystemRenderer::RendererBecameInvisible() { //Super::RendererBecameInvisible(); //ParticleSystem* system = QueryComponent(ParticleSystem); //if(system) // system->RendererBecameInvisible(); } //void ParticleSystemRenderer::UpdateLocalAABB() //{ // AABB aabb; // GetLocalAABB(aabb); // m_TransformInfo.localAABB = aabb; //} template void GenerateParticleGeometry (ParticleSystemVertex* vbPtr, const ParticleSystemGeomConstInputData& constData, const ParticleSystemRendererData& rendererData, const ParticleSystemParticles& ps, const ParticleSystemParticlesTempData& psTemp, size_t startIndex, size_t endIndex, const Matrix4x4f& worldViewMatrix, const Matrix4x4f& viewToWorldMatrix) { float maxPlaneScale = constData.maxPlaneScale; float maxOrthoSize = constData.maxOrthoSize; float numUVFrame = constData.numUVFrame; Vector3f xSpan = constData.xSpan; Vector3f ySpan = constData.ySpan; Vector3f cameraVelocity = constData.m_CameraVelocity * rendererData.cameraVelocityScale; int numTilesX = constData.m_NumTilesX; float animUScale = constData.animUScale; float animVScale = constData.animVScale; bool usesSheetIndex = constData.usesSheetIndex; int uvModuleMode = constData.uvModuleMode; float lengthScale = rendererData.lengthScale; float velocityScale = rendererData.velocityScale; float bentNormalFactor = constData.bentNormalFactor; Vector3f bentNormalVector = constData.bentNormalVector; bool isSpriteFrame = constData.isSpriteFrame; const RRP_PARTICLEQUAD_VERTEX_INFO* vertexInfo = constData.vertexInfo; auto frameCount = rendererData.cachedVertexInfos.size(); Matrix3x3f scaleMatrix; scaleMatrix.SetScale(constData.globalScale); // Vector2f uv[4] = { Vector2f(0.0f, 1.0f), // Vector2f(1.0f, 1.0f), // Vector2f(1.0f, 0.0f), // Vector2f(0.0f, 0.0f)}; // Vector4f uv2[4] = { Vector4f(0.0f, 1.0f, 0.0f, 0.0f), // Vector4f(1.0f, 1.0f, 0.0f, 0.0f), // Vector4f(1.0f, 0.0f, 0.0f, 0.0f), // Vector4f(0.0f, 0.0f, 0.0f, 0.0f)}; Tex2F uv[4] = { vertexInfo->tl, vertexInfo->tr, vertexInfo->br, vertexInfo->bl }; float invAnimVScale = 1.0f - animVScale; #if REDREAM_EDITOR auto stageContentToWorldMatrix = Transform::GetContentToWorldMatrix(); #endif for( size_t i = startIndex; i < endIndex; ++i ) { if (usesSheetIndex && uvModuleMode == 1 && frameCount > 0) { auto sheetIndex = psTemp.sheetIndex[i] * frameCount; const int index0 = FloorfToIntPos (sheetIndex); vertexInfo = &rendererData.cachedVertexInfos[index0]; uv[0] = vertexInfo->tl, uv[1] = vertexInfo->tr; uv[2] = vertexInfo->br; uv[3] = vertexInfo->bl; } Vector3f vert[4]; Vector3f n0, n1; Vector3f position; worldViewMatrix.MultiplyPoint3 (ps.position[i], position); // Constrain the size to be a fraction of the viewport size. // v[0].z * / farPlaneZ * farPlaneWorldSpaceLength * maxLength[0...1] // Also all valid z's are negative so we just negate the whole equation // float maxWorldSpaceLength = position.z * maxPlaneScale + maxOrthoSize; // float hsize = std::min (psTemp.size[i], maxWorldSpaceLength) * 0.5f; float hsize = psTemp.size[i] * 0.5f; if (renderMode == kSRMBillboard) { float r = ps.rotation[i] * kDeg2Rad; float s = Sin (r); float c = Cos (r); if (isSpriteFrame) { GLfloat x1 = -hsize * vertexInfo->centerPercentage.left; GLfloat y1 = -hsize * vertexInfo->centerPercentage.bottom; GLfloat x2 = hsize * vertexInfo->centerPercentage.right; GLfloat y2 = hsize * vertexInfo->centerPercentage.top; vert[0] = position + scaleMatrix.MultiplyVector3(Vec3(x1 * c + y2 * s, y2 * c - x1 * s, 0.0f)); vert[1] = position + scaleMatrix.MultiplyVector3(Vec3(x2 * c + y2 * s, y2 * c - x2 * s, 0.0f)); vert[2] = position + scaleMatrix.MultiplyVector3(Vec3(x2 * c + y1 * s, y1 * c - x2 * s, 0.0f)); vert[3] = position + scaleMatrix.MultiplyVector3(Vec3(x1 * c + y1 * s, y1 * c - x1 * s, 0.0f)); } else { n0 = scaleMatrix.MultiplyVector3(Vector3f(-c+s, s+c, 0.0f) * hsize); n1 = scaleMatrix.MultiplyVector3(Vector3f( c+s, -s+c, 0.0f) * hsize); vert[0] = position + n0; vert[1] = position + n1; vert[2] = position - n0; vert[3] = position - n1; } } else if (renderMode == kSRMBillboardFixedHorizontal || renderMode == kSRMBillboardFixedVertical) { float s = Sin ((ps.rotation[i]+0.78539816339744830961566084581988f) * kDeg2Rad); float c = Cos ((ps.rotation[i]+0.78539816339744830961566084581988f) * kDeg2Rad); n0 = scaleMatrix.MultiplyVector3((xSpan*c + ySpan*s) * hsize); n1 = scaleMatrix.MultiplyVector3((ySpan*c - xSpan*s) * hsize); vert[0] = position + n0; vert[1] = position + n1; vert[2] = position - n0; vert[3] = position - n1; } else if (renderMode == kSRMStretch3D) { //RH BUG FOR LATER: Here we see the stretching bug as described by case no 434115...this is a Flash VM error, where a writeFloat (or readFloat) fails. Vector3f velocity; worldViewMatrix.MultiplyVector3(ps.velocity[i] + ps.animatedVelocity[i], velocity); velocity -= cameraVelocity; float sqrVelocity = SqrMagnitude (velocity); auto camPos = Camera::getDefaultCamera()->getPosition3D(); position -= camPos; Vector2f delta; Vector3f endProj; bool nonZeroVelocity = sqrVelocity > Vector3f::epsilon; if (nonZeroVelocity) { endProj = position - velocity * (velocityScale + FastInvSqrt (sqrVelocity) * (lengthScale * psTemp.size[i])); delta.x = position.z*endProj.y - position.y*endProj.z; delta.y = position.x*endProj.z - position.z*endProj.x; delta = NormalizeFast(delta); } else { endProj = position; delta = Vector2f::UNIT_X; } n0 = n1 = scaleMatrix.MultiplyVector3(Vector3f(delta.x, delta.y, 0.0f) * hsize); if (isSpriteFrame) { n0 *= vertexInfo->centerPercentage.top; n1 *= vertexInfo->centerPercentage.bottom; auto posTemp = position; position = endProj.lerp(position, vertexInfo->centerPercentage.left * 0.5f + 0.5f); endProj = posTemp.lerp(endProj, vertexInfo->centerPercentage.right * 0.5f + 0.5f); } position += camPos; endProj += camPos; vert[0] = position + n0; vert[1] = endProj + n0; vert[2] = endProj - n1; vert[3] = position - n1; } // UV animation float sheetIndex; if(usesSheetIndex && uvModuleMode == 0 && !isSpriteFrame) { // TODO: Pretty much the perfect candidate for SIMD sheetIndex = psTemp.sheetIndex[i] * numUVFrame; Assert (psTemp.sheetIndex[i] >= 0.0f && psTemp.sheetIndex[i] <= 1.0f); const int index0 = FloorfToIntPos (sheetIndex); const int index1 = index0 + 1; Vector2f offset0, offset1; const float blend = sheetIndex - (float)index0; int vIdx = index0 / numTilesX; int uIdx = index0 - vIdx * numTilesX; offset0.x = (float)uIdx * animUScale; // offset0.y = invAnimVScale - (float)vIdx * animVScale; offset0.y = (float)vIdx * animVScale; vIdx = index1 / numTilesX; uIdx = index1 - vIdx * numTilesX; offset1.x = (float)uIdx * animUScale; // offset1.y = invAnimVScale - (float)vIdx * animVScale; offset1.y = (float)vIdx * animVScale; // uv[0].set(offset0.x, offset0.y + animVScale ); // uv[1].set(offset0.x + animUScale, offset0.y + animVScale ); // uv[2].set(offset0.x + animUScale, offset0.y ); // uv[3].set(offset0.x, offset0.y ); uv[0].u = offset0.x; uv[0].v = offset0.y; // invers v, top-left uv[1].u = offset0.x + animUScale; uv[1].v = offset0.y; // invers v, top-right uv[2].u = offset0.x + animUScale; uv[2].v = offset0.y + animVScale; // invers v, bottom-right uv[3].u = offset0.x; uv[3].v = offset0.y + animVScale; // invers v, bottom-left // uv2[0].set(offset1.x, offset1.y + animVScale, blend, 0.0f ); // uv2[1].set(offset1.x + animUScale, offset1.y + animVScale, blend, 0.0f ); // uv2[2].set(offset1.x + animUScale, offset1.y, blend, 0.0f ); // uv2[3].set(offset1.x, offset1.y, blend, 0.0f ); } n0 = viewToWorldMatrix.MultiplyVector3(n0 * bentNormalFactor); n1 = viewToWorldMatrix.MultiplyVector3(n1 * bentNormalFactor); // ColorRGBAf color = ColorRGBAf(psTemp.color[i]); auto& color = psTemp.color[i]; #if REDREAM_EDITOR for (int i = 0; i < 4; i++) { vert[i] = stageContentToWorldMatrix.MultiplyPoint3(vert[i]); } #endif vbPtr->tl.vertices = vert[0]; // vbPtr[0].normal = bentNormalVector + n0; vbPtr->tl.colors = color; vbPtr->tl.texCoords = Tex2F(uv[0]); // vbPtr[0].tangent = uv2[0]; vbPtr->tr.vertices = vert[1]; // vbPtr[1].normal = bentNormalVector + n1; vbPtr->tr.colors = color; vbPtr->tr.texCoords = Tex2F(uv[1]); // vbPtr[1].tangent = uv2[1]; vbPtr->br.vertices = vert[2]; // vbPtr[2].normal = bentNormalVector - n0; vbPtr->br.colors = color; vbPtr->br.texCoords = Tex2F(uv[2]); // vbPtr[2].tangent = uv2[2]; vbPtr->bl.vertices = vert[3]; // vbPtr[3].normal = bentNormalVector - n1; vbPtr->bl.colors = color; vbPtr->bl.texCoords = Tex2F(uv[3]); // vbPtr[3].tangent = uv2[3]; // Next four vertices // vbPtr += 4; vbPtr++; } } //static void DrawMeshParticles (const ParticleSystemGeomConstInputData& constInput, const ParticleSystemRendererData& rendererData, const Matrix4x4f& worldMatrix, const ParticleSystemParticles& ps, const ParticleSystemParticlesTempData& psTemp, const ChannelAssigns& channels) //{ // int numMeshes = 0; // ParticleMeshData particleMeshes[ParticleSystemRendererData::kMaxNumParticleMeshes]; // Vector3f defaultNormal(0, 0, 0); // Vector4f defaultTangent(0, 0, 0, 0); // ColorRGBA32 defaultColor(255, 255, 255, 255); // Vector2f defaultTexCoords(0, 0); // for(int i = 0; i < ParticleSystemRendererData::kMaxNumParticleMeshes; i++) // { // if(constInput.m_MeshIndexCount[i] == 0) // break; // const Mesh* mesh = rendererData.cachedMesh[i]; // if(mesh == NULL || !mesh->HasVertexData()) // break; // ParticleMeshData& dest = particleMeshes[i]; // dest.vertexCount = mesh->GetVertexCount(); // dest.positions = mesh->GetVertexBegin(); // dest.normals = mesh->GetNormalBegin(); // if (dest.normals.IsNull()) // dest.normals = StrideIterator(&defaultNormal, 0); // dest.tangents = mesh->GetTangentBegin(); // if (dest.tangents.IsNull()) // dest.tangents = StrideIterator(&defaultTangent, 0); // dest.texCoords = mesh->GetUvBegin(); // if (dest.texCoords.IsNull()) // dest.texCoords = StrideIterator(&defaultTexCoords, 0); // dest.colors = mesh->GetColorBegin(); // if (dest.colors.IsNull()) // dest.colors = StrideIterator(&defaultColor, 0); // dest.indexCount = constInput.m_MeshIndexCount[i]; // dest.indexBuffer = constInput.m_MeshIndexBuffer[i]; // numMeshes++; // } // // if(0 == numMeshes) // return; // // GfxDevice& device = GetGfxDevice(); // // Matrix4x4f viewMatrix; // CopyMatrix (device.GetViewMatrix (), viewMatrix.GetPtr ()); // // const size_t particleCount = ps.array_size (); // // float probability = 1.0f / (float)numMeshes; // // // @TODO: We should move all these platform dependent numbers into Gfx specific code and get it from there. // const int kMaxVertices = 65536; // //#if UNITY_WII // const int kMaxIndices = 65536; //#else // const int kMaxIndices = kDynamicBatchingIndicesThreshold; //#endif // // int particleOffset = 0; // while (particleOffset < particleCount) // { // int numVertices = 0; // int numIndices = 0; // int particleCountBatch = 0; // // // Figure out batch size // for(int i = particleOffset; i < particleCount; i++) // { // const float randomValue = GenerateRandom(ps.randomSeed[i] + kParticleSystemMeshSelectionId); // int lastNumVertices = 0; // int lastNumIndices = 0; // for(int j = 0; j < numMeshes; j++) // { // const float lower = probability * j; // const float upper = probability * (j + 1); // if((randomValue >= lower) && (randomValue <= upper)) // { // lastNumVertices = particleMeshes[j].vertexCount; // lastNumIndices = particleMeshes[j].indexCount; // break; // } // } // if((numVertices >= kMaxVertices) || (numIndices >= kMaxIndices)) // { // break; // } // else // { // numVertices += lastNumVertices; // numIndices += lastNumIndices; // particleCountBatch++; // } // } // // const int vertexCount = numVertices; // const int indexCount = numIndices; // // // Figure out if normals and tangents are needed by shader // UInt32 normalTangentMask = channels.GetSourceMap() & VERTEX_FORMAT2(Normal, Tangent); // // // Tangents requires normals // if( normalTangentMask & VERTEX_FORMAT1(Tangent) ) // normalTangentMask |= VERTEX_FORMAT1(Normal); // // // Get VBO chunk // DynamicVBO& vbo = device.GetDynamicVBO(); // UInt8* vbPtr = NULL; // UInt16* ibPtr = NULL; // const UInt32 mandatoryChannels = VERTEX_FORMAT3(Vertex, Color, TexCoord0); // if( !vbo.GetChunk( mandatoryChannels | normalTangentMask, // vertexCount, indexCount, // DynamicVBO::kDrawIndexedTriangles, // (void**)&vbPtr, (void**)&ibPtr ) ) // { // return; // } // // int vertexOffset = 0; // int indexOffset = 0; // const int startIndex = particleOffset; // const int endIndex = particleOffset + particleCountBatch; // for( int i = startIndex; i < endIndex; ++i ) // { // const Vector3f position = ps.position[i]; // const float rotation = ps.rotation[i]; // const float size = psTemp.size[i]; // const Vector3f axisOfRotation = NormalizeSafe (ps.axisOfRotation[i], Vector3f::yAxis); // const ColorRGBA32 particleColor = psTemp.color[i]; // // // Only shared part is actually rotation. xformNoScale doesn't need a translation, so no need to copy that data // Matrix4x4f xformNoScale; // xformNoScale.SetTR (position, AxisAngleToQuaternion (axisOfRotation, rotation)); // // Matrix4x4f xform = xformNoScale; // ScaleMatrix(xform, size); // // // Figure out which mesh to use // const float randomValue = GenerateRandom(ps.randomSeed[i] + kParticleSystemMeshSelectionId); // int meshIndex = 0; // for(int j = 0; j < numMeshes; j++) // { // const float lower = probability * j; // const float upper = probability * (j + 1); // if((randomValue >= lower) && (randomValue <= upper)) // { // meshIndex = j; // break; // } // } // // const ParticleMeshData& mesh = particleMeshes[meshIndex]; // // // Fill up vbo here // if( normalTangentMask == VERTEX_FORMAT2(Normal, Tangent) ) // TransformParticleMesh(mesh, particleColor, xform, xformNoScale, &vbPtr); // else if( normalTangentMask == VERTEX_FORMAT1(Normal) ) // TransformParticleMesh(mesh, particleColor, xform, xformNoScale, &vbPtr); // else if( normalTangentMask == 0 ) // TransformParticleMesh(mesh, particleColor, xform, xformNoScale, &vbPtr); // else // ErrorString("Invalid normalTangentMask"); // // const int meshIndexMax = mesh.indexCount - 2; // for(int index = 0; index < meshIndexMax; index+=3) // { // ibPtr[index+0] = mesh.indexBuffer[index+0] + vertexOffset; // ibPtr[index+1] = mesh.indexBuffer[index+1] + vertexOffset; // ibPtr[index+2] = mesh.indexBuffer[index+2] + vertexOffset; // } // ibPtr += mesh.indexCount; // // vertexOffset += mesh.vertexCount; // indexOffset += mesh.indexCount; // } // // vbo.ReleaseChunk (vertexCount, indexCount); // device.SetViewMatrix(viewMatrix.GetPtr()); // device.SetWorldMatrix(worldMatrix.GetPtr()); // vbo.DrawChunk (channels); // GPU_TIMESTAMP(); // // particleOffset += particleCountBatch; // } //} static void DrawParticlesInternal(const ParticleSystemGeomConstInputData& constData, const ParticleSystemRendererData& rendererData, const Matrix4x4f& worldViewMatrix, const Matrix4x4f& viewToWorldMatrix, const ParticleSystemParticles& ps, const ParticleSystemParticlesTempData& psTemp, ParticleSystemVertex* vbPtr, const size_t particleOffset, const size_t numParticles, int renderMode) { const size_t endIndex = particleOffset + numParticles; //renderMode = kSRMStretch3D; if (renderMode == kSRMBillboard) GenerateParticleGeometry (vbPtr, constData, rendererData, ps, psTemp, particleOffset, endIndex, worldViewMatrix, viewToWorldMatrix); if (renderMode == kSRMStretch3D) GenerateParticleGeometry (vbPtr, constData, rendererData, ps, psTemp, particleOffset, endIndex, worldViewMatrix, viewToWorldMatrix); if (renderMode == kSRMBillboardFixedHorizontal) GenerateParticleGeometry (vbPtr, constData, rendererData, ps, psTemp, particleOffset, endIndex, worldViewMatrix, viewToWorldMatrix); if (renderMode == kSRMBillboardFixedVertical) GenerateParticleGeometry (vbPtr, constData, rendererData, ps, psTemp, particleOffset, endIndex, worldViewMatrix, viewToWorldMatrix); } static void DrawParticles(const ParticleSystemGeomConstInputData& constData, const ParticleSystemRendererData& rendererData, const Matrix4x4f& worldViewMatrix, const Matrix4x4f& viewToWorldMatrix, const ParticleSystemParticles& ps, const ParticleSystemParticlesTempData& psTemp, ParticleSystemVertex* vbPtr) { //GfxDevice& device = GetGfxDevice(); const size_t particleCount = ps.array_size(); if(vbPtr) { DrawParticlesInternal(constData, rendererData, worldViewMatrix, viewToWorldMatrix, ps, psTemp, vbPtr, 0, particleCount, rendererData.renderMode); } else { int particleOffset = 0; while (particleOffset < particleCount) { const int particleCountBatch = std::min(kMaxNumParticlesPerBatch, (int)particleCount - particleOffset); unsigned int vertexCnount = sizeof(V3F_C4B_T2F); vbPtr = (ParticleSystemVertex*)malloc(vertexCnount * particleCountBatch * 4); DrawParticlesInternal(constData, rendererData, worldViewMatrix, viewToWorldMatrix, ps, psTemp, vbPtr, particleOffset, particleCountBatch, rendererData.renderMode); particleOffset += particleCountBatch; GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR | GL::VERTEX_ATTRIB_FLAG_TEX_COORD); glBindBuffer(GL_ARRAY_BUFFER, 0); if (rendererData.orthographic) { glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, vertexCnount, &(vbPtr->tl.vertices)); } else { glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, vertexCnount, &(vbPtr->tl.vertices)); } glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, vertexCnount, &(vbPtr->tl.texCoords)); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexCnount, &(vbPtr->tl.colors)); GLuint* vertexIndexBuff = new GLuint[particleCountBatch * 6]; for(int particleIdx = 0; particleIdx < particleCountBatch; particleIdx++){ int idx0 = particleIdx * 4 + 0; int idx1 = particleIdx * 4 + 1; int idx2 = particleIdx * 4 + 2; int idx3 = particleIdx * 4 + 3; vertexIndexBuff[particleIdx * 6 + 0] = idx0; vertexIndexBuff[particleIdx * 6 + 1] = idx1; vertexIndexBuff[particleIdx * 6 + 2] = idx2; vertexIndexBuff[particleIdx * 6 + 3] = idx3; vertexIndexBuff[particleIdx * 6 + 4] = idx2; vertexIndexBuff[particleIdx * 6 + 5] = idx1; } glDrawElements(GL_TRIANGLES, particleCountBatch * 6, GL_UNSIGNED_INT, vertexIndexBuff); delete[] vertexIndexBuff; free(vbPtr); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, vertexCnount); CHECK_GL_ERROR_DEBUG(); } } } void ParticleSystemRenderer::CalculateTotalParticleCount(UInt32& totalNumberOfParticles, RParticleSystem& system, bool first) { //ParticleSystemRenderer* renderer = system.QueryComponent(RParticleSystemRenderer); //if(!renderer || first) //{ // totalNumberOfParticles += system.GetParticleCount(); // Transform* t = system.QueryComponent (Transform); // if (t == NULL) // return; // for (Transform::iterator i=t->begin ();i != t->end ();i++) // { // ParticleSystem* child = (**i).QueryComponent(ParticleSystem); // if (child) // CalculateTotalParticleCount(totalNumberOfParticles, *child, false); // } //} totalNumberOfParticles += system.GetParticleCount(); } void ParticleSystemRenderer::CombineParticleBuffersRec(int& offset, ParticleSystemParticles& ps, ParticleSystemParticlesTempData& psTemp, RParticleSystem& system, bool first, bool needsAxisOfRotation) { if(first) { int particleCount = system.GetParticleCount(); ps.array_merge_preallocated(system.GetParticles(), offset, needsAxisOfRotation, false); if(system.m_ReadOnlyState->useLocalSpace) { Matrix4x4f localToWorld = system.getNodeToWorldTransform(); int endIndex = offset + particleCount; for(int i = offset; i < endIndex; i++) ps.position[i] = localToWorld.MultiplyPoint3(ps.position[i]); for(int i = offset; i < endIndex; i++) ps.velocity[i] = localToWorld.MultiplyVector3(ps.velocity[i]); for(int i = offset; i < endIndex; i++) ps.animatedVelocity[i] = localToWorld.MultiplyVector3(ps.animatedVelocity[i]); if(ps.usesAxisOfRotation) for(int i = offset; i < endIndex; i++) ps.axisOfRotation[i] = localToWorld.MultiplyVector3(ps.axisOfRotation[i]); } RParticleSystem::UpdateModulesNonIncremental(system, ps, psTemp, offset, offset + particleCount); offset += particleCount; } } void ParticleSystemRenderer::SetUsesAxisOfRotationRec(RParticleSystem& shuriken, bool first) { if(first) { shuriken.SetUsesAxisOfRotation(); } } //void ParticleSystemRenderer::CombineBoundsRec(RParticleSystem& shuriken, MinMaxAABB& aabb, bool first) //{ // ParticleSystemRenderer* renderer = shuriken.QueryComponent(ParticleSystemRenderer); // if(!renderer || first) // { // AABB result = shuriken.m_State->minMaxAABB; // if(!shuriken.m_ReadOnlyState->useLocalSpace) // InverseTransformAABB (result, renderer->GetTransform().GetPosition (), renderer->GetTransform().GetRotation (), result); // // if(first) // aabb = result; // else // aabb.Encapsulate(result); // // Transform* t = shuriken.QueryComponent (Transform); // if (t == NULL) // return; // for (Transform::iterator i=t->begin ();i != t->end ();i++) // { // ParticleSystem* shuriken = (**i).QueryComponent(ParticleSystem); // if (shuriken) // CombineBoundsRec(*shuriken, aabb, false); // } // } //} void ParticleSystemRenderer::Render (RParticleSystem* system, ParticleSystemVertex* vbPtr/* int materialIndex, const ChannelAssigns& channels*/, const Matrix4x4f &transform) { //ParticleSystem::SyncJobs(); //ParticleSystem* system = QueryComponent(ParticleSystem); //if(!system) // return; //// Can't render without an active camera (case 568930) //// Can remove check when we finally kill Renderer.Render() //if (!GetCurrentCameraPtr()) // return; //PROFILER_AUTO_GFX(gParticlesSingleProfile, this); RParticleSystem::SyncJobs(); UInt32 numParticles = 0; CalculateTotalParticleCount(numParticles, *system, true); if(numParticles) RenderInternal(*system, *this, vbPtr, numParticles, transform); } //void ParticleSystemRenderer::RenderMultiple (const BatchInstanceData* instances, size_t count, const ChannelAssigns& channels) //{ // ParticleSystem::SyncJobs(); // // size_t numParticlesBatch = 0; // // BatchInstanceData const* instancesEnd = instances + count; // BatchInstanceData const* iBatchBegin = instances; // BatchInstanceData const* iBatchEnd = instances; // while(iBatchEnd != instancesEnd) // { // Assert(iBatchEnd->renderer->GetRendererType() == kRendererParticleSystem); // ParticleSystemRenderer* psRenderer = (ParticleSystemRenderer*)iBatchEnd->renderer; // Assert(psRenderer->GetRenderMode() != kSRMMesh); // ParticleSystem* system = psRenderer->QueryComponent(ParticleSystem); // if (!system ) // { // iBatchEnd++; // continue; // } // UInt32 numParticles = 0; // psRenderer->CalculateTotalParticleCount(numParticles, *system, true); // // if((numParticlesBatch + numParticles) <= kMaxNumParticlesPerBatch) // { // numParticlesBatch += numParticles; // iBatchEnd++; // } // else // { // if(numParticlesBatch) // { // RenderBatch(iBatchBegin, iBatchEnd - iBatchBegin, numParticlesBatch, channels); // numParticlesBatch = 0; // iBatchBegin = iBatchEnd; // } // else // Can't fit in one draw call // { // RenderBatch(iBatchEnd, 1, numParticles, channels); // iBatchEnd++; // iBatchBegin = iBatchEnd; // } // } // } // // if((iBatchBegin != iBatchEnd) && numParticlesBatch) // RenderBatch(iBatchBegin, iBatchEnd - iBatchBegin, numParticlesBatch, channels); //} //void ParticleSystemRenderer::RenderBatch (const BatchInstanceData* instances, size_t count, size_t numParticles, const ChannelAssigns& channels) //{ // DebugAssert(numParticles); // // GfxDevice& device = GetGfxDevice(); // // const MaterialPropertyBlock* customProps = count > 0 ? instances[0].renderer->GetCustomProperties() : NULL; // if (customProps) // device.SetMaterialProperties (*customProps); // // Matrix4x4f viewMatrix; // CopyMatrix (device.GetViewMatrix (), viewMatrix.GetPtr ()); // // ParticleSystemVertex* vbPtr = 0; // DynamicVBO& vbo = device.GetDynamicVBO(); // if(numParticles <= kMaxNumParticlesPerBatch) // { // if( !vbo.GetChunk( (1<renderer->GetRendererType() == kRendererParticleSystem); // ParticleSystemRenderer* psRenderer = (ParticleSystemRenderer*)iBatchBegin->renderer; // Assert(psRenderer->GetRenderMode() != kSRMMesh); // ParticleSystem* system = psRenderer->QueryComponent(ParticleSystem); // UInt32 particleCountTotal = 0; // if (system) // { // // It would be nice to filter out NULL particle systems earlier, but we don't (case 504744) // CalculateTotalParticleCount(particleCountTotal, *system, true); // if(particleCountTotal) // RenderInternal(*system, *psRenderer, channels, vbPtr + particleOffset * 4, particleCountTotal); // } // iBatchBegin++; // particleOffset += particleCountTotal; // } // // if(vbPtr) // { // vbo.ReleaseChunk (numParticles * 4, 0); // // // Draw // device.SetViewMatrix (Matrix4x4f::identity.GetPtr()); // implicitly sets world to identity // // PROFILER_BEGIN(gSubmitVBOParticleProfile, 0) // vbo.DrawChunk (channels); // GPU_TIMESTAMP(); // PROFILER_END // // if (count > 1) // device.AddBatchingStats(numParticles * 2, numParticles * 4, count); // // device.SetViewMatrix(viewMatrix.GetPtr()); // } //} void ParticleSystemRenderer::RenderInternal (RParticleSystem& system, const ParticleSystemRenderer& renderer, ParticleSystemVertex* vbPtr, UInt32 particleCountTotal, const Matrix4x4f &transform) { Assert(particleCountTotal); #if UNITY_EDITOR if (!renderer.m_EditorEnabled) return; #endif //c-edit GfxDevice& device = GetGfxDevice(); // Render matrix Matrix4x4f viewMatrix; viewMatrix = Matrix4x4f::IDENTITY; //c-edit CopyMatrix (device.GetViewMatrix (), viewMatrix.GetPtr ()); ParticleSystemParticles* ps = &system.GetParticles (); size_t particleCount = ps->array_size (); AssertBreak(particleCountTotal >= particleCount); UInt8* combineBuffer = 0; ParticleSystemParticles combineParticles; if(particleCountTotal > particleCount) { particleCount = particleCountTotal; combineBuffer = ALLOC_TEMP_MANUAL(UInt8, particleCountTotal * ParticleSystemParticles::GetParticleSize()); combineParticles.array_assign_external((void*)&combineBuffer[0], particleCountTotal); ps = &combineParticles; } if(!particleCount) return; const bool needsAxisOfRotation = !renderer.GetScreenSpaceRotation(); if(needsAxisOfRotation) { SetUsesAxisOfRotationRec (system, true); } ParticleSystemSortMode sortMode = (ParticleSystemSortMode)renderer.m_Data.sortMode; bool isInLocalSpace = system.m_ReadOnlyState->useLocalSpace && !combineBuffer; Matrix4x4f worldMatrix = Matrix4x4f::IDENTITY; #if REDREAM_EDITOR if(isInLocalSpace){ //worldMatrix = system.GetComponent (Transform).GetLocalToWorldMatrixNoScale (); worldMatrix = Transform::GetLocalToWorldMatrixNoScale(&system); } #else if(isInLocalSpace){ //worldMatrix = system.GetComponent (Transform).GetLocalToWorldMatrixNoScale (); worldMatrix = transform; } else { worldMatrix = Director::getInstance()->getRunningScene()->getNodeToParentTransform(); } #endif ParticleSystemParticlesTempData psTemp; psTemp.color = ALLOC_TEMP_MANUAL(ColorRGBA32, particleCount); psTemp.size = ALLOC_TEMP_MANUAL(float, particleCount); psTemp.sheetIndex = 0; psTemp.particleCount = particleCount; psTemp.particleSysytemWorldPos = ALLOC_TEMP_MANUAL(Vec3, particleCount); if(combineBuffer) { int offset = 0; CombineParticleBuffersRec(offset, *ps, psTemp, system, true, needsAxisOfRotation); if (kSSMNone != sortMode) Sort(viewMatrix, *ps, sortMode, &psTemp, true); } else { if(system.m_UVModule->GetEnabled()) psTemp.sheetIndex = ALLOC_TEMP_MANUAL(float, particleCount); if (kSSMNone != sortMode) { Matrix4x4f objectToViewMatrix; MultiplyMatrices3x4(viewMatrix, worldMatrix, objectToViewMatrix); Sort(objectToViewMatrix, *ps, sortMode, 0, false); } RParticleSystem::UpdateModulesNonIncremental(system, *ps, psTemp, 0, particleCount); } if (system._opacityModifyRGB) { for (int i = 0; i < particleCount; i++) { auto& color = psTemp.color[i]; color.r *= color.a / 255.0f; color.g *= color.a / 255.0f; color.b *= color.a / 255.0f; } } // Constrain the size to be a fraction of the viewport size. // In perspective case, max size is (z*factorA). In ortho case, max size is just factorB. To have both // without branches, we do (z*factorA+factorB) and set one of factors to zero. float maxPlaneScale = 0.0f; float maxOrthoSize = 0.0f; // Getting the camera isn't totally free, so do it once. Camera* camera = Camera::getDefaultCamera(); //if (!camera.GetOrthographic()) // maxPlaneScale = -camera.CalculateFarPlaneWorldSpaceLength() * renderer.m_Data.maxParticleSize / camera.GetFar(); //else // maxOrthoSize = camera.CalculateFarPlaneWorldSpaceLength() * renderer.m_Data.maxParticleSize; //maxOrthoSize = camera->getFarPlane() * renderer.m_Data.maxParticleSize; if (true){ Size fSize = Director::getInstance()->getOpenGLView()->getFrameSize(); float len = Vec2(fSize.width, fSize.height).getLength(); maxPlaneScale = - len * renderer.m_Data.maxParticleSize / camera->getFarPlane(); //maxPlaneScale = -camera.CalculateFarPlaneWorldSpaceLength() * renderer.m_Data.maxParticleSize / camera.GetFar(); //maxPlaneScale = } else{ //maxOrthoSize = camera.CalculateFarPlaneWorldSpaceLength() * renderer.m_Data.maxParticleSize; Size fSize = Director::getInstance()->getOpenGLView()->getFrameSize(); float len = Vec2(fSize.width, fSize.height).getLength(); maxOrthoSize = len * renderer.m_Data.maxParticleSize; } int numMeshes = 0; for(int i = 0; i < ParticleSystemRendererData::kMaxNumParticleMeshes; i++) if(renderer.m_Data.cachedMesh[i]) numMeshes++; ParticleSystemGeomConstInputData constData; constData.m_ViewMatrix = viewMatrix; //constData.m_CameraVelocity = viewMatrix.MultiplyVector3(camera.GetVelocity ()); constData.m_CameraVelocity = viewMatrix.MultiplyVector3(Vec3::ZERO); //TODO //constData.m_Renderer = (Object*)&renderer; //for(int i = 0; i < numMeshes; i++) //{ // constData.m_MeshIndexBuffer[i] = renderer.m_CachedIndexBuffer[i].begin(); // constData.m_MeshIndexCount[i] = renderer.m_CachedIndexBuffer[i].size(); // AssertBreak((constData.m_MeshIndexCount[i] % 3) == 0); //} system.GetNumTiles(constData.m_NumTilesX, constData.m_NumTilesY); constData.maxPlaneScale = maxPlaneScale; constData.maxOrthoSize = maxOrthoSize; constData.numUVFrame = constData.m_NumTilesX * constData.m_NumTilesY; constData.animUScale = 1.0f / (float)constData.m_NumTilesX; constData.animVScale = 1.0f / (float)constData.m_NumTilesY; constData.xSpan = Vector3f(-1.0f,0.0f,0.0f); constData.ySpan = Vector3f(0.0f,0.0f,1.0f); if (renderer.m_Data.renderMode == kSRMBillboardFixedVertical) { constData.ySpan = Vector3f(0.0f,1.0f,0.0f); const Vector3f zSpan = viewMatrix.MultiplyVector3 (Vector3f::UNIT_Z);// (RotateVectorByQuat (cameraRotation, Vector3f(0.0f,0.0f,1.0f)); constData.xSpan = NormalizeSafe (Cross (constData.ySpan, zSpan)); } constData.xSpan = viewMatrix.MultiplyVector3(constData.xSpan); constData.ySpan = viewMatrix.MultiplyVector3(constData.ySpan); constData.usesSheetIndex = psTemp.sheetIndex != NULL; constData.uvModuleMode = system.getUVModuleMode(); constData.isSpriteFrame = system._isSpriteFrame; constData.vertexInfo = &system._vertexInfo; const float bentNormalAngle = renderer.m_Data.normalDirection * 90.0f * kDeg2Rad; const float scale = (renderer.m_Data.renderMode == kSRMBillboard) ? 0.707106781f : 1.0f; Matrix4x4f viewToWorldMatrix; Matrix4x4f::Invert_General3D(viewMatrix, viewToWorldMatrix); Matrix4x4f worldViewMatrix; //MultiplyMatrices4x4(&viewMatrix, &worldMatrix, &worldViewMatrix); Matrix4x4f::multiply(viewMatrix, worldMatrix, &worldViewMatrix); Vector3f billboardNormal = Vector3f::UNIT_Z; if((renderer.m_Data.renderMode == kSRMBillboardFixedHorizontal) || (renderer.m_Data.renderMode == kSRMBillboardFixedVertical)) billboardNormal = viewMatrix.MultiplyVector3 (NormalizeSafe (Cross (constData.xSpan, constData.ySpan))); constData.bentNormalVector = viewToWorldMatrix.MultiplyVector3(Sin(bentNormalAngle) * billboardNormal); constData.bentNormalFactor = Cos(bentNormalAngle) * scale; switch (system.getScalingMode()) { case kParticleSystemScalingModeHierarchy: transform.decompose(&constData.globalScale, nullptr, nullptr); break; case kParticleSystemScalingModeLocal: system.getNodeToParentTransform().decompose(&constData.globalScale, nullptr, nullptr); break; case kParticleSystemScalingModeShape: constData.globalScale.set(1, 1, 1); break; } if (renderer.m_Data.renderMode == kSRMMesh){ //DrawMeshParticles (constData, renderer.m_Data, worldMatrix, *ps, psTemp); }else{ DrawParticles(constData, renderer.m_Data, worldViewMatrix, viewToWorldMatrix, *ps, psTemp, vbPtr); //const size_t particleCount = ps->array_size(); //DrawParticlesInternal(constData, renderer.m_Data, worldViewMatrix, viewToWorldMatrix, *ps, psTemp, vbPtr, 0, particleCount, renderer.m_Data.renderMode); } FREE_TEMP_MANUAL(psTemp.color); FREE_TEMP_MANUAL(psTemp.size); FREE_TEMP_MANUAL(psTemp.particleSysytemWorldPos); if(psTemp.sheetIndex) FREE_TEMP_MANUAL(psTemp.sheetIndex); if(combineBuffer) FREE_TEMP_MANUAL(combineBuffer); } template void ParticleSystemRenderer::Transfer (TransferFunction& transfer) { // Super::Transfer (transfer); transfer.Transfer (m_Data.scale, "m_Scale"); transfer.Transfer (m_Data.renderMode, "m_RenderMode"); transfer.Transfer (m_Data.maxParticleSize, "m_MaxParticleSize"); transfer.Transfer (m_Data.cameraVelocityScale, "m_CameraVelocityScale"); transfer.Transfer (m_Data.velocityScale, "m_VelocityScale"); transfer.Transfer (m_Data.lengthScale, "m_LengthScale"); transfer.Transfer (m_Data.sortingFudge, "m_SortingFudge"); transfer.Transfer (m_Data.normalDirection, "m_NormalDirection"); transfer.Transfer (m_Data.sortMode, "m_SortMode"); //TODO: Mesh //transfer.Transfer (m_Mesh[0], "m_Mesh"); //transfer.Transfer (m_Mesh[1], "m_Mesh1"); //transfer.Transfer (m_Mesh[2], "m_Mesh2"); //transfer.Transfer (m_Mesh[3], "m_Mesh3"); } INSTANTIATE_TEMPLATE_TRANSFER(ParticleSystemRenderer) NS_RRP_END