|
|
@@ -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;
|
|
|
-
|
|
|
- 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;
|
|
|
+ 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 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;
|
|
|
-
|
|
|
- PosTexCoord0Vertex* m_vertices;
|
|
|
- uint32_t m_vertexCount;
|
|
|
- uint16_t* m_indices;
|
|
|
- uint32_t m_indexCount;
|
|
|
+ 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;
|
|
|
};
|
|
|
|
|
|
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;
|
|
|
-
|
|
|
- bgfx::init(bgfx::RendererType::Direct3D11, args.m_pciId);
|
|
|
- bgfx::reset(m_width, m_height, m_reset);
|
|
|
-
|
|
|
- // Enable m_debug text.
|
|
|
- bgfx::setDebug(m_debug);
|
|
|
-
|
|
|
- // Set view 0 clear state.
|
|
|
- bgfx::setViewClear(0
|
|
|
- , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
|
|
|
- , 0x303030ff
|
|
|
- , 1.0f
|
|
|
- , 0
|
|
|
- );
|
|
|
-
|
|
|
- // Create vertex stream declaration.
|
|
|
- PosTexCoord0Vertex::init();
|
|
|
-
|
|
|
- // Create program from shaders.
|
|
|
- m_terrainProgram = loadProgram("vs_terrain", "fs_terrain");
|
|
|
- m_terrainHeightTextureProgram = loadProgram("vs_terrain_height_texture", "fs_terrain");
|
|
|
-
|
|
|
- // Imgui.
|
|
|
- imguiCreate();
|
|
|
-
|
|
|
- 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_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_oldWidth = 0;
|
|
|
- m_oldHeight = 0;
|
|
|
- m_oldReset = m_reset;
|
|
|
-
|
|
|
- m_scrollArea = 0;
|
|
|
-
|
|
|
- m_brush.m_power = 0.5f;
|
|
|
- m_brush.m_size = 10;
|
|
|
- m_brush.m_raise = true;
|
|
|
+ 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;
|
|
|
+
|
|
|
+ bgfx::init(bgfx::RendererType::Direct3D11, args.m_pciId);
|
|
|
+ bgfx::reset(m_width, m_height, m_reset);
|
|
|
+
|
|
|
+ // Enable m_debug text.
|
|
|
+ bgfx::setDebug(m_debug);
|
|
|
+
|
|
|
+ // Set view 0 clear state.
|
|
|
+ bgfx::setViewClear(0
|
|
|
+ , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
|
|
|
+ , 0x303030ff
|
|
|
+ , 1.0f
|
|
|
+ , 0
|
|
|
+ );
|
|
|
+
|
|
|
+ // Create vertex stream declaration.
|
|
|
+ PosTexCoord0Vertex::init();
|
|
|
+
|
|
|
+ // Create program from shaders.
|
|
|
+ m_terrainProgram = loadProgram("vs_terrain", "fs_terrain");
|
|
|
+ m_terrainHeightTextureProgram = loadProgram("vs_terrain_height_texture", "fs_terrain");
|
|
|
+
|
|
|
+ // Imgui.
|
|
|
+ imguiCreate();
|
|
|
+
|
|
|
+ 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_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_oldWidth = 0;
|
|
|
+ m_oldHeight = 0;
|
|
|
+ m_oldReset = m_reset;
|
|
|
+
|
|
|
+ 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);
|