#include "RuntimeModule.h" #include "Globals.h" #include "RenderModule.h" #include "3rdparty/ocornut-imgui/imgui.h" #include "imgui/imgui.h" #define GLFW_EXPOSE_NATIVE_GLX #define GLFW_EXPOSE_NATIVE_X11 #include #include #include "SimpleMath/SimpleMath.h" #include "SimpleMath/SimpleMathMap.h" #include #include #include #include #include #include #include #include #define TINYOBJLOADER_IMPLEMENTATION #include "tiny_obj_loader.h" #include "math_types.h" #include #include #include #include "Serializer.h" using namespace std; typedef Matrix44f Matrix44f; typedef Vector4f Vector4f; typedef Matrix33f Matrix33f; typedef Vector3f Vector3f; typedef MatrixNNf MatrixNNf; typedef VectorNf VectorNf; struct Renderer; struct module_state { Renderer *renderer; }; static struct module_state *module_init() { gLog ("RenderModule init called."); assert (gWindow != nullptr && "Cannot initialize renderer module without gWindow!"); module_state *state = (module_state*) malloc(sizeof(*state)); state->renderer = new Renderer(); assert (state->renderer != nullptr); return state; } template static void module_serialize ( struct module_state *state, Serializer* serializer) { // get the state from the serializer Camera* camera = &gRenderer->cameras[gRenderer->activeCameraIndex]; assert (camera != nullptr); SerializeBool (*serializer, "protot.RenderModule.draw_floor", gRenderer->drawFloor); SerializeBool (*serializer, "protot.RenderModule.draw_skybox", gRenderer->drawSkybox); SerializeBool (*serializer, "protot.RenderModule.debug_enabled", gRenderer->drawDebug); SerializeVec3 (*serializer, "protot.RenderModule.camera.eye", camera->eye); SerializeVec3 (*serializer, "protot.RenderModule.camera.poi", camera->poi); } static void module_finalize(struct module_state *state) { gLog ("RenderModule finalize called"); assert (state->renderer != nullptr); delete state->renderer; free(state); } static void module_reload(struct module_state *state, void *read_serializer) { gLog ("RenderModule reload called"); assert (gWindow != nullptr); int width, height; glfwGetWindowSize(gWindow, &width, &height); gLog ("Renderer initialize"); assert (state != nullptr); state->renderer->initialize(width, height); gRenderer = state->renderer; // load the state of the module if (read_serializer != nullptr) { module_serialize(state, static_cast(read_serializer)); } // get the state from the serializer Camera* camera = &gRenderer->cameras[gRenderer->activeCameraIndex]; assert (camera != nullptr); camera->updateMatrices(); } static void module_unload(struct module_state *state, void* write_serializer) { // serialize the state of the module if (write_serializer != nullptr) { module_serialize(state, static_cast(write_serializer)); } gRenderer = nullptr; state->renderer->shutdown(); gLog ("RenderModule unload called"); } static bool module_step(struct module_state *state, float dt) { float deltaTime = 0.3; std::ostringstream s; s << "RenderModule: 2 Runtime Object 4 " << deltaTime << " update called!"; int width, height; assert (gWindow != nullptr); glfwGetWindowSize(gWindow, &width, &height); state->renderer->updateShaders(); state->renderer->resize (width, height); state->renderer->paintGL(); return true; } extern "C" { const struct module_api MODULE_API = { .init = module_init, .reload = module_reload, .step = module_step, .unload = module_unload, .finalize = module_finalize }; } void MeshHierarchy::updateMatrices(const Matrix44f &world_transform) { for (uint32_t i = 0; i < meshes.size(); ++i) { Matrix44f parent_matrix (world_transform); if (parent[i] != -1) { parent_matrix = meshMatrices[parent[i]]; } meshMatrices[i] = localTransforms[i].toMatrix() * parent_matrix; } } void MeshHierarchy::submit(const RenderState *state) { for (uint32_t i = 0; i < meshes.size(); ++i) { bgfxutils::meshSubmit (meshes[i], state, 1, meshMatrices[i].data()); } }; // BGFX globals bgfx::VertexBufferHandle cube_vbh; bgfx::IndexBufferHandle cube_ibh; bgfx::IndexBufferHandle cube_edges_ibh; bgfx::VertexBufferHandle plane_vbh; bgfx::IndexBufferHandle plane_ibh; bgfx::UniformHandle u_time; bgfx::UniformHandle u_color; bgfx::UniformHandle u_line_params; bgfx::UniformHandle u_mtx; bgfx::UniformHandle u_exposure; bgfx::UniformHandle u_flags; bgfx::UniformHandle u_camPos; bgfx::UniformHandle s_texCube; bgfx::UniformHandle s_texCubeIrr; namespace IBL { struct Uniforms { enum { NumVec4 = 12 }; void init() { u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4, NumVec4); } void submit() { bgfx::setUniform(u_params, m_params, NumVec4); } void destroy() { bgfx::destroyUniform(u_params); } union { struct { union { float m_mtx[16]; /* 0*/ struct { float m_mtx0[4]; }; /* 1*/ struct { float m_mtx1[4]; }; /* 2*/ struct { float m_mtx2[4]; }; /* 3*/ struct { float m_mtx3[4]; }; }; /* 4*/ struct { float m_glossiness, m_reflectivity, m_exposure, m_bgType; }; /* 5*/ struct { float m_metalOrSpec, m_unused5[3]; }; /* 6*/ struct { float m_doDiffuse, m_doSpecular, m_doDiffuseIbl, m_doSpecularIbl; }; /* 7*/ struct { float m_cameraPos[3], m_unused7[1]; }; /* 8*/ struct { float m_rgbDiff[4]; }; /* 9*/ struct { float m_rgbSpec[4]; }; /*10*/ struct { float m_lightDir[3], m_unused10[1]; }; /*11*/ struct { float m_lightCol[3], m_unused11[1]; }; }; float m_params[NumVec4*4]; }; bgfx::UniformHandle u_params; }; struct Settings { Settings() { m_envRotCurr = 0.0f; m_envRotDest = 0.0f; m_lightDir[0] = -0.8f; m_lightDir[1] = 0.2f; m_lightDir[2] = -0.5f; m_lightCol[0] = 1.0f; m_lightCol[1] = 1.0f; m_lightCol[2] = 1.0f; m_glossiness = 0.7f; m_exposure = 0.0f; m_bgType = 3.0f; m_radianceSlider = 2.0f; m_reflectivity = 0.85f; m_rgbDiff[0] = 1.0f; m_rgbDiff[1] = 1.0f; m_rgbDiff[2] = 1.0f; m_rgbSpec[0] = 1.0f; m_rgbSpec[1] = 1.0f; m_rgbSpec[2] = 1.0f; m_lod = 0.0f; m_doDiffuse = false; m_doSpecular = false; m_doDiffuseIbl = true; m_doSpecularIbl = true; m_showLightColorWheel = true; m_showDiffColorWheel = true; m_showSpecColorWheel = true; m_metalOrSpec = 0; m_meshSelection = 0; m_crossCubemapPreview = ImguiCubemap::Latlong; } float m_envRotCurr; float m_envRotDest; float m_lightDir[3]; float m_lightCol[3]; float m_glossiness; float m_exposure; float m_radianceSlider; float m_bgType; float m_reflectivity; float m_rgbDiff[3]; float m_rgbSpec[3]; float m_lod; bool m_doDiffuse; bool m_doSpecular; bool m_doDiffuseIbl; bool m_doSpecularIbl; bool m_showLightColorWheel; bool m_showDiffColorWheel; bool m_showSpecColorWheel; uint8_t m_metalOrSpec; uint8_t m_meshSelection; ImguiCubemap::Enum m_crossCubemapPreview; }; Settings settings; Uniforms uniforms; }; int64_t m_timeOffset; // // Vertex packing utilities // uint32_t packUint32(uint8_t _x, uint8_t _y, uint8_t _z, uint8_t _w) { union { uint32_t ui32; uint8_t arr[4]; } un; un.arr[0] = _x; un.arr[1] = _y; un.arr[2] = _z; un.arr[3] = _w; return un.ui32; } uint32_t packF4u(float _x, float _y = 0.0f, float _z = 0.0f, float _w = 0.0f) { const uint8_t xx = uint8_t(_x*127.0f + 128.0f); const uint8_t yy = uint8_t(_y*127.0f + 128.0f); const uint8_t zz = uint8_t(_z*127.0f + 128.0f); const uint8_t ww = uint8_t(_w*127.0f + 128.0f); return packUint32(xx, yy, zz, ww); } // // Render programs // bool RenderProgram::checkModified() const { // early out if we don't have filenames if (vertexShaderFileName == "" || fragmentShaderFileName == "") { return false; } struct stat attr; bool stat_result = false; // check mtime of vertex shader stat_result = stat(vertexShaderFileName.c_str(), &attr); if (stat_result == 0 && attr.st_mtime != vertexShaderFileModTime) { return true; } // check mtime of fragment shader stat_result = stat(fragmentShaderFileName.c_str(), &attr); if (stat_result == 0 && attr.st_mtime != fragmentShaderFileModTime) { return true; } return false; } bool RenderProgram::reload() { int vertex_mtime = -1; int fragment_mtime = -1; struct stat attr; bool stat_result = false; // get mtime of vertex shader stat_result = stat(vertexShaderFileName.c_str(), &attr); if (stat_result == 0) vertex_mtime = attr.st_mtime; stat_result = stat(fragmentShaderFileName.c_str(), &attr); if (stat_result == 0) fragment_mtime = attr.st_mtime; // we need to update the mod times, otherwise we keep reloading // the same faulty files again and again. vertexShaderFileModTime = vertex_mtime; fragmentShaderFileModTime = fragment_mtime; bgfx::ProgramHandle new_handle = bgfxutils::loadProgramFromFiles ( vertexShaderFileName.c_str(), fragmentShaderFileName.c_str() ); if (bgfx::isValid(new_handle)) { if (bgfx::isValid(program)) { bgfx::destroyProgram(program); } gLog ("Reload of shaders %s and %s success!", vertexShaderFileName.c_str(), fragmentShaderFileName.c_str()); program = new_handle; return true; } else { gLog ("Reload of shaders %s and %s failed!", vertexShaderFileName.c_str(), fragmentShaderFileName.c_str()); } return false; } // // Render states // RenderState s_renderStates[RenderState::Count] = { { // Skybox 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CW | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::Skybox }, { // ShadowMap 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CW | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::ShadowMap }, { // Scene 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CW | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::Scene }, { // SceneTextured 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CW | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::SceneTextured }, { // Lines 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_TEST_LESS // | BGFX_STATE_DEPTH_TEST_GREATER // | BGFX_STATE_PT_LINES | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::Lines }, { // LinesOccluded 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_TEST_GREATER // | BGFX_STATE_PT_LINES | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::LinesOccluded }, { // Debug 0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CCW | BGFX_STATE_PT_LINES // | BGFX_STATE_PT_POINTS | BGFX_STATE_MSAA, 0, RenderProgram(), RenderState::Debug } }; // // Vertex formats // struct PosColorVertex { float m_x; float m_y; float m_z; uint32_t m_abgr; static void init() { ms_decl .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) .end(); }; static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PosColorVertex::ms_decl; struct PosNormalVertex { float m_x; float m_y; float m_z; uint32_t m_normal; static void init() { ms_decl .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true) .end(); } static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PosNormalVertex::ms_decl; struct PosNormalColorTexcoordVertex { float m_x; float m_y; float m_z; uint32_t m_normal; uint32_t m_color; float m_u; float m_v; static void init() { ms_decl .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false) .end(); } static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PosNormalColorTexcoordVertex::ms_decl; struct PosColorTexCoord0Vertex { float m_x; float m_y; float m_z; uint32_t m_rgba; float m_u; float m_v; static void init() { ms_decl .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .end(); } static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PosColorTexCoord0Vertex::ms_decl; // Used for lines struct PathVertex { float position[3]; float prev[3]; float next[3]; // TODO: use an int for the direction float info[2]; // direction and length in screen space float color[4]; static void init() { ms_decl .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord1, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord2, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Float) .end(); } static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PathVertex::ms_decl; // // Static geometries // // Plane PosNormalColorTexcoordVertex s_hplaneVertices[] = { { -1.0f, 0.0f, 1.0f, packF4u(0.0f, 1.0f, 0.0f), packF4u(1.0f, 1.0f, 1.0f), 0.f, 0.f }, { 1.0f, 0.0f, 1.0f, packF4u(0.0f, 1.0f, 0.0f), packF4u(1.0f, 1.0f, 1.0f), 10.f, 0.f }, { -1.0f, 0.0f, -1.0f, packF4u(0.0f, 1.0f, 0.0f), packF4u(1.0f, 1.0f, 1.0f), 0.f, 10.f}, { 1.0f, 0.0f, -1.0f, packF4u(0.0f, 1.0f, 0.0f), packF4u(1.0f, 1.0f, 1.0f), 10.f, 10.f }, }; const uint16_t s_planeIndices[] = { 0, 1, 2, 1, 3, 2, }; // Cube PosColorVertex s_cubeVertices[8] = { {-1.0f, 1.0f, 1.0f, 0xffffffff }, { 1.0f, 1.0f, 1.0f, 0xffffffff }, {-1.0f, -1.0f, 1.0f, 0xffffffff }, { 1.0f, -1.0f, 1.0f, 0xffffffff }, {-1.0f, 1.0f, -1.0f, 0xffffffff }, { 1.0f, 1.0f, -1.0f, 0xffffffff }, {-1.0f, -1.0f, -1.0f, 0xffffffff }, { 1.0f, -1.0f, -1.0f, 0xffffffff }, }; const uint16_t s_cubeEdgeIndices[24] = { 0, 1, 1, 3, 3, 2, 2, 0, 4, 5, 5, 7, 7, 6, 6, 4, 0, 4, 1, 5, 2, 6, 3, 7 }; const uint16_t s_cubeIndices[36] = { 0, 1, 2, // 0 1, 3, 2, 4, 6, 5, // 2 5, 6, 7, 0, 2, 4, // 4 4, 2, 6, 1, 5, 3, // 6 5, 7, 3, 0, 4, 1, // 8 4, 5, 1, 2, 3, 6, // 10 6, 3, 7, }; bool flipV = false; static float s_texelHalf = 0.0f; void screenSpaceQuad(float _textureWidth, float _textureHeight, bool _originBottomLeft = false, float _width = 1.0f, float _height = 1.0f) { if (bgfx::checkAvailTransientVertexBuffer(3, PosColorTexCoord0Vertex::ms_decl) ) { bgfx::TransientVertexBuffer vb; bgfx::allocTransientVertexBuffer(&vb, 3, PosColorTexCoord0Vertex::ms_decl); PosColorTexCoord0Vertex* vertex = (PosColorTexCoord0Vertex*)vb.data; const float zz = 0.0f; const float minx = -_width; const float maxx = _width; const float miny = 0.0f; const float maxy = _height*2.0f; const float texelHalfW = s_texelHalf/_textureWidth; const float texelHalfH = s_texelHalf/_textureHeight; const float minu = -1.0f + texelHalfW; const float maxu = 1.0f + texelHalfW; float minv = texelHalfH; float maxv = 2.0f + texelHalfH; if (_originBottomLeft) { std::swap(minv, maxv); minv -= 1.0f; maxv -= 1.0f; } vertex[0].m_x = minx; vertex[0].m_y = miny; vertex[0].m_z = zz; vertex[0].m_rgba = 0xffffffff; vertex[0].m_u = minu; vertex[0].m_v = minv; vertex[1].m_x = maxx; vertex[1].m_y = miny; vertex[1].m_z = zz; vertex[1].m_rgba = 0xffffffff; vertex[1].m_u = maxu; vertex[1].m_v = minv; vertex[2].m_x = maxx; vertex[2].m_y = maxy; vertex[2].m_z = zz; vertex[2].m_rgba = 0xffffffff; vertex[2].m_u = maxu; vertex[2].m_v = maxv; bgfx::setVertexBuffer(&vb); } } void Camera::updateMatrices() { assert (width != -1.f && height != -1.f); // view matrix bx::mtxLookAtRh (mtxView, eye.data(), poi.data(), up.data()); // projection matrix if (orthographic) { bx::mtxOrthoRh(mtxProj, -width * 0.5f, width * 0.5f, -height * 0.5f, height * 0.5f, near, far); } else { float aspect = static_cast(width) / height; float mtx_proj[16]; bx::mtxProjRh(mtxProj, fov, aspect, near, far); } // environment matrix const float dir[3] = { poi[0] - eye[0], poi[1] - eye[1], poi[2] - eye[2] }; const float dirLen = bx::vec3Length(dir); const float invDirLen = 1.0f / (dirLen + FLT_MIN); const float dirNorm[3] = { dir[0] * invDirLen, dir[1] * invDirLen, dir[2] * invDirLen }; float tmp[3]; const float fakeUp[3] = { 0.0f, 1.0f, 0.0f }; float right[3]; bx::vec3Cross (tmp, fakeUp, dirNorm); bx::vec3Norm(right, tmp); float up[3]; bx::vec3Cross(tmp, dirNorm, right); bx::vec3Norm(up, tmp); mtxEnv[ 0] = -right[0]; mtxEnv[ 1] = -right[1]; mtxEnv[ 2] = -right[2]; mtxEnv[ 3] = 0.0f; mtxEnv[ 4] = up[0]; mtxEnv[ 5] = up[1]; mtxEnv[ 6] = up[2]; mtxEnv[ 7] = 0.0f; mtxEnv[ 8] = dirNorm[0]; mtxEnv[ 9] = dirNorm[1]; mtxEnv[10] = dirNorm[2]; mtxEnv[11] = 0.0f; mtxEnv[12] = 0.0f; mtxEnv[13] = 0.0f; mtxEnv[14] = 0.0f; mtxEnv[15] = 1.0f; } void LightProbe::load(const char* _name) { char filePath[512]; bx::snprintf(filePath, BX_COUNTOF(filePath), "data/textures/%s_lod.dds", _name); m_tex = bgfxutils::loadTexture(filePath, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_W_CLAMP); bx::snprintf(filePath, BX_COUNTOF(filePath), "data/textures/%s_irr.dds", _name); m_texIrr = bgfxutils::loadTexture(filePath, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_W_CLAMP); } void Renderer::createGeometries() { // Create vertex stream declaration. PosColorVertex::init(); PosNormalVertex::init(); PosNormalColorTexcoordVertex::init(); PosColorTexCoord0Vertex::init(); PathVertex::init(); // Create static vertex buffer. cube_vbh = bgfx::createVertexBuffer( // Static data can be passed with bgfx::makeRef bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ) , PosColorVertex::ms_decl ); // Create static index buffer. cube_ibh = bgfx::createIndexBuffer( // Static data can be passed with bgfx::makeRef bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) ); // Create static index buffer. cube_edges_ibh = bgfx::createIndexBuffer( // Static data can be passed with bgfx::makeRef bgfx::makeRef(s_cubeEdgeIndices, sizeof(s_cubeEdgeIndices) ) ); plane_vbh = bgfx::createVertexBuffer( bgfx::makeRef(s_hplaneVertices, sizeof(s_hplaneVertices) ) , PosNormalColorTexcoordVertex::ms_decl ); plane_ibh = bgfx::createIndexBuffer( bgfx::makeRef(s_planeIndices, sizeof(s_planeIndices) ) ); } Path::~Path() { if (bgfx::isValid(mVertexBufferHandle)) bgfx::destroyDynamicVertexBuffer(mVertexBufferHandle); if (bgfx::isValid(mIndexBufferHandle)) bgfx::destroyDynamicIndexBuffer(mIndexBufferHandle); } void Path::UpdateBuffers() { // create an array for the actual buffer std::vector path_vertices; float path_length = 0; // Copy points to the vertex buffer for (int i = 0; i < points.size(); i++) { PathVertex vertex; memcpy (vertex.position, points[i].data(), sizeof(float) * 3); memcpy (vertex.color, colors[i].data(), sizeof(float) * 4); if (i == 0) { assert (points.size() > 1); memcpy (vertex.prev, points[i].data(), sizeof(float) * 3); memcpy (vertex.next, points[i + 1].data(), sizeof(float) * 3); } else if (i == points.size() - 1) { memcpy (vertex.next, points[i].data(), sizeof(float) * 3); memcpy (vertex.prev, points[i - 1].data(), sizeof(float) * 3); } else { memcpy (vertex.prev, points[i - 1].data(), sizeof(float) * 3); memcpy (vertex.next, points[i + 1].data(), sizeof(float) * 3); } if (i > 0) { path_length += (points[i] - points[i - 1]).norm(); } vertex.info[0] = -1.0f; vertex.info[1] = path_length; path_vertices.push_back(vertex); vertex.info[0] = 1.0f; vertex.info[1] = path_length; path_vertices.push_back(vertex); PathVertex &last_vertex = path_vertices[path_vertices.size() - 1]; assert (last_vertex.color[0] == colors[i][0]); assert (last_vertex.color[1] == colors[i][1]); assert (last_vertex.color[2] == colors[i][2]); assert (last_vertex.color[3] == 1.0f); } // Assemble the index buffer (every point is submitted twice // and gets extruded in the vertex shader) std::vector line_indices; int index = 0; for (int i = 0; i < (path_vertices.size() / 2) - 1; i++) { int j = index; line_indices.push_back(j + 0); line_indices.push_back(j + 1); line_indices.push_back(j + 2); line_indices.push_back(j + 2); line_indices.push_back(j + 1); line_indices.push_back(j + 3); index += 2; } // create buffers if they are not yet valid if (!bgfx::isValid(mVertexBufferHandle)) { mVertexBufferHandle = bgfx::createDynamicVertexBuffer( bgfx::copy( path_vertices.data(), sizeof(PathVertex) * path_vertices.size() ), PathVertex::ms_decl ); mIndexBufferHandle = bgfx::createDynamicIndexBuffer( bgfx::copy(line_indices.data(), sizeof(uint16_t) * line_indices.size()) ); } else { bgfx::updateDynamicVertexBuffer( mVertexBufferHandle, 0, bgfx::copy( path_vertices.data(), sizeof(PathVertex) * path_vertices.size() ) ); bgfx::updateDynamicIndexBuffer( mIndexBufferHandle, 0, bgfx::copy(line_indices.data(), sizeof(uint16_t) * line_indices.size()) ); } assert (bgfx::isValid(mVertexBufferHandle)); assert (bgfx::isValid(mIndexBufferHandle)); } void Renderer::setupShaders() { // Create uniforms sceneDefaultTextureSampler = bgfx::createUniform("sceneDefaultTexture", bgfx::UniformType::Int1); u_mtx = bgfx::createUniform("u_mtx", bgfx::UniformType::Mat4); u_flags = bgfx::createUniform("u_flags", bgfx::UniformType::Vec4); u_camPos = bgfx::createUniform("u_camPos", bgfx::UniformType::Vec4); s_texCube = bgfx::createUniform("s_texCube", bgfx::UniformType::Int1); s_texCubeIrr = bgfx::createUniform("s_texCubeIrr", bgfx::UniformType::Int1); int grid_size = 1024; int grid_border = 12; uint8_t grid_color_border [4] = {32, 32, 32, 255}; // uint8_t grid_color_border [4] = {0, 0, 0, 0}; uint8_t grid_color_0[4] = {192, 192, 192, 255}; uint8_t grid_color_1[4] = {128, 128, 128, 255}; uint8_t* texture_data = NULL; texture_data = new uint8_t[grid_size * grid_size * 4]; for (int i = 0; i < grid_size; i++) { for (int j = 0; j < grid_size; j++) { uint8_t *texel = &texture_data[i * (grid_size * 4) + j * 4]; if ( (i < (grid_border / 2)) || (i > grid_size - (grid_border / 2)) || (j < (grid_border / 2)) || (j > grid_size - (grid_border / 2)) ) { memcpy (texel, grid_color_border, sizeof (uint8_t) * 4); } else { if ( (i * 2) / grid_size + (j * 2) / grid_size == 1) { memcpy (texel, grid_color_0, sizeof (uint8_t) * 4); } else { memcpy (texel, grid_color_1, sizeof (uint8_t) * 4); } } } } sceneDefaultTexture = bgfx::createTexture2D(grid_size, grid_size, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_NONE, bgfx::copy (texture_data, grid_size * grid_size * 4)); delete[] texture_data; // sceneDefaultTexture = bgfxutils::loadTexture("fieldstone-rgba.dds"); u_time = bgfx::createUniform("u_time", bgfx::UniformType::Vec4); u_color = bgfx::createUniform("u_color", bgfx::UniformType::Vec4); u_line_params = bgfx::createUniform("u_line_params", bgfx::UniformType::Vec4); m_timeOffset = bx::getHPCounter(); // Initialize light gLog ("Creating light uniforms..."); lights[0].u_shadowMap = bgfx::createUniform("u_shadowMap", bgfx::UniformType::Int1); lights[0].u_shadowMapParams = bgfx::createUniform("u_shadowMapParams", bgfx::UniformType::Vec4); lights[0].u_lightPos = bgfx::createUniform("u_lightPos", bgfx::UniformType::Vec4); lights[0].u_lightMtx = bgfx::createUniform("u_lightMtx", bgfx::UniformType::Int1); // Setup the light probe pass IBL::uniforms.init(); IBL::uniforms.m_glossiness = IBL::settings.m_glossiness; IBL::uniforms.m_reflectivity = IBL::settings.m_reflectivity; IBL::uniforms.m_exposure = IBL::settings.m_exposure; IBL::uniforms.m_bgType = IBL::settings.m_bgType; IBL::uniforms.m_metalOrSpec = float(IBL::settings.m_metalOrSpec); IBL::uniforms.m_doDiffuse = float(IBL::settings.m_doDiffuse); IBL::uniforms.m_doSpecular = float(IBL::settings.m_doSpecular); IBL::uniforms.m_doDiffuseIbl = float(IBL::settings.m_doDiffuseIbl); IBL::uniforms.m_doSpecularIbl = float(IBL::settings.m_doSpecularIbl); memcpy(IBL::uniforms.m_rgbDiff, IBL::settings.m_rgbDiff, 3*sizeof(float) ); memcpy(IBL::uniforms.m_rgbSpec, IBL::settings.m_rgbSpec, 3*sizeof(float) ); memcpy(IBL::uniforms.m_lightDir, IBL::settings.m_lightDir, 3*sizeof(float) ); memcpy(IBL::uniforms.m_lightCol, IBL::settings.m_lightCol, 3*sizeof(float) ); s_renderStates[RenderState::Skybox].m_program = RenderProgram("shaders/src/vs_ibl_skybox.sc", "shaders/src/fs_ibl_skybox.sc"); // Get renderer capabilities info. const bgfx::Caps* caps = bgfx::getCaps(); // Shadow samplers are supported at least partially supported if texture // compare less equal feature is supported. bool shadowSamplerSupported = 0 != (caps->supported & BGFX_CAPS_TEXTURE_COMPARE_LEQUAL); if (shadowSamplerSupported) { // Depth textures and shadow samplers are supported. s_renderStates[RenderState::ShadowMap].m_program = RenderProgram("shaders/src/vs_sms_mesh.sc", "shaders/src/fs_sms_shadow.sc"); s_renderStates[RenderState::Scene].m_program = RenderProgram("shaders/src/vs_sms_mesh.sc", "shaders/src/fs_sms_mesh.sc"); s_renderStates[RenderState::SceneTextured].m_program = RenderProgram("shaders/src/vs_sms_mesh_textured.sc", "shaders/src/fs_sms_mesh_textured.sc"); lights[0].shadowMapTexture= bgfx::createTexture2D(lights[0].shadowMapSize, lights[0].shadowMapSize, false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_COMPARE_LEQUAL); bgfx::TextureHandle fbtextures[] = { lights[0].shadowMapTexture }; lights[0].shadowMapFB = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); } else { // Depth textures and shadow samplers are not supported. Use float // depth packing into color buffer instead. s_renderStates[RenderState::ShadowMap].m_program.program = bgfxutils::loadProgram("vs_sms_shadow_pd", "fs_sms_shadow_pd"); s_renderStates[RenderState::Scene].m_program.program = bgfxutils::loadProgram("vs_sms_mesh", "fs_sms_mesh_pd"); s_renderStates[RenderState::SceneTextured].m_program.program = bgfxutils::loadProgram("vs_sms_mesh_textured", "fs_sms_mesh_pd_textured"); lights[0].shadowMapTexture = bgfx::createTexture2D(lights[0].shadowMapSize, lights[0].shadowMapSize, false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT); bgfx::TextureHandle fbtextures[] = { lights[0].shadowMapTexture, bgfx::createTexture2D(lights[0].shadowMapSize, lights[0].shadowMapSize, false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY), }; lights[0].shadowMapFB = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); } s_renderStates[RenderState::Lines].m_program = RenderProgram("shaders/lines/vs_lines.sc", "shaders/lines/fs_lines.sc"); s_renderStates[RenderState::LinesOccluded].m_program = RenderProgram("shaders/lines/vs_lines.sc", "shaders/lines/fs_lines_occluded.sc"); s_renderStates[RenderState::Debug].m_program = RenderProgram("shaders/src/vs_debug.sc", "shaders/src/fs_debug.sc"); } void Renderer::setupRenderPasses() { // ShadowMap s_renderStates[RenderState::ShadowMap].m_viewId = RenderState::ShadowMap; // Scene s_renderStates[RenderState::Scene].m_viewId = RenderState::Scene; s_renderStates[RenderState::Scene].m_numTextures = 1; // Scene: shadow map texture s_renderStates[RenderState::Scene].m_textures[0].m_flags = UINT32_MAX; s_renderStates[RenderState::Scene].m_textures[0].m_stage = 0; s_renderStates[RenderState::Scene].m_textures[0].m_sampler = lights[0].u_shadowMap; s_renderStates[RenderState::Scene].m_textures[0].m_texture = lights[0].shadowMapTexture; // Scene: default texture s_renderStates[RenderState::SceneTextured].m_viewId = RenderState::SceneTextured; s_renderStates[RenderState::SceneTextured].m_numTextures = 2; s_renderStates[RenderState::SceneTextured].m_textures[0].m_flags = UINT32_MAX; s_renderStates[RenderState::SceneTextured].m_textures[0].m_stage = 0; s_renderStates[RenderState::SceneTextured].m_textures[0].m_sampler = lights[0].u_shadowMap; s_renderStates[RenderState::SceneTextured].m_textures[0].m_texture = lights[0].shadowMapTexture; s_renderStates[RenderState::SceneTextured].m_textures[1].m_flags = UINT32_MAX; s_renderStates[RenderState::SceneTextured].m_textures[1].m_stage = 1; s_renderStates[RenderState::SceneTextured].m_textures[1].m_sampler = sceneDefaultTextureSampler; s_renderStates[RenderState::SceneTextured].m_textures[1].m_texture = sceneDefaultTexture; // Lines s_renderStates[RenderState::Lines].m_viewId = RenderState::Lines; // Lines s_renderStates[RenderState::LinesOccluded].m_viewId = RenderState::LinesOccluded; // Debug s_renderStates[RenderState::Debug].m_viewId = RenderState::Debug; } // void Renderer::setupWindowX11 (Display* x11_display, int x11_window_id) { // bgfx::x11SetDisplayWindow(x11_display, x11_window_id); // } class BGFXCallbacks: public bgfx::CallbackI { virtual void fatal (bgfx::Fatal::Enum _code, const char *_str) { std::cerr << "Fatal (" << _code << "): " << _str << std::endl; } virtual void traceVargs (const char *_filePath, uint16_t _line, const char* _format, va_list _argList) { char output_buffer[255]; vsprintf (output_buffer, _format, _argList); std::cerr << "Trace " << _filePath << ":" << _line << " : " << output_buffer; } virtual uint32_t cacheReadSize(uint64_t _id) { return 0; } virtual bool cacheRead(uint64_t _id, void *_data, uint32_t _size) { return false; } virtual void cacheWrite(uint64_t _id, const void *_data, uint32_t _size) { } virtual void screenShot(const char *_filePath, uint32_t _width, uint32_t _height, uint32_t _pitch, const void *_data, uint32_t _size, bool _yflip) { } virtual void captureBegin(uint32_t _width, uint32_t _height, uint32_t _pitch, bgfx::TextureFormat::Enum _format, bool _yflip) { } virtual void captureEnd() { }; virtual void captureFrame(const void *_data, uint32_t _size) { }; }; namespace bgfx { inline void glfwSetWindow(GLFWwindow* _window) { bgfx::PlatformData pd; # if BX_PLATFORM_LINUX || BX_PLATFORM_BSD pd.ndt = glfwGetX11Display(); pd.nwh = (void*)(uintptr_t)glfwGetGLXWindow(_window); pd.context = glfwGetGLXContext(_window); # elif BX_PLATFORM_OSX pd.ndt = NULL; pd.nwh = glfwGetCocoaWindow(_window); pd.context = glfwGetNSGLContext(_window); # elif BX_PLATFORM_WINDOWS pd.ndt = NULL; pd.nwh = glfwGetWin32Window(_window); pd.context = NULL; # endif // BX_PLATFORM_WINDOWS pd.backBuffer = NULL; pd.backBufferDS = NULL; bgfx::setPlatformData(pd); } } void Renderer::initialize(int width, int height) { this->width = width; this->height = height; uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = BGFX_RESET_VSYNC; reset = BGFX_RESET_VSYNC | BGFX_RESET_MAXANISOTROPY | BGFX_RESET_MSAA_X16; bgfx::reset(width, height, reset); bgfx::setViewClear(0 , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH , 0x303030ff , 1.0f , 0 ); bgfx::setViewRect(0, 0, 0, width, height); bgfx::RendererType::Enum renderer = bgfx::getRendererType(); flipV = false || renderer == bgfx::RendererType::OpenGL || renderer == bgfx::RendererType::OpenGLES ; bgfx::setDebug(debug); gLog ("Creating Cameras"); cameras.push_back (Camera()); activeCameraIndex = 0; lights.push_back (Light()); createGeometries(); setupShaders(); setupRenderPasses(); mLightProbes[LightProbe::Bolonga].load("bolonga"); mLightProbes[LightProbe::Kyoto ].load("kyoto"); mCurrentLightProbe = LightProbe::Bolonga; initialized = true; resize (width, height); bgfx::frame(); } void Renderer::shutdown() { bgfx::destroyIndexBuffer(cube_ibh); bgfx::destroyIndexBuffer(cube_edges_ibh); bgfx::destroyVertexBuffer(cube_vbh); bgfx::destroyIndexBuffer(plane_ibh); bgfx::destroyVertexBuffer(plane_vbh); bgfx::destroyUniform(u_camPos); bgfx::destroyUniform(u_flags); bgfx::destroyUniform(u_mtx); IBL::uniforms.destroy(); bgfx::destroyUniform(s_texCube); bgfx::destroyUniform(s_texCubeIrr); bgfx::destroyUniform(u_time); bgfx::destroyUniform(u_color); bgfx::destroyUniform(u_line_params); for (uint8_t ii = 0; ii < RenderState::Count; ++ii) { if (bgfx::isValid(s_renderStates[ii].m_program.program)) { bgfx::destroyProgram(s_renderStates[ii].m_program.program); } } for (uint8_t ii = 0; ii < LightProbe::Count; ++ii) { mLightProbes[ii].destroy(); } for (size_t i = 0; i < entities.size(); i++) { delete entities[i]; entities[i] = NULL; } for (size_t i = 0; i < meshes.size(); i++) { bgfxutils::meshUnload(meshes[i]); meshes[i] = NULL; } for (size_t i = 0; i < lights.size(); i++) { gLog ("Destroying light uniforms for light %d", i); bgfx::destroyFrameBuffer(lights[i].shadowMapFB); bgfx::destroyUniform(lights[i].u_shadowMap); bgfx::destroyUniform(lights[i].u_shadowMapParams); bgfx::destroyUniform(lights[i].u_lightPos); bgfx::destroyUniform(lights[i].u_lightMtx); } lights.clear(); cameras.clear(); } void Renderer::resize (int width, int height) { if (initialized) { bgfx::reset (width, height); this->width = width; this->height = height; for (uint32_t i = 0; i < cameras.size(); i++) { cameras[i].width = static_cast(width); cameras[i].height = static_cast(height); } } } void Renderer::paintGLSimple() { // Set view 0 default viewport. bgfx::setViewRect(0, 0, 0, width, height); // This dummy draw call is here to make sure that view 0 is cleared // if no other draw calls are submitted to view 0. bgfx::touch(0); int64_t now = bx::getHPCounter(); static int64_t last = now; const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); const double toMs = 1000.0/freq; // Use debug font to print information about this example. bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/00-helloworld"); bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Initialization and debug text."); bgfx::dbgTextPrintf(0, 3, 0x8f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); bgfx::dbgTextClear(); } void Renderer::paintGL() { int64_t now = bx::getHPCounter(); static int64_t last = now; const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); const double toMs = 1000.0/freq; float time = (float)( (now-m_timeOffset)/double(bx::getHPFrequency() ) ); bgfx::setUniform (u_time, &time); // Use debug font to print information about this example. bgfx::dbgTextClear(); // debug font is 8 pixels wide int num_chars = width / 8; bgfx::dbgTextPrintf(num_chars - 18, 0, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); // This dummy draw call is here to make sure that view 0 is cleared // if no other draw calls are submitted to view 0. bgfx::touch(0); // update camera matrices for (uint32_t i = 0; i < cameras.size(); i++) { cameras[i].updateMatrices(); } // lights: update view and projection matrices and shadow map parameters for (uint32_t i = 0; i < lights.size(); i++) { bgfx::setUniform(lights[i].u_lightPos, lights[i].pos); float shadow_map_params[4]; shadow_map_params[0] = static_cast(lights[i].shadowMapSize); shadow_map_params[1] = lights[0].shadowMapBias; shadow_map_params[2] = 0.f; shadow_map_params[3] = 0.f; bgfx::setUniform(lights[i].u_shadowMapParams, &shadow_map_params); float eye[3]; eye[0] = lights[i].pos[0]; eye[1] = lights[i].pos[1]; eye[2] = lights[i].pos[2]; float at[3]; at[0] = - lights[i].pos[0] + lights[i].dir[0]; at[1] = - lights[i].pos[1] + lights[i].dir[1]; at[2] = - lights[i].pos[2] + lights[i].dir[2]; bx::mtxLookAtRh(lights[i].mtxView, eye, at); lights[i].area = 10.0f; lights[i].near = 10.f; lights[i].far = 20.f; // bx::mtxProj(lightProj, 20.0f, 1., 5.f, 10.0f); bx::mtxOrthoRh(lights[i].mtxProj, lights[i].area, -lights[i].area, lights[i].area, -lights[i].area, lights[i].near, lights[i].far); // lights: shadow matrix const float sy = flipV ? 0.5f : -0.5f; const float mtxCrop[16] = { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, sy, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, }; float mtxTmp[16]; bx::mtxMul(mtxTmp, lights[i].mtxProj, mtxCrop); bx::mtxMul(lights[i].mtxShadow, lights[i].mtxView, mtxTmp); } // setup render passes float view[16]; float proj[16]; bx::mtxIdentity(view); bx::mtxOrthoRh(proj, 0.f, 1.f, 1.f, 0.f, 0.f, 100.0f); bgfx::setViewRect(RenderState::Skybox, 0, 0, width, height); bgfx::setViewTransform(RenderState::Skybox, view, proj); bgfx::setViewRect(RenderState::ShadowMap, 0, 0, lights[0].shadowMapSize, lights[0].shadowMapSize); bgfx::setViewFrameBuffer(RenderState::ShadowMap, lights[0].shadowMapFB); bgfx::setViewTransform(RenderState::ShadowMap, lights[0].mtxView, lights[0].mtxProj); bgfx::setViewRect(RenderState::Scene, 0, 0, width, height); bgfx::setViewTransform(RenderState::Scene, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); bgfx::setViewRect(RenderState::SceneTextured, 0, 0, width, height); bgfx::setViewTransform(RenderState::SceneTextured, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); bgfx::setViewRect(RenderState::Lines, 0, 0, width, height); bgfx::setViewTransform(RenderState::Lines, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); bgfx::setViewRect(RenderState::LinesOccluded, 0, 0, width, height); bgfx::setViewTransform(RenderState::LinesOccluded, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); bgfx::setViewRect(RenderState::Debug, 0, 0, width, height); bgfx::setViewTransform(RenderState::Debug, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); // // Pass: floor // // setup floor float mtxFloor[16]; bx::mtxSRT(mtxFloor , 10.0f, 10.0f, 10.0f , 0.0f, 0.0f, 0.0f , 0.0f, -0.009f, 0.0f ); float lightMtx[16]; // Floor. bx::mtxMul(lightMtx, mtxFloor, lights[0].mtxShadow); bgfx::setUniform(lights[0].u_lightMtx, lightMtx); bgfx::setUniform(lights[0].u_lightPos, lights[0].pos); // Clear backbuffer and shadowmap framebuffer at beginning. bgfx::setViewClear(RenderState::Skybox , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH , 0x000000ff, 1.0f, 0 ); bgfx::setViewClear(RenderState::ShadowMap , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH , 0x303030ff, 1.0f, 0 ); // bgfx::setViewClear(RenderState::Scene // , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH // , 0x303030ff, 1.0f, 0 // ); bgfx::touch(RenderState::Scene); bgfx::touch(RenderState::Skybox); // // Pass: skybox // if (drawSkybox) { // Skybox pass memcpy (IBL::uniforms.m_cameraPos, cameras[activeCameraIndex].eye.data(), 3 * sizeof(float)); const float amount = bx::fmin(0.012/0.12f, 1.0f); IBL::settings.m_envRotCurr = bx::flerp(IBL::settings.m_envRotCurr, IBL::settings.m_envRotDest, amount); float mtxEnvRot[16]; float env_rot_cur = 0.0f; float mtx_u_mtx[16]; bx::mtxRotateY(mtxEnvRot, env_rot_cur); bx::mtxMul(IBL::uniforms.m_mtx, cameras[activeCameraIndex].mtxEnv, mtxEnvRot); // Used for Skybox. bgfx::setTexture(0, s_texCube, mLightProbes[mCurrentLightProbe].m_tex); bgfx::setTexture(1, s_texCubeIrr, mLightProbes[mCurrentLightProbe].m_texIrr); bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE); screenSpaceQuad( (float)cameras[activeCameraIndex].width, (float)cameras[activeCameraIndex].height, true); IBL::uniforms.submit(); bgfx::submit(RenderState::Skybox, s_renderStates[RenderState::Skybox].m_program.program); } if (drawFloor) { // render the plane uint32_t cached = bgfx::setTransform(mtxFloor); for (uint32_t pass = 0; pass < RenderState::Count; ++pass) { // Only draw plane textured or during the shadow map passes if (pass != RenderState::SceneTextured && pass != RenderState::ShadowMap) continue; const RenderState& st = s_renderStates[pass]; if (!isValid(st.m_program.program)) { continue; } bgfx::setTransform(cached); for (uint8_t tex = 0; tex < st.m_numTextures; ++tex) { const RenderState::Texture& texture = st.m_textures[tex]; bgfx::setTexture(texture.m_stage , texture.m_sampler , texture.m_texture , texture.m_flags ); } bgfx::setUniform(lights[0].u_lightMtx, lightMtx); bgfx::setUniform(lights[0].u_lightPos, lights[0].pos); bgfx::setUniform(u_color, Vector4f(1.f, 1.f, 1.f, 1.f).data(), 4); bgfx::setIndexBuffer(plane_ibh); bgfx::setVertexBuffer(plane_vbh); bgfx::setState(st.m_state); bgfx::submit(st.m_viewId, st.m_program.program); } } // // Pass: shadow map and scene pass // // render entities for (size_t i = 0; i < entities.size(); i++) { float mtxLightViewProjInv[16]; float light_pos_world[3]; // shadow map pass for (uint32_t j = 0; j < entities[i]->mesh.meshes.size(); ++j) { bx::mtxMul( lightMtx, entities[i]->mesh.meshMatrices[j].data(), lights[0].mtxShadow ); bgfx::setUniform(lights[0].u_lightMtx, lightMtx); bgfxutils::meshSubmit ( entities[i]->mesh.meshes[j], &s_renderStates[RenderState::ShadowMap], 1, entities[i]->mesh.meshMatrices[j].data() ); } // scene pass for (uint32_t j = 0; j < entities[i]->mesh.meshes.size(); ++j) { bx::mtxMul( lightMtx, entities[i]->mesh.meshMatrices[j].data(), lights[0].mtxShadow ); // compute world position of the light Vector4f light_pos = entities[i]->mesh.meshMatrices[j] * SimpleMath::Map(lights[0].pos, 4, 1); bgfx::setUniform(lights[0].u_lightPos, light_pos.data()); bgfx::setUniform(lights[0].u_lightMtx, lightMtx); bgfx::setUniform(u_color, entities[i]->color); bgfxutils::meshSubmit ( entities[i]->mesh.meshes[j], &s_renderStates[RenderState::Scene], 1, entities[i]->mesh.meshMatrices[j].data() ); } } // render debug information if (drawDebug) { float tmp[16]; // render light frustums for (uint32_t i = 0; i < lights.size(); i++) { bx::mtxMul (tmp, lights[i].mtxView, lights[i].mtxProj); float mtxLightViewProjInv[16]; bx::mtxInverse (mtxLightViewProjInv, tmp); bgfx::setUniform(u_color, Vector4f(1.f, 1.f, 0.3f, 1.0f).data(), 4); const RenderState& st = s_renderStates[RenderState::Debug]; bgfx::setTransform(mtxLightViewProjInv); bgfx::setIndexBuffer(cube_edges_ibh); bgfx::setVertexBuffer(cube_vbh); bgfx::setState(st.m_state); bgfx::submit(st.m_viewId, st.m_program.program); } // render camera frustums for (uint32_t i = 0; i < cameras.size(); i++) { bx::mtxMul (tmp, cameras[i].mtxView, cameras[i].mtxProj); float mtxCameraViewProjInv[16]; bx::mtxInverse (mtxCameraViewProjInv, tmp); bgfx::setUniform(u_color, Vector4f(0.5f, 0.5f, 0.8f, 1.f).data(), 4); const RenderState& st = s_renderStates[RenderState::Debug]; bgfx::setTransform(mtxCameraViewProjInv); bgfx::setIndexBuffer(cube_edges_ibh); bgfx::setVertexBuffer(cube_vbh); bgfx::setState(st.m_state); bgfx::submit(st.m_viewId, st.m_program.program); } // debug commands bgfx::setUniform(u_color, Vector4f(1.0f, 1.0f, 1.0f, 1.f).data(), 4); // assemble lines for alls debug lines debugPaths.resize(debugCommands.size()); for (uint32_t i = 0; i < debugCommands.size(); i++) { Path &line = debugPaths[i]; if (debugCommands[i].type == DebugCommand::Line) { line.points.clear(); line.colors.clear(); line.points.push_back(debugCommands[i].from); line.colors.push_back(debugCommands[i].color); line.points.push_back(debugCommands[i].to); line.colors.push_back(debugCommands[i].color); line.UpdateBuffers(); } else if (debugCommands[i].type == DebugCommand::Circle) { line.points.clear(); line.colors.clear(); float radius = debugCommands[i].radius; float c,s,angle; // construct an orthogonal vector from the normal. Vector3f plane1 ( debugCommands[i].to[1] - debugCommands[i].to[2], debugCommands[i].to[0], -debugCommands[i].to[0] ); plane1.normalize(); Vector3f plane2 = debugCommands[i].to.cross(plane1); const int cNumSegments = 64; for (uint32_t j = 0; j < cNumSegments; j++) { angle = M_PI * 0.5f + 2. * M_PI * static_cast(j) / static_cast(cNumSegments - 1); s = sin(angle) * radius; c = cos(angle) * radius; line.points.push_back(debugCommands[i].from + plane1 * s + plane2 * c); line.colors.push_back(debugCommands[i].color); } line.UpdateBuffers(); } float thickness = 0.05143f; float miter = 0.0f; float aspect = static_cast(width) / height; Vector4f params (thickness, miter, aspect, 0.0f); // submit data to regular lines state const RenderState& st = s_renderStates[RenderState::Lines]; bgfx::setUniform(u_line_params, params.data(), 1); bgfx::setIndexBuffer(line.mIndexBufferHandle); bgfx::setVertexBuffer(line.mVertexBufferHandle); bgfx::setState(st.m_state); bgfx::submit(st.m_viewId, st.m_program.program); // submit data to state LinesOccluded bgfx::setState(s_renderStates[RenderState::LinesOccluded].m_state); bgfx::setUniform(u_line_params, params.data(), 1); bgfx::setIndexBuffer(line.mIndexBufferHandle); bgfx::setVertexBuffer(line.mVertexBufferHandle); bgfx::submit( s_renderStates[RenderState::LinesOccluded].m_viewId, s_renderStates[RenderState::LinesOccluded].m_program.program ); } } // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); ImGui::SetNextWindowSize (ImVec2(400.f, 300.0f), ImGuiSetCond_Once); ImGui::SetNextWindowPos (ImVec2(10.f, 300.0f), ImGuiSetCond_Once); ImGui::Begin("Render Settings"); if(ImGui::DragFloat3 ("Light0 Pos", lights[0].pos, 1.0f, -10.0f, 10.0f)) { } if(ImGui::DragFloat3 ("Light0 Dir", lights[0].dir, 1.0f, -10.0f, 10.0f)) { } float light_at[3]; light_at[0] = lights[0].dir[0] - lights[0].pos[0]; light_at[1] = lights[0].dir[1] - lights[0].pos[1]; light_at[2] = lights[0].dir[2] - lights[0].pos[2]; if(ImGui::DragFloat3 ("Light0 At", light_at, 1.0f, -10.0f, 10.0f)) { lights[0].dir[0] = lights[0].pos[0]- light_at[0]; lights[0].dir[1] = lights[0].pos[1]- light_at[1]; lights[0].dir[2] = lights[0].pos[2]- light_at[2]; } assert (lights.size() == 1); ImGui::Checkbox("Draw Floor", &drawFloor); ImGui::Checkbox("Draw Skybox", &drawSkybox); ImGui::Checkbox("Draw Debug", &drawDebug); for (int i = 0; i < lights.size(); i++) { ImGui::SliderFloat("Bias", &lights[i].shadowMapBias, 0.0001f, 0.10f ); } ImGui::End(); // clear debug commands as they have to be issued every frame debugCommands.clear(); } bool Renderer::updateShaders() { bool result = true; for (int i = 0; i < RenderState::Count; i++) { RenderState& st = s_renderStates[i]; if (st.m_program.vertexShaderFileName != "" && st.m_program.fragmentShaderFileName!= "" ) { if (st.m_program.checkModified()) { bool load_success = st.m_program.reload(); // if so far everything was successful but this one failed // make sure to set the return value to false if (result == true && ! load_success) result = false; } } } return true; } Entity* Renderer::createEntity() { Entity* result = new Entity(); entities.push_back(result); return result; } bool Renderer::destroyEntity(Entity* entity) { int i = 0; for (i = 0; i < entities.size(); i++) { if (entities[i] == entity) { break; } } if (i != entities.size()) { delete entity; entities.erase(entities.begin() + i); return true; } return false; } bgfxutils::Mesh* Renderer::loadMesh(const char* filename) { MeshIdMap::iterator mesh_iter = meshIdMap.find (filename); bgfxutils::Mesh* result = NULL; if (mesh_iter == meshIdMap.end()) { std::string filename_str (filename); if (filename_str.substr(filename_str.size() - 4, 4) == ".obj") { std::vector shapes; std::vector materials; std::string err; bool result = tinyobj::LoadObj(shapes, materials, err, filename); if (!result) { std::cerr << "Error loading '" << filename << "': " << err << std::endl; exit(-1); } // result = bgfxutils::createMeshFromVBO (vbo); } else { result = bgfxutils::meshLoad(filename); } meshes.push_back (result); meshIdMap[filename] = meshes.size() - 1; } else { result = meshes[mesh_iter->second]; } return result; } // debug commands void Renderer::drawDebugLine ( const Vector3f &from, const Vector3f &to, const Vector3f &color) { DebugCommand cmd; cmd.type = DebugCommand::Line; cmd.from = from; cmd.to = to; cmd.color = Vector4f (color[0], color[1], color[2], 1.0f); debugCommands.push_back(cmd); } void Renderer::drawDebugAxes ( const Vector3f &pos, const Matrix33f &orientation, const float &scale) { drawDebugLine (pos, pos + Vector3f (orientation.block<3,1>(0,0)) * scale, Vector3f (1.f, 0.f, 0.f)); drawDebugLine (pos, pos + Vector3f (orientation.block<3,1>(0,1)) * scale, Vector3f (0.f, 1.f, 0.f)); drawDebugLine (pos, pos + Vector3f (orientation.block<3,1>(0,2)) * scale, Vector3f (0.f, 0.f, 1.f)); } void Renderer::drawDebugCircle ( const Vector3f &pos, const Vector3f &normal, const float radius, const Vector4f &color) { DebugCommand cmd; cmd.type = DebugCommand::Circle; cmd.from = pos; cmd.to = normal; cmd.color = color; cmd.radius = radius; debugCommands.push_back(cmd); } void Renderer::drawDebugSphere ( const Vector3f &pos, float radius, const Vector4f &color) { drawDebugCircle ( pos, Vector3f (1.0f, 0.0f, 0.0f), radius, color); drawDebugCircle ( pos, Vector3f (0.0f, 1.0f, 0.0f), radius, color); drawDebugCircle ( pos, Vector3f (0.0f, 0.0f, 1.0f), radius, color); }