Changeset View
Changeset View
Standalone View
Standalone View
source/graphics/Terrain.cpp
Show First 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
// Initialise: initialise this terrain to the given size | // Initialise: initialise this terrain to the given size | ||||
// using given heightmap to setup elevation data | // using given heightmap to setup elevation data | ||||
bool CTerrain::Initialize(ssize_t patchesPerSide, const u16* data) | bool CTerrain::Initialize(ssize_t patchesPerSide, const u16* data) | ||||
{ | { | ||||
// clean up any previous terrain | // clean up any previous terrain | ||||
ReleaseData(); | ReleaseData(); | ||||
// store terrain size | // store terrain size | ||||
m_MapSize = patchesPerSide*PATCH_SIZE+1; | m_MapSize = patchesPerSide * PATCH_SIZE + 1; | ||||
m_MapSizePatches = patchesPerSide; | m_MapSizePatches = patchesPerSide; | ||||
// allocate data for new terrain | // allocate data for new terrain | ||||
m_Heightmap = new u16[m_MapSize*m_MapSize]; | m_Heightmap = new u16[m_MapSize * m_MapSize]; | ||||
m_Patches = new CPatch[m_MapSizePatches*m_MapSizePatches]; | m_Patches = new CPatch[m_MapSizePatches * m_MapSizePatches]; | ||||
// given a heightmap? | // given a heightmap? | ||||
if (data) | if (data) | ||||
{ | { | ||||
// yes; keep a copy of it | // yes; keep a copy of it | ||||
memcpy(m_Heightmap, data, m_MapSize*m_MapSize*sizeof(u16)); | memcpy(m_Heightmap, data, m_MapSize*m_MapSize*sizeof(u16)); | ||||
} | } | ||||
else | else | ||||
▲ Show 20 Lines • Show All 401 Lines • ▼ Show 20 Lines | bool CTerrain::GetTriangulationDir(ssize_t i, ssize_t j) const | ||||
// Prefer triangulating in whichever direction means the midpoint of the diagonal | // Prefer triangulating in whichever direction means the midpoint of the diagonal | ||||
// will be the highest. (In particular this means a diagonal edge will be straight | // will be the highest. (In particular this means a diagonal edge will be straight | ||||
// along the top, and jagged along the bottom, which makes sense for terrain.) | // along the top, and jagged along the bottom, which makes sense for terrain.) | ||||
int mid1 = h00+h11; | int mid1 = h00+h11; | ||||
int mid2 = h01+h10; | int mid2 = h01+h10; | ||||
return (mid1 < mid2); | return (mid1 < mid2); | ||||
} | } | ||||
/////////////////////////////////////////////////////////////////////////////// | // Resize/Recenter: resize this terrain to the given size (in patches per side). | ||||
// Resize: resize this terrain to the given size (in patches per side) | // The offset is in patches from the center of the source. | ||||
void CTerrain::Resize(ssize_t size) | void CTerrain::ResizeRecenter(ssize_t size, i32 horizontalOffset, i32 verticalOffset) | ||||
{ | |||||
if (size == m_MapSizePatches && horizontalOffset == 0 && verticalOffset == 0) | |||||
{ | { | ||||
vladislavbelov: One line isn't so long. | |||||
if (size==m_MapSizePatches) { | // Inexplicable request to resize terrain to the same size .. ignore it | ||||
// inexplicable request to resize terrain to the same size .. ignore it | |||||
return; | return; | ||||
} | } | ||||
if (!m_Heightmap) { | if (!m_Heightmap || | ||||
// not yet created a terrain; build a default terrain of the given size now | std::abs(horizontalOffset) > std::max(size, m_MapSizePatches) / 2 || | ||||
Done Inline ActionsI think it should be std::abs(horizontalOffset) >= (size + m_MapSizePatches) / 2 (same for vertical) if we also want to have a little piece of the source. vladislavbelov: I think it should be `std::abs(horizontalOffset) >= (size + m_MapSizePatches) / 2` (same for… | |||||
std::abs(verticalOffset) > std::max(size, m_MapSizePatches) / 2) | |||||
{ | |||||
// We have not yet created a terrain, or we are offsetting outside the current source. | |||||
// Let's build a default terrain of the given size now. | |||||
Initialize(size,0); | Initialize(size, 0); | ||||
return; | return; | ||||
} | } | ||||
// allocate data for new terrain | // Allocate data for new terrain | ||||
ssize_t newMapSize=size*PATCH_SIZE+1; | ssize_t newMapSize = size * PATCH_SIZE + 1; | ||||
u16* newHeightmap=new u16[newMapSize*newMapSize]; | u16* newHeightmap = new u16[newMapSize * newMapSize]; | ||||
CPatch* newPatches=new CPatch[size*size]; | CPatch* newPatches = new CPatch[size * size]; | ||||
if (size>m_MapSizePatches) { | // Restate center offset as a window over destination. | ||||
// new map is bigger than old one - zero the heightmap so we don't get uninitialised | // This has the effect of always considering the source to be the same size or smaller. | ||||
// height data along the expanded edges | const ssize_t upperLeftX = std::max(static_cast<ssize_t>(0), (size - m_MapSizePatches) / 2 + horizontalOffset); | ||||
memset(newHeightmap,0,newMapSize*newMapSize*sizeof(u16)); | const ssize_t upperLeftZ = std::max(static_cast<ssize_t>(0), (size - m_MapSizePatches) / 2 + verticalOffset); | ||||
} | const ssize_t width = std::min(size, (size - m_MapSizePatches) / 2 + horizontalOffset + m_MapSizePatches) - upperLeftX; | ||||
const ssize_t height = std::min(size, (size - m_MapSizePatches) / 2 + verticalOffset + m_MapSizePatches) - upperLeftZ; | |||||
// now copy over rows of data | |||||
u16* src=m_Heightmap; | |||||
u16* dst=newHeightmap; | |||||
ssize_t copysize=std::min(newMapSize, m_MapSize); | |||||
for (ssize_t j=0;j<copysize;j++) { | |||||
memcpy(dst,src,copysize*sizeof(u16)); | |||||
dst+=copysize; | |||||
src+=m_MapSize; | |||||
if (newMapSize>m_MapSize) { | |||||
// extend the last height to the end of the row | |||||
for (size_t i=0;i<newMapSize-(size_t)m_MapSize;i++) { | |||||
*dst++=*(src-1); | |||||
} | |||||
} | |||||
} | |||||
const ssize_t upperLeftXSource = std::max(static_cast<ssize_t>(0), (m_MapSizePatches - size) / 2 - horizontalOffset); | |||||
const ssize_t upperLeftZSource = std::max(static_cast<ssize_t>(0), (m_MapSizePatches - size) / 2 - verticalOffset); | |||||
if (newMapSize>m_MapSize) { | for (ssize_t j = upperLeftZ * PATCH_SIZE; j < (upperLeftZ + height) * PATCH_SIZE + 1; ++j) | ||||
// copy over heights of the last row to any remaining rows | { | ||||
src=newHeightmap+((m_MapSize-1)*newMapSize); | u16* dst = newHeightmap + j * newMapSize; | ||||
dst=src+newMapSize; | u16* src = m_Heightmap + (upperLeftZSource * PATCH_SIZE + (j - upperLeftZ * PATCH_SIZE)) * m_MapSize + upperLeftXSource * PATCH_SIZE; | ||||
for (ssize_t i=0;i<newMapSize-m_MapSize;i++) { | |||||
memcpy(dst,src,newMapSize*sizeof(u16)); | dst = std::fill_n(dst, upperLeftX * PATCH_SIZE, *src); | ||||
dst+=newMapSize; | dst = std::copy_n(src, width * PATCH_SIZE + 1, dst); | ||||
std::fill_n(dst, newMapSize - (upperLeftX + width) * PATCH_SIZE, *(src + (width * PATCH_SIZE + 1) - 1)); | |||||
} | } | ||||
// Copy over heights from preceding/succeeding rows | |||||
for (ssize_t j = 0; j < upperLeftZ * PATCH_SIZE; ++j) | |||||
{ | |||||
u16* dst = newHeightmap + j * newMapSize; | |||||
u16* src = newHeightmap + upperLeftZ * PATCH_SIZE * newMapSize; | |||||
std::copy_n(src, newMapSize, dst); | |||||
} | |||||
Done Inline ActionsI'm not sure that +1 is needed here. vladislavbelov: I'm not sure that `+1` is needed here. | |||||
for (ssize_t j = (upperLeftZ + height)*PATCH_SIZE + 1; j < newMapSize; ++j) | |||||
{ | |||||
u16* dst = newHeightmap + j * newMapSize; | |||||
u16* src = newHeightmap + (upperLeftZ + height) * PATCH_SIZE * newMapSize; | |||||
std::copy_n(src, newMapSize, dst); | |||||
Done Inline ActionsI think src[0] is better than *src as it's more explicit. vladislavbelov: I think `src[0]` is better than `*src` as it's more explicit. | |||||
} | } | ||||
Done Inline Actionssrc[(width * PATCH_SIZE + 1) - 1] vladislavbelov: `src[(width * PATCH_SIZE + 1) - 1]` | |||||
// now build new patches | // now build new patches | ||||
for (ssize_t j=0;j<size;j++) { | for (ssize_t j = upperLeftZ; j < upperLeftZ + height; ++j) | ||||
for (ssize_t i=0;i<size;i++) { | { | ||||
for (ssize_t i = upperLeftX; i < upperLeftX + width; ++i) | |||||
{ | |||||
// copy over texture data from existing tiles, if possible | // copy over texture data from existing tiles, if possible | ||||
if (i<m_MapSizePatches && j<m_MapSizePatches) { | // Incrementing offsets in source need to be adjusted to 0-based, since the X/ZSource variables are the new "0" | ||||
memcpy(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*PATCH_SIZE*PATCH_SIZE); | CPatch& src = m_Patches[(upperLeftZSource + (j - upperLeftZ)) * m_MapSizePatches + upperLeftXSource + (i - upperLeftX)]; | ||||
} | CPatch& dst = newPatches[j * size + i]; | ||||
std::copy_n(&src.m_MiniPatches[0][0], PATCH_SIZE * PATCH_SIZE, &dst.m_MiniPatches[0][0]); | |||||
} | } | ||||
for (ssize_t i = 0; i < upperLeftX; ++i) | |||||
if (j<m_MapSizePatches && size>m_MapSizePatches) { | { | ||||
// copy over the last tile from each column | for (ssize_t patch_j = 0; patch_j < PATCH_SIZE; ++patch_j) | ||||
Done Inline ActionsBrackets on the new line (below too), the file should contain the one style. vladislavbelov: Brackets on the new line (below too), the file should contain the one style. | |||||
for (ssize_t n=0;n<size-m_MapSizePatches;n++) { | { | ||||
for (ssize_t m=0;m<PATCH_SIZE;m++) { | CMiniPatch& src = newPatches[j * size + upperLeftX].m_MiniPatches[patch_j][0]; | ||||
CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15]; | for (ssize_t patch_i = 0; patch_i < PATCH_SIZE; ++patch_i) | ||||
for (ssize_t k=0;k<PATCH_SIZE;k++) { | { | ||||
CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k]; | CMiniPatch& dst = newPatches[j * size + i].m_MiniPatches[patch_j][patch_i]; | ||||
dst = src; | dst = src; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
for (ssize_t i = upperLeftX + width; i < size; ++i) | |||||
{ | |||||
for (ssize_t patch_j = 0; patch_j < PATCH_SIZE; ++patch_j) | |||||
{ | |||||
CMiniPatch& src = newPatches[j * size + upperLeftX + width - 1].m_MiniPatches[patch_j][PATCH_SIZE - 1]; | |||||
for (ssize_t patch_i = 0; patch_i < PATCH_SIZE; ++patch_i) | |||||
{ | |||||
CMiniPatch& dst = newPatches[j * size + i].m_MiniPatches[patch_j][patch_i]; | |||||
dst = src; | |||||
} | } | ||||
} | } | ||||
} | |||||
if (size>m_MapSizePatches) { | } | ||||
// copy over the last tile from each column | for (ssize_t j = 0; j < upperLeftZ; ++j) | ||||
CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size]; | { | ||||
CPatch* dstpatch=srcpatch+size; | CPatch* srcpatch = newPatches + (upperLeftZ * size); | ||||
for (ssize_t p=0;p<(ssize_t)size-m_MapSizePatches;p++) { | CPatch* dstpatch = newPatches + j * size; | ||||
for (ssize_t n=0;n<(ssize_t)size;n++) { | for (ssize_t i = 0; i < size; ++i) | ||||
for (ssize_t m=0;m<PATCH_SIZE;m++) { | { | ||||
for (ssize_t k=0;k<PATCH_SIZE;k++) { | for (ssize_t patch_j = 0; patch_j < PATCH_SIZE; ++patch_j) | ||||
CMiniPatch& src=srcpatch->m_MiniPatches[15][k]; | { | ||||
CMiniPatch& dst=dstpatch->m_MiniPatches[m][k]; | for (ssize_t patch_i = 0; patch_i < PATCH_SIZE; ++patch_i) | ||||
{ | |||||
CMiniPatch& src = srcpatch->m_MiniPatches[0][patch_i]; | |||||
CMiniPatch& dst = dstpatch->m_MiniPatches[patch_j][patch_i]; | |||||
dst = src; | dst = src; | ||||
} | } | ||||
} | } | ||||
srcpatch++; | ++srcpatch; | ||||
dstpatch++; | ++dstpatch; | ||||
} | |||||
} | |||||
for (ssize_t j = upperLeftZ + height; j < size; ++j) | |||||
{ | |||||
CPatch* srcpatch = newPatches + ((upperLeftZ + height - 1) * size); | |||||
CPatch* dstpatch = newPatches + j * size; | |||||
for (ssize_t i = 0; i < size; ++i) | |||||
{ | |||||
for (ssize_t patch_j = 0; patch_j < PATCH_SIZE; ++patch_j) | |||||
{ | |||||
for (ssize_t patch_i = 0; patch_i < PATCH_SIZE; ++patch_i) | |||||
{ | |||||
CMiniPatch& src = srcpatch->m_MiniPatches[PATCH_SIZE - 1][patch_i]; | |||||
CMiniPatch& dst = dstpatch->m_MiniPatches[patch_j][patch_i]; | |||||
dst = src; | |||||
} | |||||
} | } | ||||
++srcpatch; | |||||
++dstpatch; | |||||
} | } | ||||
} | } | ||||
// release all the original data | // release all the original data | ||||
ReleaseData(); | ReleaseData(); | ||||
// store new data | // store new data | ||||
m_Heightmap=newHeightmap; | m_Heightmap = newHeightmap; | ||||
m_Patches=newPatches; | m_Patches = newPatches; | ||||
m_MapSize=(ssize_t)newMapSize; | m_MapSize = newMapSize; | ||||
m_MapSizePatches=(ssize_t)size; | m_MapSizePatches = size; | ||||
// initialise all the new patches | // initialise all the new patches | ||||
InitialisePatches(); | InitialisePatches(); | ||||
// initialise mipmap | // initialise mipmap | ||||
m_HeightMipmap.Initialize(m_MapSize,m_Heightmap); | m_HeightMipmap.Initialize(m_MapSize, m_Heightmap); | ||||
} | } | ||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
// InitialisePatches: initialise patch data | // InitialisePatches: initialise patch data | ||||
void CTerrain::InitialisePatches() | void CTerrain::InitialisePatches() | ||||
{ | { | ||||
for (ssize_t j = 0; j < m_MapSizePatches; j++) | for (ssize_t j = 0; j < m_MapSizePatches; j++) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 109 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
One line isn't so long.