From 8493775a8b0381d5846c808ef3f17234f406669f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sun, 13 Dec 2015 09:48:21 -0800 Subject: [PATCH] Cleanup. --- examples/27-terrain/fs_terrain.sc | 2 +- examples/27-terrain/terrain.cpp | 904 +++++++++--------- examples/27-terrain/vs_terrain.sc | 8 +- .../27-terrain/vs_terrain_height_texture.sc | 8 +- 4 files changed, 479 insertions(+), 443 deletions(-) diff --git a/examples/27-terrain/fs_terrain.sc b/examples/27-terrain/fs_terrain.sc index a6c52984..5e23d5d3 100644 --- a/examples/27-terrain/fs_terrain.sc +++ b/examples/27-terrain/fs_terrain.sc @@ -9,5 +9,5 @@ $input v_position, v_texcoord0 void main() { - gl_FragColor = vec4(v_texcoord0.x, v_texcoord0.y, v_position.y / 50.0, 1.0); + gl_FragColor = vec4(v_texcoord0.x, v_texcoord0.y, v_position.y / 50.0, 1.0); } diff --git a/examples/27-terrain/terrain.cpp b/examples/27-terrain/terrain.cpp index 36e0c492..d0cd0c39 100644 --- a/examples/27-terrain/terrain.cpp +++ b/examples/27-terrain/terrain.cpp @@ -17,470 +17,506 @@ static uint32_t s_terrainSize = 256; struct PosTexCoord0Vertex { - float m_x; - float m_y; - float m_z; - float m_u; - float m_v; + float m_x; + float m_y; + float m_z; + float m_u; + float m_v; - static void init() - { - ms_decl - .begin() - .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) - .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) - .end(); - } + static void init() + { + ms_decl + .begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) + .end(); + } - static bgfx::VertexDecl ms_decl; + static bgfx::VertexDecl ms_decl; }; bgfx::VertexDecl PosTexCoord0Vertex::ms_decl; struct TerrainData { - uint32_t m_mode; - bool m_dirty; - float m_transform[16]; - uint8_t* m_heightMap; + uint32_t m_mode; + bool m_dirty; + float m_transform[16]; + uint8_t* m_heightMap; - PosTexCoord0Vertex* m_vertices; - uint32_t m_vertexCount; - uint16_t* m_indices; - uint32_t m_indexCount; + PosTexCoord0Vertex* m_vertices; + uint32_t m_vertexCount; + uint16_t* m_indices; + uint32_t m_indexCount; }; struct BrushData { - bool m_raise; - int32_t m_size; - float m_power; + bool m_raise; + int32_t m_size; + float m_power; }; class Terrain : public entry::AppI { - void init(int _argc, char** _argv) BX_OVERRIDE - { - Args args(_argc, _argv); - - m_width = 1280; - m_height = 720; - m_debug = BGFX_DEBUG_TEXT; - m_reset = BGFX_RESET_VSYNC; + void init(int _argc, char** _argv) BX_OVERRIDE + { + Args args(_argc, _argv); - bgfx::init(bgfx::RendererType::Direct3D11, args.m_pciId); - bgfx::reset(m_width, m_height, m_reset); + m_width = 1280; + m_height = 720; + m_debug = BGFX_DEBUG_TEXT; + m_reset = BGFX_RESET_VSYNC; - // Enable m_debug text. - bgfx::setDebug(m_debug); + bgfx::init(bgfx::RendererType::Direct3D11, args.m_pciId); + bgfx::reset(m_width, m_height, m_reset); - // Set view 0 clear state. - bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH - , 0x303030ff - , 1.0f - , 0 - ); + // Enable m_debug text. + bgfx::setDebug(m_debug); - // Create vertex stream declaration. - PosTexCoord0Vertex::init(); + // Set view 0 clear state. + bgfx::setViewClear(0 + , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH + , 0x303030ff + , 1.0f + , 0 + ); - // Create program from shaders. - m_terrainProgram = loadProgram("vs_terrain", "fs_terrain"); - m_terrainHeightTextureProgram = loadProgram("vs_terrain_height_texture", "fs_terrain"); + // Create vertex stream declaration. + PosTexCoord0Vertex::init(); - // Imgui. - imguiCreate(); + // Create program from shaders. + m_terrainProgram = loadProgram("vs_terrain", "fs_terrain"); + m_terrainHeightTextureProgram = loadProgram("vs_terrain_height_texture", "fs_terrain"); - m_timeOffset = bx::getHPCounter(); - const bgfx::RendererType::Enum renderer = bgfx::getRendererType(); - s_texelHalf = bgfx::RendererType::Direct3D9 == renderer ? 0.5f : 0.0f; - s_originBottomLeft = bgfx::RendererType::OpenGL == renderer || bgfx::RendererType::OpenGLES == renderer; + // Imgui. + imguiCreate(); - m_vbh.idx = bgfx::invalidHandle; - m_ibh.idx = bgfx::invalidHandle; - m_dvbh.idx = bgfx::invalidHandle; - m_dibh.idx = bgfx::invalidHandle; - m_heightTexture.idx = bgfx::invalidHandle; - s_heightTexture = bgfx::createUniform("s_heightTexture", bgfx::UniformType::Int1); + m_timeOffset = bx::getHPCounter(); + const bgfx::RendererType::Enum renderer = bgfx::getRendererType(); + s_texelHalf = bgfx::RendererType::Direct3D9 == renderer ? 0.5f : 0.0f; + s_originBottomLeft = bgfx::RendererType::OpenGL == renderer || bgfx::RendererType::OpenGLES == renderer; - m_oldWidth = 0; - m_oldHeight = 0; - m_oldReset = m_reset; + m_vbh.idx = bgfx::invalidHandle; + m_ibh.idx = bgfx::invalidHandle; + m_dvbh.idx = bgfx::invalidHandle; + m_dibh.idx = bgfx::invalidHandle; + m_heightTexture.idx = bgfx::invalidHandle; + s_heightTexture = bgfx::createUniform("s_heightTexture", bgfx::UniformType::Int1); - m_scrollArea = 0; + m_oldWidth = 0; + m_oldHeight = 0; + m_oldReset = m_reset; - m_brush.m_power = 0.5f; - m_brush.m_size = 10; - m_brush.m_raise = true; + m_scrollArea = 0; + + m_brush.m_power = 0.5f; + m_brush.m_size = 10; + m_brush.m_raise = true; m_terrain.m_mode = 0; - m_terrain.m_dirty = true; - m_terrain.m_vertices = new PosTexCoord0Vertex[s_terrainSize * s_terrainSize]; - m_terrain.m_indices = new uint16_t[s_terrainSize * s_terrainSize * 6]; - m_terrain.m_heightMap = new uint8_t[s_terrainSize * s_terrainSize]; - - bx::mtxSRT(m_terrain.m_transform, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); - memset(m_terrain.m_heightMap, 0, sizeof(uint8_t) * s_terrainSize * s_terrainSize); - - cameraCreate(); - - const float initialPos[3] = { 0.0f, 15.0f, 0.0f }; - cameraSetPosition(initialPos); - cameraSetVerticalAngle(0.0f); - } - - virtual int shutdown() BX_OVERRIDE - { - // Cleanup. - cameraDestroy(); - imguiDestroy(); - - if (bgfx::isValid(m_ibh)) - bgfx::destroyIndexBuffer(m_ibh); - if (bgfx::isValid(m_vbh)) - bgfx::destroyVertexBuffer(m_vbh); - - if (bgfx::isValid(m_dibh)) - bgfx::destroyDynamicIndexBuffer(m_dibh); - if (bgfx::isValid(m_dvbh)) - bgfx::destroyDynamicVertexBuffer(m_dvbh); - - bgfx::destroyUniform(s_heightTexture); - if (bgfx::isValid(m_heightTexture)) - bgfx::destroyTexture(m_heightTexture); - - bgfx::destroyProgram(m_terrainProgram); - bgfx::destroyProgram(m_terrainHeightTextureProgram); - - delete[] m_terrain.m_vertices; - delete[] m_terrain.m_indices; - delete[] m_terrain.m_heightMap; - - // Shutdown bgfx. - bgfx::shutdown(); - - return 0; - } - - void updateTerrainMesh() - { - m_terrain.m_vertexCount = 0; - for (uint32_t y = 0; y < s_terrainSize; y++) - { - for (uint32_t x = 0; x < s_terrainSize; x++) - { - PosTexCoord0Vertex* vert = &m_terrain.m_vertices[m_terrain.m_vertexCount]; - vert->m_x = (float)x; - vert->m_y = m_terrain.m_heightMap[(y * s_terrainSize) + x]; - vert->m_z = (float)y; - vert->m_u = (float)x / (float)s_terrainSize; - vert->m_v = (float)y / (float)s_terrainSize; - - m_terrain.m_vertexCount++; - } - } - - m_terrain.m_indexCount = 0; - for (uint32_t y = 0; y < (s_terrainSize - 1); y++) - { - uint32_t y_offset = (y * s_terrainSize); - for (uint32_t x = 0; x < (s_terrainSize - 1); x++) - { - m_terrain.m_indices[m_terrain.m_indexCount] = y_offset + x + 1; - m_terrain.m_indices[m_terrain.m_indexCount + 1] = y_offset + x + s_terrainSize; - m_terrain.m_indices[m_terrain.m_indexCount + 2] = y_offset + x; - m_terrain.m_indices[m_terrain.m_indexCount + 3] = y_offset + x + s_terrainSize + 1; - m_terrain.m_indices[m_terrain.m_indexCount + 4] = y_offset + x + s_terrainSize; - m_terrain.m_indices[m_terrain.m_indexCount + 5] = y_offset + x + 1; - - m_terrain.m_indexCount += 6; - } - } - } - - void updateTerrain() - { - const bgfx::Memory* mem; - - // Vertex Buffer : Destroy and recreate a regular vertex buffer to update terrain. - if (m_terrain.m_mode == 0) - { - updateTerrainMesh(); - - if (bgfx::isValid(m_vbh)) - bgfx::destroyVertexBuffer(m_vbh); - - mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); - m_vbh = bgfx::createVertexBuffer(mem, PosTexCoord0Vertex::ms_decl); - - if (bgfx::isValid(m_ibh)) - bgfx::destroyIndexBuffer(m_ibh); - - mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); - m_ibh = bgfx::createIndexBuffer(mem); - } - - // Dynamic Vertex Buffer : Utilize dynamic vertex buffer to update terrain. - if (m_terrain.m_mode == 1) - { - updateTerrainMesh(); - - if (!bgfx::isValid(m_dvbh)) - m_dvbh = bgfx::createDynamicVertexBuffer(m_terrain.m_vertexCount, PosTexCoord0Vertex::ms_decl); - - mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); - bgfx::updateDynamicVertexBuffer(m_dvbh, 0, mem); - - if (!bgfx::isValid(m_dibh)) - m_dibh = bgfx::createDynamicIndexBuffer(m_terrain.m_indexCount); - - mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); - bgfx::updateDynamicIndexBuffer(m_dibh, 0, mem); - } - - // Height Texture: Update a height texture that is sampled in the terrain vertex shader. - if (m_terrain.m_mode == 2) - { - if (!bgfx::isValid(m_vbh) || !bgfx::isValid(m_ibh)) - { - updateTerrainMesh(); - - mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); - m_vbh = bgfx::createVertexBuffer(mem, PosTexCoord0Vertex::ms_decl); - - mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); - m_ibh = bgfx::createIndexBuffer(mem); - } - - if (!bgfx::isValid(m_heightTexture)) - m_heightTexture = bgfx::createTexture2D(s_terrainSize, s_terrainSize, 1, bgfx::TextureFormat::R8); - - mem = bgfx::makeRef(&m_terrain.m_heightMap[0], sizeof(uint8_t) * s_terrainSize * s_terrainSize); - bgfx::updateTexture2D(m_heightTexture, 0, 0, 0, s_terrainSize, s_terrainSize, mem); - } - } - - void paintTerrainHeight(uint32_t _x, uint32_t _y) - { - for (int32_t area_y = -m_brush.m_size; area_y < m_brush.m_size; ++area_y) - { - for (int32_t area_x = -m_brush.m_size; area_x < m_brush.m_size; ++area_x) - { - int32_t brush_x = _x + area_x; - if (brush_x < 0 || brush_x > (int32_t)s_terrainSize) continue; - int32_t brush_y = _y + area_y; - if (brush_y < 0 || brush_y > (int32_t)s_terrainSize) continue; - - uint32_t heightMapPos = (brush_y * s_terrainSize) + brush_x; - float height = (float)m_terrain.m_heightMap[heightMapPos]; - - // Brush attenuation - float a2 = (float)(area_x * area_x); - float b2 = (float)(area_y * area_y); - float brushAttn = m_brush.m_size - sqrtf(a2 + b2); - - // Raise/Lower and scale by brush power. - height += bx::fclamp(brushAttn * m_brush.m_power, 0.0, m_brush.m_power) * m_brush.m_raise ? 1.0 : -1.0; - - m_terrain.m_heightMap[heightMapPos] = (uint8_t)bx::fclamp(height, 0.0, 255.0); - m_terrain.m_dirty = true; - } - } - } - - void mousePickTerrain() - { - float ray_clip[4]; - ray_clip[0] = ((2.0f * m_mouseState.m_mx) / m_width - 1.0f) * -1.0f; - ray_clip[1] = ((1.0f - (2.0f * m_mouseState.m_my) / m_height)) * -1.0f; - ray_clip[2] = -1.0; - ray_clip[3] = 1.0; - - float invProjMtx[16]; - bx::mtxInverse(invProjMtx, m_projMtx); - - float ray_eye[4]; - bx::vec4MulMtx(ray_eye, ray_clip, invProjMtx); - ray_eye[2] = -1.0f; - ray_eye[3] = 0.0f; - - float invViewMtx[16]; - bx::mtxInverse(invViewMtx, m_viewMtx); - - float ray_world[4]; - bx::vec4MulMtx(ray_world, ray_eye, invViewMtx); - - float ray_dir[3]; - bx::vec3Norm(ray_dir, ray_world); - ray_dir[0] *= -1.0; - ray_dir[1] *= -1.0; - ray_dir[2] *= -1.0; - - float pos[3]; - cameraGetPosition(pos); - for (int i = 0; i < 1000; ++i) - { - bx::vec3Add(pos, pos, ray_dir); - - if (pos[0] < 0 || pos[0] > s_terrainSize || pos[2] < 0 || pos[2] > s_terrainSize) - continue; - - uint32_t heightMapPos = ((uint32_t)pos[2] * s_terrainSize) + (uint32_t)pos[0]; - if ( pos[1] < m_terrain.m_heightMap[heightMapPos] ) - { - paintTerrainHeight((uint32_t)pos[0], (uint32_t)pos[2]); - return; - } - } - } - - bool update() BX_OVERRIDE - { - if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) ) - { - 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; - const float deltaTime = float(frameTime/freq); - - // Use m_debug font to print information about this example. - bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/27-terrain"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Terrain painting example."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); - - 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 - , m_width - , m_height - ); - - imguiBeginScrollArea("Settings", m_width - m_width / 5 - 10, 10, m_width / 5, m_height / 3, &m_scrollArea); - imguiSeparatorLine(); - - if (imguiCheck("Vertex Buffer", (m_terrain.m_mode == 0)) ) - { - m_terrain.m_mode = 0; - m_terrain.m_dirty = true; - } - - if (imguiCheck("Dynamic Vertex Buffer", (m_terrain.m_mode == 1)) ) - { - m_terrain.m_mode = 1; - m_terrain.m_dirty = true; - } - - if (imguiCheck("Height Texture", (m_terrain.m_mode == 2)) ) - { - m_terrain.m_mode = 2; - m_terrain.m_dirty = true; - } - - imguiSeparatorLine(); - - if (imguiCheck("Raise Terrain", m_brush.m_raise)) - { - m_brush.m_raise = !m_brush.m_raise; - } - - imguiSlider("Brush Size", m_brush.m_size, 1, 50); - imguiSlider("Brush Power", m_brush.m_power, 0.0f, 1.0f, 0.01f); - - imguiEndScrollArea(); - imguiEndFrame(); - - // Update camera. - cameraUpdate(deltaTime, m_mouseState); - - bool leftMouseButtonDown = !!m_mouseState.m_buttons[entry::MouseButton::Left]; - if (leftMouseButtonDown) - { - mousePickTerrain(); - } - - // Update terrain. - if (m_terrain.m_dirty) - { - updateTerrain(); - m_terrain.m_dirty = false; - } - - // Set view 0 default viewport. - bgfx::setViewRect(0, 0, 0, m_width, m_height); - - cameraGetViewMtx(m_viewMtx); - bx::mtxProj(m_projMtx, 60.0f, float(m_width) / float(m_height), 0.1f, 2000.0f, s_originBottomLeft); - - bgfx::setViewTransform(0, m_viewMtx, m_projMtx); - bgfx::setTransform(m_terrain.m_transform); - - if (m_terrain.m_mode == 0) - { - bgfx::setVertexBuffer(m_vbh); - bgfx::setIndexBuffer(m_ibh); - bgfx::submit(0, m_terrainProgram); - } - else if (m_terrain.m_mode == 1) - { - bgfx::setVertexBuffer(m_dvbh); - bgfx::setIndexBuffer(m_dibh); - bgfx::submit(0, m_terrainProgram); - } - else if (m_terrain.m_mode == 2) - { - bgfx::setVertexBuffer(m_vbh); - bgfx::setIndexBuffer(m_ibh); - bgfx::setTexture(0, s_heightTexture, m_heightTexture); - bgfx::submit(0, m_terrainHeightTextureProgram); - } - - // Advance to next frame. Rendering thread will be kicked to - // process submitted rendering primitives. - bgfx::frame(); - - return true; - } - - return false; - } - - bgfx::VertexBufferHandle m_vbh; - bgfx::IndexBufferHandle m_ibh; - bgfx::DynamicVertexBufferHandle m_dvbh; - bgfx::DynamicIndexBufferHandle m_dibh; - bgfx::ProgramHandle m_terrainProgram; - bgfx::ProgramHandle m_terrainHeightTextureProgram; - bgfx::UniformHandle s_heightTexture; - bgfx::TextureHandle m_heightTexture; - - float m_viewMtx[16]; - float m_projMtx[16]; - - uint32_t m_width; - uint32_t m_height; - uint32_t m_debug; - uint32_t m_reset; - - uint32_t m_oldWidth; - uint32_t m_oldHeight; - uint32_t m_oldReset; - - int32_t m_scrollArea; - - TerrainData m_terrain; - BrushData m_brush; - - entry::MouseState m_mouseState; - - int64_t m_timeOffset; + m_terrain.m_dirty = true; + m_terrain.m_vertices = new PosTexCoord0Vertex[s_terrainSize * s_terrainSize]; + m_terrain.m_indices = new uint16_t[s_terrainSize * s_terrainSize * 6]; + m_terrain.m_heightMap = new uint8_t[s_terrainSize * s_terrainSize]; + + bx::mtxSRT(m_terrain.m_transform, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + memset(m_terrain.m_heightMap, 0, sizeof(uint8_t) * s_terrainSize * s_terrainSize); + + cameraCreate(); + + const float initialPos[3] = { 0.0f, 15.0f, 0.0f }; + cameraSetPosition(initialPos); + cameraSetVerticalAngle(0.0f); + } + + virtual int shutdown() BX_OVERRIDE + { + // Cleanup. + cameraDestroy(); + imguiDestroy(); + + if (bgfx::isValid(m_ibh) ) + { + bgfx::destroyIndexBuffer(m_ibh); + } + + if (bgfx::isValid(m_vbh) ) + { + bgfx::destroyVertexBuffer(m_vbh); + } + + if (bgfx::isValid(m_dibh) ) + { + bgfx::destroyDynamicIndexBuffer(m_dibh); + } + + if (bgfx::isValid(m_dvbh) ) + { + bgfx::destroyDynamicVertexBuffer(m_dvbh); + } + + bgfx::destroyUniform(s_heightTexture); + if (bgfx::isValid(m_heightTexture) ) + { + bgfx::destroyTexture(m_heightTexture); + } + + bgfx::destroyProgram(m_terrainProgram); + bgfx::destroyProgram(m_terrainHeightTextureProgram); + + delete[] m_terrain.m_vertices; + delete[] m_terrain.m_indices; + delete[] m_terrain.m_heightMap; + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; + } + + void updateTerrainMesh() + { + m_terrain.m_vertexCount = 0; + for (uint32_t y = 0; y < s_terrainSize; y++) + { + for (uint32_t x = 0; x < s_terrainSize; x++) + { + PosTexCoord0Vertex* vert = &m_terrain.m_vertices[m_terrain.m_vertexCount]; + vert->m_x = (float)x; + vert->m_y = m_terrain.m_heightMap[(y * s_terrainSize) + x]; + vert->m_z = (float)y; + vert->m_u = (float)x / (float)s_terrainSize; + vert->m_v = (float)y / (float)s_terrainSize; + + m_terrain.m_vertexCount++; + } + } + + m_terrain.m_indexCount = 0; + for (uint32_t y = 0; y < (s_terrainSize - 1); y++) + { + uint32_t y_offset = (y * s_terrainSize); + for (uint32_t x = 0; x < (s_terrainSize - 1); x++) + { + m_terrain.m_indices[m_terrain.m_indexCount + 0] = y_offset + x + 1; + m_terrain.m_indices[m_terrain.m_indexCount + 1] = y_offset + x + s_terrainSize; + m_terrain.m_indices[m_terrain.m_indexCount + 2] = y_offset + x; + m_terrain.m_indices[m_terrain.m_indexCount + 3] = y_offset + x + s_terrainSize + 1; + m_terrain.m_indices[m_terrain.m_indexCount + 4] = y_offset + x + s_terrainSize; + m_terrain.m_indices[m_terrain.m_indexCount + 5] = y_offset + x + 1; + + m_terrain.m_indexCount += 6; + } + } + } + + void updateTerrain() + { + const bgfx::Memory* mem; + + // Vertex Buffer : Destroy and recreate a regular vertex buffer to update terrain. + if (m_terrain.m_mode == 0) + { + updateTerrainMesh(); + + if (bgfx::isValid(m_vbh) ) + { + bgfx::destroyVertexBuffer(m_vbh); + } + + mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); + m_vbh = bgfx::createVertexBuffer(mem, PosTexCoord0Vertex::ms_decl); + + if (bgfx::isValid(m_ibh) ) + { + bgfx::destroyIndexBuffer(m_ibh); + } + + mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); + m_ibh = bgfx::createIndexBuffer(mem); + } + + // Dynamic Vertex Buffer : Utilize dynamic vertex buffer to update terrain. + if (m_terrain.m_mode == 1) + { + updateTerrainMesh(); + + if (!bgfx::isValid(m_dvbh) ) + { + m_dvbh = bgfx::createDynamicVertexBuffer(m_terrain.m_vertexCount, PosTexCoord0Vertex::ms_decl); + } + + mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); + bgfx::updateDynamicVertexBuffer(m_dvbh, 0, mem); + + if (!bgfx::isValid(m_dibh) ) + { + m_dibh = bgfx::createDynamicIndexBuffer(m_terrain.m_indexCount); + } + + mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); + bgfx::updateDynamicIndexBuffer(m_dibh, 0, mem); + } + + // Height Texture: Update a height texture that is sampled in the terrain vertex shader. + if (m_terrain.m_mode == 2) + { + if (!bgfx::isValid(m_vbh) || !bgfx::isValid(m_ibh) ) + { + updateTerrainMesh(); + + mem = bgfx::makeRef(&m_terrain.m_vertices[0], sizeof(PosTexCoord0Vertex) * m_terrain.m_vertexCount); + m_vbh = bgfx::createVertexBuffer(mem, PosTexCoord0Vertex::ms_decl); + + mem = bgfx::makeRef(&m_terrain.m_indices[0], sizeof(uint16_t) * m_terrain.m_indexCount); + m_ibh = bgfx::createIndexBuffer(mem); + } + + if (!bgfx::isValid(m_heightTexture) ) + { + m_heightTexture = bgfx::createTexture2D(s_terrainSize, s_terrainSize, 1, bgfx::TextureFormat::R8); + } + + mem = bgfx::makeRef(&m_terrain.m_heightMap[0], sizeof(uint8_t) * s_terrainSize * s_terrainSize); + bgfx::updateTexture2D(m_heightTexture, 0, 0, 0, s_terrainSize, s_terrainSize, mem); + } + } + + void paintTerrainHeight(uint32_t _x, uint32_t _y) + { + for (int32_t area_y = -m_brush.m_size; area_y < m_brush.m_size; ++area_y) + { + for (int32_t area_x = -m_brush.m_size; area_x < m_brush.m_size; ++area_x) + { + int32_t brush_x = _x + area_x; + if (brush_x < 0 + || brush_x > (int32_t)s_terrainSize) + { + continue; + } + + int32_t brush_y = _y + area_y; + if (brush_y < 0 + || brush_y > (int32_t)s_terrainSize) + { + continue; + } + + uint32_t heightMapPos = (brush_y * s_terrainSize) + brush_x; + float height = (float)m_terrain.m_heightMap[heightMapPos]; + + // Brush attenuation + float a2 = (float)(area_x * area_x); + float b2 = (float)(area_y * area_y); + float brushAttn = m_brush.m_size - sqrtf(a2 + b2); + + // Raise/Lower and scale by brush power. + height += bx::fclamp(brushAttn * m_brush.m_power, 0.0, m_brush.m_power) * m_brush.m_raise ? 1.0 : -1.0; + + m_terrain.m_heightMap[heightMapPos] = (uint8_t)bx::fclamp(height, 0.0, 255.0); + m_terrain.m_dirty = true; + } + } + } + + void mousePickTerrain() + { + float ray_clip[4]; + ray_clip[0] = ( (2.0f * m_mouseState.m_mx) / m_width - 1.0f) * -1.0f; + ray_clip[1] = ( (1.0f - (2.0f * m_mouseState.m_my) / m_height) ) * -1.0f; + ray_clip[2] = -1.0; + ray_clip[3] = 1.0; + + float invProjMtx[16]; + bx::mtxInverse(invProjMtx, m_projMtx); + + float ray_eye[4]; + bx::vec4MulMtx(ray_eye, ray_clip, invProjMtx); + ray_eye[2] = -1.0f; + ray_eye[3] = 0.0f; + + float invViewMtx[16]; + bx::mtxInverse(invViewMtx, m_viewMtx); + + float ray_world[4]; + bx::vec4MulMtx(ray_world, ray_eye, invViewMtx); + + float ray_dir[3]; + bx::vec3Norm(ray_dir, ray_world); + ray_dir[0] *= -1.0; + ray_dir[1] *= -1.0; + ray_dir[2] *= -1.0; + + float pos[3]; + cameraGetPosition(pos); + for (int i = 0; i < 1000; ++i) + { + bx::vec3Add(pos, pos, ray_dir); + + if (pos[0] < 0 + || pos[0] > s_terrainSize + || pos[2] < 0 + || pos[2] > s_terrainSize) + { + continue; + } + + uint32_t heightMapPos = ( (uint32_t)pos[2] * s_terrainSize) + (uint32_t)pos[0]; + if ( pos[1] < m_terrain.m_heightMap[heightMapPos] ) + { + paintTerrainHeight( (uint32_t)pos[0], (uint32_t)pos[2]); + return; + } + } + } + + bool update() BX_OVERRIDE + { + if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) ) + { + 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; + const float deltaTime = float(frameTime/freq); + + // Use m_debug font to print information about this example. + bgfx::dbgTextClear(); + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/27-terrain"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Terrain painting example."); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + + 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 + , m_width + , m_height + ); + + imguiBeginScrollArea("Settings", m_width - m_width / 5 - 10, 10, m_width / 5, m_height / 3, &m_scrollArea); + imguiSeparatorLine(); + + if (imguiCheck("Vertex Buffer", (m_terrain.m_mode == 0) ) ) + { + m_terrain.m_mode = 0; + m_terrain.m_dirty = true; + } + + if (imguiCheck("Dynamic Vertex Buffer", (m_terrain.m_mode == 1) ) ) + { + m_terrain.m_mode = 1; + m_terrain.m_dirty = true; + } + + if (imguiCheck("Height Texture", (m_terrain.m_mode == 2) ) ) + { + m_terrain.m_mode = 2; + m_terrain.m_dirty = true; + } + + imguiSeparatorLine(); + + if (imguiCheck("Raise Terrain", m_brush.m_raise) ) + { + m_brush.m_raise = !m_brush.m_raise; + } + + imguiSlider("Brush Size", m_brush.m_size, 1, 50); + imguiSlider("Brush Power", m_brush.m_power, 0.0f, 1.0f, 0.01f); + + imguiEndScrollArea(); + imguiEndFrame(); + + // Update camera. + cameraUpdate(deltaTime, m_mouseState); + + bool leftMouseButtonDown = !!m_mouseState.m_buttons[entry::MouseButton::Left]; + if (leftMouseButtonDown) + { + mousePickTerrain(); + } + + // Update terrain. + if (m_terrain.m_dirty) + { + updateTerrain(); + m_terrain.m_dirty = false; + } + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, m_width, m_height); + + cameraGetViewMtx(m_viewMtx); + bx::mtxProj(m_projMtx, 60.0f, float(m_width) / float(m_height), 0.1f, 2000.0f, s_originBottomLeft); + + bgfx::setViewTransform(0, m_viewMtx, m_projMtx); + bgfx::setTransform(m_terrain.m_transform); + + if (m_terrain.m_mode == 0) + { + bgfx::setVertexBuffer(m_vbh); + bgfx::setIndexBuffer(m_ibh); + bgfx::submit(0, m_terrainProgram); + } + else if (m_terrain.m_mode == 1) + { + bgfx::setVertexBuffer(m_dvbh); + bgfx::setIndexBuffer(m_dibh); + bgfx::submit(0, m_terrainProgram); + } + else if (m_terrain.m_mode == 2) + { + bgfx::setVertexBuffer(m_vbh); + bgfx::setIndexBuffer(m_ibh); + bgfx::setTexture(0, s_heightTexture, m_heightTexture); + bgfx::submit(0, m_terrainHeightTextureProgram); + } + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + + return true; + } + + return false; + } + + bgfx::VertexBufferHandle m_vbh; + bgfx::IndexBufferHandle m_ibh; + bgfx::DynamicVertexBufferHandle m_dvbh; + bgfx::DynamicIndexBufferHandle m_dibh; + bgfx::ProgramHandle m_terrainProgram; + bgfx::ProgramHandle m_terrainHeightTextureProgram; + bgfx::UniformHandle s_heightTexture; + bgfx::TextureHandle m_heightTexture; + + float m_viewMtx[16]; + float m_projMtx[16]; + + uint32_t m_width; + uint32_t m_height; + uint32_t m_debug; + uint32_t m_reset; + + uint32_t m_oldWidth; + uint32_t m_oldHeight; + uint32_t m_oldReset; + + int32_t m_scrollArea; + + TerrainData m_terrain; + BrushData m_brush; + + entry::MouseState m_mouseState; + + int64_t m_timeOffset; }; ENTRY_IMPLEMENT_MAIN(Terrain); diff --git a/examples/27-terrain/vs_terrain.sc b/examples/27-terrain/vs_terrain.sc index 0adcaa2e..826ca608 100644 --- a/examples/27-terrain/vs_terrain.sc +++ b/examples/27-terrain/vs_terrain.sc @@ -10,8 +10,8 @@ $output v_position, v_texcoord0 void main() { - v_position = a_position.xyz; - v_texcoord0 = a_texcoord0; - - gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0)); + v_position = a_position.xyz; + v_texcoord0 = a_texcoord0; + + gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0)); } diff --git a/examples/27-terrain/vs_terrain_height_texture.sc b/examples/27-terrain/vs_terrain_height_texture.sc index 559a115c..4609b0fb 100644 --- a/examples/27-terrain/vs_terrain_height_texture.sc +++ b/examples/27-terrain/vs_terrain_height_texture.sc @@ -12,9 +12,9 @@ SAMPLER2D(s_heightTexture, 0); void main() { - v_texcoord0 = a_texcoord0; - v_position = a_position.xyz; - v_position.y = texture2DLod(s_heightTexture, a_texcoord0, 0).x * 255.0; + v_texcoord0 = a_texcoord0; + v_position = a_position.xyz; + v_position.y = texture2DLod(s_heightTexture, a_texcoord0, 0).x * 255.0; - gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0)); + gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0)); }