SubMesh* Mesh::BuildSubMesh(const Primitive& primitive, const MeshParams& params) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Mesh not created"); return nullptr; } if (m_impl->animationType != AnimationType_Static) { NazaraError("Mesh must be static"); return nullptr; } if (!params.IsValid()) { NazaraError("Parameters must be valid"); return nullptr; } #endif Boxf aabb; IndexBufferRef indexBuffer; VertexBufferRef vertexBuffer; Matrix4f matrix(primitive.matrix); matrix.ApplyScale(params.scale); VertexDeclaration* declaration = VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent); switch (primitive.type) { case PrimitiveType_Box: { unsigned int indexCount; unsigned int vertexCount; ComputeBoxIndexVertexCount(primitive.box.subdivision, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GenerateBox(primitive.box.lengths, primitive.box.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } case PrimitiveType_Cone: { unsigned int indexCount; unsigned int vertexCount; ComputeConeIndexVertexCount(primitive.cone.subdivision, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GenerateCone(primitive.cone.length, primitive.cone.radius, primitive.cone.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } case PrimitiveType_Plane: { unsigned int indexCount; unsigned int vertexCount; ComputePlaneIndexVertexCount(primitive.plane.subdivision, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GeneratePlane(primitive.plane.subdivision, primitive.plane.size, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } case PrimitiveType_Sphere: { switch (primitive.sphere.type) { case SphereType_Cubic: { unsigned int indexCount; unsigned int vertexCount; ComputeCubicSphereIndexVertexCount(primitive.sphere.cubic.subdivision, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_ReadWrite); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GenerateCubicSphere(primitive.sphere.size, primitive.sphere.cubic.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } case SphereType_Ico: { unsigned int indexCount; unsigned int vertexCount; ComputeIcoSphereIndexVertexCount(primitive.sphere.ico.recursionLevel, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GenerateIcoSphere(primitive.sphere.size, primitive.sphere.ico.recursionLevel, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } case SphereType_UV: { unsigned int indexCount; unsigned int vertexCount; ComputeUvSphereIndexVertexCount(primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, &indexCount, &vertexCount); indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indexCount, params.storage, BufferUsage_Static); vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, BufferUsage_Static); VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); VertexPointers pointers; pointers.normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal); pointers.positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position); pointers.tangentPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Tangent); pointers.uvPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); GenerateUvSphere(primitive.sphere.size, primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } } break; } } StaticMeshRef subMesh = StaticMesh::New(this); if (!subMesh->Create(vertexBuffer)) { NazaraError("Failed to create StaticMesh"); return nullptr; } if (params.optimizeIndexBuffers) indexBuffer->Optimize(); subMesh->SetAABB(aabb); subMesh->SetIndexBuffer(indexBuffer); AddSubMesh(subMesh); return subMesh; }
void NzForwardRenderTechnique::DrawBillboards(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); const NzShader* lastShader = nullptr; const ShaderUniforms* shaderUniforms = nullptr; if (NzRenderer::HasCapability(nzRendererCap_Instancing)) { NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer(); instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); NzRenderer::SetVertexBuffer(&s_quadVertexBuffer); for (auto& matIt : m_renderQueue.billboards) { const NzMaterial* material = matIt.first; auto& entry = matIt.second; auto& billboardVector = entry.billboards; unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { // On commence par appliquer du matériau (et récupérer le shader ainsi activé) const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing | nzShaderFlags_VertexColor); // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas if (shader != lastShader) { // Index des uniformes dans le shader shaderUniforms = GetShaderUniforms(shader); // Couleur ambiante de la scène shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor()); // Position de la caméra shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition()); lastShader = shader; } const NzForwardRenderQueue::BillboardData* data = &billboardVector[0]; unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount(); do { unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); billboardCount -= renderedBillboardCount; instanceBuffer->Fill(data, 0, renderedBillboardCount, true); data += renderedBillboardCount; NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4); } while (billboardCount > 0); billboardVector.clear(); } } } else { NzRenderer::SetIndexBuffer(&s_quadIndexBuffer); NzRenderer::SetVertexBuffer(&m_billboardPointBuffer); for (auto& matIt : m_renderQueue.billboards) { const NzMaterial* material = matIt.first; auto& entry = matIt.second; auto& billboardVector = entry.billboards; unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { // On commence par appliquer du matériau (et récupérer le shader ainsi activé) const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_VertexColor); // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas if (shader != lastShader) { // Couleur ambiante de la scène shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor()); // Position de la caméra shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition()); lastShader = shader; } const NzForwardRenderQueue::BillboardData* data = &billboardVector[0]; unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4); do { unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); billboardCount -= renderedBillboardCount; NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4); BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer()); for (unsigned int i = 0; i < renderedBillboardCount; ++i) { const NzForwardRenderQueue::BillboardData& billboard = *data++; vertices->color = billboard.color; vertices->position = billboard.center; vertices->sinCos = billboard.sinCos; vertices->size = billboard.size; vertices->uv.Set(0.f, 1.f); vertices++; vertices->color = billboard.color; vertices->position = billboard.center; vertices->sinCos = billboard.sinCos; vertices->size = billboard.size; vertices->uv.Set(1.f, 1.f); vertices++; vertices->color = billboard.color; vertices->position = billboard.center; vertices->sinCos = billboard.sinCos; vertices->size = billboard.size; vertices->uv.Set(0.f, 0.f); vertices++; vertices->color = billboard.color; vertices->position = billboard.center; vertices->sinCos = billboard.sinCos; vertices->size = billboard.size; vertices->uv.Set(1.f, 0.f); vertices++; } vertexMapper.Unmap(); NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedBillboardCount*6); } while (billboardCount > 0); billboardVector.clear(); } } } }
NzSubMesh* NzMesh::BuildSubMesh(const NzPrimitive& primitive, const NzMeshParams& params) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Mesh not created"); return nullptr; } if (m_impl->animationType != nzAnimationType_Static) { NazaraError("Mesh must be static"); return nullptr; } if (!params.IsValid()) { NazaraError("Parameters must be valid"); return nullptr; } #endif NzBoxf aabb; std::unique_ptr<NzIndexBuffer> indexBuffer; std::unique_ptr<NzVertexBuffer> vertexBuffer; NzMatrix4f matrix(primitive.matrix); matrix.ApplyScale(params.scale); NzVertexDeclaration* declaration = NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent); switch (primitive.type) { case nzPrimitiveType_Box: { unsigned int indexCount; unsigned int vertexCount; NzComputeBoxIndexVertexCount(primitive.box.subdivision, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGenerateBox(primitive.box.lengths, primitive.box.subdivision, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } case nzPrimitiveType_Cone: { unsigned int indexCount; unsigned int vertexCount; NzComputeConeIndexVertexCount(primitive.cone.subdivision, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGenerateCone(primitive.cone.length, primitive.cone.radius, primitive.cone.subdivision, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } case nzPrimitiveType_Plane: { unsigned int indexCount; unsigned int vertexCount; NzComputePlaneIndexVertexCount(primitive.plane.subdivision, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGeneratePlane(primitive.plane.subdivision, primitive.plane.size, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } case nzPrimitiveType_Sphere: { switch (primitive.sphere.type) { case nzSphereType_Cubic: { unsigned int indexCount; unsigned int vertexCount; NzComputeCubicSphereIndexVertexCount(primitive.sphere.cubic.subdivision, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGenerateCubicSphere(primitive.sphere.size, primitive.sphere.cubic.subdivision, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } case nzSphereType_Ico: { unsigned int indexCount; unsigned int vertexCount; NzComputeIcoSphereIndexVertexCount(primitive.sphere.ico.recursionLevel, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGenerateIcoSphere(primitive.sphere.size, primitive.sphere.ico.recursionLevel, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } case nzSphereType_UV: { unsigned int indexCount; unsigned int vertexCount; NzComputeUvSphereIndexVertexCount(primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, &indexCount, &vertexCount); indexBuffer.reset(new NzIndexBuffer(vertexCount > std::numeric_limits<nzUInt16>::max(), indexCount, params.storage, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); vertexBuffer.reset(new NzVertexBuffer(declaration, vertexCount, params.storage, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); NzGenerateUvSphere(primitive.sphere.size, primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, matrix, primitive.textureCoords, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), indexMapper.begin(), &aabb); break; } } break; } } std::unique_ptr<NzStaticMesh> subMesh(new NzStaticMesh(this)); if (!subMesh->Create(vertexBuffer.get())) { NazaraError("Failed to create StaticMesh"); return nullptr; } vertexBuffer.release(); if (params.optimizeIndexBuffers) indexBuffer->Optimize(); subMesh->SetIndexBuffer(indexBuffer.get()); indexBuffer.release(); subMesh->SetAABB(aabb); AddSubMesh(subMesh.get()); return subMesh.release(); }
void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); const NzShader* lastShader = nullptr; const ShaderUniforms* shaderUniforms = nullptr; NzRenderer::SetIndexBuffer(&s_quadIndexBuffer); NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity()); NzRenderer::SetVertexBuffer(&m_spriteBuffer); for (auto& matIt : m_renderQueue.basicSprites) { const NzMaterial* material = matIt.first; auto& matEntry = matIt.second; if (matEntry.enabled) { auto& overlayMap = matEntry.overlayMap; for (auto& overlayIt : overlayMap) { const NzTexture* overlay = overlayIt.first; auto& spriteChainVector = overlayIt.second.spriteChains; unsigned int spriteChainCount = spriteChainVector.size(); if (spriteChainCount > 0) { // On commence par appliquer du matériau (et récupérer le shader ainsi activé) nzUInt32 flags = nzShaderFlags_VertexColor; if (overlay) flags |= nzShaderFlags_TextureOverlay; nzUInt8 overlayUnit; const NzShader* shader = material->Apply(flags, 0, &overlayUnit); if (overlay) { overlayUnit++; NzRenderer::SetTexture(overlayUnit, overlay); NzRenderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); } // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas if (shader != lastShader) { // Index des uniformes dans le shader shaderUniforms = GetShaderUniforms(shader); // Couleur ambiante de la scène shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor()); // Overlay shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); // Position de la caméra shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition()); lastShader = shader; } unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés do { // On ouvre le buffer en écriture NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite); NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer()); unsigned int spriteCount = 0; unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4); do { NzForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset); std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV)); vertices += count*4; spriteCount += count; spriteChainOffset += count; // Avons-nous traité la chaîne entière ? if (spriteChainOffset == currentChain.spriteCount) { spriteChain++; spriteChainOffset = 0; } } while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); vertexMapper.Unmap(); NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6); } while (spriteChain < spriteChainCount); spriteChainVector.clear(); } } // On remet à zéro matEntry.enabled = false; } } }