|
|
@@ -5,6 +5,14 @@
|
|
|
#include "CmVector3.h"
|
|
|
#include "CmDebug.h"
|
|
|
#include "CmHardwareBufferManager.h"
|
|
|
+#include "CmRenderSystem.h"
|
|
|
+#include "CmRenderSystemManager.h"
|
|
|
+
|
|
|
+#if CM_DEBUG_MODE
|
|
|
+#define THROW_IF_NOT_RENDER_THREAD throwIfNotRenderThread();
|
|
|
+#else
|
|
|
+#define THROW_IF_NOT_RENDER_THREAD
|
|
|
+#endif
|
|
|
|
|
|
namespace CamelotEngine
|
|
|
{
|
|
|
@@ -16,6 +24,8 @@ namespace CamelotEngine
|
|
|
|
|
|
Mesh::~Mesh()
|
|
|
{
|
|
|
+ THROW_IF_NOT_RENDER_THREAD;
|
|
|
+
|
|
|
if(mVertexData)
|
|
|
delete mVertexData;
|
|
|
|
|
|
@@ -25,7 +35,134 @@ namespace CamelotEngine
|
|
|
|
|
|
void Mesh::setMeshData(MeshDataPtr meshData)
|
|
|
{
|
|
|
- mMeshData = meshData;
|
|
|
+ RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Mesh::setMeshData_internal, this, meshData));
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::setMeshData_internal(MeshDataPtr meshData)
|
|
|
+ {
|
|
|
+ THROW_IF_NOT_RENDER_THREAD;
|
|
|
+
|
|
|
+ if(meshData == nullptr)
|
|
|
+ {
|
|
|
+ CM_EXCEPT(InternalErrorException, "Cannot load mesh. Mesh data is null.");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Submeshes
|
|
|
+ for(UINT32 i = 0; i < meshData->subMeshes.size(); i++)
|
|
|
+ mSubMeshes.push_back(SubMesh(meshData->subMeshes[i].indexOffset, meshData->subMeshes[i].indexCount));
|
|
|
+
|
|
|
+ // Indices
|
|
|
+ mIndexData = new IndexData();
|
|
|
+
|
|
|
+ mIndexData->indexCount = meshData->indexCount;
|
|
|
+ mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
|
|
|
+ HardwareIndexBuffer::IT_16BIT,
|
|
|
+ mIndexData->indexCount,
|
|
|
+ HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
+
|
|
|
+ UINT16* idxData = static_cast<UINT16*>(mIndexData->indexBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
|
|
+
|
|
|
+ for(UINT32 i = 0; i < mIndexData->indexCount; i++)
|
|
|
+ {
|
|
|
+ idxData[i] = (UINT16)meshData->index[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ mIndexData->indexBuffer->unlock();
|
|
|
+
|
|
|
+ // Vertices
|
|
|
+ mVertexData = new VertexData();
|
|
|
+
|
|
|
+ mVertexData->vertexStart = 0;
|
|
|
+ mVertexData->vertexCount = meshData->vertexCount;
|
|
|
+
|
|
|
+ mVertexData->vertexDeclaration = meshData->declaration->clone();
|
|
|
+
|
|
|
+ for(auto iter = meshData->vertexBuffers.begin(); iter != meshData->vertexBuffers.end(); ++iter)
|
|
|
+ {
|
|
|
+ int streamIdx = iter->first;
|
|
|
+
|
|
|
+ HardwareVertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
|
|
|
+ mVertexData->vertexDeclaration->getVertexSize(streamIdx),
|
|
|
+ mVertexData->vertexCount,
|
|
|
+ HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
+
|
|
|
+ mVertexData->vertexBufferBinding->setBinding(streamIdx, vertexBuffer);
|
|
|
+
|
|
|
+ UINT32 vertexSize = vertexBuffer->getVertexSize();
|
|
|
+ UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
|
|
+
|
|
|
+ UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
|
|
|
+
|
|
|
+ for(UINT32 j = 0; j < numElements; j++)
|
|
|
+ {
|
|
|
+ const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
|
|
|
+ VertexElementSemantic semantic = element->getSemantic();
|
|
|
+ UINT32 offset = element->getOffset();
|
|
|
+ UINT32 elemSize = element->getSize();
|
|
|
+
|
|
|
+ std::shared_ptr<MeshData::VertexData> vertexData = meshData->vertexBuffers[streamIdx];
|
|
|
+
|
|
|
+ UINT8* source = nullptr;
|
|
|
+ switch(semantic)
|
|
|
+ {
|
|
|
+ case VES_POSITION:
|
|
|
+ if(vertexData->vertex)
|
|
|
+ source = (UINT8*)vertexData->vertex;
|
|
|
+
|
|
|
+ break;
|
|
|
+ case VES_DIFFUSE:
|
|
|
+ if(vertexData->color)
|
|
|
+ source = (UINT8*)vertexData->color;
|
|
|
+
|
|
|
+ break;
|
|
|
+ case VES_NORMAL:
|
|
|
+ if(vertexData->normal)
|
|
|
+ source = (UINT8*)vertexData->normal;
|
|
|
+
|
|
|
+ break;
|
|
|
+ case VES_TANGENT:
|
|
|
+ if(vertexData->tangent)
|
|
|
+ source = (UINT8*)vertexData->tangent;
|
|
|
+
|
|
|
+ break;
|
|
|
+ case VES_BITANGENT:
|
|
|
+ if(vertexData->bitangent)
|
|
|
+ source = (UINT8*)vertexData->bitangent;
|
|
|
+
|
|
|
+ break;
|
|
|
+ case VES_TEXTURE_COORDINATES:
|
|
|
+ if(element->getIndex() == 0)
|
|
|
+ {
|
|
|
+ if(vertexData->uv0)
|
|
|
+ source = (UINT8*)vertexData->uv0;
|
|
|
+ }
|
|
|
+ else if(element->getIndex() == 1)
|
|
|
+ {
|
|
|
+ if(vertexData->uv1)
|
|
|
+ source = (UINT8*)vertexData->uv1;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(source != nullptr)
|
|
|
+ {
|
|
|
+ for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
|
|
|
+ memcpy(&vertBufferData[k * vertexSize + offset], &source[k * elemSize], elemSize);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOGWRN("Vertex declaration contains semantic (" + toString(semantic) + ") but mesh doesn't have data for it. Data for the semantic will be zeroed out.");
|
|
|
+
|
|
|
+ for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
|
|
|
+ memset(&vertBufferData[k * vertexSize + offset], 0, elemSize);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ vertexBuffer->unlock();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
MeshDataPtr Mesh::getMeshData()
|
|
|
@@ -159,132 +296,28 @@ namespace CamelotEngine
|
|
|
|
|
|
return ro;
|
|
|
}
|
|
|
+ void Mesh::initialize()
|
|
|
+ {
|
|
|
+ RenderSystemManager::getActive()->queueResourceCommand(boost::bind(&Mesh::initialize_internal, this));
|
|
|
+ }
|
|
|
|
|
|
void Mesh::initialize_internal()
|
|
|
{
|
|
|
- if(mMeshData == nullptr)
|
|
|
- {
|
|
|
- CM_EXCEPT(InternalErrorException, "Cannot load mesh. Mesh data hasn't been set.");
|
|
|
- }
|
|
|
-
|
|
|
- // Submeshes
|
|
|
- for(UINT32 i = 0; i < mMeshData->subMeshes.size(); i++)
|
|
|
- mSubMeshes.push_back(SubMesh(mMeshData->subMeshes[i].indexOffset, mMeshData->subMeshes[i].indexCount));
|
|
|
-
|
|
|
- // Indices
|
|
|
- mIndexData = new IndexData();
|
|
|
-
|
|
|
- mIndexData->indexCount = mMeshData->indexCount;
|
|
|
- mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
|
|
|
- HardwareIndexBuffer::IT_16BIT,
|
|
|
- mIndexData->indexCount,
|
|
|
- HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
-
|
|
|
- UINT16* idxData = static_cast<UINT16*>(mIndexData->indexBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
|
|
-
|
|
|
- for(UINT32 i = 0; i < mIndexData->indexCount; i++)
|
|
|
- {
|
|
|
- idxData[i] = (UINT16)mMeshData->index[i];
|
|
|
- }
|
|
|
-
|
|
|
- mIndexData->indexBuffer->unlock();
|
|
|
-
|
|
|
- // Vertices
|
|
|
- mVertexData = new VertexData();
|
|
|
-
|
|
|
- mVertexData->vertexStart = 0;
|
|
|
- mVertexData->vertexCount = mMeshData->vertexCount;
|
|
|
-
|
|
|
- mVertexData->vertexDeclaration = mMeshData->declaration->clone();
|
|
|
-
|
|
|
- for(auto iter = mMeshData->vertexBuffers.begin(); iter != mMeshData->vertexBuffers.end(); ++iter)
|
|
|
- {
|
|
|
- int streamIdx = iter->first;
|
|
|
-
|
|
|
- HardwareVertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
|
|
|
- mVertexData->vertexDeclaration->getVertexSize(streamIdx),
|
|
|
- mVertexData->vertexCount,
|
|
|
- HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
-
|
|
|
- mVertexData->vertexBufferBinding->setBinding(streamIdx, vertexBuffer);
|
|
|
-
|
|
|
- UINT32 vertexSize = vertexBuffer->getVertexSize();
|
|
|
- UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
|
|
-
|
|
|
- UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
|
|
|
-
|
|
|
- for(UINT32 j = 0; j < numElements; j++)
|
|
|
- {
|
|
|
- const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
|
|
|
- VertexElementSemantic semantic = element->getSemantic();
|
|
|
- UINT32 offset = element->getOffset();
|
|
|
- UINT32 elemSize = element->getSize();
|
|
|
-
|
|
|
- std::shared_ptr<MeshData::VertexData> vertexData = mMeshData->vertexBuffers[streamIdx];
|
|
|
-
|
|
|
- UINT8* source = nullptr;
|
|
|
- switch(semantic)
|
|
|
- {
|
|
|
- case VES_POSITION:
|
|
|
- if(vertexData->vertex)
|
|
|
- source = (UINT8*)vertexData->vertex;
|
|
|
-
|
|
|
- break;
|
|
|
- case VES_DIFFUSE:
|
|
|
- if(vertexData->color)
|
|
|
- source = (UINT8*)vertexData->color;
|
|
|
-
|
|
|
- break;
|
|
|
- case VES_NORMAL:
|
|
|
- if(vertexData->normal)
|
|
|
- source = (UINT8*)vertexData->normal;
|
|
|
-
|
|
|
- break;
|
|
|
- case VES_TANGENT:
|
|
|
- if(vertexData->tangent)
|
|
|
- source = (UINT8*)vertexData->tangent;
|
|
|
-
|
|
|
- break;
|
|
|
- case VES_BITANGENT:
|
|
|
- if(vertexData->bitangent)
|
|
|
- source = (UINT8*)vertexData->bitangent;
|
|
|
+ THROW_IF_NOT_RENDER_THREAD;
|
|
|
|
|
|
- break;
|
|
|
- case VES_TEXTURE_COORDINATES:
|
|
|
- if(element->getIndex() == 0)
|
|
|
- {
|
|
|
- if(vertexData->uv0)
|
|
|
- source = (UINT8*)vertexData->uv0;
|
|
|
- }
|
|
|
- else if(element->getIndex() == 1)
|
|
|
- {
|
|
|
- if(vertexData->uv1)
|
|
|
- source = (UINT8*)vertexData->uv1;
|
|
|
- }
|
|
|
+ // TODO Low priority - Initialize an empty mesh. A better way would be to only initialize the mesh
|
|
|
+ // once we set the proper mesh data (then we don't have to do it twice), but this makes the code less complex.
|
|
|
+ // Consider changing it if there are performance issues.
|
|
|
+ MeshDataPtr meshData = MeshDataPtr(new MeshData());
|
|
|
+ setMeshData_internal(meshData);
|
|
|
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if(source != nullptr)
|
|
|
- {
|
|
|
- for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
|
|
|
- memcpy(&vertBufferData[k * vertexSize + offset], &source[k * elemSize], elemSize);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- LOGWRN("Vertex declaration contains semantic (" + toString(semantic) + ") but mesh doesn't have data for it. Data for the semantic will be zeroed out.");
|
|
|
-
|
|
|
- for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
|
|
|
- memset(&vertBufferData[k * vertexSize + offset], 0, elemSize);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- vertexBuffer->unlock();
|
|
|
- }
|
|
|
+ Resource::initialize_internal();
|
|
|
+ }
|
|
|
|
|
|
- mMeshData = nullptr;
|
|
|
+ void Mesh::throwIfNotRenderThread() const
|
|
|
+ {
|
|
|
+ if(CM_THREAD_CURRENT_ID != RenderSystemManager::getActive()->getRenderThreadId())
|
|
|
+ CM_EXCEPT(InternalErrorException, "Calling an internal texture method from a non-render thread!");
|
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
|
@@ -307,6 +340,18 @@ namespace CamelotEngine
|
|
|
|
|
|
MeshPtr Mesh::create()
|
|
|
{
|
|
|
- return MeshPtr(new Mesh());
|
|
|
+ MeshPtr mesh = MeshPtr(new Mesh());
|
|
|
+ mesh->initialize();
|
|
|
+
|
|
|
+ return mesh;
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ MeshPtr Mesh::createEmpty()
|
|
|
+ {
|
|
|
+ MeshPtr mesh = MeshPtr(new Mesh());
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#undef THROW_IF_NOT_RENDER_THREAD
|