|
|
@@ -16,6 +16,283 @@ namespace bs
|
|
|
{
|
|
|
MESH_DESC MESH_DESC::DEFAULT = MESH_DESC();
|
|
|
|
|
|
+ Mesh::Mesh(const MESH_DESC& desc)
|
|
|
+ :MeshBase(desc.numVertices, desc.numIndices, desc.subMeshes), mVertexDesc(desc.vertexDesc), mUsage(desc.usage),
|
|
|
+ mIndexType(desc.indexType), mSkeleton(desc.skeleton), mMorphShapes(desc.morphShapes)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
+ :MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), desc.subMeshes),
|
|
|
+ mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()),
|
|
|
+ mUsage(desc.usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(desc.skeleton),
|
|
|
+ mMorphShapes(desc.morphShapes)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Mesh::Mesh()
|
|
|
+ :MeshBase(0, 0, DOT_TRIANGLE_LIST), mUsage(MU_STATIC), mIndexType(IT_32BIT)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Mesh::~Mesh()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ AsyncOp Mesh::writeData(const SPtr<MeshData>& data, bool discardEntireBuffer)
|
|
|
+ {
|
|
|
+ updateBounds(*data);
|
|
|
+ updateCPUBuffer(0, *data);
|
|
|
+
|
|
|
+ data->_lock();
|
|
|
+
|
|
|
+ std::function<void(const SPtr<ct::MeshCore>&, const SPtr<MeshData>&, bool, AsyncOp&)> func =
|
|
|
+ [&](const SPtr<ct::MeshCore>& mesh, const SPtr<MeshData>& _meshData, bool _discardEntireBuffer, AsyncOp& asyncOp)
|
|
|
+ {
|
|
|
+ mesh->writeData(*_meshData, _discardEntireBuffer, false);
|
|
|
+ _meshData->_unlock();
|
|
|
+ asyncOp._completeOperation();
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ return gCoreThread().queueReturnCommand(std::bind(func, getCore(),
|
|
|
+ data, discardEntireBuffer, std::placeholders::_1));
|
|
|
+ }
|
|
|
+
|
|
|
+ AsyncOp Mesh::readData(const SPtr<MeshData>& data)
|
|
|
+ {
|
|
|
+ data->_lock();
|
|
|
+
|
|
|
+ std::function<void(const SPtr<ct::MeshCore>&, const SPtr<MeshData>&, AsyncOp&)> func =
|
|
|
+ [&](const SPtr<ct::MeshCore>& mesh, const SPtr<MeshData>& _meshData, AsyncOp& asyncOp)
|
|
|
+ {
|
|
|
+ // Make sure any queued command start executing before reading
|
|
|
+ ct::RenderAPICore::instance().submitCommandBuffer(nullptr);
|
|
|
+
|
|
|
+ mesh->readData(*_meshData);
|
|
|
+ _meshData->_unlock();
|
|
|
+ asyncOp._completeOperation();
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ return gCoreThread().queueReturnCommand(std::bind(func, getCore(),
|
|
|
+ data, std::placeholders::_1));
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<MeshData> Mesh::allocBuffer() const
|
|
|
+ {
|
|
|
+ SPtr<MeshData> meshData = bs_shared_ptr_new<MeshData>(mProperties.mNumVertices, mProperties.mNumIndices,
|
|
|
+ mVertexDesc, mIndexType);
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::initialize()
|
|
|
+ {
|
|
|
+ if (mCPUData != nullptr)
|
|
|
+ updateBounds(*mCPUData);
|
|
|
+
|
|
|
+ MeshBase::initialize();
|
|
|
+
|
|
|
+ if ((mUsage & MU_CPUCACHED) != 0 && mCPUData == nullptr)
|
|
|
+ createCPUBuffer();
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::updateBounds(const MeshData& meshData)
|
|
|
+ {
|
|
|
+ mProperties.mBounds = meshData.calculateBounds();
|
|
|
+ markCoreDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<ct::MeshCore> Mesh::getCore() const
|
|
|
+ {
|
|
|
+ return std::static_pointer_cast<ct::MeshCore>(mCoreSpecific);
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<ct::CoreObjectCore> Mesh::createCore() const
|
|
|
+ {
|
|
|
+ MESH_DESC desc;
|
|
|
+ desc.numVertices = mProperties.mNumVertices;
|
|
|
+ desc.numIndices = mProperties.mNumIndices;
|
|
|
+ desc.vertexDesc = mVertexDesc;
|
|
|
+ desc.subMeshes = mProperties.mSubMeshes;
|
|
|
+ desc.usage = mUsage;
|
|
|
+ desc.indexType = mIndexType;
|
|
|
+ desc.skeleton = mSkeleton;
|
|
|
+ desc.morphShapes = mMorphShapes;
|
|
|
+
|
|
|
+ ct::MeshCore* obj = new (bs_alloc<ct::MeshCore>()) ct::MeshCore(mCPUData, desc, GDF_DEFAULT);
|
|
|
+
|
|
|
+ SPtr<ct::CoreObjectCore> meshCore = bs_shared_ptr<ct::MeshCore>(obj);
|
|
|
+ meshCore->_setThisPtr(meshCore);
|
|
|
+
|
|
|
+ if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
+ mCPUData = nullptr;
|
|
|
+
|
|
|
+ return meshCore;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::updateCPUBuffer(UINT32 subresourceIdx, const MeshData& pixelData)
|
|
|
+ {
|
|
|
+ if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (subresourceIdx > 0)
|
|
|
+ {
|
|
|
+ LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. 1.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pixelData.getNumIndices() != mProperties.getNumIndices() ||
|
|
|
+ pixelData.getNumVertices() != mProperties.getNumVertices() ||
|
|
|
+ pixelData.getIndexType() != mIndexType ||
|
|
|
+ pixelData.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
|
|
|
+ {
|
|
|
+ LOGERR("Provided buffer is not of valid dimensions or format in order to update this mesh.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mCPUData->getSize() != pixelData.getSize())
|
|
|
+ BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
|
|
|
+
|
|
|
+ UINT8* dest = mCPUData->getData();
|
|
|
+ UINT8* src = pixelData.getData();
|
|
|
+
|
|
|
+ memcpy(dest, src, pixelData.getSize());
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::readCachedData(MeshData& dest)
|
|
|
+ {
|
|
|
+ if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
+ {
|
|
|
+ LOGERR("Attempting to read CPU data from a mesh that is created without CPU caching.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dest.getNumIndices() != mProperties.getNumIndices() ||
|
|
|
+ dest.getNumVertices() != mProperties.getNumVertices() ||
|
|
|
+ dest.getIndexType() != mIndexType ||
|
|
|
+ dest.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
|
|
|
+ {
|
|
|
+ LOGERR("Provided buffer is not of valid dimensions or format in order to read from this mesh.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mCPUData->getSize() != dest.getSize())
|
|
|
+ BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
|
|
|
+
|
|
|
+ UINT8* srcPtr = mCPUData->getData();
|
|
|
+ UINT8* destPtr = dest.getData();
|
|
|
+
|
|
|
+ memcpy(destPtr, srcPtr, dest.getSize());
|
|
|
+ }
|
|
|
+
|
|
|
+ void Mesh::createCPUBuffer()
|
|
|
+ {
|
|
|
+ mCPUData = allocBuffer();
|
|
|
+ }
|
|
|
+
|
|
|
+ HMesh Mesh::dummy()
|
|
|
+ {
|
|
|
+ return MeshManager::instance().getDummyMesh();
|
|
|
+ }
|
|
|
+
|
|
|
+ /************************************************************************/
|
|
|
+ /* SERIALIZATION */
|
|
|
+ /************************************************************************/
|
|
|
+
|
|
|
+ RTTITypeBase* Mesh::getRTTIStatic()
|
|
|
+ {
|
|
|
+ return MeshRTTI::instance();
|
|
|
+ }
|
|
|
+
|
|
|
+ RTTITypeBase* Mesh::getRTTI() const
|
|
|
+ {
|
|
|
+ return Mesh::getRTTIStatic();
|
|
|
+ }
|
|
|
+
|
|
|
+ /************************************************************************/
|
|
|
+ /* STATICS */
|
|
|
+ /************************************************************************/
|
|
|
+
|
|
|
+ HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
|
|
|
+ int usage, DrawOperationType drawOp, IndexType indexType)
|
|
|
+ {
|
|
|
+ MESH_DESC desc;
|
|
|
+ desc.numVertices = numVertices;
|
|
|
+ desc.numIndices = numIndices;
|
|
|
+ desc.vertexDesc = vertexDesc;
|
|
|
+ desc.usage = usage;
|
|
|
+ desc.subMeshes.push_back(SubMesh(0, numIndices, drawOp));
|
|
|
+ desc.indexType = indexType;
|
|
|
+
|
|
|
+ SPtr<Mesh> meshPtr = _createPtr(desc);
|
|
|
+ return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
+ }
|
|
|
+
|
|
|
+ HMesh Mesh::create(const MESH_DESC& desc)
|
|
|
+ {
|
|
|
+ SPtr<Mesh> meshPtr = _createPtr(desc);
|
|
|
+ return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
+ }
|
|
|
+
|
|
|
+ HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
+ {
|
|
|
+ SPtr<Mesh> meshPtr = _createPtr(initialMeshData, desc);
|
|
|
+ return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
+ }
|
|
|
+
|
|
|
+ HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
|
|
|
+ {
|
|
|
+ SPtr<Mesh> meshPtr = _createPtr(initialMeshData, usage, drawOp);
|
|
|
+ return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<Mesh> Mesh::_createPtr(const MESH_DESC& desc)
|
|
|
+ {
|
|
|
+ SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(desc));
|
|
|
+ mesh->_setThisPtr(mesh);
|
|
|
+ mesh->initialize();
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
+ {
|
|
|
+ SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialMeshData, desc));
|
|
|
+ mesh->_setThisPtr(mesh);
|
|
|
+ mesh->initialize();
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
|
|
|
+ {
|
|
|
+ MESH_DESC desc;
|
|
|
+ desc.usage = usage;
|
|
|
+ desc.subMeshes.push_back(SubMesh(0, initialMeshData->getNumIndices(), drawOp));
|
|
|
+
|
|
|
+ SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialMeshData, desc));
|
|
|
+ mesh->_setThisPtr(mesh);
|
|
|
+ mesh->initialize();
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ }
|
|
|
+
|
|
|
+ SPtr<Mesh> Mesh::createEmpty()
|
|
|
+ {
|
|
|
+ SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh());
|
|
|
+ mesh->_setThisPtr(mesh);
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ }
|
|
|
+
|
|
|
+ namespace ct
|
|
|
+ {
|
|
|
MeshCore::MeshCore(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc, GpuDeviceFlags deviceMask)
|
|
|
: MeshCoreBase(desc.numVertices, desc.numIndices, desc.subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr)
|
|
|
, mVertexDesc(desc.vertexDesc), mUsage(desc.usage), mIndexType(desc.indexType), mDeviceMask(deviceMask)
|
|
|
@@ -183,464 +460,190 @@ namespace bs
|
|
|
if (!meshData.getVertexDesc()->hasElement(VES_COLOR, semanticIdx, i))
|
|
|
continue;
|
|
|
|
|
|
- UINT8* colorData = bufferCopy + mVertexDesc->getElementOffsetFromStream(VES_COLOR, semanticIdx, i);
|
|
|
- for (UINT32 j = 0; j < mVertexData->vertexCount; j++)
|
|
|
- {
|
|
|
- UINT32* curColor = (UINT32*)colorData;
|
|
|
-
|
|
|
- (*curColor) = ((*curColor) & 0xFF00FF00) | ((*curColor >> 16) & 0x000000FF) | ((*curColor << 16) & 0x00FF0000);
|
|
|
-
|
|
|
- colorData += vertexStride;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- vertexBuffer->writeData(0, bufferSize, bufferCopy, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL, queueIdx);
|
|
|
-
|
|
|
- bs_free(bufferCopy);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- vertexBuffer->writeData(0, bufferSize, srcVertBufferData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL,
|
|
|
- queueIdx);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (performUpdateBounds)
|
|
|
- updateBounds(meshData);
|
|
|
- }
|
|
|
-
|
|
|
- void MeshCore::readData(MeshData& meshData, UINT32 deviceIdx, UINT32 queueIdx)
|
|
|
- {
|
|
|
- THROW_IF_NOT_CORE_THREAD;
|
|
|
-
|
|
|
- IndexType indexType = IT_32BIT;
|
|
|
- if (mIndexBuffer)
|
|
|
- indexType = mIndexBuffer->getProperties().getType();
|
|
|
-
|
|
|
- if (mIndexBuffer)
|
|
|
- {
|
|
|
- const IndexBufferProperties& ibProps = mIndexBuffer->getProperties();
|
|
|
-
|
|
|
- if (meshData.getIndexElementSize() != ibProps.getIndexSize())
|
|
|
- {
|
|
|
- LOGERR("Provided index size doesn't match meshes index size. Needed: " +
|
|
|
- toString(ibProps.getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- UINT8* idxData = static_cast<UINT8*>(mIndexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
|
|
|
- UINT32 idxElemSize = ibProps.getIndexSize();
|
|
|
-
|
|
|
- UINT8* indices = nullptr;
|
|
|
-
|
|
|
- if (indexType == IT_16BIT)
|
|
|
- indices = (UINT8*)meshData.getIndices16();
|
|
|
- else
|
|
|
- indices = (UINT8*)meshData.getIndices32();
|
|
|
-
|
|
|
- UINT32 numIndicesToCopy = std::min(mProperties.mNumIndices, meshData.getNumIndices());
|
|
|
-
|
|
|
- UINT32 indicesSize = numIndicesToCopy * idxElemSize;
|
|
|
- if (indicesSize > meshData.getIndexBufferSize())
|
|
|
- {
|
|
|
- LOGERR("Provided buffer doesn't have enough space to store mesh indices.");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(indices, idxData, numIndicesToCopy * idxElemSize);
|
|
|
-
|
|
|
- mIndexBuffer->unlock();
|
|
|
- }
|
|
|
-
|
|
|
- if (mVertexData)
|
|
|
- {
|
|
|
- auto vertexBuffers = mVertexData->getBuffers();
|
|
|
-
|
|
|
- UINT32 streamIdx = 0;
|
|
|
- for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
|
|
|
- {
|
|
|
- if (!meshData.getVertexDesc()->hasStream(streamIdx))
|
|
|
- continue;
|
|
|
-
|
|
|
- SPtr<VertexBufferCore> vertexBuffer = iter->second;
|
|
|
- const VertexBufferProperties& vbProps = vertexBuffer->getProperties();
|
|
|
-
|
|
|
- // Ensure both have the same sized vertices
|
|
|
- UINT32 myVertSize = mVertexDesc->getVertexStride(streamIdx);
|
|
|
- UINT32 otherVertSize = meshData.getVertexDesc()->getVertexStride(streamIdx);
|
|
|
- if (myVertSize != otherVertSize)
|
|
|
- {
|
|
|
- LOGERR("Provided vertex size for stream " + toString(streamIdx) + " doesn't match meshes vertex size. Needed: " +
|
|
|
- toString(myVertSize) + ". Got: " + toString(otherVertSize));
|
|
|
-
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- UINT32 numVerticesToCopy = meshData.getNumVertices();
|
|
|
- UINT32 bufferSize = vbProps.getVertexSize() * numVerticesToCopy;
|
|
|
-
|
|
|
- if (bufferSize > vertexBuffer->getSize())
|
|
|
- {
|
|
|
- LOGERR("Vertex buffer values for stream \"" + toString(streamIdx) + "\" are being read out of valid range.");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
|
|
|
-
|
|
|
- UINT8* dest = meshData.getStreamData(streamIdx);
|
|
|
- memcpy(dest, vertDataPtr, bufferSize);
|
|
|
-
|
|
|
- vertexBuffer->unlock();
|
|
|
-
|
|
|
- streamIdx++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void MeshCore::updateBounds(const MeshData& meshData)
|
|
|
- {
|
|
|
- mProperties.mBounds = meshData.calculateBounds();
|
|
|
-
|
|
|
- // TODO - Sync this to sim-thread possibly?
|
|
|
- }
|
|
|
-
|
|
|
- SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
|
|
|
- int usage, DrawOperationType drawOp, IndexType indexType, GpuDeviceFlags deviceMask)
|
|
|
- {
|
|
|
- MESH_DESC desc;
|
|
|
- desc.numVertices = numVertices;
|
|
|
- desc.numIndices = numIndices;
|
|
|
- desc.vertexDesc = vertexDesc;
|
|
|
- desc.subMeshes.push_back(SubMesh(0, numIndices, drawOp));
|
|
|
- desc.usage = usage;
|
|
|
- desc.indexType = indexType;
|
|
|
-
|
|
|
- SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc, deviceMask));
|
|
|
- mesh->_setThisPtr(mesh);
|
|
|
- mesh->initialize();
|
|
|
-
|
|
|
- return mesh;
|
|
|
- }
|
|
|
-
|
|
|
- SPtr<MeshCore> MeshCore::create(const MESH_DESC& desc, GpuDeviceFlags deviceMask)
|
|
|
- {
|
|
|
- SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc, deviceMask));
|
|
|
-
|
|
|
- mesh->_setThisPtr(mesh);
|
|
|
- mesh->initialize();
|
|
|
-
|
|
|
- return mesh;
|
|
|
- }
|
|
|
-
|
|
|
- SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc, GpuDeviceFlags deviceMask)
|
|
|
- {
|
|
|
- MESH_DESC descCopy = desc;
|
|
|
- descCopy.numVertices = initialMeshData->getNumVertices();
|
|
|
- descCopy.numIndices = initialMeshData->getNumIndices();
|
|
|
- descCopy.vertexDesc = initialMeshData->getVertexDesc();
|
|
|
- descCopy.indexType = initialMeshData->getIndexType();
|
|
|
-
|
|
|
- SPtr<MeshCore> mesh =
|
|
|
- bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(initialMeshData, descCopy, deviceMask));
|
|
|
-
|
|
|
- mesh->_setThisPtr(mesh);
|
|
|
- mesh->initialize();
|
|
|
-
|
|
|
- return mesh;
|
|
|
- }
|
|
|
-
|
|
|
- SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp,
|
|
|
- GpuDeviceFlags deviceMask)
|
|
|
- {
|
|
|
- MESH_DESC desc;
|
|
|
- desc.numVertices = initialMeshData->getNumVertices();
|
|
|
- desc.numIndices = initialMeshData->getNumIndices();
|
|
|
- desc.vertexDesc = initialMeshData->getVertexDesc();
|
|
|
- desc.indexType = initialMeshData->getIndexType();
|
|
|
- desc.subMeshes.push_back(SubMesh(0, initialMeshData->getNumIndices(), drawOp));
|
|
|
- desc.usage = usage;
|
|
|
-
|
|
|
- SPtr<MeshCore> mesh =
|
|
|
- bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(initialMeshData, desc, deviceMask));
|
|
|
-
|
|
|
- mesh->_setThisPtr(mesh);
|
|
|
- mesh->initialize();
|
|
|
-
|
|
|
- return mesh;
|
|
|
- }
|
|
|
-
|
|
|
- Mesh::Mesh(const MESH_DESC& desc)
|
|
|
- :MeshBase(desc.numVertices, desc.numIndices, desc.subMeshes), mVertexDesc(desc.vertexDesc), mUsage(desc.usage),
|
|
|
- mIndexType(desc.indexType), mSkeleton(desc.skeleton), mMorphShapes(desc.morphShapes)
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
- :MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), desc.subMeshes),
|
|
|
- mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()),
|
|
|
- mUsage(desc.usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(desc.skeleton),
|
|
|
- mMorphShapes(desc.morphShapes)
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- Mesh::Mesh()
|
|
|
- :MeshBase(0, 0, DOT_TRIANGLE_LIST), mUsage(MU_STATIC), mIndexType(IT_32BIT)
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- Mesh::~Mesh()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- AsyncOp Mesh::writeData(const SPtr<MeshData>& data, bool discardEntireBuffer)
|
|
|
- {
|
|
|
- updateBounds(*data);
|
|
|
- updateCPUBuffer(0, *data);
|
|
|
-
|
|
|
- data->_lock();
|
|
|
-
|
|
|
- std::function<void(const SPtr<MeshCore>&, const SPtr<MeshData>&, bool, AsyncOp&)> func =
|
|
|
- [&](const SPtr<MeshCore>& mesh, const SPtr<MeshData>& _meshData, bool _discardEntireBuffer, AsyncOp& asyncOp)
|
|
|
- {
|
|
|
- mesh->writeData(*_meshData, _discardEntireBuffer, false);
|
|
|
- _meshData->_unlock();
|
|
|
- asyncOp._completeOperation();
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- return gCoreThread().queueReturnCommand(std::bind(func, getCore(),
|
|
|
- data, discardEntireBuffer, std::placeholders::_1));
|
|
|
- }
|
|
|
-
|
|
|
- AsyncOp Mesh::readData(const SPtr<MeshData>& data)
|
|
|
- {
|
|
|
- data->_lock();
|
|
|
-
|
|
|
- std::function<void(const SPtr<MeshCore>&, const SPtr<MeshData>&, AsyncOp&)> func =
|
|
|
- [&](const SPtr<MeshCore>& mesh, const SPtr<MeshData>& _meshData, AsyncOp& asyncOp)
|
|
|
- {
|
|
|
- // Make sure any queued command start executing before reading
|
|
|
- RenderAPICore::instance().submitCommandBuffer(nullptr);
|
|
|
-
|
|
|
- mesh->readData(*_meshData);
|
|
|
- _meshData->_unlock();
|
|
|
- asyncOp._completeOperation();
|
|
|
+ UINT8* colorData = bufferCopy + mVertexDesc->getElementOffsetFromStream(VES_COLOR, semanticIdx, i);
|
|
|
+ for (UINT32 j = 0; j < mVertexData->vertexCount; j++)
|
|
|
+ {
|
|
|
+ UINT32* curColor = (UINT32*)colorData;
|
|
|
|
|
|
- };
|
|
|
+ (*curColor) = ((*curColor) & 0xFF00FF00) | ((*curColor >> 16) & 0x000000FF) | ((*curColor << 16) & 0x00FF0000);
|
|
|
|
|
|
- return gCoreThread().queueReturnCommand(std::bind(func, getCore(),
|
|
|
- data, std::placeholders::_1));
|
|
|
- }
|
|
|
+ colorData += vertexStride;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- SPtr<MeshData> Mesh::allocBuffer() const
|
|
|
- {
|
|
|
- SPtr<MeshData> meshData = bs_shared_ptr_new<MeshData>(mProperties.mNumVertices, mProperties.mNumIndices,
|
|
|
- mVertexDesc, mIndexType);
|
|
|
+ vertexBuffer->writeData(0, bufferSize, bufferCopy, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL, queueIdx);
|
|
|
|
|
|
- return meshData;
|
|
|
+ bs_free(bufferCopy);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ vertexBuffer->writeData(0, bufferSize, srcVertBufferData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL,
|
|
|
+ queueIdx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (performUpdateBounds)
|
|
|
+ updateBounds(meshData);
|
|
|
}
|
|
|
|
|
|
- void Mesh::initialize()
|
|
|
+ void MeshCore::readData(MeshData& meshData, UINT32 deviceIdx, UINT32 queueIdx)
|
|
|
{
|
|
|
- if (mCPUData != nullptr)
|
|
|
- updateBounds(*mCPUData);
|
|
|
-
|
|
|
- MeshBase::initialize();
|
|
|
+ THROW_IF_NOT_CORE_THREAD;
|
|
|
|
|
|
- if ((mUsage & MU_CPUCACHED) != 0 && mCPUData == nullptr)
|
|
|
- createCPUBuffer();
|
|
|
- }
|
|
|
+ IndexType indexType = IT_32BIT;
|
|
|
+ if (mIndexBuffer)
|
|
|
+ indexType = mIndexBuffer->getProperties().getType();
|
|
|
|
|
|
- void Mesh::updateBounds(const MeshData& meshData)
|
|
|
- {
|
|
|
- mProperties.mBounds = meshData.calculateBounds();
|
|
|
- markCoreDirty();
|
|
|
- }
|
|
|
+ if (mIndexBuffer)
|
|
|
+ {
|
|
|
+ const IndexBufferProperties& ibProps = mIndexBuffer->getProperties();
|
|
|
|
|
|
- SPtr<MeshCore> Mesh::getCore() const
|
|
|
- {
|
|
|
- return std::static_pointer_cast<MeshCore>(mCoreSpecific);
|
|
|
- }
|
|
|
+ if (meshData.getIndexElementSize() != ibProps.getIndexSize())
|
|
|
+ {
|
|
|
+ LOGERR("Provided index size doesn't match meshes index size. Needed: " +
|
|
|
+ toString(ibProps.getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- SPtr<CoreObjectCore> Mesh::createCore() const
|
|
|
- {
|
|
|
- MESH_DESC desc;
|
|
|
- desc.numVertices = mProperties.mNumVertices;
|
|
|
- desc.numIndices = mProperties.mNumIndices;
|
|
|
- desc.vertexDesc = mVertexDesc;
|
|
|
- desc.subMeshes = mProperties.mSubMeshes;
|
|
|
- desc.usage = mUsage;
|
|
|
- desc.indexType = mIndexType;
|
|
|
- desc.skeleton = mSkeleton;
|
|
|
- desc.morphShapes = mMorphShapes;
|
|
|
+ UINT8* idxData = static_cast<UINT8*>(mIndexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
|
|
|
+ UINT32 idxElemSize = ibProps.getIndexSize();
|
|
|
|
|
|
- MeshCore* obj = new (bs_alloc<MeshCore>()) MeshCore(mCPUData, desc, GDF_DEFAULT);
|
|
|
+ UINT8* indices = nullptr;
|
|
|
|
|
|
- SPtr<CoreObjectCore> meshCore = bs_shared_ptr<MeshCore>(obj);
|
|
|
- meshCore->_setThisPtr(meshCore);
|
|
|
+ if (indexType == IT_16BIT)
|
|
|
+ indices = (UINT8*)meshData.getIndices16();
|
|
|
+ else
|
|
|
+ indices = (UINT8*)meshData.getIndices32();
|
|
|
|
|
|
- if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
- mCPUData = nullptr;
|
|
|
+ UINT32 numIndicesToCopy = std::min(mProperties.mNumIndices, meshData.getNumIndices());
|
|
|
|
|
|
- return meshCore;
|
|
|
- }
|
|
|
+ UINT32 indicesSize = numIndicesToCopy * idxElemSize;
|
|
|
+ if (indicesSize > meshData.getIndexBufferSize())
|
|
|
+ {
|
|
|
+ LOGERR("Provided buffer doesn't have enough space to store mesh indices.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- void Mesh::updateCPUBuffer(UINT32 subresourceIdx, const MeshData& pixelData)
|
|
|
- {
|
|
|
- if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
- return;
|
|
|
+ memcpy(indices, idxData, numIndicesToCopy * idxElemSize);
|
|
|
|
|
|
- if (subresourceIdx > 0)
|
|
|
- {
|
|
|
- LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. 1.");
|
|
|
- return;
|
|
|
+ mIndexBuffer->unlock();
|
|
|
}
|
|
|
|
|
|
- if (pixelData.getNumIndices() != mProperties.getNumIndices() ||
|
|
|
- pixelData.getNumVertices() != mProperties.getNumVertices() ||
|
|
|
- pixelData.getIndexType() != mIndexType ||
|
|
|
- pixelData.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
|
|
|
+ if (mVertexData)
|
|
|
{
|
|
|
- LOGERR("Provided buffer is not of valid dimensions or format in order to update this mesh.");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (mCPUData->getSize() != pixelData.getSize())
|
|
|
- BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
|
|
|
+ auto vertexBuffers = mVertexData->getBuffers();
|
|
|
|
|
|
- UINT8* dest = mCPUData->getData();
|
|
|
- UINT8* src = pixelData.getData();
|
|
|
+ UINT32 streamIdx = 0;
|
|
|
+ for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
|
|
|
+ {
|
|
|
+ if (!meshData.getVertexDesc()->hasStream(streamIdx))
|
|
|
+ continue;
|
|
|
|
|
|
- memcpy(dest, src, pixelData.getSize());
|
|
|
- }
|
|
|
+ SPtr<VertexBufferCore> vertexBuffer = iter->second;
|
|
|
+ const VertexBufferProperties& vbProps = vertexBuffer->getProperties();
|
|
|
|
|
|
- void Mesh::readCachedData(MeshData& dest)
|
|
|
- {
|
|
|
- if ((mUsage & MU_CPUCACHED) == 0)
|
|
|
- {
|
|
|
- LOGERR("Attempting to read CPU data from a mesh that is created without CPU caching.");
|
|
|
- return;
|
|
|
- }
|
|
|
+ // Ensure both have the same sized vertices
|
|
|
+ UINT32 myVertSize = mVertexDesc->getVertexStride(streamIdx);
|
|
|
+ UINT32 otherVertSize = meshData.getVertexDesc()->getVertexStride(streamIdx);
|
|
|
+ if (myVertSize != otherVertSize)
|
|
|
+ {
|
|
|
+ LOGERR("Provided vertex size for stream " + toString(streamIdx) + " doesn't match meshes vertex size. Needed: " +
|
|
|
+ toString(myVertSize) + ". Got: " + toString(otherVertSize));
|
|
|
|
|
|
- if (dest.getNumIndices() != mProperties.getNumIndices() ||
|
|
|
- dest.getNumVertices() != mProperties.getNumVertices() ||
|
|
|
- dest.getIndexType() != mIndexType ||
|
|
|
- dest.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
|
|
|
- {
|
|
|
- LOGERR("Provided buffer is not of valid dimensions or format in order to read from this mesh.");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (mCPUData->getSize() != dest.getSize())
|
|
|
- BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- UINT8* srcPtr = mCPUData->getData();
|
|
|
- UINT8* destPtr = dest.getData();
|
|
|
+ UINT32 numVerticesToCopy = meshData.getNumVertices();
|
|
|
+ UINT32 bufferSize = vbProps.getVertexSize() * numVerticesToCopy;
|
|
|
|
|
|
- memcpy(destPtr, srcPtr, dest.getSize());
|
|
|
- }
|
|
|
+ if (bufferSize > vertexBuffer->getSize())
|
|
|
+ {
|
|
|
+ LOGERR("Vertex buffer values for stream \"" + toString(streamIdx) + "\" are being read out of valid range.");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- void Mesh::createCPUBuffer()
|
|
|
- {
|
|
|
- mCPUData = allocBuffer();
|
|
|
- }
|
|
|
+ UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
|
|
|
|
|
|
- HMesh Mesh::dummy()
|
|
|
- {
|
|
|
- return MeshManager::instance().getDummyMesh();
|
|
|
- }
|
|
|
+ UINT8* dest = meshData.getStreamData(streamIdx);
|
|
|
+ memcpy(dest, vertDataPtr, bufferSize);
|
|
|
|
|
|
- /************************************************************************/
|
|
|
- /* SERIALIZATION */
|
|
|
- /************************************************************************/
|
|
|
+ vertexBuffer->unlock();
|
|
|
|
|
|
- RTTITypeBase* Mesh::getRTTIStatic()
|
|
|
- {
|
|
|
- return MeshRTTI::instance();
|
|
|
+ streamIdx++;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- RTTITypeBase* Mesh::getRTTI() const
|
|
|
+ void MeshCore::updateBounds(const MeshData& meshData)
|
|
|
{
|
|
|
- return Mesh::getRTTIStatic();
|
|
|
+ mProperties.mBounds = meshData.calculateBounds();
|
|
|
+
|
|
|
+ // TODO - Sync this to sim-thread possibly?
|
|
|
}
|
|
|
|
|
|
- /************************************************************************/
|
|
|
- /* STATICS */
|
|
|
- /************************************************************************/
|
|
|
-
|
|
|
- HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
|
|
|
- int usage, DrawOperationType drawOp, IndexType indexType)
|
|
|
+ SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
|
|
|
+ int usage, DrawOperationType drawOp, IndexType indexType, GpuDeviceFlags deviceMask)
|
|
|
{
|
|
|
MESH_DESC desc;
|
|
|
desc.numVertices = numVertices;
|
|
|
desc.numIndices = numIndices;
|
|
|
desc.vertexDesc = vertexDesc;
|
|
|
- desc.usage = usage;
|
|
|
desc.subMeshes.push_back(SubMesh(0, numIndices, drawOp));
|
|
|
+ desc.usage = usage;
|
|
|
desc.indexType = indexType;
|
|
|
|
|
|
- SPtr<Mesh> meshPtr = _createPtr(desc);
|
|
|
- return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
- }
|
|
|
-
|
|
|
- HMesh Mesh::create(const MESH_DESC& desc)
|
|
|
- {
|
|
|
- SPtr<Mesh> meshPtr = _createPtr(desc);
|
|
|
- return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
- }
|
|
|
+ SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc, deviceMask));
|
|
|
+ mesh->_setThisPtr(mesh);
|
|
|
+ mesh->initialize();
|
|
|
|
|
|
- HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
- {
|
|
|
- SPtr<Mesh> meshPtr = _createPtr(initialMeshData, desc);
|
|
|
- return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
+ return mesh;
|
|
|
}
|
|
|
|
|
|
- HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
|
|
|
+ SPtr<MeshCore> MeshCore::create(const MESH_DESC& desc, GpuDeviceFlags deviceMask)
|
|
|
{
|
|
|
- SPtr<Mesh> meshPtr = _createPtr(initialMeshData, usage, drawOp);
|
|
|
- return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
|
|
|
- }
|
|
|
+ SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc, deviceMask));
|
|
|
|
|
|
- SPtr<Mesh> Mesh::_createPtr(const MESH_DESC& desc)
|
|
|
- {
|
|
|
- SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(desc));
|
|
|
mesh->_setThisPtr(mesh);
|
|
|
mesh->initialize();
|
|
|
|
|
|
return mesh;
|
|
|
}
|
|
|
|
|
|
- SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
|
|
|
+ SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc, GpuDeviceFlags deviceMask)
|
|
|
{
|
|
|
- SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialMeshData, desc));
|
|
|
+ MESH_DESC descCopy = desc;
|
|
|
+ descCopy.numVertices = initialMeshData->getNumVertices();
|
|
|
+ descCopy.numIndices = initialMeshData->getNumIndices();
|
|
|
+ descCopy.vertexDesc = initialMeshData->getVertexDesc();
|
|
|
+ descCopy.indexType = initialMeshData->getIndexType();
|
|
|
+
|
|
|
+ SPtr<MeshCore> mesh =
|
|
|
+ bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(initialMeshData, descCopy, deviceMask));
|
|
|
+
|
|
|
mesh->_setThisPtr(mesh);
|
|
|
mesh->initialize();
|
|
|
|
|
|
return mesh;
|
|
|
}
|
|
|
|
|
|
- SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
|
|
|
+ SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp,
|
|
|
+ GpuDeviceFlags deviceMask)
|
|
|
{
|
|
|
MESH_DESC desc;
|
|
|
- desc.usage = usage;
|
|
|
+ desc.numVertices = initialMeshData->getNumVertices();
|
|
|
+ desc.numIndices = initialMeshData->getNumIndices();
|
|
|
+ desc.vertexDesc = initialMeshData->getVertexDesc();
|
|
|
+ desc.indexType = initialMeshData->getIndexType();
|
|
|
desc.subMeshes.push_back(SubMesh(0, initialMeshData->getNumIndices(), drawOp));
|
|
|
+ desc.usage = usage;
|
|
|
+
|
|
|
+ SPtr<MeshCore> mesh =
|
|
|
+ bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(initialMeshData, desc, deviceMask));
|
|
|
|
|
|
- SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialMeshData, desc));
|
|
|
mesh->_setThisPtr(mesh);
|
|
|
mesh->initialize();
|
|
|
|
|
|
return mesh;
|
|
|
}
|
|
|
-
|
|
|
- SPtr<Mesh> Mesh::createEmpty()
|
|
|
- {
|
|
|
- SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh());
|
|
|
- mesh->_setThisPtr(mesh);
|
|
|
-
|
|
|
- return mesh;
|
|
|
}
|
|
|
}
|