//////////////////////////////////////////////////////////////////////
// Read a mesh
//////////////////////////////////////////////////////////////////////
Mesh *MeshReader::BuildMesh( const string &inputFile )
{
	// Open the input file
	ifstream f( inputFile.c_str() );

	Real E, v, density;
	int numGaussPoints;
	int elementType;
	int numVertices, numElements, numConstrained;

  Tuple3i divisions;

	f >> E;
	f >> v;
	f >> density;
	f >> numGaussPoints;
	f >> elementType;
	f >> numVertices;
	f >> numElements;
	f >> numConstrained;
  f >> divisions[ 0 ];
  f >> divisions[ 1 ];
  f >> divisions[ 2 ];

	Vector3Array vertices;
	for ( int i = 0; i < numVertices; i++ )
	{
		VEC3F p;

		f >> p[0];
		f >> p[1];
		f >> p[2];

		vertices.push_back( p );
	}

	// Read in elements
	if ( elementType < 0 || elementType >= Mesh::NUM_ELEMENT_TYPES )
	{
		cout << "Invalid element type!" << endl;
		return NULL;
	}

	IntArray connectivity;

	if ( elementType == Mesh::ISO_8_NODE )
	{
		for ( int i = 0; i < numElements; i++ )
		{
			for ( int j = 0; j < 8; j++ )
			{
				int nodeNum;
				f >> nodeNum;
				connectivity.push_back( nodeNum );
			}
		}
	}

	vector<bool> constrained(vertices.size());

	for (int i = 0; i < constrained.size(); i++)
	{
		constrained.at(i) = false;
	}

	// Read in constrained nodes
	for ( int i = 0; i < numConstrained; i++ )
	{
		int nodeNum;
		f >> nodeNum;
		constrained.at(nodeNum) = true;
	}

	f.close();

	// Finish building the mesh
	return new Mesh( vertices, (Mesh::ElementType)elementType, connectivity,
									 constrained, E, v, density, numGaussPoints, divisions );
}
//------------------------------------------------------------------------------------------------
void VertexIndexToShape::addAnimatedVertexData(const Ogre::VertexData *vertex_data,
                                               const Ogre::VertexData *blend_data,
                                               const Ogre::Mesh::IndexMap *indexMap)
{
    // Get the bone index element
    assert(vertex_data);

    const Ogre::VertexData *data = blend_data;
    const unsigned int prev_size = mVertexCount;
    mVertexCount += (unsigned int)data->vertexCount;
    Ogre::Vector3 *tmp_vert = new Ogre::Vector3[mVertexCount];
    if (mVertexBuffer)
    {
        memcpy(tmp_vert, mVertexBuffer, sizeof(Ogre::Vector3) * prev_size);
        delete[] mVertexBuffer;
    }
    mVertexBuffer = tmp_vert;

    // Get the positional buffer element
    {	
        const Ogre::VertexElement *posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
        assert(posElem);
        Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource());
        const unsigned int vSize = (unsigned int)vbuf->getVertexSize();

        unsigned char *vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
        float *pReal;
        Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size];
        const unsigned int vertexCount = (unsigned int)data->vertexCount;
        for (unsigned int j = 0; j < vertexCount; ++j)
        {
            posElem->baseVertexPointerToElement(vertex, &pReal);
            vertex += vSize;

            curVertices->x = (*pReal++);
            curVertices->y = (*pReal++);
            curVertices->z = (*pReal++);

            *curVertices = mTransform * (*curVertices);

            curVertices++;
        }
        vbuf->unlock();
    }

    {
        const Ogre::VertexElement *bneElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_BLEND_INDICES);
        assert(bneElem);
		
        Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(bneElem->getSource());
        const unsigned int vSize = (unsigned int)vbuf->getVertexSize();
        unsigned char *vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

        unsigned char *pBone = NULL;

        if (!mBoneIndex)
        {
            mBoneIndex = new BoneIndex();	
        }

        Ogre::Vector3 *curVertices = &mVertexBuffer[prev_size];

        const unsigned int vertexCount = (unsigned int)vertex_data->vertexCount;
        for (unsigned int j = 0; j < vertexCount; ++j)
        {
            bneElem->baseVertexPointerToElement(vertex, &pBone);
            vertex += vSize;

            const unsigned char currBone = (indexMap) ? (*indexMap)[*pBone] : *pBone;
            const BoneIndex::iterator i = mBoneIndex->find(currBone);
            Vector3Array *l = NULL;
            if (i == mBoneIndex->end())
            {
                l = new Vector3Array;
                mBoneIndex->insert(BoneKeyIndex(currBone, l));
            }
            else 
            {
                  l = i->second;
            }

            l->push_back(*curVertices);

            curVertices++;
        }

        vbuf->unlock();
    }
}
Example #3
0
int main(int _argc, const char* _argv[])
{
	bx::CommandLine cmdLine(_argc, _argv);

	const char* filePath = cmdLine.findOption('f');
	if (NULL == filePath)
	{
		help("Input file name must be specified.");
		return EXIT_FAILURE;
	}

	const char* outFilePath = cmdLine.findOption('o');
	if (NULL == outFilePath)
	{
		help("Output file name must be specified.");
		return EXIT_FAILURE;
	}

	float scale = 1.0f;
	const char* scaleArg = cmdLine.findOption('s', "scale");
	if (NULL != scaleArg)
	{
		scale = (float)atof(scaleArg);
	}

	cmdLine.hasArg(s_obbSteps, '\0', "obb");
	s_obbSteps = bx::uint32_min(bx::uint32_max(s_obbSteps, 1), 90);

	uint32_t packNormal = 0;
	cmdLine.hasArg(packNormal, '\0', "packnormal");

	uint32_t packUv = 0;
	cmdLine.hasArg(packUv, '\0', "packuv");
	
	bool ccw = cmdLine.hasArg("ccw");
	bool flipV = cmdLine.hasArg("flipv");
	bool hasTangent = cmdLine.hasArg("tangent");

	FILE* file = fopen(filePath, "r");
	if (NULL == file)
	{
		printf("Unable to open input file '%s'.", filePath);
		exit(EXIT_FAILURE);
	}

	int64_t parseElapsed = -bx::getHPCounter();
	int64_t triReorderElapsed = 0;

	uint32_t size = (uint32_t)fsize(file);
	char* data = new char[size+1];
	size = (uint32_t)fread(data, 1, size, file);
	data[size] = '\0';
	fclose(file);

	// https://en.wikipedia.org/wiki/Wavefront_.obj_file

	Vector3Array positions;
	Vector3Array normals;
	Vector3Array texcoords;
	Index3Map indexMap;
	TriangleArray triangles;
	GroupArray groups;

	uint32_t num = 0;

	Group group;
	group.m_startTriangle = 0;
	group.m_numTriangles = 0;

	char commandLine[2048];
	uint32_t len = sizeof(commandLine);
	int argc;
	char* argv[64];
	const char* next = data;
	do
	{
		next = bx::tokenizeCommandLine(next, commandLine, len, argc, argv, BX_COUNTOF(argv), '\n');
		if (0 < argc)
		{
			if (0 == strcmp(argv[0], "#") )
			{
				if (2 < argc
				&&  0 == strcmp(argv[2], "polygons") )
				{
				}
			}
			else if (0 == strcmp(argv[0], "f") )
			{
				Triangle triangle;
				memset(&triangle, 0, sizeof(Triangle) );

				for (uint32_t edge = 0, numEdges = argc-1; edge < numEdges; ++edge)
				{
					Index3 index;
					index.m_texcoord = -1;
					index.m_normal = -1;
					index.m_vertexIndex = -1;

					char* vertex = argv[edge+1];
					char* texcoord = strchr(vertex, '/');
					if (NULL != texcoord)
					{
						*texcoord++ = '\0';

						char* normal = strchr(texcoord, '/');
						if (NULL != normal)
						{
							*normal++ = '\0';
							index.m_normal = atoi(normal)-1;
						}

						index.m_texcoord = atoi(texcoord)-1;
					}

					index.m_position = atoi(vertex)-1;

					uint64_t hash0 = index.m_position;
					uint64_t hash1 = uint64_t(index.m_texcoord)<<20;
					uint64_t hash2 = uint64_t(index.m_normal)<<40;
					uint64_t hash = hash0^hash1^hash2;

					stl::pair<Index3Map::iterator, bool> result = indexMap.insert(stl::make_pair(hash, index) );
					if (!result.second)
					{
						Index3& oldIndex = result.first->second;
						BX_UNUSED(oldIndex);
						BX_CHECK(oldIndex.m_position == index.m_position
							&& oldIndex.m_texcoord == index.m_texcoord
							&& oldIndex.m_normal == index.m_normal
							, "Hash collision!"
							);
					}

					switch (edge)
					{
					case 0:
					case 1:
					case 2:
						triangle.m_index[edge] = hash;
						if (2 == edge)
						{
							if (ccw)
							{
								std::swap(triangle.m_index[1], triangle.m_index[2]);
							}
							triangles.push_back(triangle);
						}
						break;

					default:
						if (ccw)
						{
							triangle.m_index[2] = triangle.m_index[1];
							triangle.m_index[1] = hash;
						}
						else
						{
							triangle.m_index[1] = triangle.m_index[2];
							triangle.m_index[2] = hash;
						}
						triangles.push_back(triangle);
						break;
					}
				}
			}
			else if (0 == strcmp(argv[0], "g") )
			{
				EXPECT(1 < argc);
				group.m_name = argv[1];
			}
			else if (*argv[0] == 'v')
			{
				group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
				if (0 < group.m_numTriangles)
				{
					groups.push_back(group);
					group.m_startTriangle = (uint32_t)(triangles.size() );
					group.m_numTriangles = 0;
				}

				if (0 == strcmp(argv[0], "vn") )
				{
					Vector3 normal;
					normal.x = (float)atof(argv[1]);
					normal.y = (float)atof(argv[2]);
					normal.z = (float)atof(argv[3]);

					normals.push_back(normal);
				}
				else if (0 == strcmp(argv[0], "vp") )
				{
					static bool once = true;
					if (once)
					{
						once = false;
						printf("warning: 'parameter space vertices' are unsupported.\n");
					}
				}
				else if (0 == strcmp(argv[0], "vt") )
				{
					Vector3 texcoord;
					texcoord.x = (float)atof(argv[1]);
					texcoord.y = 0.0f;
					texcoord.z = 0.0f;
					switch (argc)
					{
					case 4:
						texcoord.z = (float)atof(argv[3]);
						// fallthrough
					case 3:
						texcoord.y = (float)atof(argv[2]);
						break;

					default:
						break;
					}

					texcoords.push_back(texcoord);
				}
				else
				{
					float px = (float)atof(argv[1]);
					float py = (float)atof(argv[2]);
					float pz = (float)atof(argv[3]);
					float pw = 1.0f;
					if (argc > 4)
					{
						pw = (float)atof(argv[4]);
					}

					float invW = scale/pw;
					px *= invW;
					py *= invW;
					pz *= invW;

					Vector3 pos;
					pos.x = px;
					pos.y = py;
					pos.z = pz;

					positions.push_back(pos);
				}
			}
			else if (0 == strcmp(argv[0], "usemtl") )
			{
				std::string material(argv[1]);

				if (material != group.m_material)
				{
					group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
					if (0 < group.m_numTriangles)
					{
						groups.push_back(group);
						group.m_startTriangle = (uint32_t)(triangles.size() );
						group.m_numTriangles = 0;
					}
				}

				group.m_material = material;
			}
// unsupported tags
// 				else if (0 == strcmp(argv[0], "mtllib") )
// 				{
// 				}
// 				else if (0 == strcmp(argv[0], "o") )
// 				{
// 				}
// 				else if (0 == strcmp(argv[0], "s") )
// 				{
// 				}
		}

		++num;
	}
	while ('\0' != *next);

	group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
	if (0 < group.m_numTriangles)
	{
		groups.push_back(group);
		group.m_startTriangle = (uint32_t)(triangles.size() );
		group.m_numTriangles = 0;
	}

	delete [] data;

	int64_t now = bx::getHPCounter();
	parseElapsed += now;
	int64_t convertElapsed = -now;

	std::sort(groups.begin(), groups.end(), GroupSortByMaterial() );

	bool hasColor = false;
	bool hasNormal;
	bool hasTexcoord;
	{
		Index3Map::const_iterator it = indexMap.begin();
		hasNormal = -1 != it->second.m_normal;
		hasTexcoord = -1 != it->second.m_texcoord;

		if (!hasTexcoord
		&&  texcoords.size() == positions.size() )
		{
			hasTexcoord = true;

			for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
			{
				it->second.m_texcoord = it->second.m_position;
			}
		}

		if (!hasNormal
		&&  normals.size() == positions.size() )
		{
			hasNormal = true;

			for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
			{
				it->second.m_normal = it->second.m_position;
			}
		}
	}

	bgfx::VertexDecl decl;
	decl.begin();
	decl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);

	if (hasColor)
	{
		decl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
	}

	if (hasTexcoord)
	{
		switch (packUv)
		{
		default:
		case 0:
			decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
			break;

		case 1:
			decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Half);
			break;
		}
	}

	if (hasNormal)
	{
		hasTangent &= hasTexcoord;

		switch (packNormal)
		{
		default:
		case 0:
			decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float);
			if (hasTangent)
			{
				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Float);
			}
			break;

		case 1:
			decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
			if (hasTangent)
			{
				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
			}
			break;
		}
	}
	decl.end();

	uint32_t stride = decl.getStride();
	uint8_t* vertexData = new uint8_t[triangles.size() * 3 * stride];
	uint16_t* indexData = new uint16_t[triangles.size() * 3];
	int32_t numVertices = 0;
	int32_t numIndices = 0;
	int32_t numPrimitives = 0;

	uint8_t* vertices = vertexData;
	uint16_t* indices = indexData;

	std::string material = groups.begin()->m_material;

	PrimitiveArray primitives;

	bx::CrtFileWriter writer;
	if (0 != writer.open(outFilePath) )
	{
		printf("Unable to open output file '%s'.", outFilePath);
		exit(EXIT_FAILURE);
	}

	Primitive prim;
	prim.m_startVertex = 0;
	prim.m_startIndex = 0;

	uint32_t positionOffset = decl.getOffset(bgfx::Attrib::Position);
	uint32_t color0Offset = decl.getOffset(bgfx::Attrib::Color0);

	uint32_t ii = 0;
	for (GroupArray::const_iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt, ++ii)
	{
		for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
		{
			if (material != groupIt->m_material
			||  65533 < numVertices)
			{
				prim.m_numVertices = numVertices - prim.m_startVertex;
				prim.m_numIndices = numIndices - prim.m_startIndex;
				if (0 < prim.m_numVertices)
				{
					primitives.push_back(prim);
				}

				triReorderElapsed -= bx::getHPCounter();
				for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
				{
					const Primitive& prim = *primIt;
					triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
				}
				triReorderElapsed += bx::getHPCounter();

				if (hasTangent)
				{
					calcTangents(vertexData, numVertices, decl, indexData, numIndices);
				}

				write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
				primitives.clear();

				for (Index3Map::iterator indexIt = indexMap.begin(); indexIt != indexMap.end(); ++indexIt)
				{
					indexIt->second.m_vertexIndex = -1;
				}

				vertices = vertexData;
				indices = indexData;
				numVertices = 0;
				numIndices = 0;
				prim.m_startVertex = 0;
				prim.m_startIndex = 0;
				++numPrimitives;

				material = groupIt->m_material;
			}

			Triangle& triangle = triangles[tri];
			for (uint32_t edge = 0; edge < 3; ++edge)
			{
				uint64_t hash = triangle.m_index[edge];
				Index3& index = indexMap[hash];
				if (index.m_vertexIndex == -1)
				{
		 			index.m_vertexIndex = numVertices++;

					float* position = (float*)(vertices + positionOffset);
					memcpy(position, &positions[index.m_position], 3*sizeof(float) );

					if (hasColor)
					{
						uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
						*color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
					}

					if (hasTexcoord)
					{
						float uv[2];
						memcpy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) );

						if (flipV)
						{
							uv[1] = -uv[1];
						}

						bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
					}

					if (hasNormal)
					{
						float normal[4];
						bx::vec3Norm(normal, (float*)&normals[index.m_normal]);
						bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
					}

					vertices += stride;
				}

				*indices++ = (uint16_t)index.m_vertexIndex;
				++numIndices;
			}
		}

		if (0 < numVertices)
		{
			prim.m_numVertices = numVertices - prim.m_startVertex;
			prim.m_numIndices = numIndices - prim.m_startIndex;
			prim.m_name = groupIt->m_name;
			primitives.push_back(prim);
			prim.m_startVertex = numVertices;
			prim.m_startIndex = numIndices;
		}

		BX_TRACE("%3d: s %5d, n %5d, %s\n"
			, ii
			, groupIt->m_startTriangle
			, groupIt->m_numTriangles
			, groupIt->m_material.c_str()
			);
	}

	if (0 < primitives.size() )
	{
		triReorderElapsed -= bx::getHPCounter();
		for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
		{
			const Primitive& prim = *primIt;
			triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
		}
		triReorderElapsed += bx::getHPCounter();

		if (hasTangent)
		{
			calcTangents(vertexData, numVertices, decl, indexData, numIndices);
		}

		write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
	}

	printf("size: %d\n", uint32_t(writer.seek() ) );
	writer.close();

	delete [] indexData;
	delete [] vertexData;

	now = bx::getHPCounter();
	convertElapsed += now;

	printf("parse %f [s]\ntri reorder %f [s]\nconvert %f [s]\n# %d, g %d, p %d, v %d, i %d\n"
		, double(parseElapsed)/bx::getHPFrequency()
		, double(triReorderElapsed)/bx::getHPFrequency()
		, double(convertElapsed)/bx::getHPFrequency()
		, num
		, uint32_t(groups.size() )
		, numPrimitives
		, numVertices
		, numIndices
		);

	return EXIT_SUCCESS;
}
Example #4
0
uint32_t objToBin(const uint8_t* _objData
                  , bx::WriterSeekerI* _writer
                  , uint32_t _packUv
                  , uint32_t _packNormal
                  , bool _ccw
                  , bool _flipV
                  , bool _hasTangent
                  , float _scale
                 )
{
    int64_t parseElapsed = -bx::getHPCounter();
    int64_t triReorderElapsed = 0;

    const int64_t begin = _writer->seek();

    Vector3Array positions;
    Vector3Array normals;
    Vector3Array texcoords;
    Index3Map indexMap;
    TriangleArray triangles;
    BgfxGroupArray groups;

    uint32_t num = 0;

    MeshGroup group;
    group.m_startTriangle = 0;
    group.m_numTriangles = 0;
    group.m_name = "";
    group.m_material = "";

    char commandLine[2048];
    uint32_t len = sizeof(commandLine);
    int argc;
    char* argv[64];
    const char* next = (const char*)_objData;
    do
    {
        next = bx::tokenizeCommandLine(next, commandLine, len, argc, argv, BX_COUNTOF(argv), '\n');
        if (0 < argc)
        {
            if (0 == strcmp(argv[0], "#") )
            {
                if (2 < argc
                        &&  0 == strcmp(argv[2], "polygons") )
                {
                }
            }
            else if (0 == strcmp(argv[0], "f") )
            {
                Triangle triangle;
                memset(&triangle, 0, sizeof(Triangle) );

                const int numNormals   = (int)normals.size();
                const int numTexcoords = (int)texcoords.size();
                const int numPositions = (int)positions.size();
                for (uint32_t edge = 0, numEdges = argc-1; edge < numEdges; ++edge)
                {
                    Index3 index;
                    index.m_texcoord = 0;
                    index.m_normal = 0;
                    index.m_vertexIndex = -1;

                    char* vertex = argv[edge+1];
                    char* texcoord = strchr(vertex, '/');
                    if (NULL != texcoord)
                    {
                        *texcoord++ = '\0';

                        char* normal = strchr(texcoord, '/');
                        if (NULL != normal)
                        {
                            *normal++ = '\0';
                            const int nn = atoi(normal);
                            index.m_normal = (nn < 0) ? nn+numNormals : nn-1;
                        }

                        const int tex = atoi(texcoord);
                        index.m_texcoord = (tex < 0) ? tex+numTexcoords : tex-1;
                    }

                    const int pos = atoi(vertex);
                    index.m_position = (pos < 0) ? pos+numPositions : pos-1;

                    uint64_t hash0 = index.m_position;
                    uint64_t hash1 = uint64_t(index.m_texcoord)<<20;
                    uint64_t hash2 = uint64_t(index.m_normal)<<40;
                    uint64_t hash = hash0^hash1^hash2;

                    CS_STL::pair<Index3Map::iterator, bool> result = indexMap.insert(CS_STL::make_pair(hash, index) );
                    if (!result.second)
                    {
                        Index3& oldIndex = result.first->second;
                        BX_UNUSED(oldIndex);
                        BX_CHECK(oldIndex.m_position == index.m_position
                                 && oldIndex.m_texcoord == index.m_texcoord
                                 && oldIndex.m_normal == index.m_normal
                                 , "Hash collision!"
                                );
                    }

                    switch (edge)
                    {
                    case 0:
                    case 1:
                    case 2:
                        triangle.m_index[edge] = hash;
                        if (2 == edge)
                        {
                            if (_ccw)
                            {
                                std::swap(triangle.m_index[1], triangle.m_index[2]);
                            }
                            triangles.push_back(triangle);
                        }
                        break;

                    default:
                        if (_ccw)
                        {
                            triangle.m_index[2] = triangle.m_index[1];
                            triangle.m_index[1] = hash;
                        }
                        else
                        {
                            triangle.m_index[1] = triangle.m_index[2];
                            triangle.m_index[2] = hash;
                        }
                        triangles.push_back(triangle);
                        break;
                    }
                }
            }
            else if (0 == strcmp(argv[0], "g") )
            {
                if (1 >= argc)
                {
                    CS_PRINT("Error parsing *.obj file.\n");
                    return 0;
                }
                group.m_name = argv[1];
            }
            else if (*argv[0] == 'v')
            {
                group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
                if (0 < group.m_numTriangles)
                {
                    groups.push_back(group);
                    group.m_startTriangle = (uint32_t)(triangles.size() );
                    group.m_numTriangles = 0;
                }

                if (0 == strcmp(argv[0], "vn") )
                {
                    Vector3 normal;
                    normal.x = (float)atof(argv[1]);
                    normal.y = (float)atof(argv[2]);
                    normal.z = (float)atof(argv[3]);

                    normals.push_back(normal);
                }
                else if (0 == strcmp(argv[0], "vp") )
                {
                    static bool once = true;
                    if (once)
                    {
                        once = false;
                        CS_PRINT("warning: 'parameter space vertices' are unsupported.\n");
                    }
                }
                else if (0 == strcmp(argv[0], "vt") )
                {
                    Vector3 texcoord;
                    texcoord.x = (float)atof(argv[1]);
                    texcoord.y = 0.0f;
                    texcoord.z = 0.0f;
                    switch (argc)
                    {
                    case 4:
                        texcoord.z = (float)atof(argv[3]);
                    // fallthrough
                    case 3:
                        texcoord.y = (float)atof(argv[2]);
                        break;

                    default:
                        break;
                    }

                    texcoords.push_back(texcoord);
                }
                else
                {
                    float px = (float)atof(argv[1]);
                    float py = (float)atof(argv[2]);
                    float pz = (float)atof(argv[3]);
                    float pw = 1.0f;
                    if (argc > 4)
                    {
                        pw = (float)atof(argv[4]);
                    }

                    float invW = _scale/pw;
                    px *= invW;
                    py *= invW;
                    pz *= invW;

                    Vector3 pos;
                    pos.x = px;
                    pos.y = py;
                    pos.z = pz;

                    positions.push_back(pos);
                }
            }
            else if (0 == strcmp(argv[0], "usemtl") )
            {
                std::string material(argv[1]);

                if (material != group.m_material)
                {
                    group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
                    if (0 < group.m_numTriangles)
                    {
                        groups.push_back(group);
                        group.m_startTriangle = (uint32_t)(triangles.size() );
                        group.m_numTriangles = 0;
                    }
                }

                group.m_material = material;
            }
// unsupported tags
//              else if (0 == strcmp(argv[0], "mtllib") )
//              {
//              }
//              else if (0 == strcmp(argv[0], "o") )
//              {
//              }
//              else if (0 == strcmp(argv[0], "s") )
//              {
//              }
        }

        ++num;
    }
    while ('\0' != *next);

    group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
    if (0 < group.m_numTriangles)
    {
        groups.push_back(group);
        group.m_startTriangle = (uint32_t)(triangles.size() );
        group.m_numTriangles = 0;
    }

    int64_t now = bx::getHPCounter();
    parseElapsed += now;
    int64_t convertElapsed = -now;

    std::sort(groups.begin(), groups.end(), GroupSortByMaterial() );

    bool hasColor = false;
    bool hasNormal;
    bool hasTexcoord;
    {
        Index3Map::const_iterator it = indexMap.begin();
        hasNormal   = 0 != it->second.m_normal;
        hasTexcoord = 0 != it->second.m_texcoord;

        if (!hasTexcoord
                &&  texcoords.size() == positions.size() )
        {
            hasTexcoord = true;

            for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
            {
                it->second.m_texcoord = it->second.m_position;
            }
        }

        if (!hasNormal
                &&  normals.size() == positions.size() )
        {
            hasNormal = true;

            for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
            {
                it->second.m_normal = it->second.m_position;
            }
        }
    }

    bgfx::VertexDecl decl;
    decl.begin();
    decl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);

    if (hasColor)
    {
        decl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
    }

    if (hasTexcoord)
    {
        switch (_packUv)
        {
        default:
        case 0:
            decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
            break;

        case 1:
            decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Half);
            break;
        }
    }

    if (hasNormal)
    {
        _hasTangent &= hasTexcoord;

        switch (_packNormal)
        {
        default:
        case 0:
            decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float);
            if (_hasTangent)
            {
                decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Float);
            }
            break;

        case 1:
            decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
            if (_hasTangent)
            {
                decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
            }
            break;
        }
    }
    decl.end();

    uint32_t stride = decl.getStride();
    uint8_t* vertexData = new uint8_t[triangles.size() * 3 * stride];
    uint16_t* indexData = new uint16_t[triangles.size() * 3];
    int32_t numVertices = 0;
    int32_t numIndices = 0;
    int32_t numPrimitives = 0;

    uint8_t* vertices = vertexData;
    uint16_t* indices = indexData;

    std::string material = groups.begin()->m_material;

    BgfxPrimitiveArray primitives;

    Primitive prim;
    prim.m_startVertex = 0;
    prim.m_startIndex  = 0;

    uint32_t positionOffset = decl.getOffset(bgfx::Attrib::Position);
    uint32_t color0Offset   = decl.getOffset(bgfx::Attrib::Color0);

    uint32_t ii = 0;
    for (BgfxGroupArray::const_iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt, ++ii)
    {
        for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
        {
            if (material != groupIt->m_material
                    ||  65533 < numVertices)
            {
                prim.m_numVertices = numVertices - prim.m_startVertex;
                prim.m_numIndices = numIndices - prim.m_startIndex;
                if (0 < prim.m_numVertices)
                {
                    primitives.push_back(prim);
                }

                triReorderElapsed -= bx::getHPCounter();
                for (BgfxPrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
                {
                    const Primitive& prim = *primIt;
                    triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
                }
                triReorderElapsed += bx::getHPCounter();

                if (_hasTangent)
                {
                    calculateTangents(vertexData, numVertices, decl, indexData, numIndices);
                }

                write(_writer
                      , vertexData
                      , numVertices
                      , decl
                      , indexData
                      , numIndices
                      , material.c_str()
                      , primitives.data()
                      , (uint32_t)primitives.size()
                     );
                primitives.clear();

                for (Index3Map::iterator indexIt = indexMap.begin(); indexIt != indexMap.end(); ++indexIt)
                {
                    indexIt->second.m_vertexIndex = -1;
                }

                vertices = vertexData;
                indices = indexData;
                numVertices = 0;
                numIndices = 0;
                prim.m_startVertex = 0;
                prim.m_startIndex = 0;
                ++numPrimitives;

                material = groupIt->m_material;
            }

            Triangle& triangle = triangles[tri];
            for (uint32_t edge = 0; edge < 3; ++edge)
            {
                uint64_t hash = triangle.m_index[edge];
                Index3& index = indexMap[hash];
                if (index.m_vertexIndex == -1)
                {
                    index.m_vertexIndex = numVertices++;

                    float* position = (float*)(vertices + positionOffset);
                    memcpy(position, &positions[index.m_position], 3*sizeof(float) );

                    if (hasColor)
                    {
                        uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
                        *color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
                    }

                    if (hasTexcoord)
                    {
                        float uv[2];
                        memcpy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) );

                        if (_flipV)
                        {
                            uv[1] = -uv[1];
                        }

                        bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
                    }

                    if (hasNormal)
                    {
                        float normal[4];
                        bx::vec3Norm(normal, (float*)&normals[index.m_normal]);
                        bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
                    }

                    vertices += stride;
                }

                *indices++ = (uint16_t)index.m_vertexIndex;
                ++numIndices;
            }
        }

        if (0 < numVertices)
        {
            prim.m_numVertices = numVertices - prim.m_startVertex;
            prim.m_numIndices = numIndices - prim.m_startIndex;
            bx::strlcpy(prim.m_name, groupIt->m_name.c_str(), 128);
            primitives.push_back(prim);
            prim.m_startVertex = numVertices;
            prim.m_startIndex = numIndices;
        }

        //CS_PRINT("%3d: s %5d, n %5d, %s\n"
        //    , ii
        //    , groupIt->m_startTriangle
        //    , groupIt->m_numTriangles
        //    , groupIt->m_material.c_str()
        //    );
    }

    if (0 < primitives.size() )
    {
        triReorderElapsed -= bx::getHPCounter();
        for (BgfxPrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
        {
            const Primitive& prim = *primIt;
            triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
        }
        triReorderElapsed += bx::getHPCounter();

        if (_hasTangent)
        {
            calculateTangents(vertexData, numVertices, decl, indexData, numIndices);
        }

        write(_writer, vertexData, numVertices, decl, indexData, numIndices, material.c_str(), primitives.data(), (uint32_t)primitives.size());
    }

    delete [] indexData;
    delete [] vertexData;

    now = bx::getHPCounter();
    convertElapsed += now;

    const int64_t end = _writer->seek();
    const uint32_t dataSize = uint32_t(end-begin);
    CS_PRINT("size: %u\n", dataSize);

    CS_PRINT("parse %f [s]\ntri reorder %f [s]\nconvert %f [s]\n# %d, g %d, p %d, v %d, i %d\n"
             , double(parseElapsed)/bx::getHPFrequency()
             , double(triReorderElapsed)/bx::getHPFrequency()
             , double(convertElapsed)/bx::getHPFrequency()
             , num
             , uint32_t(groups.size() )
             , numPrimitives
             , numVertices
             , numIndices
            );

    return dataSize;
}
Example #5
0
bool
PMDHandler::doLoad(Model& model, istream& stream) noexcept
{
	PMD _pmd;
	if (!stream.read((char*)&_pmd.Header, sizeof(_pmd.Header))) return false;

	// vertex
	if (!stream.read((char*)&_pmd.VertexCount, sizeof(_pmd.VertexCount))) return false;

	if (_pmd.VertexCount > 0)
	{
		_pmd.VertexList.resize(_pmd.VertexCount);

		if (!stream.read((char*)&_pmd.VertexList[0], (std::streamsize)(sizeof(PMD_Vertex)* _pmd.VertexCount))) return false;
	}

	// index
	if (!stream.read((char*)&_pmd.IndexCount, sizeof(_pmd.IndexCount))) return false;

	if (_pmd.IndexCount > 0)
	{
		_pmd.IndexList.resize(_pmd.IndexCount);

		if (!stream.read((char*)&_pmd.IndexList[0], (std::streamsize)(sizeof(PMD_Index)* _pmd.IndexCount))) return false;
	}

	// materal
	if (!stream.read((char*)&_pmd.MaterialCount, sizeof(_pmd.MaterialCount))) return false;

	if (_pmd.MaterialCount > 0)
	{
		_pmd.MaterialList.resize(_pmd.MaterialCount);

		if (!stream.read((char*)&_pmd.MaterialList[0], (std::streamsize)(sizeof(PMD_Material)* _pmd.MaterialCount))) return false;
	}

	// bone
	if (!stream.read((char*)&_pmd.BoneCount, sizeof(_pmd.BoneCount))) return false;

	if (_pmd.BoneCount > 0)
	{
		_pmd.BoneList.resize(_pmd.BoneCount);

		if (!stream.read((char*)&_pmd.BoneList[0], (std::streamsize)(sizeof(PMD_Bone)* _pmd.BoneCount))) return false;
	}

	// IK
	if (!stream.read((char*)&_pmd.IkCount, sizeof(_pmd.IkCount))) return false;

	if (_pmd.IkCount > 0)
	{
		_pmd.IkList.resize(_pmd.IkCount);

		for (std::size_t i = 0; i < (std::size_t)_pmd.IkCount; i++)
		{
			if (!stream.read((char*)&_pmd.IkList[i].IK, sizeof(_pmd.IkList[i].IK))) return false;
			if (!stream.read((char*)&_pmd.IkList[i].Target, sizeof(_pmd.IkList[i].Target))) return false;
			if (!stream.read((char*)&_pmd.IkList[i].LinkCount, sizeof(_pmd.IkList[i].LinkCount))) return false;
			if (!stream.read((char*)&_pmd.IkList[i].LoopCount, sizeof(_pmd.IkList[i].LoopCount))) return false;
			if (!stream.read((char*)&_pmd.IkList[i].LimitOnce, sizeof(_pmd.IkList[i].LimitOnce))) return false;

			_pmd.IkList[i].LinkList.resize(_pmd.IkList[i].LinkCount);

			if (!stream.read((char*)&_pmd.IkList[i].LinkList[0], (std::streamsize)(sizeof(PMD_Link)* _pmd.IkList[i].LinkCount))) return false;
		}
	}

	// Morph
	if (!stream.read((char*)&_pmd.MorphCount, sizeof(_pmd.MorphCount))) return false;

	if (_pmd.MorphCount > 0)
	{
		_pmd.MorphList.resize(_pmd.MorphCount);

		for (std::size_t i = 0; i < (std::size_t)_pmd.MorphCount; i++)
		{
			if (!stream.read((char*)&_pmd.MorphList[i].Name, sizeof(_pmd.MorphList[i].Name))) return false;
			if (!stream.read((char*)&_pmd.MorphList[i].VertexCount, sizeof(_pmd.MorphList[i].VertexCount))) return false;
			if (!stream.read((char*)&_pmd.MorphList[i].Category, sizeof(_pmd.MorphList[i].Category))) return false;

			if (_pmd.MorphList[i].VertexCount > 0)
			{
				_pmd.MorphList[i].VertexList.resize(_pmd.MorphList[i].VertexCount);

				if (!stream.read((char*)&_pmd.MorphList[i].VertexList[0], (std::streamsize)(sizeof(PMD_MorphVertex)* _pmd.MorphList[i].VertexCount))) return false;
			}
		}
	}

	// frame window
	if (!stream.read((char*)&_pmd.FrameWindow.ExpressionListCount, sizeof(_pmd.FrameWindow.ExpressionListCount))) return false;

	if (_pmd.FrameWindow.ExpressionListCount > 0)
	{
		_pmd.FrameWindow.ExpressionList.resize(_pmd.FrameWindow.ExpressionListCount);

		if (!stream.read((char*)&_pmd.FrameWindow.ExpressionList[0], (std::streamsize)(sizeof(PMD_Expression)* _pmd.FrameWindow.ExpressionListCount))) return false;
	}

	if (!stream.read((char*)&_pmd.FrameWindow.NodeNameCount, sizeof(_pmd.FrameWindow.NodeNameCount))) return false;

	if (_pmd.FrameWindow.NodeNameCount > 0)
	{
		_pmd.FrameWindow.NodeNameList.resize(_pmd.FrameWindow.NodeNameCount);

		if (!stream.read((char*)&_pmd.FrameWindow.NodeNameList[0].Name, (std::streamsize)(sizeof(PMD_NodeName)* _pmd.FrameWindow.NodeNameCount))) return false;
	}

	if (!stream.read((char*)&_pmd.FrameWindow.BoneToNodeCount, sizeof(_pmd.FrameWindow.BoneToNodeCount))) return false;

	if (_pmd.FrameWindow.BoneToNodeCount > 0)
	{
		_pmd.FrameWindow.BoneToNodeList.resize(_pmd.FrameWindow.BoneToNodeCount);

		if (!stream.read((char*)&_pmd.FrameWindow.BoneToNodeList[0].Bone, (std::streamsize)(sizeof(PMD_BoneToNode)* _pmd.FrameWindow.BoneToNodeCount))) return false;
	}

	// description
	if (!stream.read((char*)&_pmd.HasDescription, sizeof(_pmd.HasDescription))) return false;

	if (_pmd.HasDescription)
	{
		if (!stream.read((char*)&_pmd.Description.ModelName, sizeof(_pmd.Description.ModelName))) return false;

		if (!stream.read((char*)&_pmd.Description.Comment, sizeof(_pmd.Description.Comment))) return false;

		for (PMD_BoneCount i = 0; i < _pmd.BoneCount; i++)
		{
			PMD_BoneName name;

			if (!stream.read((char*)&name.Name, sizeof(name))) return false;

			_pmd.Description.BoneName.push_back(name);
		}

		for (PMD_uint8_t i = 0; i < _pmd.FrameWindow.ExpressionListCount; i++)
		{
			PMD_MorphName name;

			if (!stream.read((char*)&name.Name, sizeof(name))) return false;

			_pmd.Description.FaceName.push_back(name);
		}

		for (PMD_uint8_t i = 0; i < _pmd.FrameWindow.NodeNameCount; i++)
		{
			PMD_NodeName name;

			if (!stream.read((char*)&name.Name, sizeof(name))) return false;

			_pmd.Description.FrameName.push_back(name);
		}
	}

	// toon
	_pmd.ToonCount = PMD_NUM_TOON;

	_pmd.ToonList.resize(_pmd.ToonCount);

	if (!stream.read((char*)&_pmd.ToonList[0].Name, (std::streamsize)(sizeof(PMD_Toon) * _pmd.ToonCount))) return false;

	// rigidbody
	if (!stream.read((char*)&_pmd.BodyCount, sizeof(_pmd.BodyCount))) return false;

	if (_pmd.BodyCount > 0)
	{
		_pmd.BodyList.resize(_pmd.BodyCount);

		if (!stream.read((char*)&_pmd.BodyList[0], (std::streamsize)(sizeof(PMD_Body)* _pmd.BodyCount))) return false;
	}

	// joint
	if (!stream.read((char*)&_pmd.JointCount, sizeof(_pmd.JointCount))) return false;

	if (_pmd.JointCount > 0)
	{
		_pmd.JointList.resize(_pmd.JointCount);

		if (!stream.read((char*)&_pmd.JointList[0], (std::streamsize)(sizeof(PMD_Body)* _pmd.JointCount))) return false;
	}

	for (std::size_t index = 0; index < _pmd.MaterialList.size(); index++)
	{
		auto& it = _pmd.MaterialList[index];

		auto material = std::make_shared<MaterialProperty>();
		material->set(MATKEY_COLOR_DIFFUSE, it.Diffuse);
		material->set(MATKEY_COLOR_AMBIENT, it.Ambient);
		material->set(MATKEY_COLOR_SPECULAR, it.Specular);
		material->set(MATKEY_OPACITY, it.Opacity);
		material->set(MATKEY_SHININESS, it.Shininess);

		std::string name = it.TextureName;
		std::string::size_type substr = name.find_first_of("*");
		if (substr != std::string::npos)
		{
			name.erase(name.begin() + substr, name.end());
		}

		material->set(MATKEY_TEXTURE_DIFFUSE(0), name);
		material->set(MATKEY_TEXTURE_AMBIENT(0), name);

		model.addMaterial(material);
	}

	PMD_Index* indices = _pmd.IndexList.data();
	PMD_Vertex* vertices = _pmd.VertexList.data();

	MeshPropertyPtr root = std::make_shared<MeshProperty>();
	MeshPropertyPtr mesh = root;
	MeshPropertyPtr last = nullptr;

	for (std::size_t index = 0; index < _pmd.MaterialList.size(); index++)
	{
		auto& it = _pmd.MaterialList[index];

		Vector3Array points;
		Vector3Array normals;
		Vector2Array texcoords;
		VertexWeights weights;
		UintArray faces;

		for (PMD_IndexCount i = 0; i < it.FaceVertexCount; i++, indices++)
		{
			PMD_Vertex& v = vertices[*indices];

			points.push_back(v.Position);
			normals.push_back(v.Normal);
			texcoords.push_back(v.UV);
			faces.push_back(i);

			VertexWeight weight;
			weight.weight1 = v.Weight / 100.0;
			weight.weight2 = 1.0 - weight.weight1;
			weight.weight3 = 0.0f;
			weight.weight4 = 0.0f;
			weight.bone1 = v.Bone.Bone1;
			weight.bone2 = v.Bone.Bone2;
			weight.bone3 = 0;
			weight.bone4 = 0;

			weights.push_back(weight);
		}

		if (last == mesh)
		{
			mesh = std::make_shared<MeshProperty>();
			root->addChild(mesh);
		}

		mesh->setMaterialID(index);
		mesh->setVertexArray(points);
		mesh->setNormalArray(normals);
		mesh->setTexcoordArray(texcoords);
		mesh->setWeightArray(weights);
		mesh->setFaceArray(faces);

		last = mesh;
	}


	if (_pmd.BoneCount > 0)
	{
		Bones bones;
		InverseKinematics iks;

		for (auto& it : _pmd.BoneList)
		{
			Bone bone;

			char inbuf[MAX_PATH + 1] = { 0 };
			char outbuf[MAX_PATH + 1] = { 0 };
			char *in = inbuf;
			char *out = outbuf;
			std::size_t in_size = (size_t)MAX_PATH;
			std::size_t out_size = (size_t)MAX_PATH;

			memcpy(in, it.Name.Name, sizeof(it.Name.Name));

			iconv_t ic = iconv_open("GBK", "SJIS");
			iconv(ic, &in, &in_size, &out, &out_size);
			iconv_close(ic);

			bone.setName(std::string(outbuf));
			bone.setPosition(it.Position);
			bone.setParent(it.Parent);
			bone.setChild(it.Child);

			bones.push_back(bone);
		}

		for (auto& it : _pmd.IkList)
		{
			IKAttr attr;
			attr.IKBoneIndex = it.IK;
			attr.IKTargetBoneIndex = it.Target;
			attr.IKLimitedRadian = it.LimitOnce;
			attr.IKLinkCount = it.LinkCount;
			attr.IKLoopCount = it.LoopCount;
			for (auto& bone : it.LinkList)
			{
				IKChild child;
				child.BoneIndex = bone;
				child.MinimumRadian = Vector3::Zero;
				child.MaximumRadian = Vector3(3.14, 3.14, 3.14);
				child.RotateLimited = 1;

				attr.IKList.push_back(child);
			}

			iks.push_back(attr);
		}

		root->setInverseKinematics(iks);
		root->setBoneArray(bones);
	}

	model.addMesh(root);

	return true;
}
Example #6
0
bool
SDKMeshHandler::doLoad(Model& model, istream& stream) noexcept
{
	SDKMESH_HEADER hdr;

	if (!stream.read((char*)&hdr, sizeof(hdr)))
		return false;

	std::vector<SDKMESH_VERTEX_BUFFER_HEADER> vbs;
	std::vector<SDKMESH_INDEX_BUFFER_HEADER> ibs;
	std::vector<SDKMESH_MESH> meshes;
	std::vector<SDKMESH_MATERIAL> materials;

	vbs.resize(hdr.NumVertexBuffers);
	ibs.resize(hdr.NumIndexBuffers);
	meshes.resize(hdr.NumMeshes);
	materials.resize(hdr.NumMaterials);

	if (!stream.seekg(hdr.VertexStreamHeadersOffset, ios_base::beg)) return false;
	if (!stream.read((char*)vbs.data(), sizeof(SDKMESH_VERTEX_BUFFER_HEADER) * hdr.NumVertexBuffers)) return false;

	if (!stream.seekg(hdr.IndexStreamHeadersOffset, ios_base::beg)) return false;
	if (!stream.read((char*)ibs.data(), sizeof(SDKMESH_INDEX_BUFFER_HEADER) * hdr.NumIndexBuffers)) return false;

	if (!stream.seekg(hdr.MeshDataOffset, ios_base::beg)) return false;
	if (!stream.read((char*)meshes.data(), sizeof(SDKMESH_MESH) * hdr.NumMeshes)) return false;

	if (!stream.seekg(hdr.MaterialDataOffset, ios_base::beg)) return false;
	if (!stream.read((char*)materials.data(), sizeof(SDKMESH_MATERIAL) * hdr.NumMaterials)) return false;

	Vector3Array vertices;
	Vector3Array normals;
	Vector3Array tangets;
	Vector2Array texcoord;
	UintArray faces;

	MeshPropertyPtr root = nullptr;

	for (auto& it : materials)
	{
		auto material = std::make_shared<MaterialProperty>();

		material->set(MATKEY_NAME, it.Name);
		material->set(MATKEY_COLOR_DIFFUSE, it.Diffuse);
		material->set(MATKEY_COLOR_AMBIENT, it.Ambient);
		material->set(MATKEY_COLOR_SPECULAR, Vector3(0.5,0.5,0.5));
		material->set(MATKEY_SHININESS, it.Power);

		if (it.DiffuseTexture[0] != 0)
		{
			material->set(MATKEY_TEXTURE_DIFFUSE(0), it.DiffuseTexture);
			material->set(MATKEY_TEXTURE_AMBIENT(0), it.DiffuseTexture);
		}

		if (it.NormalTexture[0] != 0)
		{
			material->set(MATKEY_TEXTURE_NORMALS(0), it.NormalTexture);
		}

		if (it.SpecularTexture[0] != 0)
		{
			material->set(MATKEY_TEXTURE_SPECULAR(0), it.SpecularTexture);
		}

		model.addMaterial(material);
	}

	for (std::size_t meshIndex = 0; meshIndex < hdr.NumMeshes; meshIndex++)
	{
		auto& mesh = meshes[meshIndex];

		for (std::size_t i = 0; i < mesh.NumVertexBuffers; i++)
		{
			stream.seekg(vbs[i].DataOffset, ios_base::beg);

			for (std::size_t j = 0; j < vbs[i].NumVertices; j++)
			{
				std::uint8_t offset = 0;
				std::uint8_t buffer[MAX_VERTEX_BUFFER];
				stream.read((char*)buffer, vbs[i].StrideBytes);

				for (std::size_t element = 0; element < MAX_VERTEX_ELEMENTS; element++)
				{
					if (vbs[i].Decl[element].Stream != 0)
					{
						offset = 0;
						break;
					}

					if (vbs[i].Decl[element].Usage == USAGE_POSITION)
					{
						vertices.push_back(*(Vector3*)((char*)&buffer + offset));
						offset += sizeof(Vector3);
					}
					else if (vbs[i].Decl[element].Usage == USAGE_NORMAL)
					{
						normals.push_back(*(Vector3*)((char*)&buffer + offset));
						offset += sizeof(Vector3);
					}
					else if (vbs[i].Decl[element].Usage == USAGE_TANGENT)
					{
						tangets.push_back(*(Vector3*)((char*)&buffer + offset));
						offset += sizeof(Vector3);
					}
					else if (vbs[i].Decl[element].Usage == USAGE_TEXCOORD)
					{
						texcoord.push_back(*(Vector2*)((char*)&buffer + offset));
						offset += sizeof(Vector2);
					}
				}
			}
		}

		stream.seekg(ibs[mesh.IndexBuffer].DataOffset, ios_base::beg);

		auto sizeofdata = ibs[mesh.IndexBuffer].SizeBytes / ibs[mesh.IndexBuffer].NumIndices;

		for (std::size_t j = 0; j < ibs[mesh.IndexBuffer].NumIndices; j++)
		{
			std::uint32_t buffer = 0;
			stream.read((char*)&buffer, sizeofdata);

			faces.push_back(buffer);
		}

		MeshPropertyPtr subset = std::make_shared<MeshProperty>();
		subset->setMaterialID(0);
		subset->setVertexArray(vertices);
		subset->setNormalArray(normals);
		subset->setTexcoordArray(texcoord);
		subset->setTangentArray(tangets);
		subset->setFaceArray(faces);

		if (root)
			root->addChild(subset);
		else
			root = subset;
	}

	model.addMesh(root);

	return true;
}