diff options
Diffstat (limited to '3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp')
-rw-r--r-- | 3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp | 1877 |
1 files changed, 979 insertions, 898 deletions
diff --git a/3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp b/3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp index 5149e79e33b..d6195526d12 100644 --- a/3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp +++ b/3rdparty/bgfx/examples/14-shadowvolumes/shadowvolumes.cpp @@ -18,12 +18,20 @@ namespace stl = tinystl; #include <bx/allocator.h> #include <bx/hash.h> #include <bx/simd_t.h> -#include <bx/fpumath.h> -#include <bx/crtimpl.h> +#include <bx/math.h> +#include <bx/file.h> #include "entry/entry.h" #include "camera.h" #include "imgui/imgui.h" +namespace bgfx +{ + int32_t read(bx::ReaderI* _reader, bgfx::VertexDecl& _decl, bx::Error* _err = NULL); +} + +namespace +{ + #define SV_USE_SIMD 1 #define MAX_INSTANCE_COUNT 25 #define MAX_LIGHTS_COUNT 5 @@ -33,31 +41,6 @@ namespace stl = tinystl; #define VIEWID_RANGE15_PASS2 3 #define VIEWID_RANGE1_PASS3 20 -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); -} - struct PosNormalTexcoordVertex { float m_x; @@ -85,18 +68,18 @@ bgfx::VertexDecl PosNormalTexcoordVertex::ms_decl; static const float s_texcoord = 50.0f; static PosNormalTexcoordVertex s_hplaneVertices[] = { - { -1.0f, 0.0f, 1.0f, packF4u(0.0f, 1.0f, 0.0f), s_texcoord, s_texcoord }, - { 1.0f, 0.0f, 1.0f, packF4u(0.0f, 1.0f, 0.0f), s_texcoord, 0.0f }, - { -1.0f, 0.0f, -1.0f, packF4u(0.0f, 1.0f, 0.0f), 0.0f, s_texcoord }, - { 1.0f, 0.0f, -1.0f, packF4u(0.0f, 1.0f, 0.0f), 0.0f, 0.0f }, + { -1.0f, 0.0f, 1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f), s_texcoord, s_texcoord }, + { 1.0f, 0.0f, 1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f), s_texcoord, 0.0f }, + { -1.0f, 0.0f, -1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f), 0.0f, s_texcoord }, + { 1.0f, 0.0f, -1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f), 0.0f, 0.0f }, }; static PosNormalTexcoordVertex s_vplaneVertices[] = { - { -1.0f, 1.0f, 0.0f, packF4u(0.0f, 0.0f, -1.0f), 1.0f, 1.0f }, - { 1.0f, 1.0f, 0.0f, packF4u(0.0f, 0.0f, -1.0f), 1.0f, 0.0f }, - { -1.0f, -1.0f, 0.0f, packF4u(0.0f, 0.0f, -1.0f), 0.0f, 1.0f }, - { 1.0f, -1.0f, 0.0f, packF4u(0.0f, 0.0f, -1.0f), 0.0f, 0.0f }, + { -1.0f, 1.0f, 0.0f, encodeNormalRgba8(0.0f, 0.0f, -1.0f), 1.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f, encodeNormalRgba8(0.0f, 0.0f, -1.0f), 1.0f, 0.0f }, + { -1.0f, -1.0f, 0.0f, encodeNormalRgba8(0.0f, 0.0f, -1.0f), 0.0f, 1.0f }, + { 1.0f, -1.0f, 0.0f, encodeNormalRgba8(0.0f, 0.0f, -1.0f), 0.0f, 0.0f }, }; static const uint16_t s_planeIndices[] = @@ -278,16 +261,16 @@ struct Uniforms void destroy() { - bgfx::destroyUniform(u_params); - bgfx::destroyUniform(u_svparams); - bgfx::destroyUniform(u_ambient); - bgfx::destroyUniform(u_diffuse); - bgfx::destroyUniform(u_specular_shininess); - bgfx::destroyUniform(u_fog); - bgfx::destroyUniform(u_color); - bgfx::destroyUniform(u_lightPosRadius); - bgfx::destroyUniform(u_lightRgbInnerR); - bgfx::destroyUniform(u_virtualLightPos_extrusionDist); + bgfx::destroy(u_params); + bgfx::destroy(u_svparams); + bgfx::destroy(u_ambient); + bgfx::destroy(u_diffuse); + bgfx::destroy(u_specular_shininess); + bgfx::destroy(u_fog); + bgfx::destroy(u_color); + bgfx::destroy(u_lightPosRadius); + bgfx::destroy(u_lightRgbInnerR); + bgfx::destroy(u_virtualLightPos_extrusionDist); } struct Params @@ -541,7 +524,7 @@ static RenderState s_renderStates[RenderState::Count] = struct ViewState { - ViewState(uint32_t _width = 1280, uint32_t _height = 720) + ViewState(uint32_t _width = 0, uint32_t _height = 0) : m_width(_width) , m_height(_height) { @@ -561,7 +544,7 @@ struct ClearValues uint8_t m_clearStencil; }; -void submit(uint8_t _id, bgfx::ProgramHandle _handle, int32_t _depth = 0) +void submit(bgfx::ViewId _id, bgfx::ProgramHandle _handle, int32_t _depth = 0) { bgfx::submit(_id, _handle, _depth); @@ -569,7 +552,7 @@ void submit(uint8_t _id, bgfx::ProgramHandle _handle, int32_t _depth = 0) s_viewMask |= 1 << _id; } -void touch(uint8_t _id) +void touch(bgfx::ViewId _id) { bgfx::ProgramHandle handle = BGFX_INVALID_HANDLE; ::submit(_id, handle); @@ -765,7 +748,7 @@ uint16_t weldVertices(WeldedVertex* _output, const bgfx::VertexDecl& _decl, cons { float pos[4]; vertexUnpack(pos, bgfx::Attrib::Position, _decl, _data, ii); - uint32_t hashValue = bx::hashMurmur2A(pos, 3*sizeof(float) ) & hashMask; + uint32_t hashValue = bx::hash<bx::HashMurmur2A>(pos, 3*sizeof(float) ) & hashMask; uint16_t offset = hashTable[hashValue]; for (; UINT16_MAX != offset; offset = next[offset]) @@ -803,8 +786,8 @@ struct Group void reset() { - m_vbh.idx = bgfx::invalidHandle; - m_ibh.idx = bgfx::invalidHandle; + m_vbh.idx = bgfx::kInvalidHandle; + m_ibh.idx = bgfx::kInvalidHandle; m_numVertices = 0; m_vertices = NULL; m_numIndices = 0; @@ -945,10 +928,10 @@ struct Group void unload() { - bgfx::destroyVertexBuffer(m_vbh); - if (bgfx::invalidHandle != m_ibh.idx) + bgfx::destroy(m_vbh); + if (bgfx::kInvalidHandle != m_ibh.idx) { - bgfx::destroyIndexBuffer(m_ibh); + bgfx::destroy(m_ibh); } free(m_vertices); m_vertices = NULL; @@ -981,11 +964,6 @@ struct Group typedef std::vector<Group> GroupArray; -namespace bgfx -{ - int32_t read(bx::ReaderI* _reader, bgfx::VertexDecl& _decl, bx::Error* _err = NULL); -} - struct Mesh { void load(const void* _vertices, uint16_t _numVertices, const bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices) @@ -1133,8 +1111,8 @@ struct Model { Model() { - m_program.idx = bgfx::invalidHandle; - m_texture.idx = bgfx::invalidHandle; + m_program.idx = bgfx::kInvalidHandle; + m_texture.idx = bgfx::kInvalidHandle; } void load(const void* _vertices, uint16_t _numVertices, const bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices) @@ -1166,10 +1144,10 @@ struct Model // Set buffers bgfx::setIndexBuffer(group.m_ibh); - bgfx::setVertexBuffer(group.m_vbh); + bgfx::setVertexBuffer(0, group.m_vbh); // Set textures - if (bgfx::invalidHandle != m_texture.idx) + if (bgfx::kInvalidHandle != m_texture.idx) { bgfx::setTexture(0, s_texColor, m_texture); } @@ -1179,7 +1157,7 @@ struct Model ::setRenderState(_renderState); // Submit - BX_CHECK(bgfx::invalidHandle != m_program, "Error, program is not set."); + BX_CHECK(bgfx::kInvalidHandle != m_program, "Error, program is not set."); ::submit(_viewId, m_program); } } @@ -1683,8 +1661,8 @@ void shadowVolumeCreate(ShadowVolume& _shadowVolume // bgfx::destroy*Buffer doesn't actually destroy buffers now. // Instead, these bgfx::destroy*Buffer commands get queued to be executed after the end of the next frame. - bgfx::destroyVertexBuffer(_shadowVolume.m_vbSides); - bgfx::destroyIndexBuffer(_shadowVolume.m_ibSides); + bgfx::destroy(_shadowVolume.m_vbSides); + bgfx::destroy(_shadowVolume.m_ibSides); if (cap) { @@ -1694,7 +1672,7 @@ void shadowVolumeCreate(ShadowVolume& _shadowVolume _shadowVolume.m_ibFrontCap = bgfx::createIndexBuffer(mem); //gets destroyed after the end of the next frame - bgfx::destroyIndexBuffer(_shadowVolume.m_ibFrontCap); + bgfx::destroy(_shadowVolume.m_ibFrontCap); //back cap isize = backCapI * sizeof(uint16_t); @@ -1702,7 +1680,7 @@ void shadowVolumeCreate(ShadowVolume& _shadowVolume _shadowVolume.m_ibBackCap = bgfx::createIndexBuffer(mem); //gets destroyed after the end of the next frame - bgfx::destroyIndexBuffer(_shadowVolume.m_ibBackCap); + bgfx::destroy(_shadowVolume.m_ibBackCap); } } @@ -1844,804 +1822,875 @@ bool clipTest(const float* _planes, uint8_t _planeNum, const Mesh& _mesh, const return false; } -int _main_(int _argc, char** _argv) +struct ShadowVolumeProgramType { - Args args(_argc, _argv); - - ViewState viewState(1280, 720); - ClearValues clearValues = {0x00000000, 1.0f, 0}; + enum Enum + { + Blank = 0, + Color, + Tex1, + Tex2, - uint32_t debug = BGFX_DEBUG_TEXT; - uint32_t reset = BGFX_RESET_VSYNC; + Count + }; +}; - bgfx::init(args.m_type, args.m_pciId); - bgfx::reset(viewState.m_width, viewState.m_height, reset); +struct ShadowVolumePart +{ + enum Enum + { + Back = 0, + Side, + Front, - // Enable debug text. - bgfx::setDebug(debug); + Count + }; +}; - const bgfx::Caps* caps = bgfx::getCaps(); - s_oglNdc = caps->homogeneousDepth; - s_texelHalf = bgfx::RendererType::Direct3D9 == caps->rendererType ? 0.5f : 0.0f; +enum LightPattern +{ + LightPattern0 = 0, + LightPattern1 +}; - // Imgui - imguiCreate(); +enum MeshChoice +{ + BunnyHighPoly = 0, + BunnyLowPoly +}; - PosNormalTexcoordVertex::init(); +enum Scene +{ + Scene0 = 0, + Scene1, - s_uniforms.init(); - s_uniforms.submitConstUniforms(); + SceneCount +}; - bgfx::TextureHandle figureTex = loadTexture("textures/figure-rgba.dds"); - bgfx::TextureHandle flareTex = loadTexture("textures/flare.dds"); - bgfx::TextureHandle fieldstoneTex = loadTexture("textures/fieldstone-rgba.dds"); +class ExampleShadowVolumes : public entry::AppI +{ +public: + ExampleShadowVolumes(const char* _name, const char* _description) + : entry::AppI(_name, _description) + { + } - bgfx::TextureHandle fbtextures[] = + void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override { - bgfx::createTexture2D(uint16_t(viewState.m_width), uint16_t(viewState.m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_RT), - bgfx::createTexture2D(uint16_t(viewState.m_width), uint16_t(viewState.m_height), false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY), - }; - s_stencilFb = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); + Args args(_argc, _argv); - s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1); - s_texStencil = bgfx::createUniform("s_texStencil", bgfx::UniformType::Int1); + m_viewState = ViewState(_width, _height); + m_clearValues = { 0x00000000, 1.0f, 0 }; - bgfx::ProgramHandle programTextureLighting = loadProgram("vs_shadowvolume_texture_lighting", "fs_shadowvolume_texture_lighting"); - bgfx::ProgramHandle programColorLighting = loadProgram("vs_shadowvolume_color_lighting", "fs_shadowvolume_color_lighting" ); - bgfx::ProgramHandle programColorTexture = loadProgram("vs_shadowvolume_color_texture", "fs_shadowvolume_color_texture" ); - bgfx::ProgramHandle programTexture = loadProgram("vs_shadowvolume_texture", "fs_shadowvolume_texture" ); + m_debug = BGFX_DEBUG_NONE; + m_reset = BGFX_RESET_VSYNC; - bgfx::ProgramHandle programBackBlank = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbackblank" ); - bgfx::ProgramHandle programSideBlank = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsideblank" ); - bgfx::ProgramHandle programFrontBlank = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfrontblank"); + bgfx::init(args.m_type, args.m_pciId); + bgfx::reset(m_viewState.m_width, m_viewState.m_height, m_reset); - bgfx::ProgramHandle programBackColor = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbackcolor" ); - bgfx::ProgramHandle programSideColor = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsidecolor" ); - bgfx::ProgramHandle programFrontColor = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfrontcolor"); + // Enable debug text. + bgfx::setDebug(m_debug); - bgfx::ProgramHandle programSideTex = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsidetex" ); - bgfx::ProgramHandle programBackTex1 = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbacktex1" ); - bgfx::ProgramHandle programBackTex2 = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbacktex2" ); - bgfx::ProgramHandle programFrontTex1 = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfronttex1" ); - bgfx::ProgramHandle programFrontTex2 = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfronttex2" ); + const bgfx::Caps* caps = bgfx::getCaps(); + s_oglNdc = caps->homogeneousDepth; + s_texelHalf = bgfx::RendererType::Direct3D9 == caps->rendererType ? 0.5f : 0.0f; - struct ShadowVolumeProgramType - { - enum Enum - { - Blank = 0, - Color, - Tex1, - Tex2, + // Imgui + imguiCreate(); - Count - }; - }; + PosNormalTexcoordVertex::init(); - struct ShadowVolumePart - { - enum Enum - { - Back = 0, - Side, - Front, + s_uniforms.init(); + + m_figureTex = loadTexture("textures/figure-rgba.dds"); + m_flareTex = loadTexture("textures/flare.dds"); + m_fieldstoneTex = loadTexture("textures/fieldstone-rgba.dds"); - Count + bgfx::TextureHandle fbtextures[] = + { + bgfx::createTexture2D(uint16_t(m_viewState.m_width), uint16_t(m_viewState.m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_RT), + bgfx::createTexture2D(uint16_t(m_viewState.m_width), uint16_t(m_viewState.m_height), false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY), }; - }; - bgfx::ProgramHandle svProgs[ShadowVolumeProgramType::Count][ShadowVolumePart::Count] = - { - { programBackBlank, programSideBlank, programFrontBlank }, // Blank - { programBackColor, programSideColor, programFrontColor }, // Color - { programBackTex1, programSideTex, programFrontTex1 }, // Tex1 - { programBackTex2, programSideTex, programFrontTex2 }, // Tex2 - }; + s_stencilFb = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); - Model bunnyLowPolyModel; - Model bunnyHighPolyModel; - Model columnModel; - Model platformModel; - Model cubeModel; - Model hplaneFieldModel; - Model hplaneFigureModel; - Model vplaneModel; + s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1); + s_texStencil = bgfx::createUniform("s_texStencil", bgfx::UniformType::Int1); - bunnyHighPolyModel.load("meshes/bunny_patched.bin"); - bunnyHighPolyModel.m_program = programColorLighting; + m_programTextureLighting = loadProgram("vs_shadowvolume_texture_lighting", "fs_shadowvolume_texture_lighting"); + m_programColorLighting = loadProgram("vs_shadowvolume_color_lighting", "fs_shadowvolume_color_lighting" ); + m_programColorTexture = loadProgram("vs_shadowvolume_color_texture", "fs_shadowvolume_color_texture" ); + m_programTexture = loadProgram("vs_shadowvolume_texture", "fs_shadowvolume_texture" ); - bunnyLowPolyModel.load("meshes/bunny_decimated.bin"); - bunnyLowPolyModel.m_program = programColorLighting; + m_programBackBlank = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbackblank" ); + m_programSideBlank = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsideblank" ); + m_programFrontBlank = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfrontblank"); - columnModel.load("meshes/column.bin"); - columnModel.m_program = programColorLighting; + m_programBackColor = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbackcolor" ); + m_programSideColor = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsidecolor" ); + m_programFrontColor = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfrontcolor"); - platformModel.load("meshes/platform.bin"); - platformModel.m_program = programTextureLighting; - platformModel.m_texture = figureTex; + m_programSideTex = loadProgram("vs_shadowvolume_svside", "fs_shadowvolume_svsidetex" ); + m_programBackTex1 = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbacktex1" ); + m_programBackTex2 = loadProgram("vs_shadowvolume_svback", "fs_shadowvolume_svbacktex2" ); + m_programFrontTex1 = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfronttex1" ); + m_programFrontTex2 = loadProgram("vs_shadowvolume_svfront", "fs_shadowvolume_svfronttex2" ); - cubeModel.load("meshes/cube.bin"); - cubeModel.m_program = programTextureLighting; - cubeModel.m_texture = figureTex; + bgfx::ProgramHandle svProgs[ShadowVolumeProgramType::Count][ShadowVolumePart::Count] = + { + { m_programBackBlank, m_programSideBlank, m_programFrontBlank }, // Blank + { m_programBackColor, m_programSideColor, m_programFrontColor }, // Color + { m_programBackTex1, m_programSideTex, m_programFrontTex1 }, // Tex1 + { m_programBackTex2, m_programSideTex, m_programFrontTex2 }, // Tex2 + }; + bx::memCopy(m_svProgs, svProgs, sizeof(svProgs)); - hplaneFieldModel.load(s_hplaneVertices, BX_COUNTOF(s_hplaneVertices), PosNormalTexcoordVertex::ms_decl, s_planeIndices, BX_COUNTOF(s_planeIndices) ); - hplaneFieldModel.m_program = programTextureLighting; - hplaneFieldModel.m_texture = fieldstoneTex; + m_bunnyHighPolyModel.load("meshes/bunny_patched.bin"); + m_bunnyHighPolyModel.m_program = m_programColorLighting; - hplaneFigureModel.load(s_hplaneVertices, BX_COUNTOF(s_hplaneVertices), PosNormalTexcoordVertex::ms_decl, s_planeIndices, BX_COUNTOF(s_planeIndices) ); - hplaneFigureModel.m_program = programTextureLighting; - hplaneFigureModel.m_texture = figureTex; + m_bunnyLowPolyModel.load("meshes/bunny_decimated.bin"); + m_bunnyLowPolyModel.m_program = m_programColorLighting; - vplaneModel.load(s_vplaneVertices, BX_COUNTOF(s_vplaneVertices), PosNormalTexcoordVertex::ms_decl, s_planeIndices, BX_COUNTOF(s_planeIndices) ); - vplaneModel.m_program = programColorTexture; - vplaneModel.m_texture = flareTex; + m_columnModel.load("meshes/column.bin"); + m_columnModel.m_program = m_programColorLighting; - // Setup lights. - const float rgbInnerR[MAX_LIGHTS_COUNT][4] = - { - { 1.0f, 0.7f, 0.2f, 0.0f }, //yellow - { 0.7f, 0.2f, 1.0f, 0.0f }, //purple - { 0.2f, 1.0f, 0.7f, 0.0f }, //cyan - { 1.0f, 0.4f, 0.2f, 0.0f }, //orange - { 0.7f, 0.7f, 0.7f, 0.0f }, //white - }; + m_platformModel.load("meshes/platform.bin"); + m_platformModel.m_program = m_programTextureLighting; + m_platformModel.m_texture = m_figureTex; - float lightRgbInnerR[MAX_LIGHTS_COUNT][4]; - for (uint8_t ii = 0, jj = 0; ii < MAX_LIGHTS_COUNT; ++ii, ++jj) - { - const uint8_t index = jj%MAX_LIGHTS_COUNT; - lightRgbInnerR[ii][0] = rgbInnerR[index][0]; - lightRgbInnerR[ii][1] = rgbInnerR[index][1]; - lightRgbInnerR[ii][2] = rgbInnerR[index][2]; - lightRgbInnerR[ii][3] = rgbInnerR[index][3]; - } + m_cubeModel.load("meshes/cube.bin"); + m_cubeModel.m_program = m_programTextureLighting; + m_cubeModel.m_texture = m_figureTex; - int64_t profTime = 0; - int64_t timeOffset = bx::getHPCounter(); - - uint32_t numShadowVolumeVertices = 0; - uint32_t numShadowVolumeIndices = 0; - - uint32_t oldWidth = 0; - uint32_t oldHeight = 0; - - // Imgui. - bool settings_showHelp = false; - bool settings_updateLights = true; - bool settings_updateScene = true; - bool settings_mixedSvImpl = true; - bool settings_useStencilTexture = false; - bool settings_drawShadowVolumes = false; - float settings_numLights = 1.0f; - float settings_instanceCount = 9.0f; - ShadowVolumeImpl::Enum settings_shadowVolumeImpl = ShadowVolumeImpl::DepthFail; - ShadowVolumeAlgorithm::Enum settings_shadowVolumeAlgorithm = ShadowVolumeAlgorithm::EdgeBased; - int32_t scrollAreaRight = 0; - - const char* titles[2] = - { - "Scene 0", - "Scene 1", - }; + m_hplaneFieldModel.load(s_hplaneVertices + , BX_COUNTOF(s_hplaneVertices) + , PosNormalTexcoordVertex::ms_decl + , s_planeIndices + , BX_COUNTOF(s_planeIndices) + ); + m_hplaneFieldModel.m_program = m_programTextureLighting; + m_hplaneFieldModel.m_texture = m_fieldstoneTex; + + m_hplaneFigureModel.load(s_hplaneVertices + , BX_COUNTOF(s_hplaneVertices) + , PosNormalTexcoordVertex::ms_decl + , s_planeIndices + , BX_COUNTOF(s_planeIndices) + ); + m_hplaneFigureModel.m_program = m_programTextureLighting; + m_hplaneFigureModel.m_texture = m_figureTex; + + m_vplaneModel.load(s_vplaneVertices + , BX_COUNTOF(s_vplaneVertices) + , PosNormalTexcoordVertex::ms_decl + , s_planeIndices + , BX_COUNTOF(s_planeIndices) + ); + m_vplaneModel.m_program = m_programColorTexture; + m_vplaneModel.m_texture = m_flareTex; - enum LightPattern - { - LightPattern0 = 0, - LightPattern1 - }; + // Setup lights. + const float rgbInnerR[MAX_LIGHTS_COUNT][4] = + { + { 1.0f, 0.7f, 0.2f, 0.0f }, //yellow + { 0.7f, 0.2f, 1.0f, 0.0f }, //purple + { 0.2f, 1.0f, 0.7f, 0.0f }, //cyan + { 1.0f, 0.4f, 0.2f, 0.0f }, //orange + { 0.7f, 0.7f, 0.7f, 0.0f }, //white + }; - enum MeshChoice - { - BunnyHighPoly = 0, - BunnyLowPoly - }; + for (uint8_t ii = 0, jj = 0; ii < MAX_LIGHTS_COUNT; ++ii, ++jj) + { + const uint8_t index = jj%MAX_LIGHTS_COUNT; + m_lightRgbInnerR[ii][0] = rgbInnerR[index][0]; + m_lightRgbInnerR[ii][1] = rgbInnerR[index][1]; + m_lightRgbInnerR[ii][2] = rgbInnerR[index][2]; + m_lightRgbInnerR[ii][3] = rgbInnerR[index][3]; + } + + m_profTime = 0; + m_timeOffset = bx::getHPCounter(); + + m_numShadowVolumeVertices = 0; + m_numShadowVolumeIndices = 0; + + m_oldWidth = 0; + m_oldHeight = 0; + + // Imgui. + m_showHelp = false; + m_updateLights = true; + m_updateScene = true; + m_mixedSvImpl = true; + m_useStencilTexture = false; + m_drawShadowVolumes = false; + m_numLights = 1; + m_instanceCount = 9; + m_shadowVolumeImpl = ShadowVolumeImpl::DepthFail; + m_shadowVolumeAlgorithm = ShadowVolumeAlgorithm::EdgeBased; + + m_lightPattern = LightPattern0; + m_currentMesh = BunnyLowPoly; + m_currentScene = Scene0; + + // Set view matrix + cameraCreate(); + float initialPos[3] = { 3.0f, 20.0f, -58.0f }; + cameraSetPosition(initialPos); + cameraSetVerticalAngle(-0.25f); + cameraGetViewMtx(m_viewState.m_view); + } - enum Scene + virtual int shutdown() override { - Scene0 = 0, - Scene1, + // Cleanup + m_bunnyLowPolyModel.unload(); + m_bunnyHighPolyModel.unload(); + m_columnModel.unload(); + m_cubeModel.unload(); + m_platformModel.unload(); + m_hplaneFieldModel.unload(); + m_hplaneFigureModel.unload(); + m_vplaneModel.unload(); + + s_uniforms.destroy(); + + bgfx::destroy(s_texColor); + bgfx::destroy(s_texStencil); + bgfx::destroy(s_stencilFb); + + bgfx::destroy(m_figureTex); + bgfx::destroy(m_fieldstoneTex); + bgfx::destroy(m_flareTex); + + bgfx::destroy(m_programTextureLighting); + bgfx::destroy(m_programColorLighting); + bgfx::destroy(m_programColorTexture); + bgfx::destroy(m_programTexture); + + bgfx::destroy(m_programBackBlank); + bgfx::destroy(m_programSideBlank); + bgfx::destroy(m_programFrontBlank); + bgfx::destroy(m_programBackColor); + bgfx::destroy(m_programSideColor); + bgfx::destroy(m_programFrontColor); + bgfx::destroy(m_programSideTex); + bgfx::destroy(m_programBackTex1); + bgfx::destroy(m_programBackTex2); + bgfx::destroy(m_programFrontTex1); + bgfx::destroy(m_programFrontTex2); + + cameraDestroy(); + imguiDestroy(); + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; + } - SceneCount - }; + bool update() override + { + if (!entry::processEvents(m_viewState.m_width, m_viewState.m_height, m_debug, m_reset, &m_mouseState) ) + { + s_uniforms.submitConstUniforms(); - LightPattern lightPattern = LightPattern0; - MeshChoice currentMesh = BunnyLowPoly; - Scene currentScene = Scene0; + // Set projection matrices. + const float fov = 60.0f; + const float aspect = float(m_viewState.m_width)/float(m_viewState.m_height); + const float nearPlane = 1.0f; + const float farPlane = 1000.0f; - // Set view and projection matrices. - const float fov = 60.0f; - const float aspect = float(viewState.m_width)/float(viewState.m_height); - const float nearPlane = 1.0f; - const float farPlane = 1000.0f; + // Respond properly on resize. + if (m_oldWidth != m_viewState.m_width + || m_oldHeight != m_viewState.m_height) + { + m_oldWidth = m_viewState.m_width; + m_oldHeight = m_viewState.m_height; - float initialPos[3] = { 3.0f, 20.0f, -58.0f }; - cameraCreate(); - cameraSetPosition(initialPos); - cameraSetVerticalAngle(-0.25f); - cameraGetViewMtx(viewState.m_view); + bgfx::destroy(s_stencilFb); - entry::MouseState mouseState; - while (!entry::processEvents(viewState.m_width, viewState.m_height, debug, reset, &mouseState) ) - { - // Respond properly on resize. - if (oldWidth != viewState.m_width - || oldHeight != viewState.m_height) - { - oldWidth = viewState.m_width; - oldHeight = viewState.m_height; + bgfx::TextureHandle fbtextures[] = + { + bgfx::createTexture2D(uint16_t(m_viewState.m_width), uint16_t(m_viewState.m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_RT), + bgfx::createTexture2D(uint16_t(m_viewState.m_width), uint16_t(m_viewState.m_height), false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY) + }; + s_stencilFb = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); + } - bgfx::destroyFrameBuffer(s_stencilFb); + // Time. + 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() ) ); + const float deltaTime = float(frameTime/freq); + s_uniforms.m_time = time; + + // Update camera. + cameraUpdate(deltaTime, m_mouseState); + + // Set view and projection matrix for view 0. + const bgfx::HMD* hmd = bgfx::getHMD(); + if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) ) + { + float eye[3]; + cameraGetPosition(eye); - fbtextures[0] = bgfx::createTexture2D(uint16_t(viewState.m_width), uint16_t(viewState.m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_RT); - fbtextures[1] = bgfx::createTexture2D(uint16_t(viewState.m_width), uint16_t(viewState.m_height), false, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY); - s_stencilFb = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true); - } + bx::mtxQuatTranslationHMD(m_viewState.m_view, hmd->eye[0].rotation, eye); + bx::mtxProj(m_viewState.m_proj, hmd->eye[0].fov, nearPlane, farPlane, s_oglNdc); - // Time. - 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 - timeOffset)/double(bx::getHPFrequency() ) ); - const float deltaTime = float(frameTime/freq); - s_uniforms.m_time = time; - - // Update camera. - cameraUpdate(deltaTime, mouseState); - - // Set view and projection matrix for view 0. - const bgfx::HMD* hmd = bgfx::getHMD(); - if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) ) - { - float eye[3]; - cameraGetPosition(eye); + m_viewState.m_width = hmd->width; + m_viewState.m_height = hmd->height; + } + else + { + cameraGetViewMtx(m_viewState.m_view); + bx::mtxProj(m_viewState.m_proj, fov, aspect, nearPlane, farPlane, s_oglNdc); + } - bx::mtxQuatTranslationHMD(viewState.m_view, hmd->eye[0].rotation, eye); - bx::mtxProj(viewState.m_proj, hmd->eye[0].fov, nearPlane, farPlane, s_oglNdc); + imguiBeginFrame( + m_mouseState.m_mx + , m_mouseState.m_my + , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0) + | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0) + | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) + , m_mouseState.m_mz + , uint16_t(m_viewState.m_width) + , uint16_t(m_viewState.m_height) + ); - viewState.m_width = hmd->width; - viewState.m_height = hmd->height; - } - else - { - cameraGetViewMtx(viewState.m_view); - bx::mtxProj(viewState.m_proj, fov, aspect, nearPlane, farPlane, s_oglNdc); - } + showExampleDialog(this); - imguiBeginFrame(mouseState.m_mx - , mouseState.m_my - , (mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0) - | (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0) - | (mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) - , mouseState.m_mz - , uint16_t(viewState.m_width) - , uint16_t(viewState.m_height) - ); + ImGui::SetNextWindowPos(ImVec2(m_viewState.m_width - 256.0f, 10.0f) ); + ImGui::Begin("Settings" + , NULL + , ImVec2(256.0f, 700.0f) + , ImGuiWindowFlags_AlwaysAutoResize + ); - imguiBeginScrollArea("Settings", viewState.m_width - 256 - 10, 10, 256, 700, &scrollAreaRight); + const char* titles[2] = + { + "Scene 0", + "Scene 1", + }; - if (imguiCheck(titles[Scene0], Scene0 == currentScene) ) - { - currentScene = Scene0; - } + if (ImGui::RadioButton(titles[Scene0], Scene0 == m_currentScene) ) + { + m_currentScene = Scene0; + } - if (imguiCheck(titles[Scene1], Scene1 == currentScene) ) - { - currentScene = Scene1; - } + if (ImGui::RadioButton(titles[Scene1], Scene1 == m_currentScene) ) + { + m_currentScene = Scene1; + } - imguiSlider("Lights", settings_numLights, 1.0f, float(MAX_LIGHTS_COUNT), 1.0f); + ImGui::SliderInt("Lights", &m_numLights, 1, MAX_LIGHTS_COUNT); + ImGui::Checkbox("Update lights", &m_updateLights); + ImGui::Indent(); - if (imguiCheck("Update lights", settings_updateLights) ) - { - settings_updateLights = !settings_updateLights; - } + if (ImGui::RadioButton("Light pattern 0", LightPattern0 == m_lightPattern) ) + { + m_lightPattern = LightPattern0; + } - imguiIndent(); + if (ImGui::RadioButton("Light pattern 1", LightPattern1 == m_lightPattern) ) + { + m_lightPattern = LightPattern1; + } - if (imguiCheck("Light pattern 0", LightPattern0 == lightPattern, settings_updateLights) ) - { - lightPattern = LightPattern0; - } + ImGui::Unindent(); - if (imguiCheck("Light pattern 1", LightPattern1 == lightPattern, settings_updateLights) ) - { - lightPattern = LightPattern1; - } + if ( Scene0 == m_currentScene ) + { + ImGui::Checkbox("Update scene", &m_updateScene); + } - imguiUnindent(); + ImGui::Separator(); - if (imguiCheck("Update scene", settings_updateScene, Scene0 == currentScene) ) - { - settings_updateScene = !settings_updateScene; - } + ImGui::Text("Stencil buffer implementation:"); + ImGui::Checkbox("Mixed", &m_mixedSvImpl); + if (!m_mixedSvImpl) + { + m_shadowVolumeImpl = (ImGui::RadioButton("Depth fail", ShadowVolumeImpl::DepthFail == m_shadowVolumeImpl) ? ShadowVolumeImpl::DepthFail : m_shadowVolumeImpl); + m_shadowVolumeImpl = (ImGui::RadioButton("Depth pass", ShadowVolumeImpl::DepthPass == m_shadowVolumeImpl) ? ShadowVolumeImpl::DepthPass : m_shadowVolumeImpl); + } - imguiSeparatorLine(); - imguiLabel("Stencil buffer implementation:"); - settings_shadowVolumeImpl = (imguiCheck("Depth fail", ShadowVolumeImpl::DepthFail == settings_shadowVolumeImpl, !settings_mixedSvImpl) ? ShadowVolumeImpl::DepthFail : settings_shadowVolumeImpl); - settings_shadowVolumeImpl = (imguiCheck("Depth pass", ShadowVolumeImpl::DepthPass == settings_shadowVolumeImpl, !settings_mixedSvImpl) ? ShadowVolumeImpl::DepthPass : settings_shadowVolumeImpl); - settings_mixedSvImpl = (imguiCheck("Mixed", settings_mixedSvImpl) ? !settings_mixedSvImpl : settings_mixedSvImpl); + ImGui::Text("Shadow volume implementation:"); + m_shadowVolumeAlgorithm = (ImGui::RadioButton("Face based impl.", ShadowVolumeAlgorithm::FaceBased == m_shadowVolumeAlgorithm) ? ShadowVolumeAlgorithm::FaceBased : m_shadowVolumeAlgorithm); + m_shadowVolumeAlgorithm = (ImGui::RadioButton("Edge based impl.", ShadowVolumeAlgorithm::EdgeBased == m_shadowVolumeAlgorithm) ? ShadowVolumeAlgorithm::EdgeBased : m_shadowVolumeAlgorithm); - imguiLabel("Shadow volume implementation:"); - settings_shadowVolumeAlgorithm = (imguiCheck("Face based impl.", ShadowVolumeAlgorithm::FaceBased == settings_shadowVolumeAlgorithm) ? ShadowVolumeAlgorithm::FaceBased : settings_shadowVolumeAlgorithm); - settings_shadowVolumeAlgorithm = (imguiCheck("Edge based impl.", ShadowVolumeAlgorithm::EdgeBased == settings_shadowVolumeAlgorithm) ? ShadowVolumeAlgorithm::EdgeBased : settings_shadowVolumeAlgorithm); + ImGui::Text("Stencil:"); + if (ImGui::RadioButton("Use stencil buffer", !m_useStencilTexture) ) + { + if (m_useStencilTexture) + { + m_useStencilTexture = false; + } + } + if (ImGui::RadioButton("Use texture as stencil", m_useStencilTexture) ) + { + if (!m_useStencilTexture) + { + m_useStencilTexture = true; + } + } - imguiLabel("Stencil:"); - if (imguiCheck("Use stencil buffer", !settings_useStencilTexture) ) - { - if (settings_useStencilTexture) + ImGui::Separator(); + ImGui::Text("Mesh:"); + if (ImGui::RadioButton("Bunny - high poly", BunnyHighPoly == m_currentMesh) ) { - settings_useStencilTexture = false; + m_currentMesh = BunnyHighPoly; } - } - if (imguiCheck("Use texture as stencil", settings_useStencilTexture) ) - { - if (!settings_useStencilTexture) + + if (ImGui::RadioButton("Bunny - low poly", BunnyLowPoly == m_currentMesh) ) { - settings_useStencilTexture = true; + m_currentMesh = BunnyLowPoly; } - } - imguiSeparatorLine(); - imguiLabel("Mesh:"); - if (imguiCheck("Bunny - high poly", BunnyHighPoly == currentMesh) ) - { - currentMesh = BunnyHighPoly; - } + if (Scene1 == m_currentScene) + { + ImGui::SliderInt("Instance count", &m_instanceCount, 1, MAX_INSTANCE_COUNT); + } - if (imguiCheck("Bunny - low poly", BunnyLowPoly == currentMesh) ) - { - currentMesh = BunnyLowPoly; - } + ImGui::Text("CPU Time: %7.1f [ms]", double(m_profTime)*toMs); + ImGui::Text("Volume Vertices: %5.uk", m_numShadowVolumeVertices/1000); + ImGui::Text("Volume Indices: %6.uk", m_numShadowVolumeIndices/1000); + m_numShadowVolumeVertices = 0; + m_numShadowVolumeIndices = 0; - if (Scene1 == currentScene) - { - imguiSlider("Instance count", settings_instanceCount, 1.0f, float(MAX_INSTANCE_COUNT), 1.0f); - } + ImGui::Separator(); + ImGui::Checkbox("Draw Shadow Volumes", &m_drawShadowVolumes); - imguiLabel("CPU Time: %7.1f [ms]", double(profTime)*toMs); - imguiLabel("Volume Vertices: %5.uk", numShadowVolumeVertices/1000); - imguiLabel("Volume Indices: %6.uk", numShadowVolumeIndices/1000); - numShadowVolumeVertices = 0; - numShadowVolumeIndices = 0; - - imguiSeparatorLine(); - settings_drawShadowVolumes = imguiCheck("Draw Shadow Volumes", settings_drawShadowVolumes) - ? !settings_drawShadowVolumes - : settings_drawShadowVolumes - ; - imguiIndent(); - imguiUnindent(); - - imguiEndScrollArea(); - - static int32_t scrollAreaLeft = 0; - imguiBeginScrollArea("Show help:", 10, viewState.m_height - 77 - 10, 120, 77, &scrollAreaLeft); - settings_showHelp = imguiButton(settings_showHelp ? "ON" : "OFF") - ? !settings_showHelp - : settings_showHelp - ; - - imguiEndScrollArea(); - - imguiEndFrame(); - - //update settings - s_uniforms.m_params.m_ambientPass = 1.0f; - s_uniforms.m_params.m_lightingPass = 1.0f; - s_uniforms.m_params.m_texelHalf = s_texelHalf; - s_uniforms.m_svparams.m_useStencilTex = float(settings_useStencilTexture); - - //set picked bunny model - Model* bunnyModel = BunnyLowPoly == currentMesh ? &bunnyLowPolyModel : &bunnyHighPolyModel; - - //update time accumulators - static float sceneTimeAccumulator = 0.0f; - if (settings_updateScene) - { - sceneTimeAccumulator += deltaTime; - } + ImGui::End(); - static float lightTimeAccumulator = 0.0f; - if (settings_updateLights) - { - lightTimeAccumulator += deltaTime; - } + ImGui::SetNextWindowPos(ImVec2(10, float(m_viewState.m_height) - 77.0f - 10.0f) ); + ImGui::Begin("Show help:" + , NULL + , ImVec2(120.0f, 77.0f) + , ImGuiWindowFlags_AlwaysAutoResize + ); - //setup light positions - float lightPosRadius[MAX_LIGHTS_COUNT][4]; - if (LightPattern0 == lightPattern) - { - for (uint8_t ii = 0; ii < settings_numLights; ++ii) - { - lightPosRadius[ii][0] = bx::fcos(2.0f*bx::pi/settings_numLights * float(ii) + lightTimeAccumulator * 1.1f + 3.0f) * 20.0f; - lightPosRadius[ii][1] = 20.0f; - lightPosRadius[ii][2] = bx::fsin(2.0f*bx::pi/settings_numLights * float(ii) + lightTimeAccumulator * 1.1f + 3.0f) * 20.0f; - lightPosRadius[ii][3] = 20.0f; - } - } - else - { - for (uint8_t ii = 0; ii < settings_numLights; ++ii) + if (ImGui::Button(m_showHelp ? "ON" : "OFF") ) { - lightPosRadius[ii][0] = bx::fcos(float(ii) * 2.0f/settings_numLights + lightTimeAccumulator * 1.3f + bx::pi) * 40.0f; - lightPosRadius[ii][1] = 20.0f; - lightPosRadius[ii][2] = bx::fsin(float(ii) * 2.0f/settings_numLights + lightTimeAccumulator * 1.3f + bx::pi) * 40.0f; - lightPosRadius[ii][3] = 20.0f; + m_showHelp = !m_showHelp; } - } - //use debug font to print information about this example. - bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/14-shadowvolumes"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Shadow volumes."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + ImGui::End(); - if (settings_showHelp) - { - uint8_t row = 5; - bgfx::dbgTextPrintf(3, row++, 0x0f, "Stencil buffer implementation:"); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Depth fail - Robust, but slower than 'Depth pass'. Requires computing and drawing of shadow volume caps."); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Depth pass - Faster, but not stable. Shadows are wrong when camera is in the shadow."); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Mixed - 'Depth pass' where possible, 'Depth fail' where necessary. Best of both words."); - - row++; - bgfx::dbgTextPrintf(3, row++, 0x0f, "Shadow volume implementation:"); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Face Based - Slower. Works fine with either stencil buffer or texture as stencil."); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Edge Based - Faster, but requires +2 incr/decr on stencil buffer. To avoid massive redraw, use RGBA texture as stencil."); - - row++; - bgfx::dbgTextPrintf(3, row++, 0x0f, "Stencil:"); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Stencil buffer - Faster, but capable only of +1 incr."); - bgfx::dbgTextPrintf(8, row++, 0x0f, "Texture as stencil - Slower, but capable of +2 incr."); - } + imguiEndFrame(); - // Setup instances - Instance shadowCasters[SceneCount][60]; - uint16_t shadowCastersCount[SceneCount]; - for (uint8_t ii = 0; ii < SceneCount; ++ii) - { - shadowCastersCount[ii] = 0; - } + //update settings + s_uniforms.m_params.m_ambientPass = 1.0f; + s_uniforms.m_params.m_lightingPass = 1.0f; + s_uniforms.m_params.m_texelHalf = s_texelHalf; + s_uniforms.m_svparams.m_useStencilTex = float(m_useStencilTexture); - Instance shadowReceivers[SceneCount][10]; - uint16_t shadowReceiversCount[SceneCount]; - for (uint8_t ii = 0; ii < SceneCount; ++ii) - { - shadowReceiversCount[ii] = 0; - } + //set picked bunny model + Model* bunnyModel = BunnyLowPoly == m_currentMesh ? &m_bunnyLowPolyModel : &m_bunnyHighPolyModel; - // Scene 0 - shadow casters - Bunny - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 5.0f; - inst.m_scale[1] = 5.0f; - inst.m_scale[2] = 5.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = float(4.0f - sceneTimeAccumulator * 0.7f); - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = 0.0f; - inst.m_pos[1] = 10.0f; - inst.m_pos[2] = 0.0f; - inst.m_color[0] = 0.68f; - inst.m_color[1] = 0.65f; - inst.m_color[2] = 0.60f; - inst.m_model = bunnyModel; - } + //update time accumulators + static float sceneTimeAccumulator = 0.0f; + if (m_updateScene) + { + sceneTimeAccumulator += deltaTime; + } - // Scene 0 - shadow casters - Cubes top. - const uint8_t numCubesTop = 9; - for (uint16_t ii = 0; ii < numCubesTop; ++ii) - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 1.0f; - inst.m_scale[1] = 1.0f; - inst.m_scale[2] = 1.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = bx::fsin(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; - inst.m_pos[1] = 6.0f; - inst.m_pos[2] = bx::fcos(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; - inst.m_model = &cubeModel; - } + static float lightTimeAccumulator = 0.0f; + if (m_updateLights) + { + lightTimeAccumulator += deltaTime; + } - // Scene 0 - shadow casters - Cubes bottom. - const uint8_t numCubesBottom = 9; - for (uint16_t ii = 0; ii < numCubesBottom; ++ii) - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 1.0f; - inst.m_scale[1] = 1.0f; - inst.m_scale[2] = 1.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = bx::fsin(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; - inst.m_pos[1] = 22.0f; - inst.m_pos[2] = bx::fcos(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; - inst.m_model = &cubeModel; - } + //setup light positions + float lightPosRadius[MAX_LIGHTS_COUNT][4]; + if (LightPattern0 == m_lightPattern) + { + for (uint8_t ii = 0; ii < m_numLights; ++ii) + { + lightPosRadius[ii][0] = bx::fcos(2.0f*bx::kPi/float(m_numLights) * float(ii) + lightTimeAccumulator * 1.1f + 3.0f) * 20.0f; + lightPosRadius[ii][1] = 20.0f; + lightPosRadius[ii][2] = bx::fsin(2.0f*bx::kPi/float(m_numLights) * float(ii) + lightTimeAccumulator * 1.1f + 3.0f) * 20.0f; + lightPosRadius[ii][3] = 20.0f; + } + } + else + { + for (uint8_t ii = 0; ii < m_numLights; ++ii) + { + lightPosRadius[ii][0] = bx::fcos(float(ii) * 2.0f/float(m_numLights) + lightTimeAccumulator * 1.3f + bx::kPi) * 40.0f; + lightPosRadius[ii][1] = 20.0f; + lightPosRadius[ii][2] = bx::fsin(float(ii) * 2.0f/float(m_numLights) + lightTimeAccumulator * 1.3f + bx::kPi) * 40.0f; + lightPosRadius[ii][3] = 20.0f; + } + } - // Scene 0 - shadow casters - Columns. - const float dist = 16.0f; - const float columnPositions[][3] = - { - { dist, 3.3f, dist }, - { -dist, 3.3f, dist }, - { dist, 3.3f, -dist }, - { -dist, 3.3f, -dist }, - }; + if (m_showHelp) + { + uint8_t row = 5; + bgfx::dbgTextPrintf(3, row++, 0x0f, "Stencil buffer implementation:"); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Depth fail - Robust, but slower than 'Depth pass'. Requires computing and drawing of shadow volume caps."); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Depth pass - Faster, but not stable. Shadows are wrong when camera is in the shadow."); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Mixed - 'Depth pass' where possible, 'Depth fail' where necessary. Best of both words."); + + row++; + bgfx::dbgTextPrintf(3, row++, 0x0f, "Shadow volume implementation:"); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Face Based - Slower. Works fine with either stencil buffer or texture as stencil."); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Edge Based - Faster, but requires +2 incr/decr on stencil buffer. To avoid massive redraw, use RGBA texture as stencil."); + + row++; + bgfx::dbgTextPrintf(3, row++, 0x0f, "Stencil:"); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Stencil buffer - Faster, but capable only of +1 incr."); + bgfx::dbgTextPrintf(8, row++, 0x0f, "Texture as stencil - Slower, but capable of +2 incr."); + } - for (uint8_t ii = 0; ii < 4; ++ii) - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 1.5f; - inst.m_scale[1] = 1.5f; - inst.m_scale[2] = 1.5f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 1.57f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = columnPositions[ii][0]; - inst.m_pos[1] = columnPositions[ii][1]; - inst.m_pos[2] = columnPositions[ii][2]; - inst.m_color[0] = 0.25f; - inst.m_color[1] = 0.25f; - inst.m_color[2] = 0.25f; - inst.m_model = &columnModel; - } + // Setup instances + Instance shadowCasters[SceneCount][60]; + uint16_t shadowCastersCount[SceneCount]; + for (uint8_t ii = 0; ii < SceneCount; ++ii) + { + shadowCastersCount[ii] = 0; + } - // Scene 0 - shadow casters - Ceiling. - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 21.0f; - inst.m_scale[1] = 21.0f; - inst.m_scale[2] = 21.0f; - inst.m_rotation[0] = bx::pi; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = 0.0f; - inst.m_pos[1] = 28.2f; - inst.m_pos[2] = 0.0f; - inst.m_model = &platformModel; - inst.m_svExtrusionDistance = 2.0f; //prevent culling on tight view frustum - } + Instance shadowReceivers[SceneCount][10]; + uint16_t shadowReceiversCount[SceneCount]; + for (uint8_t ii = 0; ii < SceneCount; ++ii) + { + shadowReceiversCount[ii] = 0; + } - // Scene 0 - shadow casters - Platform. - { - Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; - inst.m_scale[0] = 24.0f; - inst.m_scale[1] = 24.0f; - inst.m_scale[2] = 24.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = 0.0f; - inst.m_pos[1] = 0.0f; - inst.m_pos[2] = 0.0f; - inst.m_model = &platformModel; - inst.m_svExtrusionDistance = 2.0f; //prevent culling on tight view frustum - } + // Scene 0 - shadow casters - Bunny + { + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 5.0f; + inst.m_scale[1] = 5.0f; + inst.m_scale[2] = 5.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = float(4.0f - sceneTimeAccumulator * 0.7f); + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = 0.0f; + inst.m_pos[1] = 10.0f; + inst.m_pos[2] = 0.0f; + inst.m_color[0] = 0.68f; + inst.m_color[1] = 0.65f; + inst.m_color[2] = 0.60f; + inst.m_model = bunnyModel; + } - // Scene 0 - shadow receivers - Floor. - { - Instance& inst = shadowReceivers[Scene0][shadowReceiversCount[Scene0]++]; - inst.m_scale[0] = 500.0f; - inst.m_scale[1] = 500.0f; - inst.m_scale[2] = 500.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = 0.0f; - inst.m_pos[1] = 0.0f; - inst.m_pos[2] = 0.0f; - inst.m_model = &hplaneFieldModel; - } + // Scene 0 - shadow casters - Cubes top. + const uint8_t numCubesTop = 9; + for (uint16_t ii = 0; ii < numCubesTop; ++ii) + { + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 1.0f; + inst.m_scale[1] = 1.0f; + inst.m_scale[2] = 1.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = 0.0f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = bx::fsin(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; + inst.m_pos[1] = 6.0f; + inst.m_pos[2] = bx::fcos(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; + inst.m_model = &m_cubeModel; + } - // Scene 1 - shadow casters - Bunny instances - { - enum Direction + // Scene 0 - shadow casters - Cubes bottom. + const uint8_t numCubesBottom = 9; + for (uint16_t ii = 0; ii < numCubesBottom; ++ii) + { + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 1.0f; + inst.m_scale[1] = 1.0f; + inst.m_scale[2] = 1.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = 0.0f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = bx::fsin(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; + inst.m_pos[1] = 22.0f; + inst.m_pos[2] = bx::fcos(ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f) * 13.0f; + inst.m_model = &m_cubeModel; + } + + // Scene 0 - shadow casters - Columns. + const float dist = 16.0f; + const float columnPositions[][3] = { - Left = 0x0, - Down = 0x1, - Right = 0x2, - Up = 0x3, + { dist, 3.3f, dist }, + { -dist, 3.3f, dist }, + { dist, 3.3f, -dist }, + { -dist, 3.3f, -dist }, }; - const uint8_t directionMask = 0x3; - uint8_t currentDirection = Left; - float currX = 0.0f; - float currY = 0.0f; - const float stepX = 20.0f; - const float stepY = 20.0f; - uint8_t stateStep = 0; - uint8_t stateChange = 1; + for (uint8_t ii = 0; ii < 4; ++ii) + { + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 1.5f; + inst.m_scale[1] = 1.5f; + inst.m_scale[2] = 1.5f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = 1.57f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = columnPositions[ii][0]; + inst.m_pos[1] = columnPositions[ii][1]; + inst.m_pos[2] = columnPositions[ii][2]; + inst.m_color[0] = 0.25f; + inst.m_color[1] = 0.25f; + inst.m_color[2] = 0.25f; + inst.m_model = &m_columnModel; + } - for (uint8_t ii = 0; ii < settings_instanceCount; ++ii) + // Scene 0 - shadow casters - Ceiling. { - Instance& inst = shadowCasters[Scene1][shadowCastersCount[Scene1]++]; - inst.m_scale[0] = 5.0f; - inst.m_scale[1] = 5.0f; - inst.m_scale[2] = 5.0f; + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 21.0f; + inst.m_scale[1] = 21.0f; + inst.m_scale[2] = 21.0f; + inst.m_rotation[0] = bx::kPi; + inst.m_rotation[1] = 0.0f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = 0.0f; + inst.m_pos[1] = 28.2f; + inst.m_pos[2] = 0.0f; + inst.m_model = &m_platformModel; + inst.m_svExtrusionDistance = 2.0f; //prevent culling on tight view frustum + } + + // Scene 0 - shadow casters - Platform. + { + Instance& inst = shadowCasters[Scene0][shadowCastersCount[Scene0]++]; + inst.m_scale[0] = 24.0f; + inst.m_scale[1] = 24.0f; + inst.m_scale[2] = 24.0f; inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = bx::pi; + inst.m_rotation[1] = 0.0f; inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = currX; + inst.m_pos[0] = 0.0f; inst.m_pos[1] = 0.0f; - inst.m_pos[2] = currY; - inst.m_model = bunnyModel; + inst.m_pos[2] = 0.0f; + inst.m_model = &m_platformModel; + inst.m_svExtrusionDistance = 2.0f; //prevent culling on tight view frustum + } + + // Scene 0 - shadow receivers - Floor. + { + Instance& inst = shadowReceivers[Scene0][shadowReceiversCount[Scene0]++]; + inst.m_scale[0] = 500.0f; + inst.m_scale[1] = 500.0f; + inst.m_scale[2] = 500.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = 0.0f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = 0.0f; + inst.m_pos[1] = 0.0f; + inst.m_pos[2] = 0.0f; + inst.m_model = &m_hplaneFieldModel; + } - ++stateStep; - if (stateStep >= ( (stateChange & ~0x1) >> 1) ) + // Scene 1 - shadow casters - Bunny instances + { + enum Direction { - currentDirection = (currentDirection + 1) & directionMask; - stateStep = 0; - ++stateChange; - } + Left = 0x0, + Down = 0x1, + Right = 0x2, + Up = 0x3, + }; + const uint8_t directionMask = 0x3; - switch (currentDirection) + uint8_t currentDirection = Left; + float currX = 0.0f; + float currY = 0.0f; + const float stepX = 20.0f; + const float stepY = 20.0f; + uint8_t stateStep = 0; + uint8_t stateChange = 1; + + for (uint8_t ii = 0; ii < m_instanceCount; ++ii) { - case Left: currX -= stepX; break; - case Down: currY -= stepY; break; - case Right: currX += stepX; break; - case Up: currY += stepY; break; + Instance& inst = shadowCasters[Scene1][shadowCastersCount[Scene1]++]; + inst.m_scale[0] = 5.0f; + inst.m_scale[1] = 5.0f; + inst.m_scale[2] = 5.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = bx::kPi; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = currX; + inst.m_pos[1] = 0.0f; + inst.m_pos[2] = currY; + inst.m_model = bunnyModel; + + ++stateStep; + if (stateStep >= ( (stateChange & ~0x1) >> 1) ) + { + currentDirection = (currentDirection + 1) & directionMask; + stateStep = 0; + ++stateChange; + } + + switch (currentDirection) + { + case Left: currX -= stepX; break; + case Down: currY -= stepY; break; + case Right: currX += stepX; break; + case Up: currY += stepY; break; + } } } - } - // Scene 1 - shadow receivers - Floor. - { - Instance& inst = shadowReceivers[Scene1][shadowReceiversCount[Scene1]++]; - inst.m_scale[0] = 500.0f; - inst.m_scale[1] = 500.0f; - inst.m_scale[2] = 500.0f; - inst.m_rotation[0] = 0.0f; - inst.m_rotation[1] = 0.0f; - inst.m_rotation[2] = 0.0f; - inst.m_pos[0] = 0.0f; - inst.m_pos[1] = 0.0f; - inst.m_pos[2] = 0.0f; - inst.m_model = &hplaneFigureModel; - } + // Scene 1 - shadow receivers - Floor. + { + Instance& inst = shadowReceivers[Scene1][shadowReceiversCount[Scene1]++]; + inst.m_scale[0] = 500.0f; + inst.m_scale[1] = 500.0f; + inst.m_scale[2] = 500.0f; + inst.m_rotation[0] = 0.0f; + inst.m_rotation[1] = 0.0f; + inst.m_rotation[2] = 0.0f; + inst.m_pos[0] = 0.0f; + inst.m_pos[1] = 0.0f; + inst.m_pos[2] = 0.0f; + inst.m_model = &m_hplaneFigureModel; + } - // Make sure at the beginning everything gets cleared. - bgfx::setViewClear(0 + // Make sure at the beginning everything gets cleared. + bgfx::setViewClear(0 , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL - , clearValues.m_clearRgba - , clearValues.m_clearDepth - , clearValues.m_clearStencil + , m_clearValues.m_clearRgba + , m_clearValues.m_clearDepth + , m_clearValues.m_clearStencil ); - ::touch(0); - - // Draw ambient only. - s_uniforms.m_params.m_ambientPass = 1.0f; - s_uniforms.m_params.m_lightingPass = 0.0f; - - s_uniforms.m_color[0] = 1.0f; - s_uniforms.m_color[1] = 1.0f; - s_uniforms.m_color[2] = 1.0f; + ::touch(0); - const RenderState& drawAmbient = (settings_useStencilTexture ? - s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_DrawAmbient]: - s_renderStates[RenderState::ShadowVolume_UsingStencilBuffer_DrawAmbient]); + // Draw ambient only. + s_uniforms.m_params.m_ambientPass = 1.0f; + s_uniforms.m_params.m_lightingPass = 0.0f; - // Draw shadow casters. - for (uint8_t ii = 0; ii < shadowCastersCount[currentScene]; ++ii) - { - shadowCasters[currentScene][ii].submit(VIEWID_RANGE1_PASS0, drawAmbient); - } - - // Draw shadow receivers. - for (uint8_t ii = 0; ii < shadowReceiversCount[currentScene]; ++ii) - { - shadowReceivers[currentScene][ii].submit(VIEWID_RANGE1_PASS0, drawAmbient); - } + s_uniforms.m_color[0] = 1.0f; + s_uniforms.m_color[1] = 1.0f; + s_uniforms.m_color[2] = 1.0f; - // Using stencil texture requires rendering to separate render target. first pass is building depth buffer. - if (settings_useStencilTexture) - { - bgfx::setViewClear(VIEWID_RANGE1_RT_PASS1, BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); - bgfx::setViewFrameBuffer(VIEWID_RANGE1_RT_PASS1, s_stencilFb); - - const RenderState& renderState = s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_BuildDepth]; + const RenderState& drawAmbient = m_useStencilTexture + ? s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_DrawAmbient] + : s_renderStates[RenderState::ShadowVolume_UsingStencilBuffer_DrawAmbient] + ; - for (uint8_t ii = 0; ii < shadowCastersCount[currentScene]; ++ii) + // Draw shadow casters. + for (uint8_t ii = 0; ii < shadowCastersCount[m_currentScene]; ++ii) { - shadowCasters[currentScene][ii].submit(VIEWID_RANGE1_RT_PASS1, renderState); + shadowCasters[m_currentScene][ii].submit(VIEWID_RANGE1_PASS0, drawAmbient); } - for (uint8_t ii = 0; ii < shadowReceiversCount[currentScene]; ++ii) + // Draw shadow receivers. + for (uint8_t ii = 0; ii < shadowReceiversCount[m_currentScene]; ++ii) { - shadowReceivers[currentScene][ii].submit(VIEWID_RANGE1_RT_PASS1, renderState); + shadowReceivers[m_currentScene][ii].submit(VIEWID_RANGE1_PASS0, drawAmbient); } - } - profTime = bx::getHPCounter(); + // Using stencil texture requires rendering to separate render target. first pass is building depth buffer. + if (m_useStencilTexture) + { + bgfx::setViewClear(VIEWID_RANGE1_RT_PASS1, BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); + bgfx::setViewFrameBuffer(VIEWID_RANGE1_RT_PASS1, s_stencilFb); - /** - * For each light: - * 1. Compute and draw shadow volume to stencil buffer - * 2. Draw diffuse with stencil test - */ - for (uint8_t ii = 0, viewId = VIEWID_RANGE15_PASS2; ii < settings_numLights; ++ii, ++viewId) - { - const float* lightPos = lightPosRadius[ii]; + const RenderState& renderState = s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_BuildDepth]; - bx::memCopy(s_uniforms.m_lightPosRadius, lightPosRadius[ii], 4*sizeof(float) ); - bx::memCopy(s_uniforms.m_lightRgbInnerR, lightRgbInnerR[ii], 3*sizeof(float) ); - bx::memCopy(s_uniforms.m_color, lightRgbInnerR[ii], 3*sizeof(float) ); + for (uint8_t ii = 0; ii < shadowCastersCount[m_currentScene]; ++ii) + { + shadowCasters[m_currentScene][ii].submit(VIEWID_RANGE1_RT_PASS1, renderState); + } - if (settings_useStencilTexture) + for (uint8_t ii = 0; ii < shadowReceiversCount[m_currentScene]; ++ii) + { + shadowReceivers[m_currentScene][ii].submit(VIEWID_RANGE1_RT_PASS1, renderState); + } + } + + m_profTime = bx::getHPCounter(); + + /** + * For each light: + * 1. Compute and draw shadow volume to stencil buffer + * 2. Draw diffuse with stencil test + */ + for (uint8_t ii = 0, viewId = VIEWID_RANGE15_PASS2; ii < m_numLights; ++ii, ++viewId) { - bgfx::setViewFrameBuffer(viewId, s_stencilFb); + const float* lightPos = lightPosRadius[ii]; + + bx::memCopy(s_uniforms.m_lightPosRadius, lightPosRadius[ii], 4*sizeof(float) ); + bx::memCopy(s_uniforms.m_lightRgbInnerR, m_lightRgbInnerR[ii], 3*sizeof(float) ); + bx::memCopy(s_uniforms.m_color, m_lightRgbInnerR[ii], 3*sizeof(float) ); + + if (m_useStencilTexture) + { + bgfx::setViewFrameBuffer(viewId, s_stencilFb); - bgfx::setViewClear(viewId + bgfx::setViewClear(viewId , BGFX_CLEAR_COLOR , 0x00000000 , 1.0f , 0 ); - } - else - { - const bgfx::FrameBufferHandle invalid = BGFX_INVALID_HANDLE; - bgfx::setViewFrameBuffer(viewId, invalid); + } + else + { + const bgfx::FrameBufferHandle invalid = BGFX_INVALID_HANDLE; + bgfx::setViewFrameBuffer(viewId, invalid); - bgfx::setViewClear(viewId + bgfx::setViewClear(viewId , BGFX_CLEAR_STENCIL - , clearValues.m_clearRgba - , clearValues.m_clearDepth - , clearValues.m_clearStencil + , m_clearValues.m_clearRgba + , m_clearValues.m_clearDepth + , m_clearValues.m_clearStencil ); - } - - // Create near clip volume for current light. - float nearClipVolume[6 * 4] = {}; - float pointLight[4]; - if (settings_mixedSvImpl) - { - pointLight[0] = lightPos[0]; - pointLight[1] = lightPos[1]; - pointLight[2] = lightPos[2]; - pointLight[3] = 1.0f; - createNearClipVolume(nearClipVolume, pointLight, viewState.m_view, fov, aspect, nearPlane); - } - - for (uint8_t jj = 0; jj < shadowCastersCount[currentScene]; ++jj) - { - const Instance& instance = shadowCasters[currentScene][jj]; - Model* model = instance.m_model; + } - ShadowVolumeImpl::Enum shadowVolumeImpl = settings_shadowVolumeImpl; - if (settings_mixedSvImpl) + // Create near clip volume for current light. + float nearClipVolume[6 * 4] = {}; + float pointLight[4]; + if (m_mixedSvImpl) { - // If instance is inside near clip volume, depth fail must be used, else depth pass is fine. - bool isInsideVolume = clipTest(nearClipVolume, 6, model->m_mesh, instance.m_scale, instance.m_pos); - shadowVolumeImpl = (isInsideVolume ? ShadowVolumeImpl::DepthFail : ShadowVolumeImpl::DepthPass); + pointLight[0] = lightPos[0]; + pointLight[1] = lightPos[1]; + pointLight[2] = lightPos[2]; + pointLight[3] = 1.0f; + createNearClipVolume(nearClipVolume, pointLight, m_viewState.m_view, fov, aspect, nearPlane); } - s_uniforms.m_svparams.m_dfail = float(ShadowVolumeImpl::DepthFail == shadowVolumeImpl); - - // Compute virtual light position for shadow volume generation. - float transformedLightPos[3]; - shadowVolumeLightTransform(transformedLightPos - , instance.m_scale - , instance.m_rotation - , instance.m_pos - , lightPos - ); - - // Set virtual light pos. - bx::memCopy(s_uniforms.m_virtualLightPos_extrusionDist, transformedLightPos, 3*sizeof(float) ); - s_uniforms.m_virtualLightPos_extrusionDist[3] = instance.m_svExtrusionDistance; - - // Compute transform for shadow volume. - float shadowVolumeMtx[16]; - bx::mtxSRT(shadowVolumeMtx + + for (uint8_t jj = 0; jj < shadowCastersCount[m_currentScene]; ++jj) + { + const Instance& instance = shadowCasters[m_currentScene][jj]; + Model* model = instance.m_model; + + ShadowVolumeImpl::Enum shadowVolumeImpl = m_shadowVolumeImpl; + if (m_mixedSvImpl) + { + // If instance is inside near clip volume, depth fail must be used, else depth pass is fine. + bool isInsideVolume = clipTest(nearClipVolume, 6, model->m_mesh, instance.m_scale, instance.m_pos); + shadowVolumeImpl = (isInsideVolume ? ShadowVolumeImpl::DepthFail : ShadowVolumeImpl::DepthPass); + } + s_uniforms.m_svparams.m_dfail = float(ShadowVolumeImpl::DepthFail == shadowVolumeImpl); + + // Compute virtual light position for shadow volume generation. + float transformedLightPos[3]; + shadowVolumeLightTransform(transformedLightPos + , instance.m_scale + , instance.m_rotation + , instance.m_pos + , lightPos + ); + + // Set virtual light pos. + bx::memCopy(s_uniforms.m_virtualLightPos_extrusionDist, transformedLightPos, 3*sizeof(float) ); + s_uniforms.m_virtualLightPos_extrusionDist[3] = instance.m_svExtrusionDistance; + + // Compute transform for shadow volume. + float shadowVolumeMtx[16]; + bx::mtxSRT(shadowVolumeMtx , instance.m_scale[0] , instance.m_scale[1] , instance.m_scale[2] @@ -2653,207 +2702,239 @@ int _main_(int _argc, char** _argv) , instance.m_pos[2] ); - GroupArray& groups = model->m_mesh.m_groups; - const uint16_t stride = model->m_mesh.m_decl.getStride(); - for (GroupArray::iterator it = groups.begin(), itEnd = groups.end(); it != itEnd; ++it) - { - Group& group = *it; - - // Create shadow volume. - ShadowVolume shadowVolume; - shadowVolumeCreate(shadowVolume - , group - , stride - , shadowVolumeMtx - , transformedLightPos - , shadowVolumeImpl - , settings_shadowVolumeAlgorithm - , settings_useStencilTexture - ); - - numShadowVolumeVertices += shadowVolume.m_numVertices; - numShadowVolumeIndices += shadowVolume.m_numIndices; - - ShadowVolumeProgramType::Enum programIndex = ShadowVolumeProgramType::Blank; - RenderState::Enum renderStateIndex; - if (settings_useStencilTexture) - { - renderStateIndex = ShadowVolumeImpl::DepthFail == shadowVolumeImpl - ? RenderState::ShadowVolume_UsingStencilTexture_CraftStencil_DepthFail - : RenderState::ShadowVolume_UsingStencilTexture_CraftStencil_DepthPass - ; - - programIndex = ShadowVolumeAlgorithm::FaceBased == settings_shadowVolumeAlgorithm - ? ShadowVolumeProgramType::Tex1 - : ShadowVolumeProgramType::Tex2 - ; - } - else - { - renderStateIndex = ShadowVolumeImpl::DepthFail == shadowVolumeImpl - ? RenderState::ShadowVolume_UsingStencilBuffer_CraftStencil_DepthFail - : RenderState::ShadowVolume_UsingStencilBuffer_CraftStencil_DepthPass - ; - } - const RenderState& renderStateCraftStencil = s_renderStates[renderStateIndex]; - - s_uniforms.submitPerDrawUniforms(); - bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(shadowVolume.m_vbSides); - bgfx::setIndexBuffer(shadowVolume.m_ibSides); - setRenderState(renderStateCraftStencil); - ::submit(viewId, svProgs[programIndex][ShadowVolumePart::Side]); - - if (shadowVolume.m_cap) + GroupArray& groups = model->m_mesh.m_groups; + const uint16_t stride = model->m_mesh.m_decl.getStride(); + for (GroupArray::iterator it = groups.begin(), itEnd = groups.end(); it != itEnd; ++it) { - s_uniforms.submitPerDrawUniforms(); - bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(group.m_vbh); - bgfx::setIndexBuffer(shadowVolume.m_ibFrontCap); - setRenderState(renderStateCraftStencil); - ::submit(viewId, svProgs[programIndex][ShadowVolumePart::Front]); + Group& group = *it; + + // Create shadow volume. + ShadowVolume shadowVolume; + shadowVolumeCreate(shadowVolume + , group + , stride + , shadowVolumeMtx + , transformedLightPos + , shadowVolumeImpl + , m_shadowVolumeAlgorithm + , m_useStencilTexture + ); - s_uniforms.submitPerDrawUniforms(); - bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(group.m_vbh); - bgfx::setIndexBuffer(shadowVolume.m_ibBackCap); - ::setRenderState(renderStateCraftStencil); - ::submit(viewId, svProgs[programIndex][ShadowVolumePart::Back]); - } + m_numShadowVolumeVertices += shadowVolume.m_numVertices; + m_numShadowVolumeIndices += shadowVolume.m_numIndices; - if (settings_drawShadowVolumes) - { - const RenderState& renderState = s_renderStates[RenderState::Custom_DrawShadowVolume_Lines]; + ShadowVolumeProgramType::Enum programIndex = ShadowVolumeProgramType::Blank; + RenderState::Enum renderStateIndex; + if (m_useStencilTexture) + { + renderStateIndex = ShadowVolumeImpl::DepthFail == shadowVolumeImpl + ? RenderState::ShadowVolume_UsingStencilTexture_CraftStencil_DepthFail + : RenderState::ShadowVolume_UsingStencilTexture_CraftStencil_DepthPass + ; + + programIndex = ShadowVolumeAlgorithm::FaceBased == m_shadowVolumeAlgorithm + ? ShadowVolumeProgramType::Tex1 + : ShadowVolumeProgramType::Tex2 + ; + } + else + { + renderStateIndex = ShadowVolumeImpl::DepthFail == shadowVolumeImpl + ? RenderState::ShadowVolume_UsingStencilBuffer_CraftStencil_DepthFail + : RenderState::ShadowVolume_UsingStencilBuffer_CraftStencil_DepthPass + ; + } + const RenderState& renderStateCraftStencil = s_renderStates[renderStateIndex]; s_uniforms.submitPerDrawUniforms(); bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(shadowVolume.m_vbSides); + bgfx::setVertexBuffer(0, shadowVolume.m_vbSides); bgfx::setIndexBuffer(shadowVolume.m_ibSides); - ::setRenderState(renderState); - ::submit(VIEWID_RANGE1_PASS3, svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Side]); + setRenderState(renderStateCraftStencil); + ::submit(viewId, m_svProgs[programIndex][ShadowVolumePart::Side]); if (shadowVolume.m_cap) { s_uniforms.submitPerDrawUniforms(); bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(group.m_vbh); + bgfx::setVertexBuffer(0, group.m_vbh); bgfx::setIndexBuffer(shadowVolume.m_ibFrontCap); - ::setRenderState(renderState); - ::submit(VIEWID_RANGE1_PASS3, svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Front]); + setRenderState(renderStateCraftStencil); + ::submit(viewId, m_svProgs[programIndex][ShadowVolumePart::Front]); s_uniforms.submitPerDrawUniforms(); bgfx::setTransform(shadowVolumeMtx); - bgfx::setVertexBuffer(group.m_vbh); + bgfx::setVertexBuffer(0, group.m_vbh); bgfx::setIndexBuffer(shadowVolume.m_ibBackCap); + ::setRenderState(renderStateCraftStencil); + ::submit(viewId, m_svProgs[programIndex][ShadowVolumePart::Back]); + } + + if (m_drawShadowVolumes) + { + const RenderState& renderState = s_renderStates[RenderState::Custom_DrawShadowVolume_Lines]; + + s_uniforms.submitPerDrawUniforms(); + bgfx::setTransform(shadowVolumeMtx); + bgfx::setVertexBuffer(0, shadowVolume.m_vbSides); + bgfx::setIndexBuffer(shadowVolume.m_ibSides); ::setRenderState(renderState); - ::submit(VIEWID_RANGE1_PASS3, svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Back]); + ::submit(VIEWID_RANGE1_PASS3, m_svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Side]); + + if (shadowVolume.m_cap) + { + s_uniforms.submitPerDrawUniforms(); + bgfx::setTransform(shadowVolumeMtx); + bgfx::setVertexBuffer(0, group.m_vbh); + bgfx::setIndexBuffer(shadowVolume.m_ibFrontCap); + ::setRenderState(renderState); + ::submit(VIEWID_RANGE1_PASS3, m_svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Front]); + + s_uniforms.submitPerDrawUniforms(); + bgfx::setTransform(shadowVolumeMtx); + bgfx::setVertexBuffer(0, group.m_vbh); + bgfx::setIndexBuffer(shadowVolume.m_ibBackCap); + ::setRenderState(renderState); + ::submit(VIEWID_RANGE1_PASS3, m_svProgs[ShadowVolumeProgramType::Color][ShadowVolumePart::Back]); + } } } } - } - // Draw diffuse only. - s_uniforms.m_params.m_ambientPass = 0.0f; - s_uniforms.m_params.m_lightingPass = 1.0f; + // Draw diffuse only. + s_uniforms.m_params.m_ambientPass = 0.0f; + s_uniforms.m_params.m_lightingPass = 1.0f; - RenderState& drawDiffuse = settings_useStencilTexture - ? s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_DrawDiffuse] - : s_renderStates[RenderState::ShadowVolume_UsingStencilBuffer_DrawDiffuse] - ; + RenderState& drawDiffuse = m_useStencilTexture + ? s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_DrawDiffuse] + : s_renderStates[RenderState::ShadowVolume_UsingStencilBuffer_DrawDiffuse] + ; - // If using stencil texture, viewId is set to render target. Incr it to render to default back buffer. - viewId += uint8_t(settings_useStencilTexture); + // If using stencil texture, viewId is set to render target. Incr it to render to default back buffer. + viewId += uint8_t(m_useStencilTexture); - // Draw shadow casters. - for (uint8_t jj = 0; jj < shadowCastersCount[currentScene]; ++jj) - { - shadowCasters[currentScene][jj].submit(viewId, drawDiffuse); + // Draw shadow casters. + for (uint8_t jj = 0; jj < shadowCastersCount[m_currentScene]; ++jj) + { + shadowCasters[m_currentScene][jj].submit(viewId, drawDiffuse); + } + + // Draw shadow receivers. + for (uint8_t jj = 0; jj < shadowReceiversCount[m_currentScene]; ++jj) + { + shadowReceivers[m_currentScene][jj].submit(viewId, drawDiffuse); + } } - // Draw shadow receivers. - for (uint8_t jj = 0; jj < shadowReceiversCount[currentScene]; ++jj) + m_profTime = bx::getHPCounter() - m_profTime; + + // Lights. + const float lightScale[3] = { 1.5f, 1.5f, 1.5f }; + for (uint8_t ii = 0; ii < m_numLights; ++ii) { - shadowReceivers[currentScene][jj].submit(viewId, drawDiffuse); - } - } + bx::memCopy(s_uniforms.m_color, m_lightRgbInnerR[ii], 3*sizeof(float) ); - profTime = bx::getHPCounter() - profTime; + float lightMtx[16]; + mtxBillboard(lightMtx, m_viewState.m_view, lightPosRadius[ii], lightScale); - // Lights. - const float lightScale[3] = { 1.5f, 1.5f, 1.5f }; - for (uint8_t ii = 0; ii < settings_numLights; ++ii) - { - bx::memCopy(s_uniforms.m_color, lightRgbInnerR[ii], 3*sizeof(float) ); + m_vplaneModel.submit(VIEWID_RANGE1_PASS3, lightMtx, s_renderStates[RenderState::Custom_BlendLightTexture]); + } - float lightMtx[16]; - mtxBillboard(lightMtx, viewState.m_view, lightPosRadius[ii], lightScale); + // Setup view rect and transform for all used views. + setViewRectMask(s_viewMask, 0, 0, uint16_t(m_viewState.m_width), uint16_t(m_viewState.m_height) ); + setViewTransformMask(s_viewMask, m_viewState.m_view, m_viewState.m_proj); + s_viewMask = 0; - vplaneModel.submit(VIEWID_RANGE1_PASS3, lightMtx, s_renderStates[RenderState::Custom_BlendLightTexture]); - } + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); - // Setup view rect and transform for all used views. - setViewRectMask(s_viewMask, 0, 0, uint16_t(viewState.m_width), uint16_t(viewState.m_height) ); - setViewTransformMask(s_viewMask, viewState.m_view, viewState.m_proj); - s_viewMask = 0; + // Swap memory pages. + s_svAllocator.swap(); - // Advance to next frame. Rendering thread will be kicked to - // process submitted rendering primitives. - bgfx::frame(); + // Reset clear values. + setViewClearMask(UINT32_MAX + , BGFX_CLEAR_NONE + , m_clearValues.m_clearRgba + , m_clearValues.m_clearDepth + , m_clearValues.m_clearStencil + ); - // Swap memory pages. - s_svAllocator.swap(); + return true; + } - // Reset clear values. - setViewClearMask(UINT32_MAX - , BGFX_CLEAR_NONE - , clearValues.m_clearRgba - , clearValues.m_clearDepth - , clearValues.m_clearStencil - ); + return false; } - // Cleanup - bunnyLowPolyModel.unload(); - bunnyHighPolyModel.unload(); - columnModel.unload(); - cubeModel.unload(); - platformModel.unload(); - hplaneFieldModel.unload(); - hplaneFigureModel.unload(); - vplaneModel.unload(); - - s_uniforms.destroy(); - - bgfx::destroyUniform(s_texColor); - bgfx::destroyUniform(s_texStencil); - bgfx::destroyFrameBuffer(s_stencilFb); - - bgfx::destroyTexture(figureTex); - bgfx::destroyTexture(fieldstoneTex); - bgfx::destroyTexture(flareTex); - - bgfx::destroyProgram(programTextureLighting); - bgfx::destroyProgram(programColorLighting); - bgfx::destroyProgram(programColorTexture); - bgfx::destroyProgram(programTexture); - - bgfx::destroyProgram(programBackBlank); - bgfx::destroyProgram(programSideBlank); - bgfx::destroyProgram(programFrontBlank); - bgfx::destroyProgram(programBackColor); - bgfx::destroyProgram(programSideColor); - bgfx::destroyProgram(programFrontColor); - bgfx::destroyProgram(programSideTex); - bgfx::destroyProgram(programBackTex1); - bgfx::destroyProgram(programBackTex2); - bgfx::destroyProgram(programFrontTex1); - bgfx::destroyProgram(programFrontTex2); - - cameraDestroy(); - imguiDestroy(); - - // Shutdown bgfx. - bgfx::shutdown(); - - return 0; -} + ViewState m_viewState; + ClearValues m_clearValues; + + uint32_t m_debug; + uint32_t m_reset; + + bgfx::TextureHandle m_figureTex; + bgfx::TextureHandle m_flareTex; + bgfx::TextureHandle m_fieldstoneTex; + + bgfx::ProgramHandle m_programTextureLighting; + bgfx::ProgramHandle m_programColorLighting; + bgfx::ProgramHandle m_programColorTexture; + bgfx::ProgramHandle m_programTexture; + + bgfx::ProgramHandle m_programBackBlank; + bgfx::ProgramHandle m_programSideBlank; + bgfx::ProgramHandle m_programFrontBlank; + + bgfx::ProgramHandle m_programBackColor; + bgfx::ProgramHandle m_programSideColor; + bgfx::ProgramHandle m_programFrontColor; + + bgfx::ProgramHandle m_programSideTex; + bgfx::ProgramHandle m_programBackTex1; + bgfx::ProgramHandle m_programBackTex2; + bgfx::ProgramHandle m_programFrontTex1; + bgfx::ProgramHandle m_programFrontTex2; + + bgfx::ProgramHandle m_svProgs[ShadowVolumeProgramType::Count][ShadowVolumePart::Count]; + + Model m_bunnyLowPolyModel; + Model m_bunnyHighPolyModel; + Model m_columnModel; + Model m_platformModel; + Model m_cubeModel; + Model m_hplaneFieldModel; + Model m_hplaneFigureModel; + Model m_vplaneModel; + + float m_lightRgbInnerR[MAX_LIGHTS_COUNT][4]; + + int64_t m_profTime; + int64_t m_timeOffset; + + uint32_t m_numShadowVolumeVertices; + uint32_t m_numShadowVolumeIndices; + + uint32_t m_oldWidth; + uint32_t m_oldHeight; + + int32_t m_numLights; + int32_t m_instanceCount; + bool m_showHelp; + bool m_updateLights; + bool m_updateScene; + bool m_mixedSvImpl; + bool m_useStencilTexture; + bool m_drawShadowVolumes; + ShadowVolumeImpl::Enum m_shadowVolumeImpl; + ShadowVolumeAlgorithm::Enum m_shadowVolumeAlgorithm; + + LightPattern m_lightPattern; + MeshChoice m_currentMesh; + Scene m_currentScene; + + entry::MouseState m_mouseState; +}; + +} // namespace + +ENTRY_IMPLEMENT_MAIN(ExampleShadowVolumes, "14-shadowvolumes", "Shadow volumes."); |