From 2b99174d346135750b74c0be1c0414fa936691aa Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Fri, 23 Sep 2016 09:06:46 +0200 Subject: [PATCH] Moved renderer to separate module, moved modules to src/modules --- CMakeLists.txt | 7 +- src/RuntimeModuleManager.cc | 5 +- src/main.cc | 47 +- src/modules/CMakeLists.txt | 12 + src/modules/RenderModule.cc | 933 +++++++++++++++++++++++++++++++ src/modules/RenderModule.h | 218 ++++++++ src/{ => modules}/RenderUtils.cc | 0 src/{ => modules}/RenderUtils.h | 0 src/{ => modules}/TestModule.cc | 5 +- 9 files changed, 1190 insertions(+), 37 deletions(-) create mode 100644 src/modules/CMakeLists.txt create mode 100644 src/modules/RenderModule.cc create mode 100644 src/modules/RenderModule.h rename src/{ => modules}/RenderUtils.cc (100%) rename src/{ => modules}/RenderUtils.h (100%) rename src/{ => modules}/TestModule.cc (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0342af1..8ac0958 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,13 +54,12 @@ INCLUDE_DIRECTORIES ( SUBDIRS ( # tests/ + src/modules 3rdparty/glfw 3rdparty/bgfx ) SET ( protot_SRCS - src/Renderer.cc - src/RenderUtils.cc src/shaderc_compile.cpp src/shaderc_glsl.cpp src/shaderc_hlsl.cpp @@ -90,10 +89,6 @@ file(GLOB glcpp-library_sources list(REMOVE_ITEM glcpp-library_sources ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/bgfx/3rdparty/glsl-optimizer/src/glsl/main.cpp) -ADD_LIBRARY (TestModule SHARED - src/TestModule.cc - ) - ADD_LIBRARY (glsl-optimizer ${glcpp-library_sources} diff --git a/src/RuntimeModuleManager.cc b/src/RuntimeModuleManager.cc index 3c79f5a..b81e870 100644 --- a/src/RuntimeModuleManager.cc +++ b/src/RuntimeModuleManager.cc @@ -11,7 +11,7 @@ #include struct RuntimeModule { - std::string name =""; + std::string name = ""; void *handle = nullptr; ino_t id = 0; void *data = nullptr; @@ -40,7 +40,6 @@ void RuntimeModuleManager::LoadModule(RuntimeModule* module) { if (handle) { module->handle = handle; module->id = attr.st_ino; - std::cerr << "Loading API symbol" << std::endl; const struct module_api *api = (module_api*) dlsym(module->handle, "MODULE_API"); if (api != NULL) { module->api = *api; @@ -48,7 +47,7 @@ void RuntimeModuleManager::LoadModule(RuntimeModule* module) { std::cerr << "Initializing module" << std::endl; module->state = module->api.init(); } - std::cerr << "Reloading module" << std::endl; + std::cerr << "Reloading module " << module->name << std::endl; module->api.reload(module->state); } else { dlclose(module->handle); diff --git a/src/main.cc b/src/main.cc index d6e1fb9..291d38d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -12,8 +12,9 @@ #include "bgfx/bgfxplatform.h" #include "bx/timer.h" -#include "Renderer.h" #include "RuntimeModuleManager.h" +#include "imgui/imgui.h" + #include "Globals.h" Renderer* gRenderer = nullptr; @@ -57,7 +58,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, int main(void) { - // TODO GLFW error checking + // Initialize GLFW glfwSetErrorCallback(error_callback); glfwInit(); @@ -71,17 +72,26 @@ int main(void) int width, height; glfwGetWindowSize(gWindow, &width, &height); - Renderer renderer; + // Initialize Renderer bgfx::glfwSetWindow(gWindow); bgfx::renderFrame(); - renderer.initialize(width, height); + uint32_t debug = BGFX_DEBUG_TEXT; + uint32_t reset = BGFX_RESET_VSYNC; + + bool result = bgfx::init(); + if (!result) { + std::cerr << "Error: could not initialize renderer!" << std::endl; + exit (EXIT_FAILURE); + } + + // imgui initialization. + imguiCreate(); - gRenderer = &renderer; - printf("Initializing ModuleManager...\n"); RuntimeModuleManager module_manager; - module_manager.RegisterModule("libTestModule.so"); + module_manager.RegisterModule("src/modules/libTestModule.so"); + module_manager.RegisterModule("src/modules/libRenderModule.so"); printf("Starting main loop...\n"); glfwSetKeyCallback(gWindow, key_callback); @@ -97,36 +107,19 @@ int main(void) float time = (float)( (now-time_offset)/double(bx::getHPFrequency() ) ); - int width, height; - glfwGetWindowSize(gWindow, &width, &height); - if (width != renderer.width || height != renderer.height) { - renderer.resize(width, height); - } - module_manager.Update((float)(frameTime / freq)); - renderer.paintGL(); - glfwPollEvents(); - // send inputs to the input state of the renderer - double mouse_x, mouse_y; - glfwGetCursorPos(gWindow, &mouse_x, &mouse_y); - renderer.inputState.mousedX = mouse_x - renderer.inputState.mouseX; - renderer.inputState.mousedY = mouse_y - renderer.inputState.mouseY; - renderer.inputState.mouseX = mouse_x; - renderer.inputState.mouseY = mouse_y; - renderer.inputState.mouseButton = - glfwGetMouseButton(gWindow, 0) - + (glfwGetMouseButton(gWindow, 1) << 1) - + (glfwGetMouseButton(gWindow, 2) << 2); - usleep(16000); } module_manager.UnloadModules(); gRenderer = nullptr; + + imguiDestroy(); + bgfx::shutdown(); } //! [code] diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt new file mode 100644 index 0000000..2c5e24a --- /dev/null +++ b/src/modules/CMakeLists.txt @@ -0,0 +1,12 @@ +INCLUDE_DIRECTORIES ( + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +ADD_LIBRARY (RenderModule SHARED + RenderModule.cc + RenderUtils.cc + ) + +ADD_LIBRARY (TestModule SHARED + TestModule.cc + ) diff --git a/src/modules/RenderModule.cc b/src/modules/RenderModule.cc new file mode 100644 index 0000000..79b00d1 --- /dev/null +++ b/src/modules/RenderModule.cc @@ -0,0 +1,933 @@ +#include "RuntimeModule.h" +#include "Globals.h" +#include "RenderModule.h" +#include "3rdparty/ocornut-imgui/imgui.h" +#include "imgui/imgui.h" +#include +#include "SimpleMath/SimpleMath.h" +#include "SimpleMath/SimpleMathMap.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +#include "math_types.h" + +#include +#include +#include + +typedef SimpleMath::Matrix44f Matrix44f; +typedef SimpleMath::Vector4f Vector4f; +typedef SimpleMath::Matrix33f Matrix33f; +typedef SimpleMath::Vector3f Vector3f; +typedef SimpleMath::MatrixNNf MatrixNNf; +typedef SimpleMath::VectorNf VectorNf; + +struct Renderer; + +struct module_state { + Renderer *renderer; +}; + +static struct module_state *module_init() { + std::cout << "RenderModule init called" << std::endl; + 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; +} + +static void module_finalize(struct module_state *state) { + std::cout << "RenderModule finalize called" << std::endl; + + assert (state->renderer != nullptr); + delete state->renderer; + + free(state); +} + +static void module_reload(struct module_state *state) { + std::cout << "RenderModule reload called" << std::endl; + assert (gWindow != nullptr); + int width, height; + glfwGetWindowSize(gWindow, &width, &height); + + assert (state != nullptr); + state->renderer->initialize(width, height); + gRenderer = state->renderer; +} + +static void module_unload(struct module_state *state) { + gRenderer = nullptr; + state->renderer->shutdown(); + std::cout << "RenderModule unload called" << std::endl; +} + +static bool module_step(struct module_state *state) { + 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->resize (width, height); + + + double mouse_x, mouse_y; + glfwGetCursorPos(gWindow, &mouse_x, &mouse_y); + state->renderer->inputState.mousedX = mouse_x - state->renderer->inputState.mouseX; + state->renderer->inputState.mousedY = mouse_y - state->renderer->inputState.mouseY; + state->renderer->inputState.mouseX = mouse_x; + state->renderer->inputState.mouseY = mouse_y; + state->renderer->inputState.mouseButton = + glfwGetMouseButton(gWindow, 0) + + (glfwGetMouseButton(gWindow, 1) << 1) + + (glfwGetMouseButton(gWindow, 2) << 2); + + + 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 +}; +} + +// 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; +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 states +// + +RenderState s_renderStates[RenderState::Count] = { + { // ShadowMap + 0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + | BGFX_STATE_DEPTH_WRITE + | BGFX_STATE_DEPTH_TEST_LESS + | BGFX_STATE_CULL_CCW + | BGFX_STATE_MSAA, + 0, + UINT16_MAX, + RenderState::ShadowMap + }, + { // Scene + 0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + | BGFX_STATE_DEPTH_WRITE + | BGFX_STATE_DEPTH_TEST_LESS + | BGFX_STATE_CULL_CCW + | BGFX_STATE_MSAA, + 0, + UINT16_MAX, + RenderState::Scene + }, + { // SceneTextured + 0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + | BGFX_STATE_DEPTH_WRITE + | BGFX_STATE_DEPTH_TEST_LESS + | BGFX_STATE_CULL_CCW + | BGFX_STATE_MSAA, + 0, + UINT16_MAX, + RenderState::SceneTextured + }, + { // 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_MSAA, + 0, + UINT16_MAX, + 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; + +// +// 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; + +void Camera::updateMatrices() { + assert (width != -1.f && height != -1.f); + float aspect = width / height; + + bx::mtxLookAt (mtxView, eye, poi, up); + + if (orthographic) { + bx::mtxOrtho(mtxProj, + -width * 0.5f, width * 0.5f, + -height * 0.5f, height * 0.5f, + near, far); + } else { + bx::mtxProj(mtxProj, fov, aspect, near, far); + } +} + +void Renderer::createGeometries() { + // Create vertex stream declaration. + PosColorVertex::init(); + PosNormalVertex::init(); + PosNormalColorTexcoordVertex::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) ) + ); +} + +void Renderer::setupShaders() { + // Create uniforms + sceneDefaultTextureSampler = bgfx::createUniform("sceneDefaultTexture", bgfx::UniformType::Int1); + + int grid_size = 1024; + int grid_border = 12; + uint8_t grid_color_border [4] = {255, 255, 255, 255}; + uint8_t grid_color_0[4] = {192, 192, 192, 255}; + uint8_t grid_color_1[4] = {96, 96, 96, 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); + + m_timeOffset = bx::getHPCounter(); + + // Initialize light + 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::Int1); + lights[0].u_lightMtx = bgfx::createUniform("u_lightMtx", bgfx::UniformType::Int1); + + // 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 = bgfxutils::loadProgramFromFiles("shaders/src/vs_sms_mesh.sc", "shaders/src/fs_sms_shadow.sc"); + s_renderStates[RenderState::Scene].m_program = bgfxutils::loadProgramFromFiles("shaders/src/vs_sms_mesh.sc", "shaders/src/fs_sms_mesh.sc"); + s_renderStates[RenderState::SceneTextured].m_program = bgfxutils::loadProgramFromFiles("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 = bgfxutils::loadProgram("vs_sms_shadow_pd", "fs_sms_shadow_pd"); + s_renderStates[RenderState::Scene].m_program = bgfxutils::loadProgram("vs_sms_mesh", "fs_sms_mesh_pd"); + s_renderStates[RenderState::SceneTextured].m_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::Debug].m_program = bgfxutils::loadProgramFromFiles("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; + + // 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) { + }; +}; + +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); + + cameras.push_back (Camera()); + activeCameraIndex = 0; + lights.push_back (Light()); + + // set the clear state +// for (int i = 0; i < 2; i++) { +// bgfx::setViewClear(i +// , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH +// , 0x303030ff +// , 1.0f +// , 0 +// ); +// } + + createGeometries(); + + setupShaders(); + + setupRenderPasses(); + + // Start the imgui frame such that widgets can be submitted + imguiBeginFrame (inputState.mouseX, + inputState.mouseY, + inputState.mouseButton, + inputState.mouseScroll, + width, + height); + + initialized = true; + resize (width, height); + bgfx::frame(); +} + +void Renderer::shutdown() { + bgfx::destroyFrameBuffer(lights[0].shadowMapFB); + + bgfx::destroyUniform(lights[0].u_shadowMap); + bgfx::destroyUniform(lights[0].u_shadowMapParams); + bgfx::destroyUniform(lights[0].u_lightPos); + bgfx::destroyUniform(lights[0].u_lightMtx); + + bgfx::destroyIndexBuffer(cube_ibh); + bgfx::destroyIndexBuffer(cube_edges_ibh); + bgfx::destroyVertexBuffer(cube_vbh); + bgfx::destroyIndexBuffer(plane_ibh); + bgfx::destroyVertexBuffer(plane_vbh); + + bgfx::destroyUniform(u_time); + bgfx::destroyUniform(u_color); + + 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; + } + + lights.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(); + bgfx::dbgTextPrintf(0, 0, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + + // submit the imgui widgets + imguiEndFrame(); + + // 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[0].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::mtxLookAt(lights[i].mtxView, eye, at); + + lights[i].area = 2.5f; + lights[i].near = 0.f; + lights[i].far = 5.f; + + // bx::mtxProj(lightProj, 20.0f, 1., 5.f, 10.0f); + + bx::mtxOrtho(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 + 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::Debug, 0, 0, width, height); + bgfx::setViewTransform(RenderState::Debug, cameras[activeCameraIndex].mtxView, cameras[activeCameraIndex].mtxProj); + + // setup floor + float mtxFloor[16]; + bx::mtxSRT(mtxFloor + , 10.0f, 10.0f, 10.0f + , 0.0f, 0.0f, 0.0f + , 0.0f, 0.0f, 0.0f + ); + + float lightMtx[16]; + // Floor. + bx::mtxMul(lightMtx, mtxFloor, lights[0].mtxShadow); + bgfx::setUniform(lights[0].u_lightMtx, lightMtx); + + // Clear backbuffer and shadowmap framebuffer at beginning. + 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); + + // 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]; + 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(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); + } + + // render entities + for (size_t i = 0; i < entities.size(); i++) { + // shadow map pass + bx::mtxMul(lightMtx, entities[i]->transform, lights[0].mtxShadow); + bgfx::setUniform(lights[0].u_lightMtx, lightMtx); + bgfx::setUniform(u_color, entities[i]->color, 4); + meshSubmit(entities[i]->mesh, &s_renderStates[RenderState::ShadowMap], 1, entities[i]->transform); + + // scene pass + bx::mtxMul(lightMtx, entities[i]->transform, lights[0].mtxShadow); + bgfx::setUniform(lights[0].u_lightMtx, lightMtx); + bgfx::setUniform(u_color, entities[i]->color, 4); + meshSubmit(entities[i]->mesh, &s_renderStates[RenderState::Scene], 1, entities[i]->transform); + } + + // 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); + } + + // 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); + } + } + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + + // Start the next imgui frame + imguiBeginFrame (inputState.mouseX, + inputState.mouseY, + inputState.mouseButton, + inputState.mouseScroll, + width, + height); +} + +Entity* Renderer::createEntity() { + Entity* result = new Entity(); + entities.push_back(result); + + return result; +} + +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; +} + diff --git a/src/modules/RenderModule.h b/src/modules/RenderModule.h new file mode 100644 index 0000000..30b1faa --- /dev/null +++ b/src/modules/RenderModule.h @@ -0,0 +1,218 @@ +#pragma once + +#include + +#include +#include + +#include + +#include "RenderUtils.h" + +struct Entity; + +struct InputState { + int32_t mousedX; + int32_t mousedY; + int32_t mouseX; + int32_t mouseY; + uint8_t mouseButton; + int32_t mouseScroll; + char key; + + InputState() : + mouseX(0), + mouseY(0), + mouseButton(0), + mouseScroll(0), + key(0) { + } +}; + +struct Camera { + float eye[3]; + float poi[3]; + float up[3]; + + float near; + float far; + float fov; + bool orthographic; + float width; + float height; + + float mtxProj[16]; + float mtxView[16]; + + Camera() : + eye {5.f, 4.f, 5.f}, + poi {0.f, 2.f, 0.f}, + up {0.f, 1.f, 0.f}, + near (1.f), + far (20.f), + fov (70.f), + orthographic (false), + width (-1.f), + height (-1.f), + + mtxProj { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f}, + mtxView { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f} + {} + + void updateMatrices(); +}; + +struct Light { + bgfx::UniformHandle u_shadowMap; + bgfx::UniformHandle u_shadowMapParams; + bgfx::UniformHandle u_lightPos; + bgfx::UniformHandle u_lightMtx; + + bgfx::TextureHandle shadowMapTexture; + bgfx::FrameBufferHandle shadowMapFB; + float pos[3]; + float dir[3]; + + float mtxView[16]; + float mtxProj[16]; + float mtxLight[16]; + float mtxShadow[16]; + + float shadowMapBias; + uint16_t shadowMapSize; + + bool enabled; + float near; + float far; + float area; + + Light() : + u_shadowMap (BGFX_INVALID_HANDLE), + u_lightPos (BGFX_INVALID_HANDLE), + u_lightMtx (BGFX_INVALID_HANDLE), + shadowMapTexture (BGFX_INVALID_HANDLE), + shadowMapFB (BGFX_INVALID_HANDLE), + pos {1.f, 1.f, 1.f}, + dir {-1.f, -1.f, -1.f}, + mtxView { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }, + mtxProj { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }, + mtxShadow { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }, + shadowMapBias (0.0001f), + shadowMapSize (1024), + near (-100.f), + far (100.f), + area (10.f), + enabled (false) + { + } +}; + +struct Entity { + float transform[16]; + float color[4]; + bgfxutils::Mesh* mesh; + + Entity() : + transform { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.0, 0.f, 1.f + }, + color { 1.f, 1.f, 1.f, 1.f }, + mesh (NULL) {}; +}; + +struct Renderer { + bool initialized; + bool drawDebug; + uint32_t width; + uint32_t height; + + bgfx::UniformHandle sceneDefaultTextureSampler; + bgfx::TextureHandle sceneDefaultTexture; + + std::vector meshes; + typedef std::map MeshIdMap; + MeshIdMap meshIdMap; + + std::vector entities; + + std::vector cameras; + std::vector lights; + + uint16_t activeCameraIndex; + + // needed to forward inputs to IMGUI + InputState inputState; + + Renderer() : + initialized(false), + drawDebug(false), + width (0), + height (0) + {} + + // initialize simple geometries (cube, sphere, ...) + void createGeometries(); + // create uniforms, load shaders, and create render targets + void setupShaders(); + // setup renderpasses and wire up render targets + void setupRenderPasses(); + + void initialize(int width, int height); + void shutdown(); + void paintGL(); + void paintGLSimple(); + void resize (int width, int height); + + Entity* createEntity(); + bgfxutils::Mesh* loadMesh(const char* filename); +}; + +struct RenderState { + enum { + ShadowMap, + Scene, + SceneTextured, + Debug, + Count + }; + + struct Texture { + uint32_t m_flags; + bgfx::UniformHandle m_sampler; + bgfx::TextureHandle m_texture; + uint8_t m_stage; + }; + + uint64_t m_state; + uint8_t m_numTextures; + bgfx::ProgramHandle m_program; + uint8_t m_viewId; + Texture m_textures[4]; +}; + diff --git a/src/RenderUtils.cc b/src/modules/RenderUtils.cc similarity index 100% rename from src/RenderUtils.cc rename to src/modules/RenderUtils.cc diff --git a/src/RenderUtils.h b/src/modules/RenderUtils.h similarity index 100% rename from src/RenderUtils.h rename to src/modules/RenderUtils.h diff --git a/src/TestModule.cc b/src/modules/TestModule.cc similarity index 97% rename from src/TestModule.cc rename to src/modules/TestModule.cc index d03e14e..21b59d0 100644 --- a/src/TestModule.cc +++ b/src/modules/TestModule.cc @@ -92,9 +92,12 @@ static void module_unload(struct module_state *state) { } static bool module_step(struct module_state *state) { + if (gRenderer == nullptr) + return false; + bool enabled = true; ImGui::Begin("Ddebug"); - if (ImGui::Button("Hallo Katrina")) { + if (ImGui::Button("Hallo Katrina Whaddup?")) { if (gRenderer->drawDebug) { gRenderer->drawDebug = false; } else {