diff --git a/tools/geometryc/geometryc.cpp b/tools/geometryc/geometryc.cpp index 91b50bc37..8304b84cd 100644 --- a/tools/geometryc/geometryc.cpp +++ b/tools/geometryc/geometryc.cpp @@ -1,22 +1,22 @@ -/* - * Copyright 2011-2012 Branimir Karadzic. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#include -#include "../../src/vertexdecl.h" - -#include -#include -#include -#include -#include +/* + * Copyright 2011-2012 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include +#include "../../src/vertexdecl.h" + +#include +#include +#include +#include +#include namespace std { namespace tr1 {} using namespace tr1; } // namespace std -#include - -#include - -#if 0 +#include + +#include + +#if 0 # define BX_TRACE(_format, ...) \ do { \ printf(BX_FILE_LINE_LITERAL "BGFX " _format "\n", ##__VA_ARGS__); \ @@ -38,30 +38,30 @@ namespace std { namespace tr1 {} using namespace tr1; } // namespace std bx::debugBreak(); \ } \ } while(0) -#endif // 0 +#endif // 0 -#define EXPECT(_condition) \ - do { \ +#define EXPECT(_condition) \ + do { \ if (!(_condition) ) \ { \ - printf("Error parsing at:\n" BX_FILE_LINE_LITERAL "\nExpected: " #_condition "\n"); \ - exit(EXIT_FAILURE); \ - } \ - } while(0) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tokenizecmd.h" -#include "bounds.h" -#include "math.h" - + printf("Error parsing at:\n" BX_FILE_LINE_LITERAL "\nExpected: " #_condition "\n"); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tokenizecmd.h" +#include "bounds.h" +#include "math.h" + struct Vector3 { float x; @@ -69,8 +69,8 @@ struct Vector3 float z; }; -typedef std::vector Vector3Array; - +typedef std::vector Vector3Array; + struct Index3 { int32_t m_position; @@ -79,43 +79,43 @@ struct Index3 int32_t m_vertexIndex; }; -typedef std::unordered_map Index3Map; - -struct Triangle -{ - uint64_t m_index[3]; -}; - -typedef std::vector TriangleArray; - -struct Group -{ - uint32_t m_startTriangle; - uint32_t m_numTriangles; - std::string m_name; - std::string m_material; -}; - -typedef std::vector GroupArray; - -struct Primitive -{ - uint32_t m_startVertex; - uint32_t m_startIndex; - uint32_t m_numVertices; - uint32_t m_numIndices; - std::string m_name; -}; - -typedef std::vector PrimitiveArray; - -static uint32_t s_obbSteps = 17; - -#define BGFX_CHUNK_MAGIC_GEO BX_MAKEFOURCC('G', 'E', 'O', 0x0) -#define BGFX_CHUNK_MAGIC_VB BX_MAKEFOURCC('V', 'B', ' ', 0x0) -#define BGFX_CHUNK_MAGIC_IB BX_MAKEFOURCC('I', 'B', ' ', 0x0) -#define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0) - +typedef std::unordered_map Index3Map; + +struct Triangle +{ + uint64_t m_index[3]; +}; + +typedef std::vector TriangleArray; + +struct Group +{ + uint32_t m_startTriangle; + uint32_t m_numTriangles; + std::string m_name; + std::string m_material; +}; + +typedef std::vector GroupArray; + +struct Primitive +{ + uint32_t m_startVertex; + uint32_t m_startIndex; + uint32_t m_numVertices; + uint32_t m_numIndices; + std::string m_name; +}; + +typedef std::vector PrimitiveArray; + +static uint32_t s_obbSteps = 17; + +#define BGFX_CHUNK_MAGIC_GEO BX_MAKEFOURCC('G', 'E', 'O', 0x0) +#define BGFX_CHUNK_MAGIC_VB BX_MAKEFOURCC('V', 'B', ' ', 0x0) +#define BGFX_CHUNK_MAGIC_IB BX_MAKEFOURCC('I', 'B', ' ', 0x0) +#define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0) + long int fsize(FILE* _file) { long int pos = ftell(_file); @@ -124,15 +124,15 @@ long int fsize(FILE* _file) fseek(_file, pos, SEEK_SET); return size; } - -void triangleReorder(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices, uint16_t _cacheSize) -{ - uint16_t* newIndexList = new uint16_t[_numIndices]; - Forsyth::OptimizeFaces(_indices, _numIndices, _numVertices, newIndexList, _cacheSize); - memcpy(_indices, newIndexList, _numIndices*2); - delete [] newIndexList; -} - + +void triangleReorder(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices, uint16_t _cacheSize) +{ + uint16_t* newIndexList = new uint16_t[_numIndices]; + Forsyth::OptimizeFaces(_indices, _numIndices, _numVertices, newIndexList, _cacheSize); + memcpy(_indices, newIndexList, _numIndices*2); + delete [] newIndexList; +} + uint32_t packUint32(uint8_t _x, uint8_t _y, uint8_t _z, uint8_t _w) { union @@ -191,10 +191,10 @@ uint32_t packF2h(float _x, float _y) uint16_t arr[2]; } un; - un.arr[0] = bx::halfFromFloat(_x); - un.arr[1] = bx::halfFromFloat(_y); - - return un.ui32; + un.arr[0] = bx::halfFromFloat(_x); + un.arr[1] = bx::halfFromFloat(_y); + + return un.ui32; } void unpackF2h(float _result[2], uint32_t _packed) @@ -288,61 +288,61 @@ void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices, void writeBounds(bx::WriterI* _writer, const void* _vertices, uint32_t _numVertices, uint32_t _stride) { - Sphere maxSphere; - calcMaxBoundingSphere(maxSphere, _vertices, _numVertices, _stride); - - Sphere minSphere; - calcMinBoundingSphere(minSphere, _vertices, _numVertices, _stride); - - if (minSphere.m_radius > maxSphere.m_radius) - { - bx::write(_writer, maxSphere); - } - else - { - bx::write(_writer, minSphere); - } - + Sphere maxSphere; + calcMaxBoundingSphere(maxSphere, _vertices, _numVertices, _stride); + + Sphere minSphere; + calcMinBoundingSphere(minSphere, _vertices, _numVertices, _stride); + + if (minSphere.m_radius > maxSphere.m_radius) + { + bx::write(_writer, maxSphere); + } + else + { + bx::write(_writer, minSphere); + } + Aabb aabb; - calcAabb(aabb, _vertices, _numVertices, _stride); - bx::write(_writer, aabb); - - Obb obb; - calcObb(obb, _vertices, _numVertices, _stride, s_obbSteps); - bx::write(_writer, obb); + calcAabb(aabb, _vertices, _numVertices, _stride); + bx::write(_writer, aabb); + + Obb obb; + calcObb(obb, _vertices, _numVertices, _stride, s_obbSteps); + bx::write(_writer, obb); } void write(bx::WriterI* _writer, const uint8_t* _vertices, uint32_t _numVertices, const bgfx::VertexDecl& _decl, const uint16_t* _indices, uint32_t _numIndices, const std::string& _material, const PrimitiveArray& _primitives) { uint32_t stride = _decl.getStride(); - bx::write(_writer, BGFX_CHUNK_MAGIC_VB); - writeBounds(_writer, _vertices, _numVertices, stride); - - bx::write(_writer, _decl); - bx::write(_writer, uint16_t(_numVertices) ); - bx::write(_writer, _vertices, _numVertices*stride); - - bx::write(_writer, BGFX_CHUNK_MAGIC_IB); - bx::write(_writer, _numIndices); - bx::write(_writer, _indices, _numIndices*2); - - bx::write(_writer, BGFX_CHUNK_MAGIC_PRI); - uint16_t nameLen = uint16_t(_material.size() ); - bx::write(_writer, nameLen); - bx::write(_writer, _material.c_str(), nameLen); - bx::write(_writer, uint16_t(_primitives.size() ) ); - for (PrimitiveArray::const_iterator primIt = _primitives.begin(); primIt != _primitives.end(); ++primIt) - { - const Primitive& prim = *primIt; - nameLen = uint16_t(prim.m_name.size() ); - bx::write(_writer, nameLen); - bx::write(_writer, prim.m_name.c_str(), nameLen); - bx::write(_writer, prim.m_startIndex); - bx::write(_writer, prim.m_numIndices); - bx::write(_writer, prim.m_startVertex); - bx::write(_writer, prim.m_numVertices); - writeBounds(_writer, &_vertices[prim.m_startVertex*stride], prim.m_numVertices, stride); - } + bx::write(_writer, BGFX_CHUNK_MAGIC_VB); + writeBounds(_writer, _vertices, _numVertices, stride); + + bx::write(_writer, _decl); + bx::write(_writer, uint16_t(_numVertices) ); + bx::write(_writer, _vertices, _numVertices*stride); + + bx::write(_writer, BGFX_CHUNK_MAGIC_IB); + bx::write(_writer, _numIndices); + bx::write(_writer, _indices, _numIndices*2); + + bx::write(_writer, BGFX_CHUNK_MAGIC_PRI); + uint16_t nameLen = uint16_t(_material.size() ); + bx::write(_writer, nameLen); + bx::write(_writer, _material.c_str(), nameLen); + bx::write(_writer, uint16_t(_primitives.size() ) ); + for (PrimitiveArray::const_iterator primIt = _primitives.begin(); primIt != _primitives.end(); ++primIt) + { + const Primitive& prim = *primIt; + nameLen = uint16_t(prim.m_name.size() ); + bx::write(_writer, nameLen); + bx::write(_writer, prim.m_name.c_str(), nameLen); + bx::write(_writer, prim.m_startIndex); + bx::write(_writer, prim.m_numIndices); + bx::write(_writer, prim.m_startVertex); + bx::write(_writer, prim.m_numVertices); + writeBounds(_writer, &_vertices[prim.m_startVertex*stride], prim.m_numVertices, stride); + } } void help(const char* _error = NULL) @@ -397,596 +397,597 @@ inline uint32_t rgbaToAbgr(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a) ; } -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(packNormal, '\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; - +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(packNormal, '\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 = tokenizeCommandLine(next, commandLine, len, argc, argv, 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; - - 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; - - std::pair result = indexMap.insert(std::make_pair(hash, index) ); - if (!result.second) - { - Index3& oldIndex = result.first->second; - 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; - - struct GroupSortByMaterial - { - bool operator()(const Group& _lhs, const Group& _rhs) - { - return _lhs.m_material < _rhs.m_material; - } - }; - - 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) - { - switch (packNormal) - { - default: - case 0: - decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float); - if (hasTangent) - { - decl.add(bgfx::Attrib::Tangent, 3, bgfx::AttribType::Float); - } - break; - - case 1: - decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true); - if (hasTangent) - { - decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, 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 normalOffset = decl.getOffset(bgfx::Attrib::Normal); - uint32_t tangentOffset = decl.getOffset(bgfx::Attrib::Tangent); - uint32_t texcoord0Offset = decl.getOffset(bgfx::Attrib::TexCoord0); - - 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(); - - 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]; - } - - switch (packUv) - { - default: - case 0: - { - float* texcoord0 = (float*)(vertices + texcoord0Offset); - memcpy(texcoord0, uv, 2*sizeof(float) ); - } - break; - - case 1: - { - uint32_t* texcoord0 = (uint32_t*)(vertices + texcoord0Offset); - *texcoord0 = packF2h(uv[0], uv[1]); - } - break; - } - } - - if (hasNormal) - { - switch (packNormal) - { - default: - case 0: - { - float* normal = (float*)(vertices + normalOffset); - vec3Norm(normal, (float*)&normals[index.m_normal]); - - if (hasTangent) - { - float* tangent = (float*)(vertices + tangentOffset); - memset(tangent, 0, 3*sizeof(float) ); - } - } - break; - - case 1: - { - float normal[3]; - vec3Norm(normal, (float*)&normals[index.m_normal]); - uint32_t* nxyz0 = (uint32_t*)(vertices + normalOffset); - *nxyz0 = packF4u(normal[0], normal[1], normal[2]); - - if (hasTangent) - { - uint32_t* txyz0 = (uint32_t*)(vertices + tangentOffset); - *txyz0 = packF4u(0.0f); - } - } - break; - } - } - - 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(); - - write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives); - } - - printf("size: %d\n", 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 - , groups.size() - , numPrimitives - , numVertices - , numIndices - ); - - return EXIT_SUCCESS; -} + do + { + next = tokenizeCommandLine(next, commandLine, len, argc, argv, 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; + + 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; + + std::pair result = indexMap.insert(std::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; + + struct GroupSortByMaterial + { + bool operator()(const Group& _lhs, const Group& _rhs) + { + return _lhs.m_material < _rhs.m_material; + } + }; + + 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) + { + switch (packNormal) + { + default: + case 0: + decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float); + if (hasTangent) + { + decl.add(bgfx::Attrib::Tangent, 3, bgfx::AttribType::Float); + } + break; + + case 1: + decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true); + if (hasTangent) + { + decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, 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 normalOffset = decl.getOffset(bgfx::Attrib::Normal); + uint32_t tangentOffset = decl.getOffset(bgfx::Attrib::Tangent); + uint32_t texcoord0Offset = decl.getOffset(bgfx::Attrib::TexCoord0); + + 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(); + + 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]; + } + + switch (packUv) + { + default: + case 0: + { + float* texcoord0 = (float*)(vertices + texcoord0Offset); + memcpy(texcoord0, uv, 2*sizeof(float) ); + } + break; + + case 1: + { + uint32_t* texcoord0 = (uint32_t*)(vertices + texcoord0Offset); + *texcoord0 = packF2h(uv[0], uv[1]); + } + break; + } + } + + if (hasNormal) + { + switch (packNormal) + { + default: + case 0: + { + float* normal = (float*)(vertices + normalOffset); + vec3Norm(normal, (float*)&normals[index.m_normal]); + + if (hasTangent) + { + float* tangent = (float*)(vertices + tangentOffset); + memset(tangent, 0, 3*sizeof(float) ); + } + } + break; + + case 1: + { + float normal[3]; + vec3Norm(normal, (float*)&normals[index.m_normal]); + uint32_t* nxyz0 = (uint32_t*)(vertices + normalOffset); + *nxyz0 = packF4u(normal[0], normal[1], normal[2]); + + if (hasTangent) + { + uint32_t* txyz0 = (uint32_t*)(vertices + tangentOffset); + *txyz0 = packF4u(0.0f); + } + } + break; + } + } + + 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(); + + 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; +}