void setMouseLock(WindowHandle _handle, bool _lock) { BX_UNUSED(_handle, _lock); }
extern "C" int fscanf(FILE* _stream, const char* _format, ...) { BX_UNUSED(_stream, _format); return -1; }
extern "C" int fclose(FILE* _stream) { BX_UNUSED(_stream); return -1; }
extern "C" int closedir (struct DIR* dirp) { BX_UNUSED(dirp); return 0; }
extern "C" int vfprintf(FILE* _stream, const char* _format, va_list _argList) { BX_UNUSED(_stream, _format, _argList); return -1; }
extern "C" float acosf(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" struct DIR* opendir(const char* dirname) { BX_UNUSED(dirname); return NULL; }
extern "C" double ldexp(double _x, int _exp) { BX_UNUSED(_x, _exp); return 0.0; }
extern "C" float log10f(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" char* strdup(const char* _src) { BX_UNUSED(_src); return NULL; }
extern "C" long int strtol(const char* _str, char** _end, int _base) { BX_UNUSED(_str, _end, _base); return -1; }
extern "C" size_t mbstowcs(wchar_t* _dst, const char* _src, size_t _max) { BX_UNUSED(_dst, _src, _max); return 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; }
void GlContext::create(uint32_t /*_width*/, uint32_t /*_height*/) { m_opengl32dll = bx::dlopen("opengl32.dll"); BGFX_FATAL(NULL != m_opengl32dll, Fatal::UnableToInitialize, "Failed to load opengl32.dll."); wglGetProcAddress = (PFNWGLGETPROCADDRESSPROC)bx::dlsym(m_opengl32dll, "wglGetProcAddress"); BGFX_FATAL(NULL != wglGetProcAddress, Fatal::UnableToInitialize, "Failed get wglGetProcAddress."); // If g_bgfxHwnd is NULL, the assumption is that GL context was created // by user (for example, using SDL, GLFW, etc.) BX_WARN(NULL != g_bgfxHwnd , "bgfx::winSetHwnd with valid window is not called. This might " "be intentional when GL context is created by the user." ); if (NULL != g_bgfxHwnd) { wglMakeCurrent = (PFNWGLMAKECURRENTPROC)bx::dlsym(m_opengl32dll, "wglMakeCurrent"); BGFX_FATAL(NULL != wglMakeCurrent, Fatal::UnableToInitialize, "Failed get wglMakeCurrent."); wglCreateContext = (PFNWGLCREATECONTEXTPROC)bx::dlsym(m_opengl32dll, "wglCreateContext"); BGFX_FATAL(NULL != wglCreateContext, Fatal::UnableToInitialize, "Failed get wglCreateContext."); wglDeleteContext = (PFNWGLDELETECONTEXTPROC)bx::dlsym(m_opengl32dll, "wglDeleteContext"); BGFX_FATAL(NULL != wglDeleteContext, Fatal::UnableToInitialize, "Failed get wglDeleteContext."); m_hdc = GetDC(g_bgfxHwnd); BGFX_FATAL(NULL != m_hdc, Fatal::UnableToInitialize, "GetDC failed!"); // Dummy window to peek into WGL functionality. // // An application can only set the pixel format of a window one time. // Once a window's pixel format is set, it cannot be changed. // MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd369049%28v=vs.85%29.aspx HWND hwnd = CreateWindowA("STATIC" , "" , WS_POPUP|WS_DISABLED , -32000 , -32000 , 0 , 0 , NULL , NULL , GetModuleHandle(NULL) , 0 ); HDC hdc = GetDC(hwnd); BGFX_FATAL(NULL != hdc, Fatal::UnableToInitialize, "GetDC failed!"); HGLRC context = createContext(hdc); wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); if (NULL != wglGetExtensionsStringARB) { const char* extensions = (const char*)wglGetExtensionsStringARB(hdc); BX_TRACE("WGL extensions:"); dumpExtensions(extensions); } if (NULL != wglChoosePixelFormatARB && NULL != wglCreateContextAttribsARB) { int32_t attrs[] = { WGL_SAMPLE_BUFFERS_ARB, 0, WGL_SAMPLES_ARB, 0, WGL_SUPPORT_OPENGL_ARB, true, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_DRAW_TO_WINDOW_ARB, true, WGL_DOUBLE_BUFFER_ARB, true, WGL_COLOR_BITS_ARB, 32, WGL_DEPTH_BITS_ARB, 24, WGL_STENCIL_BITS_ARB, 8, 0 }; int result; int pixelFormat; uint32_t numFormats = 0; do { result = wglChoosePixelFormatARB(m_hdc, attrs, NULL, 1, &pixelFormat, &numFormats); if (0 == result || 0 == numFormats) { attrs[3] >>= 1; attrs[1] = attrs[3] == 0 ? 0 : 1; } } while (0 == numFormats); PIXELFORMATDESCRIPTOR pfd; DescribePixelFormat(m_hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); BX_TRACE("Pixel format:\n" "\tiPixelType %d\n" "\tcColorBits %d\n" "\tcAlphaBits %d\n" "\tcDepthBits %d\n" "\tcStencilBits %d\n" , pfd.iPixelType , pfd.cColorBits , pfd.cAlphaBits , pfd.cDepthBits , pfd.cStencilBits ); result = SetPixelFormat(m_hdc, pixelFormat, &pfd); // When window is created by SDL and SDL_WINDOW_OPENGL is set SetPixelFormat // will fail. Just warn and continue. In case it failed for some other reason // create context will fail and it will error out there. BX_WARN(result, "SetPixelFormat failed (last err: 0x%08x)!", GetLastError() ); uint32_t flags = BGFX_CONFIG_DEBUG ? WGL_CONTEXT_DEBUG_BIT_ARB : 0; BX_UNUSED(flags); int32_t contextAttrs[9] = { #if BGFX_CONFIG_RENDERER_OPENGL >= 31 WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_FLAGS_ARB, flags, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, #else WGL_CONTEXT_MAJOR_VERSION_ARB, 2, WGL_CONTEXT_MINOR_VERSION_ARB, 1, 0, 0, 0, 0, #endif // BGFX_CONFIG_RENDERER_OPENGL >= 31 0 }; m_context = wglCreateContextAttribsARB(m_hdc, 0, contextAttrs); if (NULL == m_context) { // nVidia doesn't like context profile mask for contexts below 3.2? contextAttrs[6] = WGL_CONTEXT_PROFILE_MASK_ARB == contextAttrs[6] ? 0 : contextAttrs[6]; m_context = wglCreateContextAttribsARB(m_hdc, 0, contextAttrs); } BGFX_FATAL(NULL != m_context, Fatal::UnableToInitialize, "Failed to create context 0x%08x.", GetLastError() ); }
extern "C" float floorf(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" double pow(double _x) { BX_UNUSED(_x); return 0.0; }
extern "C" double floor(double _x) { BX_UNUSED(_x); return 0.0; }
extern "C" float tanf(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" float fmodf(float _numer, float _denom) { BX_UNUSED(_numer, _denom); return 0.0f; }
extern "C" float atan2f(float _y, float _x) { BX_UNUSED(_y, _x); return 0.0f; }
extern "C" struct dirent* readdir(struct DIR* dirp) { BX_UNUSED(dirp); return NULL; }
extern "C" float sqrtf(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" int printf(const char* _format, ...) { BX_UNUSED(_format); return -1; }
extern "C" double sqrt(double _x) { BX_UNUSED(_x); return 0.0; }
extern "C" int sscanf(const char* _str, const char* _format, ...) { BX_UNUSED(_str, _format); return -1; }
extern "C" float ceilf(float _x) { BX_UNUSED(_x); return 0.0f; }
extern "C" FILE* fopen(const char* _filename, const char* _mode) { BX_UNUSED(_filename, _mode); return NULL; }
extern "C" double ceil(double _x) { BX_UNUSED(_x); return 0.0; }
extern "C" size_t fwrite(const void* _ptr, size_t _size, size_t _count, FILE* _stream) { BX_UNUSED(_ptr, _size, _count, _stream); return -1; }
void toggleFullscreen(WindowHandle _handle) { BX_UNUSED(_handle); }