commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
264
include/engine/gpu/gpu_terrain.cpp
Normal file
264
include/engine/gpu/gpu_terrain.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "gpu/gpu_renderer.h"
|
||||
#include "core/terrain.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::GPU;
|
||||
|
||||
// Terrain patch size.
|
||||
#define _PatchSize 64
|
||||
// Terrain page count.
|
||||
#if __PLATFORM_ANDROID_NDK__ || __PLATFORM_IOS__
|
||||
#define _PageCount 4
|
||||
#else
|
||||
#define _PageCount 32
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Renderer::CreateTerrainPatch()
|
||||
{
|
||||
// Allocate terrain cache.
|
||||
if (!terrain_patch_cache.Allocate(_PageCount))
|
||||
__ERR__(__LOG_E__ << "Failed to allocate terrain cache.\n", false)
|
||||
|
||||
// Compute page stride.
|
||||
size_t stride = 0;
|
||||
|
||||
size_t vertex_offset = stride;
|
||||
stride += 3 * 4; // Vertex buffer (3x float).
|
||||
size_t normal_offset = stride;
|
||||
stride += (3 + 1) * 1; // Normal buffer (3x byte + 1 padding).
|
||||
size_t uv_offset = stride;
|
||||
stride += 2 * 4; // Large UV (2x float).
|
||||
|
||||
// Setup default page layout.
|
||||
size_t byte_size = stride * (_PatchSize + 1) * (_PatchSize + 1);
|
||||
|
||||
__LOG_H__ << "Setup terrain cache: " << terrain_patch_cache.GetCount() << " pages (" << uint(byte_size * terrain_patch_cache.GetCount()) << " bytes).\n";
|
||||
|
||||
terrain_patch_vtx.Allocate((uint)byte_size);
|
||||
if (char *p = terrain_patch_vtx)
|
||||
{
|
||||
Vector4 wp(0, 0, 0);
|
||||
for (int v = 0; v < (_PatchSize + 1); ++v)
|
||||
{
|
||||
for (int u = 0; u < (_PatchSize + 1); ++u)
|
||||
{
|
||||
float *pv = (float *)p;
|
||||
pv[0] = wp.x; pv[1] = 0; pv[2] = wp.z;
|
||||
|
||||
p += stride;
|
||||
wp.x += 1.f;
|
||||
}
|
||||
wp.x = 0.f;
|
||||
wp.z += 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate pages.
|
||||
for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n)
|
||||
{
|
||||
DisplayList *patch = terrain_patch_cache[n].patch = NewDisplayList();
|
||||
|
||||
// Create the patch index buffer.
|
||||
patch->idx = NewVBO();
|
||||
|
||||
if (patch->idx->Create(6 * _PatchSize * _PatchSize * sizeof(ushort), VBO::Index, VBO::Static))
|
||||
{
|
||||
SetIndexSource(patch->idx);
|
||||
if (ushort *p_idx = (ushort *)patch->idx->Map())
|
||||
{
|
||||
for (int v = 0; v < _PatchSize; ++v)
|
||||
for (int u = 0; u < _PatchSize; ++u)
|
||||
{
|
||||
*p_idx++ = (ushort)(u + v * (_PatchSize + 1));
|
||||
*p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1) + 1);
|
||||
*p_idx++ = (ushort)(u + v * (_PatchSize + 1) + 1);
|
||||
*p_idx++ = (ushort)(u + v * (_PatchSize + 1));
|
||||
*p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1));
|
||||
*p_idx++ = (ushort)(u + (v + 1) * (_PatchSize + 1) + 1);
|
||||
}
|
||||
|
||||
patch->idx->Unmap();
|
||||
patch->index_count = 6 * _PatchSize * _PatchSize;
|
||||
}
|
||||
SetIndexSource(NULL);
|
||||
}
|
||||
|
||||
// Create the patch vertex buffer.
|
||||
patch->vertex_offset = vertex_offset;
|
||||
patch->normal_offset = normal_offset;
|
||||
patch->uv_offset[0] = uv_offset;
|
||||
patch->stride = stride;
|
||||
|
||||
patch->vtx = NewVBO();
|
||||
if (patch->vtx->Create(byte_size, VBO::Vertex, VBO::Dynamic))
|
||||
{
|
||||
SetVertexSource(patch->vtx, patch->stride);
|
||||
patch->vtx->Update(terrain_patch_vtx);
|
||||
SetVertexSource(NULL, 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Renderer::InvalidateTerrainCache(int, int, int, int)
|
||||
{
|
||||
// Very naive invalidation that ignores the input region.
|
||||
for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n)
|
||||
terrain_patch_cache[n].terrain = NULL;
|
||||
}
|
||||
void Renderer::DecayTerrainCache()
|
||||
{
|
||||
for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n)
|
||||
if (terrain_patch_cache[n].score > 0)
|
||||
--terrain_patch_cache[n].score;
|
||||
}
|
||||
void Renderer::UploadTerrainPatchToPage(CachedTerrainPatch &page, const GS::Core::Item &item, const GS::Core::Patch &patch, const DrawContext &dc)
|
||||
{
|
||||
if (!patch.terrain || !page.patch)
|
||||
return;
|
||||
|
||||
Core::Terrain &terrain = *patch.terrain;
|
||||
DisplayList &terrain_patch = *page.patch;
|
||||
|
||||
float pixel_size = terrain.GetUnit();
|
||||
Vector4 patch_scale(pixel_size * patch.decimation, 1, pixel_size * patch.decimation);
|
||||
|
||||
#if 1
|
||||
|
||||
// Update patch CPU-side data.
|
||||
Core::Terrain::Attrib *psa = terrain.GetAttributesMap() + patch.v * terrain.GetHeightmapPitch() + patch.u;
|
||||
float *psh = terrain.GetHeightmap() + patch.v * terrain.GetHeightmapPitch() + patch.u;
|
||||
|
||||
char *p = terrain_patch_vtx;
|
||||
|
||||
Vector4 uv(0, 0, patch.v * pixel_size);
|
||||
for (int v = 0; v < (_PatchSize + 1); ++v)
|
||||
{
|
||||
uv.x = patch.u * pixel_size;
|
||||
|
||||
Core::Terrain::Attrib *pa = psa;
|
||||
float *ph = psh;
|
||||
|
||||
for (int u = 0; u < (_PatchSize + 1); ++u)
|
||||
{
|
||||
// Vertex.
|
||||
float *pv = (float *)(p + terrain_patch.vertex_offset);
|
||||
pv[1] = ph[0];
|
||||
|
||||
// Normal.
|
||||
char *pn = (char *)(p + terrain_patch.normal_offset);
|
||||
pn[0] = pa[0].nx;
|
||||
pn[1] = pa[0].ny;
|
||||
pn[2] = pa[0].nz;
|
||||
|
||||
// UV.
|
||||
float *pu = (float *)(p + terrain_patch.uv_offset[0]);
|
||||
pu[0] = uv.x / terrain.GetWidth();
|
||||
uv.x += patch_scale.x;
|
||||
pu[1] = uv.z / terrain.GetDepth();
|
||||
|
||||
p += terrain_patch.stride;
|
||||
|
||||
pa += patch.decimation;
|
||||
ph += patch.decimation;
|
||||
}
|
||||
|
||||
uv.z += patch_scale.z;
|
||||
|
||||
psa += terrain.GetHeightmapPitch() * patch.decimation;
|
||||
psh += terrain.GetHeightmapPitch() * patch.decimation;
|
||||
}
|
||||
|
||||
// Update VBO.
|
||||
SetVertexSource(terrain_patch.vtx, terrain_patch.stride);
|
||||
terrain_patch.vtx->Update(terrain_patch_vtx);
|
||||
|
||||
// [EJ 9 Mar] the display list cache MUST be reset here otherwise an invalid
|
||||
// VBO reference will be used by the next draw calls for this patch.
|
||||
dls_cache.dls = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
// Synchronize cache.
|
||||
page.terrain = patch.terrain;
|
||||
page.u = patch.u; page.v = patch.v;
|
||||
page.w = patch.w; page.h = patch.h;
|
||||
page.decimation = patch.decimation;
|
||||
}
|
||||
void Renderer::RenderTerrainPatch(const GS::Core::Patch &patch, const GS::Core::Item &item, const DrawContext &dc)
|
||||
{
|
||||
// Cache query.
|
||||
++gpu_stats.terrain_page_query_count;
|
||||
|
||||
DisplayList *dlist = NULL;
|
||||
CachedTerrainPatch *page = NULL;
|
||||
uint lowest_score = (uint)~0;
|
||||
|
||||
for (uint n = 0; n < terrain_patch_cache.GetCount(); ++n)
|
||||
if (CachedTerrainPatch *c_page = &terrain_patch_cache[n])
|
||||
{
|
||||
if (
|
||||
(c_page->terrain == patch.terrain) &&
|
||||
(c_page->u == patch.u) && (c_page->v == patch.v) &&
|
||||
(c_page->w == patch.w) && (c_page->h == patch.h) &&
|
||||
(c_page->decimation == patch.decimation)
|
||||
)
|
||||
{
|
||||
dlist = c_page->patch;
|
||||
c_page->score++; // Increase score.
|
||||
break;
|
||||
}
|
||||
|
||||
// Track the lowest scoring page.
|
||||
if (c_page->score <= lowest_score)
|
||||
{
|
||||
lowest_score = c_page->score;
|
||||
page = c_page;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss.
|
||||
if (!dlist)
|
||||
{
|
||||
++gpu_stats.terrain_page_query_miss;
|
||||
|
||||
if (!page || !page->patch)
|
||||
__ERRRAW__(__LOG_E__ << "No page to upload terrain patch.\n") // Unexpected...
|
||||
|
||||
// Create new page.
|
||||
UploadTerrainPatchToPage(*page, item, patch, dc);
|
||||
dlist = page->patch;
|
||||
page->score = 1; // Reset score (+1 for being used).
|
||||
}
|
||||
|
||||
// Draw patch scaled and translated on the GPU.
|
||||
float pixel_size = patch.terrain->GetUnit();
|
||||
Vector4 patch_scale(pixel_size * patch.decimation, 1, pixel_size * patch.decimation);
|
||||
|
||||
Matrix4 patch_matrix =
|
||||
Matrix4::TranslationMatrix(Vector4(patch.u * pixel_size - patch.terrain->GetWidth() * 0.5f, 0, patch.v * pixel_size - patch.terrain->GetDepth() * 0.5f)) *
|
||||
Matrix4::ScaleMatrix(patch_scale);
|
||||
|
||||
SetWorldMatrix(item.GetMatrix() * patch_matrix);
|
||||
m_previous_world = item.GetPreviousMatrix() * patch_matrix;
|
||||
|
||||
dls_cache.item = NULL; // Force matrices upload to program.
|
||||
|
||||
// Draw.
|
||||
if (patch.terrain->render_data)
|
||||
{
|
||||
dlist->material = patch.terrain->render_data->material;
|
||||
DrawDisplayListCached(*dlist, item, dc);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user