Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualLarryKing

Posted 03 January 2013 - 06:40 PM

Hello all, I'm looking for some feedback regrading a model format and loader I've been working on over the past few days. I'm transitioning to C++, coming from C# and this has been a great exercise thus far, but I feel this post might end up a bit lengthy.
 
Some background as to what I wanted to accomplish with the file format:

  • The model can contain a large number of meshes.
  • Each mesh can have an arbitrary number of vertex buffers; not that a mesh should have 8, 16, or even 65,535 vertex streams, just that it could.
  • Each mesh can have an arbitrary number of textures; again, see above.
  • Each mesh and the model itself and should have some sort of bounding volume.
  • Fast loading; the model should use local pointers and require minimal live processing.
  • Possibility for compression

 
After some research, it appears that loading directly into memory and then adjusting local pointers seems to be one of the fastest ways to load an object. So the entire format reflects the objects that make up my model.
 
A model contains: a pointer to some ModelTextures, a pointer to the MeshHeaders, a pointer to the MeshCullDatas and a pointer to the MeshDrawDatas.
 
I've tried to implement some Data Oriented Design – a very different concept coming from C#. I've split up the meshes into arrays of data needed for different operations: Culling and Drawing.
 
Furthermore, I'm attempting to implement this as part of my content manager, so a ModelTexture, is really just a wrapper around a shared_ptr<Texture2D> that is retrieved from another content cache.
 
All right, so here is what the model format looks like, I made a diagram!
*sorry it's so tall...
 
ModelFormat_zps271dc65c.png
 
The actual files are exported from a tool I've written in C#. I'm loading Collada files via Assimp, calculating any user requested data and displaying the model via SharpDX in a WinForms app.
 
In the end, the model gets exported to the file by the exporter first writing each mesh data object to “virtual memory,” adjusting all of the pointers and finally using a binary writer to spit out the finished file.
 
Pretty straight forward for me as I'm used to C#, but the scary stuff happens when we get to actually loading the file in C++.
 
First I load the entire file with an ifstream into a char[]. Then I cast the char[] to a Model. Now I need to offset the local pointers so that the model will work in memory; however! I read somewhere that you can't add pointers in C++, only subtract them, but to offset local pointers you needed to add!
After much internet searching, I finally found an object ptrdiff_t that I could retrieve from a pointer, add to, and then cast back to a pointer. The question then became, “Is this legal, what I'm doing?” For a full day I pondered before quizzically deciding that it should? be legal. I mean how else would you offset pointers when you shouldn't just cast to an int?
The next problem arrived when I realized that I needed to somehow delete the model from memory as well. Again not sure, as I had casted a char[] to a model, if I could delete the model. I pretended I could and wrote the destructor. Miraculously it seemed to work! The “Memory” window in Visual Studio seemed to show that the object had successfully been deleted, although I'm still not sure if I need to call delete on the model's pointers as they weren't created with new.
 
So now, I have all this code for loading a model, but I'm not sure if it's legal, safe, or even sensible!
 
Enough talk though, here's the code for loading the model:
 

std::shared_ptr<Ruined::Graphics::Model> ModelLoader::Load(const std::string &name)
{
	Ruined::Graphics::Model * model;

	std::ifstream file (m_BaseDirectory + name, std::ios::in|std::ios::binary|std::ios::ate);
	if (file.is_open())
	{
		// Get the file's total size
		unsigned int size = file.tellg();
		// Create a char[] of the size to load the file into
		char* memblock = new char [size];
		// Seek to the beginning and read the file
		file.seekg (0, std::ios::beg);
		file.read (memblock, size);
		// Finally close the file
		file.close();

		// Cast the char[] to a Ruined::Graphics::Model pointer
		model = static_cast<Ruined::Graphics::Model *>((void*)memblock);

		// The location of the model in memory
		ptrdiff_t memOffset = (ptrdiff_t)model;

		// Offset the model's local pointers
		// Mesh Headers
		ptrdiff_t intOffset;
		model->MeshHeaders = (Ruined::Graphics::MeshHeader*)(memOffset + (ptrdiff_t)model->MeshHeaders);

		// Mesh Culling Datas
		// intOffset = (ptrdiff_t)model->MeshCullDatas;
		model->MeshCullDatas = (Ruined::Graphics::MeshCullData*)(memOffset + (ptrdiff_t)model->MeshCullDatas);

		// Mesh Drawing Datas
		// intOffset = (ptrdiff_t)model->MeshDrawDatas;
		model->MeshDrawDatas = (Ruined::Graphics::MeshDrawData*)(memOffset + (ptrdiff_t)model->MeshDrawDatas);

		// Model's Ruined::Graphics::ModelTexture pointer
		// intOffset = (ptrdiff_t)model->Textures;
		model->Textures = (Ruined::Graphics::ModelTexture*)(memOffset + (ptrdiff_t)model->Textures);
				
		// Load the model's textures
		for(int t = 0; t < model->TextureCount; t++)
		{
			// Offset TextureName pointers
			// intOffset = (ptrdiff_t)(model->Textures[t].TextureName);
			model->Textures[t].TextureName = (char*)(memOffset + (ptrdiff_t)(model->Textures[t].TextureName));
			// Load the texture
			model->Textures[t].TextureContent = p_TextureCache->Load(model->Textures[t].TextureName);
		}

		HRESULT hresult;
		Ruined::Graphics::MeshDrawData * tempMeshD = nullptr;
		for(int m = 0; m < model->MeshCount; m++)
		{

			// Build the buffers
			tempMeshD = &model->MeshDrawDatas[m];

			// Offset Index Buffer
			// intOffset = (ptrdiff_t)tempMeshD->IndexBuffer;
			tempMeshD->IndexBuffer = (ID3D11Buffer*)(memOffset + (ptrdiff_t)tempMeshD->IndexBuffer);

			// Offset Vertex Buffer
			// intOffset = (ptrdiff_t)tempMeshD->VertexBuffer;
			tempMeshD->VertexBuffers = (ID3D11Buffer**)(memOffset + (ptrdiff_t)tempMeshD->VertexBuffers);

			// Offset Strides
			// intOffset = (ptrdiff_t)tempMeshD->Strides;
			tempMeshD->Strides = (unsigned int*)(memOffset + (ptrdiff_t)tempMeshD->Strides);

			// Offset Resources
			intOffset = (ptrdiff_t)tempMeshD->Resources;
			tempMeshD->Resources = (ID3D11ShaderResourceView**)(memOffset + intOffset);

			// Convert Resources * to unsigned int *
			unsigned int * index = (unsigned int*)(memOffset + intOffset);

			// Assign to the poingters from the model's textures
			for(int t = 0; t < model->MeshHeaders[m].ResourceCount; t++)		
				tempMeshD->Resources[t] = model->Textures[index[t]].TextureContent.get()->p_shaderResourceView;

			// Desc for the index buffer
			D3D11_BUFFER_DESC indexBufferDesc;		
			indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
			indexBufferDesc.ByteWidth = tempMeshD->IndexCount * (tempMeshD->IndexFormat == DXGI_FORMAT_R16_UINT ? sizeof(unsigned short) : sizeof(unsigned int));
			indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
			indexBufferDesc.CPUAccessFlags = 0;
			indexBufferDesc.MiscFlags = 0;

			D3D11_SUBRESOURCE_DATA indexData;
			indexData.pSysMem = tempMeshD->IndexBuffer;
			indexData.SysMemPitch = 0;
			indexData.SysMemSlicePitch = 0;

			hresult = p_Graphics->GetDevice()->CreateBuffer(&indexBufferDesc, &indexData, &tempMeshD->IndexBuffer);
			if(FAILED(hresult))
			{
				OutputDebugStringA("Failed to create Index Buffer");
			}

						
			// Create each vertex buffer
			Ruined::Graphics::MeshBufferDesc * tempDesc = (Ruined::Graphics::MeshBufferDesc*)(tempMeshD->VertexBuffers);
			for(unsigned int b = 0; b < tempMeshD->VertexBufferCount; b++)
			{
							
				// Each buffer gets a desc
				D3D11_BUFFER_DESC bufferDesc;
				bufferDesc.Usage = D3D11_USAGE_DEFAULT;
				bufferDesc.ByteWidth = tempDesc[b].BufferWidth;
				bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
				bufferDesc.CPUAccessFlags = 0;
				bufferDesc.MiscFlags = 0;

				// Each buffer needs a subresource data
				D3D11_SUBRESOURCE_DATA subData;
				subData.pSysMem = (void*)((ptrdiff_t)tempDesc[b].Data + memOffset);
				subData.SysMemPitch = 0;
				subData.SysMemSlicePitch = 0;

				hresult = p_Graphics->GetDevice()->CreateBuffer(&bufferDesc, &subData, &(tempMeshD->VertexBuffers[b]));
				if(FAILED(hresult))
				{
					OutputDebugStringA("Failed to create Vertex Buffer");
				}
			}

						
		}

					
	}
	else
	{
		std::string errorMsg = "Failed to load Model: ";
		errorMsg += m_BaseDirectory + name + "\n";
		OutputDebugStringA(errorMsg.c_str());

		// Set model equal to something
		model = new Ruined::Graphics::Model();
	}

	std::shared_ptr<Ruined::Graphics::Model> sModel(model);

	return sModel;
}

So that makes a little more sense, here is Model.h:

#include "MeshDrawData.h"
#include "ModelTexture.h"

#include <memory>

namespace Ruined
{
	namespace Graphics
	{
		// Combine Model Header and Model Pointers
		struct __declspec(dllexport) Model
		{

		public:
			// Header
			unsigned short _FILETYPE;
			unsigned short _FILEVERSION;
			unsigned int ModelSize;
		
			unsigned short TextureCount;
			unsigned short MeshCount;
			DirectX::BoundingBox BoundingBox;

			// Pointers
			ModelTexture * Textures;
			MeshHeader * MeshHeaders;
			MeshCullData * MeshCullDatas;
			MeshDrawData * MeshDrawDatas;

		public:
			Model(void);
			
			~Model(void);
		};
	}
}

#endif

 
Here is ModelTexture.h:

#pragma once
#ifndef _MODELTEXTURE_H
#define _MODELTEXTURE_H_ 

// Includes //
#include "Texture2D.h"

#include <memory>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) ModelTexture
		{
		public:
			char* TextureName;
			std::shared_ptr<Texture2D> TextureContent;
		};
	}
}

#endif

 
 
Here are the mesh objects:

#ifndef _MESHCULLDATA_H_
#define _MESHCULLDATA_H_

#include <DirectXCollision.h>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) MeshCullData
		{
		public:
			DirectX::BoundingBox BoundingBox;
		};
	}
}

#endif
#ifndef _MESHHEADER_H_
#define _MESHHEADER_H_

#include "MeshBufferDesc.h"

namespace Ruined
{
	namespace Graphics
	{
		enum MeshMask : unsigned short
		{
			Undefined       = 0x0000,
			Texture         = 0x0001,
			UVCoord         = 0x0002,
			Color           = 0x0004,
			Normal          = 0x0008,
			Tangent         = 0x0010,
			Binormal        = 0x0020,
			BoneIndices     = 0x0040,
			BoneWeights     = 0x0080,
			SplitBuffers    = 0x0100,
			AlphaBlend      = 0x4000
		};

		struct __declspec(dllexport) MeshHeader
		{
			MeshMask Mask;
			unsigned char UVStreamCount;
			unsigned char ColorStreamCount;
			unsigned short ResourceCount;
		};
	}
}

#endif
#ifndef _MESHDRAWDATA_H_
#define _MESHDRAWDATA_H_

#include <d3d11.h>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) MeshDrawData
		{
		public:
			unsigned int VertexBufferCount;
			ID3D11Buffer ** VertexBuffers;
			unsigned int * Strides;
			ID3D11Buffer * IndexBuffer;
			DXGI_FORMAT IndexFormat;
			ID3D11ShaderResourceView ** Resources;
			unsigned int IndexCount;
		};
	}
}

#endif
#ifndef _MESHBUFFERDESC_H_
#define _MESHBUFFERDESC_H_


namespace Ruined
{
	namespace Graphics
	{
		// Used for creating vertex buffers.
		// Only accessed at load time.
		struct __declspec(dllexport) MeshBufferDesc
		{
		public:
			unsigned int BufferWidth;
			void * Data;
		};
	}
}

#endif

Lastly here is the Model destructor:

Model::~Model(void)
{
	if(Textures != nullptr)
	{
		for(int t = 0; t < TextureCount; t++)
		{
			Textures[t].TextureContent.reset();
			Textures[t].TextureName = nullptr;
		}
	}

	if(MeshDrawDatas != nullptr)
	{
		for(int m = 0; m < MeshCount; m++)
		{
			if(MeshDrawDatas[m].IndexBuffer != nullptr)
			{
				MeshDrawDatas[m].IndexBuffer->Release();
				MeshDrawDatas[m].IndexBuffer = nullptr;
			}

			for(int v = 0; v < MeshDrawDatas[m].VertexBufferCount; v++)
			{
				if(MeshDrawDatas[m].VertexBuffers[v] != nullptr)
				{
					MeshDrawDatas[m].VertexBuffers[v]->Release();
					MeshDrawDatas[m].VertexBuffers[v] = nullptr;
				}
			}
		}
	}
}

 
Holly cow! That's one long post.
If anyone could take the time to read this, even just part of it, and lend me a hand, I would be very thankful.


#1LarryKing

Posted 03 January 2013 - 06:37 PM

Hello all, I'm looking for some feedback regrading a model format and loader I've been working on over the past few days. I'm transitioning to C++, coming from C# and this has been a great exercise thus far, but I feel this post might end up a bit lengthy.
 
Some background as to what I wanted to accomplish with the file format:

  • The model can contain a large number of meshes.
  • Each mesh can have an arbitrary number of vertex buffers; not that a mesh should have 8, 16, or even 65,535 vertex streams, just that it could.
  • Each mesh can have an arbitrary number of textures; again, see above.
  • Each mesh and the model itself and should have some sort of bounding volume.
  • Fast loading; the model should use local pointers and require minimal live processing.
  • Possibility for compression

 
After some research, it appears that loading directly into memory and then adjusting local pointers seems to be one of the fastest ways to load an object. So the entire format reflects the objects that make up my model.
 
A model contains: a pointer to some ModelTextures, a pointer to the MeshHeaders, a pointer to the MeshCullDatas and a pointer to the MeshDrawDatas.
 
I've tried to implement some Data Oriented Design – a very different concept coming from C#. I've split up the meshes into arrays of data needed for different operations: Culling and Drawing.
 
Furthermore, I'm attempting to implement this as part of my content manager, so a ModelTexture, is really just a wrapper around a shared_ptr<Texture2D> that is retrieved from another content cache.
 
All right, so here is what the model format looks like, I made a diagram!
*sorry it's so tall...
 
ModelFormat_zps271dc65c.png
 
The actual files are exported from a tool I've written in C#. I'm loading Collada files via Assimp, calculating any user requested data and displaying the model via SharpDX in a WinForms app.
 
In the end, the model gets exported to the file by the exporter first writing each mesh data object to “virtual memory,” adjusting all of the pointers and finally using a binary writer to spit out the finished file.
 
Pretty straight forward for me as I'm used to C#, but the scary stuff happens when we get to actually loading the file in C++.
 
First I load the entire file with an ifstream into a char[]. Then I cast the char[] to a Model. Now I need to offset the local pointers so that the model will work in memory; however! I read somewhere that you can't add pointers in C++, only subtract them, but to offset local pointers you needed to add!
After much internet searching, I finally found an object ptrdiff_t that I could retrieve from a pointer, add to, and then cast back to a pointer. The question then became, “Is this legal, what I'm doing?” For a full day I pondered before quizzically deciding that it should? be legal. I mean how else would you offset pointers when you shouldn't just cast to an int?
The next problem arrived when I realized that I needed to somehow delete the model from memory as well. Again not sure, as I had casted a char[] to a model, if I could delete the model. I pretended I could and wrote the destructor. Miraculously it seemed to work! The “Memory” window in Visual Studio seemed to show that the object had successfully been deleted, although I'm still not sure if I need to call delete on the model's pointers as they weren't created with new.
 
So now, I have all this code for loading a model, but I'm not sure if it's legal, safe, or even sensible!
 
Enough talk though, here's the code for loading the model:
 

std::shared_ptr<Ruined::Graphics::Model> ModelLoader::Load(const std::string &name)
{
	Ruined::Graphics::Model * model;

	std::ifstream file (m_BaseDirectory + name, std::ios::in|std::ios::binary|std::ios::ate);
	if (file.is_open())
	{
		// Get the file's total size
		unsigned int size = file.tellg();
		// Create a char[] of the size to load the file into
		char* memblock = new char [size];
		// Seek to the beginning and read the file
		file.seekg (0, std::ios::beg);
		file.read (memblock, size);
		// Finally close the file
		file.close();

		// Cast the char[] to a Ruined::Graphics::Model pointer
		model = static_cast<Ruined::Graphics::Model *>((void*)memblock);

		// The location of the model in memory
		ptrdiff_t memOffset = (ptrdiff_t)model;

		// Offset the model's local pointers
		// Mesh Headers
		ptrdiff_t intOffset;
		model->MeshHeaders = (Ruined::Graphics::MeshHeader*)(memOffset + (ptrdiff_t)model->MeshHeaders);

		// Mesh Culling Datas
		// intOffset = (ptrdiff_t)model->MeshCullDatas;
		model->MeshCullDatas = (Ruined::Graphics::MeshCullData*)(memOffset + (ptrdiff_t)model->MeshCullDatas);

		// Mesh Drawing Datas
		// intOffset = (ptrdiff_t)model->MeshDrawDatas;
		model->MeshDrawDatas = (Ruined::Graphics::MeshDrawData*)(memOffset + (ptrdiff_t)model->MeshDrawDatas);

		// Model's Ruined::Graphics::ModelTexture pointer
		// intOffset = (ptrdiff_t)model->Textures;
		model->Textures = (Ruined::Graphics::ModelTexture*)(memOffset + (ptrdiff_t)model->Textures);
				
		// Load the model's textures
		for(int t = 0; t < model->TextureCount; t++)
		{
			// Offset TextureName pointers
			// intOffset = (ptrdiff_t)(model->Textures[t].TextureName);
			model->Textures[t].TextureName = (char*)(memOffset + (ptrdiff_t)(model->Textures[t].TextureName));
			// Load the texture
			model->Textures[t].TextureContent = p_TextureCache->Load(model->Textures[t].TextureName);
		}

		HRESULT hresult;
		Ruined::Graphics::MeshDrawData * tempMeshD = nullptr;
		for(int m = 0; m < model->MeshCount; m++)
		{

			// Build the buffers
			tempMeshD = &model->MeshDrawDatas[m];

			// Offset Index Buffer
			// intOffset = (ptrdiff_t)tempMeshD->IndexBuffer;
			tempMeshD->IndexBuffer = (ID3D11Buffer*)(memOffset + (ptrdiff_t)tempMeshD->IndexBuffer);

			// Offset Vertex Buffer
			// intOffset = (ptrdiff_t)tempMeshD->VertexBuffer;
			tempMeshD->VertexBuffers = (ID3D11Buffer**)(memOffset + (ptrdiff_t)tempMeshD->VertexBuffers);

			// Offset Strides
			// intOffset = (ptrdiff_t)tempMeshD->Strides;
			tempMeshD->Strides = (unsigned int*)(memOffset + (ptrdiff_t)tempMeshD->Strides);

			// Offset Resources
			intOffset = (ptrdiff_t)tempMeshD->Resources;
			tempMeshD->Resources = (ID3D11ShaderResourceView**)(memOffset + intOffset);

			// Convert Resources * to unsigned int *
			unsigned int * index = (unsigned int*)(memOffset + intOffset);

			// Assign to the poingters from the model's textures
			for(int t = 0; t < model->MeshHeaders[m].ResourceCount; t++)		
				tempMeshD->Resources[t] = model->Textures[index[t]].TextureContent.get()->p_shaderResourceView;

			// Desc for the index buffer
			D3D11_BUFFER_DESC indexBufferDesc;		
			indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
			indexBufferDesc.ByteWidth = tempMeshD->IndexCount * (tempMeshD->IndexFormat == DXGI_FORMAT_R16_UINT ? sizeof(unsigned short) : sizeof(unsigned int));
			indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
			indexBufferDesc.CPUAccessFlags = 0;
			indexBufferDesc.MiscFlags = 0;

			D3D11_SUBRESOURCE_DATA indexData;
			indexData.pSysMem = tempMeshD->IndexBuffer;
			indexData.SysMemPitch = 0;
			indexData.SysMemSlicePitch = 0;

			hresult = p_Graphics->GetDevice()->CreateBuffer(&indexBufferDesc, &indexData, &tempMeshD->IndexBuffer);
			if(FAILED(hresult))
			{
				OutputDebugStringA("Failed to create Index Buffer");
			}

						
			// Create each vertex buffer
			Ruined::Graphics::MeshBufferDesc * tempDesc = (Ruined::Graphics::MeshBufferDesc*)(tempMeshD->VertexBuffers);
			for(unsigned int b = 0; b < tempMeshD->VertexBufferCount; b++)
			{
							
				// Each buffer gets a desc
				D3D11_BUFFER_DESC bufferDesc;
				bufferDesc.Usage = D3D11_USAGE_DEFAULT;
				bufferDesc.ByteWidth = tempDesc[b].BufferWidth;
				bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
				bufferDesc.CPUAccessFlags = 0;
				bufferDesc.MiscFlags = 0;

				// Each buffer needs a subresource data
				D3D11_SUBRESOURCE_DATA subData;
				subData.pSysMem = (void*)((ptrdiff_t)tempDesc[b].Data + memOffset);
				subData.SysMemPitch = 0;
				subData.SysMemSlicePitch = 0;

				hresult = p_Graphics->GetDevice()->CreateBuffer(&bufferDesc, &subData, &(tempMeshD->VertexBuffers[b]));
				if(FAILED(hresult))
				{
					OutputDebugStringA("Failed to create Vertex Buffer");
				}
			}

						
		}

					
	}
	else
	{
		std::string errorMsg = "Failed to load Model: ";
		errorMsg += m_BaseDirectory + name + "\n";
		OutputDebugStringA(errorMsg.c_str());

		// Set model equal to something
		model = new Ruined::Graphics::Model();
	}

	std::shared_ptr<Ruined::Graphics::Model> sModel(model);

	return sModel;
}

So that makes a little more sense, here is Model.h:

#include "MeshDrawData.h"
#include "ModelTexture.h"

#include <memory>

namespace Ruined
{
	namespace Graphics
	{
		// Combine Model Header and Model Pointers
		struct __declspec(dllexport) Model
		{

		public:
			// Header
			unsigned short _FILETYPE;
			unsigned short _FILEVERSION;
			unsigned int ModelSize;
		
			unsigned short TextureCount;
			unsigned short MeshCount;
			DirectX::BoundingBox BoundingBox;

			// Pointers
			ModelTexture * Textures;
			MeshHeader * MeshHeaders;
			MeshCullData * MeshCullDatas;
			MeshDrawData * MeshDrawDatas;

		public:
			Model(void);
			
			~Model(void);
		};
	}
}

#endif

 

Here is ModelTexture.h:

#pragma once
#ifndef _MODELTEXTURE_H
#define _MODELTEXTURE_H_ 

// Includes //
#include "Texture2D.h"

#include <memory>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) ModelTexture
		{
		public:
			char* TextureName;
			std::shared_ptr<Texture2D> TextureContent;
		};
	}
}

#endif

 

 

Here are the mesh objects:

#ifndef _MESHCULLDATA_H_
#define _MESHCULLDATA_H_

#include <DirectXCollision.h>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) MeshCullData
		{
		public:
			DirectX::BoundingBox BoundingBox;
		};
	}
}

#endif
#ifndef _MESHHEADER_H_
#define _MESHHEADER_H_

#include "MeshBufferDesc.h"

namespace Ruined
{
	namespace Graphics
	{
		enum MeshMask : unsigned short
		{
			Undefined       = 0x0000,
			Texture         = 0x0001,
			UVCoord         = 0x0002,
			Color           = 0x0004,
			Normal          = 0x0008,
			Tangent         = 0x0010,
			Binormal        = 0x0020,
			BoneIndices     = 0x0040,
			BoneWeights     = 0x0080,
			SplitBuffers    = 0x0100,
			AlphaBlend      = 0x4000
		};

		struct __declspec(dllexport) MeshHeader
		{
			MeshMask Mask;
			unsigned char UVStreamCount;
			unsigned char ColorStreamCount;
			unsigned short ResourceCount;
		};
	}
}

#endif
#ifndef _MESHDRAWDATA_H_
#define _MESHDRAWDATA_H_

#include <d3d11.h>

namespace Ruined
{
	namespace Graphics
	{
		struct __declspec(dllexport) MeshDrawData
		{
		public:
			unsigned int VertexBufferCount;
			ID3D11Buffer ** VertexBuffers;
			unsigned int * Strides;
			ID3D11Buffer * IndexBuffer;
			DXGI_FORMAT IndexFormat;
			ID3D11ShaderResourceView ** Resources;
			unsigned int IndexCount;
		};
	}
}

#endif
#ifndef _MESHBUFFERDESC_H_
#define _MESHBUFFERDESC_H_


namespace Ruined
{
	namespace Graphics
	{
		// Used for creating vertex buffers.
		// Only accessed at load time.
		struct __declspec(dllexport) MeshBufferDesc
		{
		public:
			unsigned int BufferWidth;
			void * Data;
		};
	}
}

#endif

Lastly here is the Model destructor:

Model::~Model(void)
		{
			if(Textures != nullptr)
			{
				for(int t = 0; t < TextureCount; t++)
				{
					Textures[t].TextureContent.reset();
					Textures[t].TextureName = nullptr;
				}
			}

			if(MeshDrawDatas != nullptr)
			{
				for(int m = 0; m < MeshCount; m++)
				{
					if(MeshDrawDatas[m].IndexBuffer != nullptr)
					{
						MeshDrawDatas[m].IndexBuffer->Release();
						MeshDrawDatas[m].IndexBuffer = nullptr;
					}

					for(int v = 0; v < MeshDrawDatas[m].VertexBufferCount; v++)
					{
						if(MeshDrawDatas[m].VertexBuffers[v] != nullptr)
						{
							MeshDrawDatas[m].VertexBuffers[v]->Release();
							MeshDrawDatas[m].VertexBuffers[v] = nullptr;
						}
					}
				}
			}
		}

 

Holly cow! That's one long post.

If anyone could take the time to read this, even just part of it, and lend me a hand, I would be very thankful.

 


PARTNERS