This commit is contained in:
Branimir Karadžić 2015-12-13 09:48:21 -08:00
parent 7c24a058ff
commit 8493775a8b
4 changed files with 479 additions and 443 deletions

View file

@ -9,5 +9,5 @@ $input v_position, v_texcoord0
void main() 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);
} }

View file

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

View file

@ -10,8 +10,8 @@ $output v_position, v_texcoord0
void main() void main()
{ {
v_position = a_position.xyz; v_position = a_position.xyz;
v_texcoord0 = a_texcoord0; v_texcoord0 = a_texcoord0;
gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0)); gl_Position = mul(u_modelViewProj, vec4(v_position.xyz, 1.0));
} }

View file

@ -12,9 +12,9 @@ SAMPLER2D(s_heightTexture, 0);
void main() void main()
{ {
v_texcoord0 = a_texcoord0; v_texcoord0 = a_texcoord0;
v_position = a_position.xyz; v_position = a_position.xyz;
v_position.y = texture2DLod(s_heightTexture, a_texcoord0, 0).x * 255.0; 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));
} }