mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-07-07 07:51:35 +00:00
- more work on the terrain. STILL not finished.
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@124 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
f739bf90f1
commit
367b9754b2
12 changed files with 796 additions and 619 deletions
|
@ -333,7 +333,7 @@ struct HashTable(Key, Value, Alloc = GCAlloc, Hash = DefHash,
|
||||||
// Get a pointer to value of given key, or insert a new. Useful for
|
// Get a pointer to value of given key, or insert a new. Useful for
|
||||||
// large value types when you want to avoid copying the value around
|
// large value types when you want to avoid copying the value around
|
||||||
// needlessly. Also useful if you want to do in-place
|
// needlessly. Also useful if you want to do in-place
|
||||||
// editing. Returns true if a value was inserted.
|
// editing. Returns true if a new value was inserted.
|
||||||
bool insertEdit(Key k, out Value *ptr)
|
bool insertEdit(Key k, out Value *ptr)
|
||||||
{
|
{
|
||||||
Node *p;
|
Node *p;
|
||||||
|
|
|
@ -55,7 +55,7 @@ class NiTexturingProperty : Property
|
||||||
bool inUse;
|
bool inUse;
|
||||||
NiSourceTexture texture;
|
NiSourceTexture texture;
|
||||||
|
|
||||||
/* Clamp mode (i don't understand this)
|
/* Clamp mode
|
||||||
0 - clampS clampT
|
0 - clampS clampT
|
||||||
1 - clampS wrapT
|
1 - clampS wrapT
|
||||||
2 - wrapS clampT
|
2 - wrapS clampT
|
||||||
|
@ -89,8 +89,11 @@ class NiTexturingProperty : Property
|
||||||
filter = nifFile.getIntIs(0,1,2);
|
filter = nifFile.getIntIs(0,1,2);
|
||||||
set = nifFile.getInt;
|
set = nifFile.getInt;
|
||||||
|
|
||||||
ps2L = nifFile.getShortIs(0);
|
// The combination 1222, 322, 212 was used in a bump map
|
||||||
ps2K = nifFile.getShortIs(-75,-2);
|
// NIF. Might just be bogus numbers, I should probably allow all
|
||||||
|
// values here since we ignore them anyway.
|
||||||
|
ps2L = nifFile.getShortIs(0,1222);
|
||||||
|
ps2K = nifFile.getShortIs(-75,-2,322);
|
||||||
|
|
||||||
debug(verbose)
|
debug(verbose)
|
||||||
{
|
{
|
||||||
|
@ -101,7 +104,7 @@ class NiTexturingProperty : Property
|
||||||
writefln(" ps2K ", ps2K);
|
writefln(" ps2K ", ps2K);
|
||||||
}
|
}
|
||||||
|
|
||||||
unknown2 = nifFile.wgetShortIs(0,257);
|
unknown2 = nifFile.wgetShortIs(0,257,212);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
openmw.d
18
openmw.d
|
@ -54,6 +54,20 @@ import input.events;
|
||||||
|
|
||||||
import terrain.terrain;
|
import terrain.terrain;
|
||||||
|
|
||||||
|
// Set up exit handler
|
||||||
|
alias void function() c_func;
|
||||||
|
extern(C) int atexit(c_func);
|
||||||
|
|
||||||
|
bool cleanExit = false;
|
||||||
|
|
||||||
|
void exitHandler()
|
||||||
|
{
|
||||||
|
// If we exit uncleanly, print the function stack.
|
||||||
|
if(!cleanExit)
|
||||||
|
writefln(dbg.getTrace());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//*
|
//*
|
||||||
import std.gc;
|
import std.gc;
|
||||||
import gcstats;
|
import gcstats;
|
||||||
|
@ -224,6 +238,10 @@ Try specifying another cell name on the command line, or edit openmw.ini.");
|
||||||
// Set the name for the GUI (temporary hack)
|
// Set the name for the GUI (temporary hack)
|
||||||
gui_setCellName(cd.inCell.id.ptr);
|
gui_setCellName(cd.inCell.id.ptr);
|
||||||
|
|
||||||
|
// Set up the exit handler
|
||||||
|
atexit(&exitHandler);
|
||||||
|
scope(exit) cleanExit = true;
|
||||||
|
|
||||||
if(render)
|
if(render)
|
||||||
{
|
{
|
||||||
// Warm up OGRE
|
// Warm up OGRE
|
||||||
|
|
|
@ -20,12 +20,17 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This should also be part of the generic cache system.
|
module terrain.archive;
|
||||||
|
|
||||||
|
const float TEX_SCALE = 1.0/16;
|
||||||
|
|
||||||
|
// This should be part of the generic cache system.
|
||||||
const int CACHE_MAGIC = 0x345AF815;
|
const int CACHE_MAGIC = 0x345AF815;
|
||||||
|
|
||||||
import std.mmfile;
|
import std.mmfile;
|
||||||
import std.stream;
|
|
||||||
import std.string;
|
import std.string;
|
||||||
|
import std.stdio;
|
||||||
|
import terrain.myfile;
|
||||||
|
|
||||||
version(Windows)
|
version(Windows)
|
||||||
static int pageSize = 64*1024;
|
static int pageSize = 64*1024;
|
||||||
|
@ -39,19 +44,20 @@ extern(C)
|
||||||
{ return g_archive.getString(index).ptr; }
|
{ return g_archive.getString(index).ptr; }
|
||||||
|
|
||||||
// Fill various hardware buffers from cache
|
// Fill various hardware buffers from cache
|
||||||
void d_terr_fillVertexBuffer(MeshInfo *mi, float *buffer)
|
void d_terr_fillVertexBuffer(MeshInfo *mi, float *buffer, ulong size)
|
||||||
{ mi.fillVertexBuffer(buffer); }
|
{ mi.fillVertexBuffer(buffer[0..size]); }
|
||||||
|
|
||||||
void d_terr_fillIndexBuffer(MeshInfo *mi, ushort *buffer)
|
void d_terr_fillIndexBuffer(MeshInfo *mi, ushort *buffer, ulong size)
|
||||||
{ mi.fillIndexBuffer(buffer); }
|
{ mi.fillIndexBuffer(buffer[0..size]); }
|
||||||
|
|
||||||
void d_terr_fillAlphaBuffer(AlphaInfo *mi, ubyte *buffer)
|
void d_terr_fillAlphaBuffer(AlphaInfo *mi, ubyte *buffer, ulong size)
|
||||||
{ mi.fillAlphaBuffer(buffer); }
|
{ mi.fillAlphaBuffer(buffer[0..size]); }
|
||||||
|
|
||||||
// Get a given alpha map struct belonging to a mesh
|
// Get a given alpha map struct belonging to a mesh
|
||||||
AlphaInfo *d_terr_getAlphaInfo(MeshInfo *mi, int index)
|
AlphaInfo *d_terr_getAlphaInfo(MeshInfo *mi, int index)
|
||||||
{ return mi.getAlphaInfo(index); }
|
{ return mi.getAlphaInfo(index); }
|
||||||
|
|
||||||
|
int d_terr_getAlphaSize() { return g_archive.alphaSize; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info about the entire quad. TODO: Some of this (such as the texture
|
// Info about the entire quad. TODO: Some of this (such as the texture
|
||||||
|
@ -69,9 +75,6 @@ struct QuadInfo
|
||||||
float worldWidth;
|
float worldWidth;
|
||||||
float boundingRadius;
|
float boundingRadius;
|
||||||
|
|
||||||
// Texture scale for this quad
|
|
||||||
float texScale;
|
|
||||||
|
|
||||||
// True if we should make the given child
|
// True if we should make the given child
|
||||||
bool hasChild[4];
|
bool hasChild[4];
|
||||||
|
|
||||||
|
@ -92,13 +95,14 @@ struct AlphaInfo
|
||||||
|
|
||||||
// The texture name for this layer. The actual string is stored in
|
// The texture name for this layer. The actual string is stored in
|
||||||
// the archive's string buffer.
|
// the archive's string buffer.
|
||||||
int texName;
|
int texName = -1;
|
||||||
int alphaName;
|
int alphaName = -1;
|
||||||
|
|
||||||
// Fill the alpha texture buffer
|
// Fill the alpha texture buffer
|
||||||
void fillAlphaBuffer(ubyte *abuf)
|
void fillAlphaBuffer(ubyte abuf[])
|
||||||
{
|
{
|
||||||
g_archive.copy(abuf, bufOffset, bufSize);
|
assert(abuf.length == bufSize);
|
||||||
|
g_archive.copy(abuf.ptr, bufOffset, bufSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static assert(AlphaInfo.sizeof == 6*4);
|
static assert(AlphaInfo.sizeof == 6*4);
|
||||||
|
@ -113,10 +117,6 @@ struct MeshInfo
|
||||||
|
|
||||||
// Vertex and index numbers
|
// Vertex and index numbers
|
||||||
int vertRows, vertCols;
|
int vertRows, vertCols;
|
||||||
int indexCount;
|
|
||||||
|
|
||||||
// Scene node position (relative to the parent node)
|
|
||||||
float x, y;
|
|
||||||
|
|
||||||
// Height offset to apply to all vertices
|
// Height offset to apply to all vertices
|
||||||
float heightOffset;
|
float heightOffset;
|
||||||
|
@ -129,21 +129,20 @@ struct MeshInfo
|
||||||
ulong alphaOffset;
|
ulong alphaOffset;
|
||||||
|
|
||||||
// Texture name. Index to the string table.
|
// Texture name. Index to the string table.
|
||||||
int texName;
|
int texName = -1;
|
||||||
|
|
||||||
// Fill the given vertex buffer
|
// Fill the given vertex buffer
|
||||||
void fillVertexBuffer(float *vbuf)
|
void fillVertexBuffer(float vdest[])
|
||||||
{
|
{
|
||||||
//g_archive.copy(vbuf, vertBufOffset, vertBufSize);
|
|
||||||
|
|
||||||
// The height map and normals from the archive
|
// The height map and normals from the archive
|
||||||
char *hmap = cast(char*)g_archive.getRelSlice(vertBufOffset, vertBufSize).ptr;
|
byte *hmap = cast(byte*)g_archive.getRelSlice(vertBufOffset, vertBufSize).ptr;
|
||||||
|
|
||||||
int level = getLevel();
|
|
||||||
|
|
||||||
// The generic part, containing the x,y coordinates and the uv
|
// The generic part, containing the x,y coordinates and the uv
|
||||||
// maps.
|
// maps.
|
||||||
float *gmap = g_archive.getVertexBuffer(level).ptr;
|
float *gmap = g_archive.getVertexBuffer(getLevel()).ptr;
|
||||||
|
|
||||||
|
// Destination pointer
|
||||||
|
float *vbuf = vdest.ptr;
|
||||||
|
assert(vdest.length == vertRows*vertCols*8);
|
||||||
|
|
||||||
// Calculate the factor to multiply each height value with. The
|
// Calculate the factor to multiply each height value with. The
|
||||||
// heights are very limited in range as they are stored in a
|
// heights are very limited in range as they are stored in a
|
||||||
|
@ -151,7 +150,7 @@ struct MeshInfo
|
||||||
// double this for each successive level since we're splicing
|
// double this for each successive level since we're splicing
|
||||||
// several vertices together and need to allow larger differences
|
// several vertices together and need to allow larger differences
|
||||||
// for each vertex. The formula is 8*2^(level-1).
|
// for each vertex. The formula is 8*2^(level-1).
|
||||||
float scale = 4.0 * (1<<level);
|
float scale = 4.0 * (1<<getLevel());
|
||||||
|
|
||||||
// Merge the two data sets together into the output buffer.
|
// Merge the two data sets together into the output buffer.
|
||||||
float offset = heightOffset;
|
float offset = heightOffset;
|
||||||
|
@ -178,7 +177,6 @@ struct MeshInfo
|
||||||
*vbuf++ = rowofs * scale;
|
*vbuf++ = rowofs * scale;
|
||||||
|
|
||||||
// Normal vector.
|
// Normal vector.
|
||||||
// TODO: Normalize?
|
|
||||||
*vbuf++ = *hmap++;
|
*vbuf++ = *hmap++;
|
||||||
*vbuf++ = *hmap++;
|
*vbuf++ = *hmap++;
|
||||||
*vbuf++ = *hmap++;
|
*vbuf++ = *hmap++;
|
||||||
|
@ -196,12 +194,13 @@ struct MeshInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the index buffer
|
// Fill the index buffer
|
||||||
void fillIndexBuffer(ushort *ibuf)
|
void fillIndexBuffer(ushort ibuf[])
|
||||||
{
|
{
|
||||||
// The index buffer is pregenerated. It is identical for all
|
// The index buffer is pregenerated. It is identical for all
|
||||||
// meshes on the same level, so just copy it over.
|
// meshes on the same level, so just copy it over.
|
||||||
ushort generic[] = g_archive.getIndexBuffer(getLevel());
|
ushort generic[] = g_archive.getIndexBuffer();
|
||||||
ibuf[0..generic.length] = generic[];
|
assert(ibuf.length == generic.length);
|
||||||
|
ibuf[] = generic[];
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLevel()
|
int getLevel()
|
||||||
|
@ -221,9 +220,9 @@ struct MeshInfo
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static assert(MeshInfo.sizeof == 17*4);
|
static assert(MeshInfo.sizeof == 14*4);
|
||||||
|
|
||||||
|
|
||||||
|
// The first part of the .index file
|
||||||
struct ArchiveHeader
|
struct ArchiveHeader
|
||||||
{
|
{
|
||||||
// "Magic" number to make sure we're actually reading an archive
|
// "Magic" number to make sure we're actually reading an archive
|
||||||
|
@ -263,10 +262,13 @@ struct TerrainArchive
|
||||||
0, null, pageSize);
|
0, null, pageSize);
|
||||||
|
|
||||||
// Read the index file first
|
// Read the index file first
|
||||||
File ifile = new File(name ~ ".index");
|
MyFile ifile = new MyFile(name ~ ".index");
|
||||||
|
|
||||||
ArchiveHeader head;
|
ArchiveHeader head;
|
||||||
ifile.readExact(&head, head.sizeof);
|
ifile.fill(head);
|
||||||
|
|
||||||
|
// Reads data into an array. Would be better if this was part of
|
||||||
|
// the stream.
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
assert(head.magic == CACHE_MAGIC);
|
assert(head.magic == CACHE_MAGIC);
|
||||||
|
@ -277,7 +279,7 @@ struct TerrainArchive
|
||||||
|
|
||||||
// Read all the quads
|
// Read all the quads
|
||||||
quadList = new QuadInfo[head.quads];
|
quadList = new QuadInfo[head.quads];
|
||||||
ifile.readExact(quadList.ptr, head.quads*QuadInfo.sizeof);
|
ifile.fillArray(quadList);
|
||||||
|
|
||||||
// Create an index of all the quads
|
// Create an index of all the quads
|
||||||
foreach(int index, qn; quadList)
|
foreach(int index, qn; quadList)
|
||||||
|
@ -289,6 +291,7 @@ struct TerrainArchive
|
||||||
assert(l >= 1);
|
assert(l >= 1);
|
||||||
|
|
||||||
quadMap[l][x][y] = index;
|
quadMap[l][x][y] = index;
|
||||||
|
assert(index == quadMap[l][x][y]);
|
||||||
|
|
||||||
// Store the root quad
|
// Store the root quad
|
||||||
if(l == head.rootLevel)
|
if(l == head.rootLevel)
|
||||||
|
@ -303,24 +306,24 @@ struct TerrainArchive
|
||||||
// Make sure the root was set
|
// Make sure the root was set
|
||||||
assert(rootQuad !is null);
|
assert(rootQuad !is null);
|
||||||
|
|
||||||
// Next read the string table
|
// Next read the string table. First read the main string buffer.
|
||||||
stringBuf = new char[head.stringSize];
|
stringBuf = new char[head.stringSize];
|
||||||
strings.length = head.stringNum;
|
ifile.fillArray(stringBuf);
|
||||||
|
|
||||||
// First read the main string buffer
|
|
||||||
ifile.readExact(stringBuf.ptr, head.stringSize);
|
|
||||||
|
|
||||||
// Then read the string offsets
|
// Then read the string offsets
|
||||||
int[] offsets = new int[head.stringNum];
|
int[] offsets = new int[head.stringNum];
|
||||||
ifile.readExact(offsets.ptr, offsets.length*int.sizeof);
|
ifile.fillArray(offsets);
|
||||||
|
|
||||||
// Set up the string table
|
// Set up the string table
|
||||||
char *strptr = stringBuf.ptr;
|
char *strptr = stringBuf.ptr;
|
||||||
|
strings.length = head.stringNum;
|
||||||
foreach(int i, ref str; strings)
|
foreach(int i, ref str; strings)
|
||||||
{
|
{
|
||||||
// toString(char*) returns the string up to the zero
|
// toString(char*) returns the string up to the zero
|
||||||
// terminator byte
|
// terminator byte
|
||||||
str = toString(strptr + offsets[i]);
|
str = toString(strptr + offsets[i]);
|
||||||
|
assert(str.ptr + str.length <=
|
||||||
|
stringBuf.ptr + stringBuf.length);
|
||||||
}
|
}
|
||||||
delete offsets;
|
delete offsets;
|
||||||
|
|
||||||
|
@ -328,23 +331,16 @@ struct TerrainArchive
|
||||||
int bufNum = head.rootLevel;
|
int bufNum = head.rootLevel;
|
||||||
assert(bufNum == 7);
|
assert(bufNum == 7);
|
||||||
vertBufData.length = bufNum;
|
vertBufData.length = bufNum;
|
||||||
indexBufData.length = bufNum;
|
|
||||||
|
|
||||||
// Fill the buffers. Start at level 1.
|
// Fill the vertex buffers. Start at level 1.
|
||||||
for(int i=1;i<bufNum;i++)
|
for(int i=1;i<bufNum;i++)
|
||||||
{
|
{
|
||||||
int size;
|
|
||||||
|
|
||||||
// Vertex buffer
|
// Vertex buffer
|
||||||
ifile.read(size);
|
ifile.readArray(vertBufData[i]);
|
||||||
vertBufData[i].length = size;
|
|
||||||
ifile.readExact(vertBufData[i].ptr, size);
|
|
||||||
|
|
||||||
// Index buffer
|
|
||||||
ifile.read(size);
|
|
||||||
indexBufData[i].length = size;
|
|
||||||
ifile.readExact(indexBufData[i].ptr, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Index buffer
|
||||||
|
ifile.readArray(indexBufData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get info about a given quad from the index.
|
// Get info about a given quad from the index.
|
||||||
|
@ -389,10 +385,9 @@ struct TerrainArchive
|
||||||
return vertBufData[level];
|
return vertBufData[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort[] getIndexBuffer(int level)
|
ushort[] getIndexBuffer()
|
||||||
{
|
{
|
||||||
assert(level>=1 && level<indexBufData.length);
|
return indexBufData;
|
||||||
return indexBufData[level];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -406,7 +401,7 @@ private:
|
||||||
// These contain pregenerated mesh data that is common for all
|
// These contain pregenerated mesh data that is common for all
|
||||||
// meshes on a given level.
|
// meshes on a given level.
|
||||||
float[][] vertBufData;
|
float[][] vertBufData;
|
||||||
ushort[][] indexBufData;
|
ushort[] indexBufData;
|
||||||
|
|
||||||
// Used for the mmapped file
|
// Used for the mmapped file
|
||||||
MmFile mmf;
|
MmFile mmf;
|
||||||
|
@ -448,10 +443,10 @@ private:
|
||||||
|
|
||||||
// Copy a given buffer from the file. The buffer might be a
|
// Copy a given buffer from the file. The buffer might be a
|
||||||
// compressed stream, so it's important that the buffers are written
|
// compressed stream, so it's important that the buffers are written
|
||||||
// the same as they are read. (Ie. you can't write a buffer as one
|
// in the same block sizes as they are read. (Ie. you can't write a
|
||||||
// operation and read it as two, or vice versa. Also, buffers cannot
|
// buffer as one operation and read it as two, or vice versa. Also,
|
||||||
// overlap.) The offset is relative to the current mapped file
|
// buffers cannot overlap.) The offset is relative to the current
|
||||||
// window.
|
// mapped file window.
|
||||||
void copy(void *dst, size_t offset, size_t inSize)
|
void copy(void *dst, size_t offset, size_t inSize)
|
||||||
{
|
{
|
||||||
ubyte source[] = getRelSlice(offset, inSize);
|
ubyte source[] = getRelSlice(offset, inSize);
|
||||||
|
|
|
@ -4,6 +4,7 @@ alias void *SceneNode;
|
||||||
alias void *Bounds;
|
alias void *Bounds;
|
||||||
alias void *MeshObj;
|
alias void *MeshObj;
|
||||||
|
|
||||||
|
// These are all defined in cpp_terrain.cpp:
|
||||||
extern(C):
|
extern(C):
|
||||||
|
|
||||||
SceneNode terr_createChildNode(float relX, float relY, SceneNode);
|
SceneNode terr_createChildNode(float relX, float relY, SceneNode);
|
||||||
|
@ -16,3 +17,11 @@ void terr_killMesh(MeshObj);
|
||||||
|
|
||||||
void terr_genData();
|
void terr_genData();
|
||||||
void terr_setupRendering();
|
void terr_setupRendering();
|
||||||
|
|
||||||
|
void terr_makeLandMaterial(char*,float);
|
||||||
|
ubyte *terr_makeAlphaLayer(char*,int);
|
||||||
|
void terr_closeAlpha(char*,char*,float);
|
||||||
|
void terr_cleanupAlpha(char*,void*,int);
|
||||||
|
|
||||||
|
void terr_resize(void*,void*,int,int);
|
||||||
|
void terr_saveImage(void*,int,char*);
|
||||||
|
|
|
@ -23,8 +23,11 @@
|
||||||
import terrain.archive;
|
import terrain.archive;
|
||||||
|
|
||||||
import terrain.outbuffer;
|
import terrain.outbuffer;
|
||||||
import std.stream;
|
import std.stdio, std.stream, std.string;
|
||||||
|
import terrain.myfile;
|
||||||
|
import std.math2;
|
||||||
import monster.util.string;
|
import monster.util.string;
|
||||||
|
import monster.vm.dbg;
|
||||||
|
|
||||||
// Helper structs
|
// Helper structs
|
||||||
struct AlphaHolder
|
struct AlphaHolder
|
||||||
|
@ -42,9 +45,6 @@ struct MeshHolder
|
||||||
// Actual buffers
|
// Actual buffers
|
||||||
byte[] vertexBuffer;
|
byte[] vertexBuffer;
|
||||||
|
|
||||||
// Texture name
|
|
||||||
char[] texName;
|
|
||||||
|
|
||||||
// Alpha maps (if any)
|
// Alpha maps (if any)
|
||||||
AlphaHolder alphas[];
|
AlphaHolder alphas[];
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,6 @@ struct CacheWriter
|
||||||
alphaSize = alphSize;
|
alphaSize = alphSize;
|
||||||
|
|
||||||
vertBuf.length = maxLevel;
|
vertBuf.length = maxLevel;
|
||||||
indexBuf.length = maxLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closes the main archive file and writes the index.
|
// Closes the main archive file and writes the index.
|
||||||
|
@ -83,7 +82,7 @@ struct CacheWriter
|
||||||
mainFile.close();
|
mainFile.close();
|
||||||
|
|
||||||
// Write the index file
|
// Write the index file
|
||||||
scope File ofile = new File(iname, FileMode.OutNew);
|
scope MyFile ofile = new MyFile(iname, FileMode.OutNew);
|
||||||
|
|
||||||
// Header first
|
// Header first
|
||||||
ArchiveHeader head;
|
ArchiveHeader head;
|
||||||
|
@ -93,11 +92,10 @@ struct CacheWriter
|
||||||
head.alphaSize = alphaSize;
|
head.alphaSize = alphaSize;
|
||||||
head.stringNum = stringList.length;
|
head.stringNum = stringList.length;
|
||||||
head.stringSize = totalStringLength;
|
head.stringSize = totalStringLength;
|
||||||
ofile.writeExact(&head, head.sizeof);
|
ofile.dump(head);
|
||||||
|
|
||||||
// Write the quads
|
// Write the quads
|
||||||
foreach(qi; quadList)
|
ofile.dumpArray(quadList);
|
||||||
ofile.writeExact(&qi, qi.sizeof);
|
|
||||||
|
|
||||||
// String table next. We need to sort it in order of the indices
|
// String table next. We need to sort it in order of the indices
|
||||||
// first.
|
// first.
|
||||||
|
@ -117,6 +115,10 @@ struct CacheWriter
|
||||||
// Add one byte for the zero terminator
|
// Add one byte for the zero terminator
|
||||||
int len = strVector[i].length + 1;
|
int len = strVector[i].length + 1;
|
||||||
char *ptr = strVector[i].ptr;
|
char *ptr = strVector[i].ptr;
|
||||||
|
|
||||||
|
if(ptr[len-1] != 0)
|
||||||
|
ptr = toStringz(strVector[i]);
|
||||||
|
|
||||||
assert(ptr[len-1] == 0);
|
assert(ptr[len-1] == 0);
|
||||||
|
|
||||||
ofile.writeExact(ptr, len);
|
ofile.writeExact(ptr, len);
|
||||||
|
@ -130,30 +132,20 @@ struct CacheWriter
|
||||||
assert(curOffs == head.stringSize);
|
assert(curOffs == head.stringSize);
|
||||||
|
|
||||||
// Finally, write the offset table itself
|
// Finally, write the offset table itself
|
||||||
ofile.writeExact(offsets.ptr, offsets.length * int.sizeof);
|
ofile.dumpArray(offsets);
|
||||||
|
|
||||||
// Write the common vertex and index buffers
|
// Write the common vertex and index buffers
|
||||||
|
assert(maxLevel == 7);
|
||||||
for(int i=1;i<maxLevel;i++)
|
for(int i=1;i<maxLevel;i++)
|
||||||
{
|
{
|
||||||
int size;
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
// Write vertex buffer
|
// Write vertex buffer
|
||||||
ptr = vertBuf[i].ptr;
|
ofile.writeArray(vertBuf[i]);
|
||||||
size = vertBuf[i].length;
|
|
||||||
ofile.write(size);
|
|
||||||
ofile.writeExact(ptr, size);
|
|
||||||
|
|
||||||
// Then the index buffer
|
|
||||||
ptr = indexBuf[i].ptr;
|
|
||||||
size = indexBuf[i].length;
|
|
||||||
ofile.write(size);
|
|
||||||
ofile.writeExact(ptr, size);
|
|
||||||
|
|
||||||
delete vertBuf[i];
|
delete vertBuf[i];
|
||||||
delete indexBuf[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then the index buffer
|
||||||
|
ofile.writeArray(indexBuf);
|
||||||
|
|
||||||
// Don't need these anymore
|
// Don't need these anymore
|
||||||
delete offsets;
|
delete offsets;
|
||||||
delete strVector;
|
delete strVector;
|
||||||
|
@ -165,17 +157,16 @@ struct CacheWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a common vertex buffer for a given level
|
// Add a common vertex buffer for a given level
|
||||||
void addVertexBuffer(int level, void[] buf)
|
void addVertexBuffer(int level, float[] buf)
|
||||||
{
|
{
|
||||||
assert(vertBuf.length > level);
|
assert(vertBuf.length > level);
|
||||||
vertBuf[level] = buf;
|
vertBuf[level] = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a common vertex buffer for a given level
|
// Add a common index buffer
|
||||||
void addIndexBuffer(int level, void[] buf)
|
void setIndexBuffer(ushort[] buf)
|
||||||
{
|
{
|
||||||
assert(indexBuf.length > level);
|
indexBuf = buf;
|
||||||
indexBuf[level] = buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a finished quad to the archive file. All the offsets and
|
// Write a finished quad to the archive file. All the offsets and
|
||||||
|
@ -183,15 +174,16 @@ struct CacheWriter
|
||||||
// the additional data in the Holder structs.
|
// the additional data in the Holder structs.
|
||||||
void writeQuad(ref QuadHolder qh)
|
void writeQuad(ref QuadHolder qh)
|
||||||
{
|
{
|
||||||
// Make outbuffer a simple struct that uses a region and keeps
|
scope auto _trc = new MTrace("writeQuad");
|
||||||
// track of all the slices we allocate.
|
|
||||||
OutBuffer buf;
|
|
||||||
|
|
||||||
// Write the MeshInfo's first
|
// Write the MeshInfo's first
|
||||||
int meshNum = qh.meshes.length;
|
int meshNum = qh.meshes.length;
|
||||||
|
|
||||||
MeshInfo meshes[] = buf.write!(MeshInfo)(meshNum);
|
MeshInfo meshes[] = buf.write!(MeshInfo)(meshNum);
|
||||||
|
|
||||||
|
float minh = float.infinity;
|
||||||
|
float maxh = -float.infinity;
|
||||||
|
|
||||||
// Then write the mesh data in approximately the order it's read
|
// Then write the mesh data in approximately the order it's read
|
||||||
for(int i=0; i<meshNum; i++)
|
for(int i=0; i<meshNum; i++)
|
||||||
{
|
{
|
||||||
|
@ -202,15 +194,18 @@ struct CacheWriter
|
||||||
// Copy the basic data first
|
// Copy the basic data first
|
||||||
meshes[i] = mh.info;
|
meshes[i] = mh.info;
|
||||||
|
|
||||||
|
minh = min(minh,mh.info.minHeight);
|
||||||
|
maxh = max(maxh,mh.info.maxHeight);
|
||||||
|
|
||||||
// Set everything else except the offsets
|
// Set everything else except the offsets
|
||||||
int alphaNum = mh.alphas.length;
|
int alphaNum = mh.alphas.length;
|
||||||
meshes[i].alphaNum = alphaNum;
|
meshes[i].alphaNum = alphaNum;
|
||||||
//meshes[i].texName = addString(mh.texName);
|
|
||||||
|
|
||||||
// Write the vertex buffer
|
// Write the vertex buffer
|
||||||
meshes[i].vertBufOffset = buf.size;
|
meshes[i].vertBufOffset = buf.size;
|
||||||
meshes[i].vertBufSize = mh.vertexBuffer.length;
|
meshes[i].vertBufSize = mh.vertexBuffer.length;
|
||||||
writeBuf(mh.vertexBuffer);
|
writeBuf(mh.vertexBuffer);
|
||||||
|
assert(buf.size == meshes[i].vertBufOffset + meshes[i].vertBufSize);
|
||||||
|
|
||||||
// Next write the alpha maps, if any
|
// Next write the alpha maps, if any
|
||||||
meshes[i].alphaOffset = buf.size;
|
meshes[i].alphaOffset = buf.size;
|
||||||
|
@ -231,13 +226,22 @@ struct CacheWriter
|
||||||
// Finally set up the QuadInfo itself
|
// Finally set up the QuadInfo itself
|
||||||
QuadInfo qi;
|
QuadInfo qi;
|
||||||
|
|
||||||
// Basic info
|
// Copy basic info
|
||||||
qi = qh.info;
|
qi = qh.info;
|
||||||
|
|
||||||
// Derived info
|
// Derived info
|
||||||
qi.meshNum = meshNum;
|
qi.meshNum = meshNum;
|
||||||
qi.offset = fileOffset;
|
qi.offset = fileOffset;
|
||||||
qi.size = buf.size;
|
qi.size = buf.size;
|
||||||
|
qi.minHeight = minh;
|
||||||
|
qi.maxHeight = maxh;
|
||||||
|
|
||||||
|
// Get the side length, or the height difference if that is bigger
|
||||||
|
qi.boundingRadius = max(maxh-minh,qi.worldWidth);
|
||||||
|
|
||||||
|
// Multiply with roughly sqrt(1/2), converts from side length to
|
||||||
|
// radius with some extra slack
|
||||||
|
qi.boundingRadius *= 0.8;
|
||||||
|
|
||||||
// The quad cache is done, write it to file
|
// The quad cache is done, write it to file
|
||||||
buf.writeTo(mainFile);
|
buf.writeTo(mainFile);
|
||||||
|
@ -307,8 +311,8 @@ private:
|
||||||
|
|
||||||
// Common vertex and index buffers for all quads. One buffer per
|
// Common vertex and index buffers for all quads. One buffer per
|
||||||
// level.
|
// level.
|
||||||
void[][] vertBuf;
|
float[][] vertBuf;
|
||||||
void[][] indexBuf;
|
ushort[] indexBuf;
|
||||||
|
|
||||||
// Variables that must be set during the gen phase
|
// Variables that must be set during the gen phase
|
||||||
int maxLevel;
|
int maxLevel;
|
||||||
|
|
|
@ -8,15 +8,19 @@ public:
|
||||||
: Ogre::Renderable(),
|
: Ogre::Renderable(),
|
||||||
Ogre::MovableObject()
|
Ogre::MovableObject()
|
||||||
{
|
{
|
||||||
|
TRACE("TerrainMesh()");
|
||||||
|
|
||||||
|
mLevel = level;
|
||||||
|
|
||||||
// This is a bit messy, with everything in one function. We could
|
// This is a bit messy, with everything in one function. We could
|
||||||
// split it up later.
|
// split it up later.
|
||||||
|
|
||||||
// Use MW coordinates all the way
|
// Use MW coordinates all the way
|
||||||
|
assert(info.worldWidth > 0);
|
||||||
|
assert(info.minHeight <= info.maxHeight);
|
||||||
mBounds.setExtents(0,0,info.minHeight,
|
mBounds.setExtents(0,0,info.minHeight,
|
||||||
// was (mWidth-1) * vertexSeparation
|
|
||||||
info.worldWidth, info.worldWidth,
|
info.worldWidth, info.worldWidth,
|
||||||
info.maxHeight);
|
info.maxHeight);
|
||||||
|
|
||||||
mCenter = mBounds.getCenter();
|
mCenter = mBounds.getCenter();
|
||||||
mBoundingRadius = mBounds.getHalfSize().length();
|
mBoundingRadius = mBounds.getHalfSize().length();
|
||||||
|
|
||||||
|
@ -56,16 +60,16 @@ public:
|
||||||
// Fill the buffer
|
// Fill the buffer
|
||||||
float* verts = static_cast<float*>
|
float* verts = static_cast<float*>
|
||||||
(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
||||||
info.fillVertexBuffer(verts);
|
info.fillVertexBuffer(verts,8*mVertices->vertexCount);
|
||||||
mMainBuffer->unlock();
|
mMainBuffer->unlock();
|
||||||
|
|
||||||
// Create the index data holder
|
// Create the index data holder
|
||||||
mIndices = new IndexData();
|
mIndices = new IndexData();
|
||||||
mIndices->indexCount = info.indexCount;
|
mIndices->indexCount = 64*64*6; // TODO: Shouldn't be hard-coded
|
||||||
mIndices->indexBuffer =
|
mIndices->indexBuffer =
|
||||||
HardwareBufferManager::getSingleton().createIndexBuffer
|
HardwareBufferManager::getSingleton().createIndexBuffer
|
||||||
( HardwareIndexBuffer::IT_16BIT,
|
( HardwareIndexBuffer::IT_16BIT,
|
||||||
info.indexCount,
|
mIndices->indexCount,
|
||||||
HardwareBuffer::HBU_STATIC_WRITE_ONLY,
|
HardwareBuffer::HBU_STATIC_WRITE_ONLY,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -74,17 +78,16 @@ public:
|
||||||
(mIndices->indexBuffer->lock
|
(mIndices->indexBuffer->lock
|
||||||
(0, mIndices->indexBuffer->getSizeInBytes(),
|
(0, mIndices->indexBuffer->getSizeInBytes(),
|
||||||
HardwareBuffer::HBL_DISCARD));
|
HardwareBuffer::HBL_DISCARD));
|
||||||
info.fillIndexBuffer(indices);
|
info.fillIndexBuffer(indices,mIndices->indexCount);
|
||||||
mIndices->indexBuffer->unlock();
|
mIndices->indexBuffer->unlock();
|
||||||
|
|
||||||
// Finally, create the material
|
// Finally, create the material
|
||||||
const std::string texName = info.getTexName();
|
const std::string texName = info.getTexName();
|
||||||
|
|
||||||
// TODO: A better thing to do here is to keep the material loaded
|
// Create or retrieve the material
|
||||||
// and retrieve it if it exists.
|
mMaterial = MaterialManager::getSingleton().createOrRetrieve
|
||||||
assert(!MaterialManager::getSingleton().resourceExists(texName));
|
(texName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME).first;
|
||||||
mMaterial = MaterialManager::getSingleton().create
|
|
||||||
(texName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
|
||||||
Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||||
pass->setLightingEnabled(false);
|
pass->setLightingEnabled(false);
|
||||||
|
|
||||||
|
@ -119,29 +122,32 @@ public:
|
||||||
// Name of the texture
|
// Name of the texture
|
||||||
std::string tname = alpha.getTexName();
|
std::string tname = alpha.getTexName();
|
||||||
|
|
||||||
// TODO: Need to store the result and either delete it in
|
// Create the alpha texture if it doesn't exist
|
||||||
// the destructor or fetch it again the next time we run.
|
if(!TextureManager::getSingleton().resourceExists(alphaName))
|
||||||
Ogre::TexturePtr texPtr = Ogre::TextureManager::
|
{
|
||||||
getSingleton().createManual
|
TexturePtr texPtr = Ogre::TextureManager::
|
||||||
(alphaName,
|
getSingleton().createManual
|
||||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
(alphaName,
|
||||||
Ogre::TEX_TYPE_2D,
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
g_alphaSize,g_alphaSize,
|
Ogre::TEX_TYPE_2D,
|
||||||
1,0, // depth, mipmaps
|
g_alphaSize,g_alphaSize,
|
||||||
Ogre::PF_A8, // One-channel alpha
|
1,0, // depth, mipmaps
|
||||||
Ogre::TU_STATIC_WRITE_ONLY);
|
Ogre::PF_A8, // One-channel alpha
|
||||||
|
Ogre::TU_STATIC_WRITE_ONLY);
|
||||||
|
|
||||||
// Get the pointer
|
// Get the pointer
|
||||||
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texPtr->getBuffer();
|
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texPtr->getBuffer();
|
||||||
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
|
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
|
||||||
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
|
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
|
||||||
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
|
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
|
||||||
|
|
||||||
// Copy alpha data from file
|
// Copy alpha data from file
|
||||||
alpha.fillAlphaBuffer(pDest);
|
alpha.fillAlphaBuffer(pDest,g_alphaSize*g_alphaSize);
|
||||||
|
|
||||||
|
// Close the buffer
|
||||||
|
pixelBuffer->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
// Finish everything up with a lot of Ogre-code
|
|
||||||
pixelBuffer->unlock();
|
|
||||||
pass = mMaterial->getTechnique(0)->createPass();
|
pass = mMaterial->getTechnique(0)->createPass();
|
||||||
pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
|
pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
|
||||||
pass->setLightingEnabled(false);
|
pass->setLightingEnabled(false);
|
||||||
|
@ -169,7 +175,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, set up the scene node.
|
// Finally, set up the scene node.
|
||||||
mNode = parent->createChildSceneNode(Vector3(info.x, info.y, 0.0));
|
mNode = parent->createChildSceneNode();
|
||||||
mNode->attachObject(this);
|
mNode->attachObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,8 +185,8 @@ public:
|
||||||
mNode->detachAllObjects();
|
mNode->detachAllObjects();
|
||||||
mNode->getCreator()->destroySceneNode(mNode);
|
mNode->getCreator()->destroySceneNode(mNode);
|
||||||
|
|
||||||
// TODO: This used to crash. See what happens now.
|
// TODO: This still crashes on level1 meshes. Find out why!
|
||||||
delete mVertices;
|
if(mLevel!=1)delete mVertices;
|
||||||
delete mIndices;
|
delete mIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,9 +243,11 @@ public:
|
||||||
mLightListDirty = true;
|
mLightListDirty = true;
|
||||||
queue->addRenderable(this, mRenderQueueID);
|
queue->addRenderable(this, mRenderQueueID);
|
||||||
}
|
}
|
||||||
const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
|
const Ogre::AxisAlignedBox& getBoundingBox( void ) const
|
||||||
|
{
|
||||||
return mBounds;
|
return mBounds;
|
||||||
};
|
}
|
||||||
|
|
||||||
Ogre::Real getBoundingRadius(void) const {
|
Ogre::Real getBoundingRadius(void) const {
|
||||||
return mBoundingRadius;
|
return mBoundingRadius;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +259,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
int mLevel;
|
||||||
|
|
||||||
Ogre::SceneNode* mNode;
|
Ogre::SceneNode* mNode;
|
||||||
|
|
||||||
Ogre::MaterialPtr mMaterial;
|
Ogre::MaterialPtr mMaterial;
|
||||||
|
|
|
@ -36,11 +36,13 @@ extern "C"
|
||||||
|
|
||||||
char *d_terr_getTexName(int32_t);
|
char *d_terr_getTexName(int32_t);
|
||||||
|
|
||||||
void d_terr_fillVertexBuffer(const MeshInfo*,float*);
|
void d_terr_fillVertexBuffer(const MeshInfo*,float*,uint64_t);
|
||||||
void d_terr_fillIndexBuffer(const MeshInfo*,uint16_t*);
|
void d_terr_fillIndexBuffer(const MeshInfo*,uint16_t*,uint64_t);
|
||||||
AlphaInfo *d_terr_getAlphaInfo(const MeshInfo*,int32_t);
|
AlphaInfo *d_terr_getAlphaInfo(const MeshInfo*,int32_t);
|
||||||
|
|
||||||
void d_terr_fillAlphaBuffer(const AlphaInfo*,uint8_t*);
|
void d_terr_fillAlphaBuffer(const AlphaInfo*,uint8_t*,uint64_t);
|
||||||
|
|
||||||
|
int32_t d_terr_getAlphaSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info about a submesh. This is a clone of the struct defined in
|
// Info about a submesh. This is a clone of the struct defined in
|
||||||
|
@ -54,10 +56,6 @@ struct MeshInfo
|
||||||
|
|
||||||
// Vertex and index numbers
|
// Vertex and index numbers
|
||||||
int32_t vertRows, vertCols;
|
int32_t vertRows, vertCols;
|
||||||
int32_t indexCount;
|
|
||||||
|
|
||||||
// Scene node position (relative to the parent node)
|
|
||||||
float x, y;
|
|
||||||
|
|
||||||
// Height offset to apply to all vertices
|
// Height offset to apply to all vertices
|
||||||
float heightOffset;
|
float heightOffset;
|
||||||
|
@ -72,14 +70,14 @@ struct MeshInfo
|
||||||
// Texture name. Index to the string table.
|
// Texture name. Index to the string table.
|
||||||
int32_t texName;
|
int32_t texName;
|
||||||
|
|
||||||
inline void fillVertexBuffer(float *buffer) const
|
inline void fillVertexBuffer(float *buffer, uint64_t size) const
|
||||||
{
|
{
|
||||||
d_terr_fillVertexBuffer(this, buffer);
|
d_terr_fillVertexBuffer(this, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void fillIndexBuffer(uint16_t *buffer) const
|
inline void fillIndexBuffer(uint16_t *buffer, uint64_t size) const
|
||||||
{
|
{
|
||||||
d_terr_fillIndexBuffer(this, buffer);
|
d_terr_fillIndexBuffer(this, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* getTexName() const
|
inline char* getTexName() const
|
||||||
|
@ -114,9 +112,9 @@ struct AlphaInfo
|
||||||
return d_terr_getTexName(alphaName);
|
return d_terr_getTexName(alphaName);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void fillAlphaBuffer(uint8_t *buffer) const
|
inline void fillAlphaBuffer(uint8_t *buffer, uint64_t size) const
|
||||||
{
|
{
|
||||||
return d_terr_fillAlphaBuffer(this, buffer);
|
return d_terr_fillAlphaBuffer(this, buffer, size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,12 +128,67 @@ class TerrainFrameListener : public FrameListener
|
||||||
protected:
|
protected:
|
||||||
bool frameEnded(const FrameEvent& evt)
|
bool frameEnded(const FrameEvent& evt)
|
||||||
{
|
{
|
||||||
|
TRACE("Terrain frame");
|
||||||
d_terr_terrainUpdate();
|
d_terr_terrainUpdate();
|
||||||
g_baseLand->update();
|
g_baseLand->update();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Renders a material into a texture
|
||||||
|
Ogre::TexturePtr getRenderedTexture(Ogre::MaterialPtr mp,
|
||||||
|
const std::string& name,
|
||||||
|
int texSize, Ogre::PixelFormat tt)
|
||||||
|
{
|
||||||
|
Ogre::CompositorPtr cp = Ogre::CompositorManager::getSingleton().
|
||||||
|
create("Rtt_Comp",
|
||||||
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
|
||||||
|
Ogre::CompositionTargetPass* ctp = cp->createTechnique()->getOutputTargetPass();
|
||||||
|
Ogre::CompositionPass* cpass = ctp->createPass();
|
||||||
|
cpass->setType(Ogre::CompositionPass::PT_RENDERQUAD);
|
||||||
|
cpass->setMaterial(mp);
|
||||||
|
|
||||||
|
// Create the destination texture
|
||||||
|
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().
|
||||||
|
createManual(name + "_T",
|
||||||
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
Ogre::TEX_TYPE_2D,
|
||||||
|
texSize,
|
||||||
|
texSize,
|
||||||
|
0,
|
||||||
|
tt,
|
||||||
|
Ogre::TU_RENDERTARGET
|
||||||
|
);
|
||||||
|
|
||||||
|
Ogre::RenderTexture* renderTexture = texture->getBuffer()->getRenderTarget();
|
||||||
|
Ogre::Viewport* vp = renderTexture->addViewport(mCamera);
|
||||||
|
|
||||||
|
Ogre::CompositorManager::getSingleton().addCompositor(vp, "Rtt_Comp");
|
||||||
|
Ogre::CompositorManager::getSingleton().setCompositorEnabled(vp,"Rtt_Comp", true);
|
||||||
|
|
||||||
|
renderTexture->update();
|
||||||
|
|
||||||
|
// Call the OGRE renderer.
|
||||||
|
Ogre::Root::getSingleton().renderOneFrame();
|
||||||
|
|
||||||
|
Ogre::CompositorManager::getSingleton().removeCompositor(vp, "Rtt_Comp");
|
||||||
|
Ogre::CompositorManager::getSingleton().remove(cp->getHandle());
|
||||||
|
|
||||||
|
renderTexture->removeAllViewports();
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are used between some functions below. Kinda messy. Since
|
||||||
|
// these are GLOBAL instances, they are terminated at program
|
||||||
|
// exit. However, OGRE itself is terminated before that, so we have to
|
||||||
|
// make sure we have no 'active' shared pointers after OGRE is
|
||||||
|
// finished (otherwise we get a segfault at exit.)
|
||||||
|
std::list<Ogre::ResourcePtr> createdResources;
|
||||||
|
Ogre::HardwarePixelBuffer *pixelBuffer;
|
||||||
|
MaterialPtr mat;
|
||||||
|
|
||||||
// Functions called from D
|
// Functions called from D
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
@ -163,8 +216,11 @@ extern "C"
|
||||||
Ogre::AxisAlignedBox *terr_makeBounds(float minHeight, float maxHeight,
|
Ogre::AxisAlignedBox *terr_makeBounds(float minHeight, float maxHeight,
|
||||||
float width, SceneNode* node)
|
float width, SceneNode* node)
|
||||||
{
|
{
|
||||||
|
TRACE("terr_makeBounds");
|
||||||
AxisAlignedBox *mBounds = new AxisAlignedBox;
|
AxisAlignedBox *mBounds = new AxisAlignedBox;
|
||||||
|
|
||||||
|
assert(maxHeight >= minHeight);
|
||||||
|
|
||||||
mBounds->setExtents(0,0,minHeight,
|
mBounds->setExtents(0,0,minHeight,
|
||||||
width,width,maxHeight);
|
width,width,maxHeight);
|
||||||
|
|
||||||
|
@ -177,11 +233,13 @@ extern "C"
|
||||||
|
|
||||||
void terr_killBounds(AxisAlignedBox *bounds)
|
void terr_killBounds(AxisAlignedBox *bounds)
|
||||||
{
|
{
|
||||||
|
TRACE("terr_killBounds");
|
||||||
delete bounds;
|
delete bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
float terr_getSqCamDist(AxisAlignedBox *mBounds)
|
float terr_getSqCamDist(AxisAlignedBox *mBounds)
|
||||||
{
|
{
|
||||||
|
TRACE("terr_getSqCamDist");
|
||||||
Ogre::Vector3 cpos = mCamera->getDerivedPosition();
|
Ogre::Vector3 cpos = mCamera->getDerivedPosition();
|
||||||
Ogre::Vector3 diff(0, 0, 0);
|
Ogre::Vector3 diff(0, 0, 0);
|
||||||
diff.makeFloor(cpos - mBounds->getMinimum() );
|
diff.makeFloor(cpos - mBounds->getMinimum() );
|
||||||
|
@ -193,19 +251,22 @@ extern "C"
|
||||||
MeshInfo *info,
|
MeshInfo *info,
|
||||||
int level, float scale)
|
int level, float scale)
|
||||||
{
|
{
|
||||||
|
|
||||||
return new TerrainMesh(parent, *info, level, scale);
|
return new TerrainMesh(parent, *info, level, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void terr_killMesh(TerrainMesh *mesh)
|
void terr_killMesh(TerrainMesh *mesh)
|
||||||
{ delete mesh; }
|
{
|
||||||
|
TRACE("terr_killMesh");
|
||||||
|
delete mesh;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the rendering system
|
// Set up the rendering system
|
||||||
void terr_setupRendering()
|
void terr_setupRendering()
|
||||||
{
|
{
|
||||||
|
TRACE("terr_setupRendering()");
|
||||||
// Make sure the C++ sizes match the D sizes, since the structs
|
// Make sure the C++ sizes match the D sizes, since the structs
|
||||||
// will be shared between the two.
|
// are shared between the two.
|
||||||
assert(sizeof(MeshInfo) == 17*4);
|
assert(sizeof(MeshInfo) == 14*4);
|
||||||
assert(sizeof(AlphaInfo) == 6*4);
|
assert(sizeof(AlphaInfo) == 6*4);
|
||||||
|
|
||||||
// Add the terrain directory as a resource location. TODO: Get the
|
// Add the terrain directory as a resource location. TODO: Get the
|
||||||
|
@ -226,7 +287,126 @@ extern "C"
|
||||||
// terrain mesh that makes the terrain look infinite.
|
// terrain mesh that makes the terrain look infinite.
|
||||||
g_baseLand = new BaseLand();
|
g_baseLand = new BaseLand();
|
||||||
|
|
||||||
|
g_alphaSize = d_terr_getAlphaSize();
|
||||||
|
|
||||||
// Add the frame listener
|
// Add the frame listener
|
||||||
mRoot->addFrameListener(new TerrainFrameListener);
|
mRoot->addFrameListener(new TerrainFrameListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The next four functions are called in the function genLevel2Map()
|
||||||
|
// only. This is very top-down-programming-ish and a bit messy, but
|
||||||
|
// that's what I get for mixing C++ and D like this.
|
||||||
|
void terr_makeLandMaterial(const char* name, float scale)
|
||||||
|
{
|
||||||
|
// Get a new material
|
||||||
|
mat = Ogre::MaterialManager::getSingleton().
|
||||||
|
create(name,
|
||||||
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
|
||||||
|
// Put the default texture in the bottom 'layer', so that we don't
|
||||||
|
// end up seeing through the landscape.
|
||||||
|
Ogre::Pass* np = mat->getTechnique(0)->getPass(0);
|
||||||
|
np->setLightingEnabled(false);
|
||||||
|
np->createTextureUnitState("_land_default.dds")
|
||||||
|
->setTextureScale(scale,scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *terr_makeAlphaLayer(const char* name, int32_t width)
|
||||||
|
{
|
||||||
|
// Create alpha map for this texture.
|
||||||
|
Ogre::TexturePtr texPtr = Ogre::TextureManager::getSingleton().
|
||||||
|
createManual(name,
|
||||||
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
Ogre::TEX_TYPE_2D,
|
||||||
|
width, width,
|
||||||
|
1,0, // depth, mipmaps
|
||||||
|
Ogre::PF_A8, // One-channel alpha
|
||||||
|
Ogre::TU_STATIC_WRITE_ONLY);
|
||||||
|
|
||||||
|
createdResources.push_back(texPtr);
|
||||||
|
|
||||||
|
pixelBuffer = texPtr->getBuffer().get();
|
||||||
|
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
|
||||||
|
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
|
||||||
|
|
||||||
|
return static_cast<Ogre::uint8*>(pixelBox.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void terr_closeAlpha(const char *alphaName,
|
||||||
|
const char *texName, float scale)
|
||||||
|
{
|
||||||
|
// Close the alpha pixel buffer opened in the previous function
|
||||||
|
pixelBuffer->unlock();
|
||||||
|
|
||||||
|
// Create a pass containing the alpha map
|
||||||
|
Pass *np = mat->getTechnique(0)->createPass();
|
||||||
|
np->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
|
||||||
|
np->setLightingEnabled(false);
|
||||||
|
np->setDepthFunction(Ogre::CMPF_EQUAL);
|
||||||
|
Ogre::TextureUnitState* tus = np->createTextureUnitState(alphaName);
|
||||||
|
tus->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
|
||||||
|
|
||||||
|
// Set various blending options
|
||||||
|
tus->setAlphaOperation(Ogre::LBX_BLEND_TEXTURE_ALPHA,
|
||||||
|
Ogre::LBS_TEXTURE,
|
||||||
|
Ogre::LBS_TEXTURE);
|
||||||
|
tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA,
|
||||||
|
Ogre::LBS_TEXTURE,
|
||||||
|
Ogre::LBS_TEXTURE);
|
||||||
|
tus->setIsAlpha(true);
|
||||||
|
|
||||||
|
// Add the terrain texture to the pass and scale it.
|
||||||
|
tus = np->createTextureUnitState(texName);
|
||||||
|
tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA,
|
||||||
|
Ogre::LBS_TEXTURE,
|
||||||
|
Ogre::LBS_CURRENT);
|
||||||
|
tus->setTextureScale(scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up after the above functions, render the material to
|
||||||
|
// texture and save the data in outdata and in the file outname.
|
||||||
|
void terr_cleanupAlpha(const char *outname,
|
||||||
|
void *outData, int32_t toSize)
|
||||||
|
{
|
||||||
|
TexturePtr tex1 = getRenderedTexture(mat,outname,
|
||||||
|
toSize,Ogre::PF_R8G8B8);
|
||||||
|
|
||||||
|
// Blit the texture into the given memory buffer
|
||||||
|
PixelBox pb = PixelBox(toSize, toSize, 1, PF_R8G8B8);
|
||||||
|
pb.data = outData;
|
||||||
|
tex1->getBuffer()->blitToMemory(pb);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
TextureManager::getSingleton().remove(tex1->getHandle());
|
||||||
|
const std::list<Ogre::ResourcePtr>::const_iterator iend = createdResources.end();
|
||||||
|
for ( std::list<Ogre::ResourcePtr>::const_iterator itr = createdResources.begin();
|
||||||
|
itr != iend;
|
||||||
|
++itr)
|
||||||
|
(*itr)->getCreator()->remove((*itr)->getHandle());
|
||||||
|
createdResources.clear();
|
||||||
|
|
||||||
|
MaterialManager::getSingleton().remove(mat->getHandle());
|
||||||
|
mat.setNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void terr_resize(void* srcPtr, void* dstPtr, int32_t fromW, int32_t toW)
|
||||||
|
{
|
||||||
|
// Create pixelboxes
|
||||||
|
PixelBox src = PixelBox(fromW, fromW, 1, PF_R8G8B8);
|
||||||
|
PixelBox dst = PixelBox(toW, toW, 1, PF_R8G8B8);
|
||||||
|
|
||||||
|
src.data = srcPtr;
|
||||||
|
dst.data = dstPtr;
|
||||||
|
|
||||||
|
// Resize the image. The nearest neighbour filter makes sure
|
||||||
|
// there is no blurring.
|
||||||
|
Image::scale(src, dst, Ogre::Image::FILTER_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void terr_saveImage(void *data, int32_t width, const char* name)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
img.loadDynamicImage((uchar*)data, width, width, PF_R8G8B8);
|
||||||
|
img.save(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import esm.loadcell;
|
||||||
import util.regions;
|
import util.regions;
|
||||||
import esm.filereader;
|
import esm.filereader;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
const int LAND_NUM_VERTS = 65*65;
|
const int LAND_NUM_VERTS = 65*65;
|
||||||
|
|
||||||
MWLand mwland;
|
MWLand mwland;
|
||||||
|
@ -49,23 +51,27 @@ struct MWLand
|
||||||
// Texture data for one cell
|
// Texture data for one cell
|
||||||
struct LTEXData
|
struct LTEXData
|
||||||
{
|
{
|
||||||
// TODO: Store the source file here too, so we can get the list
|
// Global list of land textures from the source ES file
|
||||||
// from the right file. The source file is the same as the one we
|
LandTextureList.TextureList source;
|
||||||
// load the landscape from in loadCell().
|
|
||||||
|
// Texture indices for this cell
|
||||||
VTEX vtex;
|
VTEX vtex;
|
||||||
|
|
||||||
// Get the texture x2,y2 from the sub map x1,x2
|
// Get the texture x2,y2 from the sub map x1,x2
|
||||||
char[] getTexture(int x1, int y1, int x2, int y2)
|
char[] getTexture(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
// Get the texture index relative to the current esm/esp file
|
// Get the texture index relative to the current esm/esp file
|
||||||
short texID = vtex[y1][x1][y2][x2];
|
short texID = vtex[y1][x1][y2][x2] - 1;
|
||||||
|
|
||||||
// Hack, will only work for Morrowind.esm. Fix this later.
|
if(texID == -1)
|
||||||
auto tl = landTextures.files["Morrowind.esm"];
|
return null;
|
||||||
|
|
||||||
// Return the 'new' texture name. This name has automatically
|
// Return the 'new' texture name. This name was automatically
|
||||||
// been converted to .dds if the .tga file was not found.
|
// been converted to .dds at load time if the .tga file was not
|
||||||
return tl[texID].getNewName();
|
// found.
|
||||||
|
assert(source !is null);
|
||||||
|
assert(texID >= 0 && texID < source.length);
|
||||||
|
return source[texID].getNewName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a texture from the 16x16 grid in one cell
|
// Get a texture from the 16x16 grid in one cell
|
||||||
|
@ -127,6 +133,9 @@ struct MWLand
|
||||||
// skip to the right part of the ESM file.
|
// skip to the right part of the ESM file.
|
||||||
auto cont = cells.getExt(x,y).land.context;
|
auto cont = cells.getExt(x,y).land.context;
|
||||||
|
|
||||||
|
// Get the land texture list from the file
|
||||||
|
currentLtex.source = landTextures.files[cont.filename];
|
||||||
|
|
||||||
// We should use an existing region later, or at least delete this
|
// We should use an existing region later, or at least delete this
|
||||||
// once we're done with the gen process.
|
// once we're done with the gen process.
|
||||||
if(reg is null)
|
if(reg is null)
|
||||||
|
@ -135,7 +144,7 @@ struct MWLand
|
||||||
// Open the ESM at this cell
|
// Open the ESM at this cell
|
||||||
esFile.restoreContext(cont, reg);
|
esFile.restoreContext(cont, reg);
|
||||||
|
|
||||||
// Store the data
|
// Store the cell-specific data
|
||||||
esFile.readHNExact(currentLand.normals.ptr,
|
esFile.readHNExact(currentLand.normals.ptr,
|
||||||
currentLand.normals.length, "VNML");
|
currentLand.normals.length, "VNML");
|
||||||
esFile.readHNExact(¤tLand.vhgt, VHGT.sizeof, "VHGT");
|
esFile.readHNExact(¤tLand.vhgt, VHGT.sizeof, "VHGT");
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,8 @@ module terrain.quad;
|
||||||
|
|
||||||
import terrain.archive;
|
import terrain.archive;
|
||||||
import terrain.bindings;
|
import terrain.bindings;
|
||||||
|
import std.stdio;
|
||||||
|
import monster.vm.dbg;
|
||||||
|
|
||||||
const int CELL_WIDTH = 8192;
|
const int CELL_WIDTH = 8192;
|
||||||
const float SPLIT_FACTOR = 0.5;
|
const float SPLIT_FACTOR = 0.5;
|
||||||
|
@ -11,6 +13,8 @@ class Quad
|
||||||
{
|
{
|
||||||
this(int cellX=0, int cellY=0, Quad parent = null)
|
this(int cellX=0, int cellY=0, Quad parent = null)
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("Quad.this");
|
||||||
|
|
||||||
mCellX = cellX;
|
mCellX = cellX;
|
||||||
mCellY = cellY;
|
mCellY = cellY;
|
||||||
|
|
||||||
|
@ -19,13 +23,6 @@ class Quad
|
||||||
{
|
{
|
||||||
mLevel = parent.mLevel-1;
|
mLevel = parent.mLevel-1;
|
||||||
|
|
||||||
if(mLevel == 1)
|
|
||||||
{
|
|
||||||
// Create the terrain and leave it there.
|
|
||||||
buildTerrain();
|
|
||||||
isStatic = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coordinates relative to our parent
|
// Coordinates relative to our parent
|
||||||
int relX = cellX - parent.mCellX;
|
int relX = cellX - parent.mCellX;
|
||||||
int relY = cellY - parent.mCellY;
|
int relY = cellY - parent.mCellY;
|
||||||
|
@ -43,12 +40,36 @@ class Quad
|
||||||
|
|
||||||
// Get the archive data for this quad.
|
// Get the archive data for this quad.
|
||||||
mInfo = g_archive.getQuad(mCellX,mCellY,mLevel);
|
mInfo = g_archive.getQuad(mCellX,mCellY,mLevel);
|
||||||
|
|
||||||
|
// Set up the bounding box. Use MW coordinates all the
|
||||||
|
// way.
|
||||||
|
mBounds = terr_makeBounds(mInfo.minHeight,
|
||||||
|
mInfo.maxHeight,
|
||||||
|
mInfo.worldWidth,
|
||||||
|
mNode);
|
||||||
|
|
||||||
|
float radius = mInfo.boundingRadius;
|
||||||
|
|
||||||
|
mSplitDistance = radius * SPLIT_FACTOR;
|
||||||
|
mUnsplitDistance = radius * UNSPLIT_FACTOR;
|
||||||
|
|
||||||
|
// Square the distances
|
||||||
|
mSplitDistance *= mSplitDistance;
|
||||||
|
mUnsplitDistance *= mUnsplitDistance;
|
||||||
|
|
||||||
|
if(mLevel == 1)
|
||||||
|
{
|
||||||
|
// Create the terrain and leave it there.
|
||||||
|
buildTerrain();
|
||||||
|
isStatic = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No parent, this is the top-most quad. Get all the info from
|
// No parent, this is the top-most quad. Get all the info from
|
||||||
// the archive.
|
// the archive.
|
||||||
mInfo = g_archive.rootQuad;
|
mInfo = g_archive.rootQuad;
|
||||||
|
assert(mInfo);
|
||||||
|
|
||||||
mLevel = mInfo.level;
|
mLevel = mInfo.level;
|
||||||
cellX = mCellX = mInfo.cellX;
|
cellX = mCellX = mInfo.cellX;
|
||||||
|
@ -68,21 +89,6 @@ class Quad
|
||||||
assert(mLevel >= 1);
|
assert(mLevel >= 1);
|
||||||
assert(mNode !is null);
|
assert(mNode !is null);
|
||||||
|
|
||||||
// Set up the bounding box. Use MW coordinates all the way
|
|
||||||
mBounds = terr_makeBounds(mInfo.minHeight,
|
|
||||||
mInfo.maxHeight,
|
|
||||||
mInfo.worldWidth,
|
|
||||||
mNode);
|
|
||||||
|
|
||||||
float radius = mInfo.boundingRadius;
|
|
||||||
|
|
||||||
mSplitDistance = radius * SPLIT_FACTOR;
|
|
||||||
mUnsplitDistance = radius * UNSPLIT_FACTOR;
|
|
||||||
|
|
||||||
// Square the distances
|
|
||||||
mSplitDistance *= mSplitDistance;
|
|
||||||
mUnsplitDistance *= mUnsplitDistance;
|
|
||||||
|
|
||||||
// Update the terrain. This will create the mesh or children if
|
// Update the terrain. This will create the mesh or children if
|
||||||
// necessary.
|
// necessary.
|
||||||
update();
|
update();
|
||||||
|
@ -90,6 +96,8 @@ class Quad
|
||||||
|
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("Quad.~this");
|
||||||
|
|
||||||
// TODO: We might rewrite the code so that the quads are never
|
// TODO: We might rewrite the code so that the quads are never
|
||||||
// actually destroyed, just 'inactivated' by hiding their scene
|
// actually destroyed, just 'inactivated' by hiding their scene
|
||||||
// node. We only call update on our children if we don't have a
|
// node. We only call update on our children if we don't have a
|
||||||
|
@ -101,12 +109,14 @@ class Quad
|
||||||
delete mChildren[i];
|
delete mChildren[i];
|
||||||
|
|
||||||
terr_destroyNode(mNode);
|
terr_destroyNode(mNode);
|
||||||
terr_killBounds(mBounds);
|
if(mBounds !is null)
|
||||||
|
terr_killBounds(mBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the landscape for this quad, and create children.
|
// Remove the landscape for this quad, and create children.
|
||||||
void split()
|
void split()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("split");
|
||||||
// Never split a static quad or a quad that already has children.
|
// Never split a static quad or a quad that already has children.
|
||||||
assert(!isStatic);
|
assert(!isStatic);
|
||||||
assert(!hasChildren);
|
assert(!hasChildren);
|
||||||
|
@ -136,6 +146,7 @@ class Quad
|
||||||
// Removes children and rebuilds terrain
|
// Removes children and rebuilds terrain
|
||||||
void unsplit()
|
void unsplit()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("unsplit");
|
||||||
// Never unsplit the root quad
|
// Never unsplit the root quad
|
||||||
assert(mLevel < g_archive.rootQuad.level);
|
assert(mLevel < g_archive.rootQuad.level);
|
||||||
// Never unsplit a static or quad that isn't split.
|
// Never unsplit a static or quad that isn't split.
|
||||||
|
@ -158,6 +169,8 @@ class Quad
|
||||||
// does it.
|
// does it.
|
||||||
void update()
|
void update()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("Quad.update()");
|
||||||
|
|
||||||
// Static quads don't change
|
// Static quads don't change
|
||||||
if(!isStatic)
|
if(!isStatic)
|
||||||
{
|
{
|
||||||
|
@ -165,6 +178,7 @@ class Quad
|
||||||
|
|
||||||
// Get (squared) camera distance. TODO: shouldn't this just
|
// Get (squared) camera distance. TODO: shouldn't this just
|
||||||
// be a simple vector difference from the mesh center?
|
// be a simple vector difference from the mesh center?
|
||||||
|
assert(mBounds !is null);
|
||||||
float camDist = terr_getSqCamDist(mBounds);
|
float camDist = terr_getSqCamDist(mBounds);
|
||||||
|
|
||||||
// No children?
|
// No children?
|
||||||
|
@ -209,10 +223,13 @@ class Quad
|
||||||
// Build the terrain for this quad
|
// Build the terrain for this quad
|
||||||
void buildTerrain()
|
void buildTerrain()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("buildTerrain");
|
||||||
|
|
||||||
assert(!hasMesh);
|
assert(!hasMesh);
|
||||||
assert(!isStatic);
|
assert(!isStatic);
|
||||||
|
|
||||||
// Map the terrain data into memory.
|
// Map the terrain data into memory.
|
||||||
|
assert(mInfo);
|
||||||
g_archive.mapQuad(mInfo);
|
g_archive.mapQuad(mInfo);
|
||||||
|
|
||||||
// Create one mesh for each segment in the quad. TerrainMesh takes
|
// Create one mesh for each segment in the quad. TerrainMesh takes
|
||||||
|
@ -221,7 +238,7 @@ class Quad
|
||||||
foreach(i, ref m; meshList)
|
foreach(i, ref m; meshList)
|
||||||
{
|
{
|
||||||
MeshInfo *mi = g_archive.getMeshInfo(i);
|
MeshInfo *mi = g_archive.getMeshInfo(i);
|
||||||
m = terr_makeMesh(mNode, mi, mInfo.level, mInfo.texScale);
|
m = terr_makeMesh(mNode, mi, mInfo.level, TEX_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMesh = true;
|
hasMesh = true;
|
||||||
|
@ -229,6 +246,8 @@ class Quad
|
||||||
|
|
||||||
void destroyTerrain()
|
void destroyTerrain()
|
||||||
{
|
{
|
||||||
|
scope auto _trc = new MTrace("destroyTerrain");
|
||||||
|
|
||||||
assert(hasMesh);
|
assert(hasMesh);
|
||||||
|
|
||||||
foreach(m; meshList)
|
foreach(m; meshList)
|
||||||
|
|
|
@ -31,6 +31,9 @@ import std.file, std.stdio;
|
||||||
|
|
||||||
char[] cacheDir = "cache/terrain/";
|
char[] cacheDir = "cache/terrain/";
|
||||||
|
|
||||||
|
// Enable this to render one single terrain mesh
|
||||||
|
//debug=singleMesh;
|
||||||
|
|
||||||
void initTerrain(bool doGen)
|
void initTerrain(bool doGen)
|
||||||
{
|
{
|
||||||
char[] fname = cacheDir ~ "landscape.cache";
|
char[] fname = cacheDir ~ "landscape.cache";
|
||||||
|
@ -50,12 +53,26 @@ void initTerrain(bool doGen)
|
||||||
|
|
||||||
terr_setupRendering();
|
terr_setupRendering();
|
||||||
|
|
||||||
// Create the root quad
|
debug(singleMesh)
|
||||||
rootQuad = new Quad;
|
{
|
||||||
|
// Used for debugging single terrain meshes
|
||||||
|
auto node = terr_createChildNode(20000,-60000,null);
|
||||||
|
auto info = g_archive.getQuad(0,0,1);
|
||||||
|
g_archive.mapQuad(info);
|
||||||
|
auto mi = g_archive.getMeshInfo(0);
|
||||||
|
auto m = terr_makeMesh(node, mi, info.level, TEX_SCALE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create the root quad
|
||||||
|
rootQuad = new Quad;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern(C) void d_terr_terrainUpdate()
|
extern(C) void d_terr_terrainUpdate()
|
||||||
{
|
{
|
||||||
|
debug(singleMesh) return;
|
||||||
|
|
||||||
// Update the root quad each frame.
|
// Update the root quad each frame.
|
||||||
assert(rootQuad !is null);
|
assert(rootQuad !is null);
|
||||||
rootQuad.update();
|
rootQuad.update();
|
||||||
|
|
Loading…
Reference in a new issue