forked from teamnwah/openmw-tes3coop
Started early work on terrain code (no rendering yet.)
parent
3e170002e2
commit
255b0d03a9
@ -0,0 +1 @@
|
|||||||
|
old
|
@ -0,0 +1,48 @@
|
|||||||
|
#include "esm_land_factory.hpp"
|
||||||
|
|
||||||
|
// The first one already includes the others implicitly, but it
|
||||||
|
// doesn't hurt to be explicit.
|
||||||
|
#include "../esm_store/store.hpp"
|
||||||
|
#include "../esm/esm_reader.hpp"
|
||||||
|
#include "../esm/loadland.hpp"
|
||||||
|
|
||||||
|
using namespace Terrain;
|
||||||
|
|
||||||
|
static class ESMLandStream : public Mangle::Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ESMLandStream(ESM::Land *l, ESM::ESMReader &r)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ESMLandFactory::has(int x, int y)
|
||||||
|
{
|
||||||
|
return store.landscapes.has(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
LandDataPtr get(int x, int y, LandInfo &info)
|
||||||
|
{
|
||||||
|
assert(has(x,y));
|
||||||
|
|
||||||
|
// Set up the info
|
||||||
|
info.grid = LGT_Quadratic;
|
||||||
|
info.data = LDT_Float;
|
||||||
|
|
||||||
|
const float SIZE = 8192; // CHECK
|
||||||
|
|
||||||
|
info.xsize = SIZE;
|
||||||
|
info.ysize = SIZE;
|
||||||
|
info.numx = 65;
|
||||||
|
info.numy = 65;
|
||||||
|
info.xoffset = SIZE*x;
|
||||||
|
info.yoffset = SIZE*y;
|
||||||
|
|
||||||
|
// Get the Land struct from store
|
||||||
|
ESM::Land* land = store.landscapes.find(x,y);
|
||||||
|
assert(land->hasData);
|
||||||
|
|
||||||
|
// Create a stream for the data and return it.
|
||||||
|
LandDataPtr ptr(new ESMLandStream(land, reader));
|
||||||
|
return ptr;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef TERRAIN_ESM_LAND_FACTORY_H
|
||||||
|
#define TERRAIN_ESM_LAND_FACTORY_H
|
||||||
|
|
||||||
|
#include "land_factory.hpp"
|
||||||
|
|
||||||
|
namespace ESMS
|
||||||
|
{
|
||||||
|
struct ESMStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Land factory that loads data from ESM files.
|
||||||
|
*/
|
||||||
|
class ESMLandFactory
|
||||||
|
{
|
||||||
|
ESMS::ESMStore &store;
|
||||||
|
ESM::ESMReader &reader;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the land factory. Note that refrences to the given
|
||||||
|
// store and reader are stored in the class, so the given objects
|
||||||
|
// must be valid for a long as you plan to use this factory.
|
||||||
|
ESMLandFactory(ESMS::ESMStore &st, ESM::ESMReader &rd)
|
||||||
|
: store(st), reader(rd) {}
|
||||||
|
|
||||||
|
// True if this factory has any data for the given grid cell.
|
||||||
|
bool has(int x, int y);
|
||||||
|
|
||||||
|
// Return stream to data for this cell. Additional data about the
|
||||||
|
// landscape is returned through the LandInfo struct.
|
||||||
|
LandDataPtr get(int x, int y, LandInfo &info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef TERRAIN_HEIGHTMAP_H
|
||||||
|
#define TERRAIN_HEIGHTMAP_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generic interface for a structure holding heightmap data.
|
||||||
|
|
||||||
|
A HeightMap returns information about landscape data in the form of
|
||||||
|
a regular grid of float heights.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
struct HeightMap
|
||||||
|
{
|
||||||
|
// Get height from grid position, counted from 0 to getNumX/Y().
|
||||||
|
virtual float getHeight(int x, int y) = 0;
|
||||||
|
|
||||||
|
// Get heigth from vertex index, assumed to be y*getNumX() + x.
|
||||||
|
virtual float getHeight(int index) = 0;
|
||||||
|
|
||||||
|
virtual float getMinX() = 0;
|
||||||
|
virtual float getMaxX() = 0;
|
||||||
|
virtual float getMinY() = 0;
|
||||||
|
virtual float getMaxY() = 0;
|
||||||
|
|
||||||
|
virtual int getNumX() = 0;
|
||||||
|
virtual int getNumY() = 0;
|
||||||
|
|
||||||
|
// True if the given coordinate is within the grid
|
||||||
|
bool isWithin(float x, float y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x >= getMinX() && x < getMaxX() &&
|
||||||
|
y >= getMinY() && y < getMaxY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,72 @@
|
|||||||
|
#ifndef TERRAIN_HEIGHTMAPBUF_H
|
||||||
|
#define TERRAIN_HEIGHTMAPBUF_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
A HeightMap implementation that stores heigths in a buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "heightmap.hpp"
|
||||||
|
#include "land_factory.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
class HeightMapBuffer : public HeightMap
|
||||||
|
{
|
||||||
|
std::vector<float> buf;
|
||||||
|
|
||||||
|
float beginX, sizeX, endX;
|
||||||
|
float beginY, sizeY, endY;
|
||||||
|
|
||||||
|
int numX, numY;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void load(LandDataPtr data, const LandInfo &info)
|
||||||
|
{
|
||||||
|
// We don't support other kinds of grid data yet.
|
||||||
|
assert(info.grid == LGT_Quadratic);
|
||||||
|
assert(info.data == LDT_Float);
|
||||||
|
|
||||||
|
// Set up internal data
|
||||||
|
beginX = info.xoffset;
|
||||||
|
sizeX = info.xsize;
|
||||||
|
endX = beginX+sizeX;
|
||||||
|
numX = info.numx;
|
||||||
|
|
||||||
|
beginY = info.yoffset;
|
||||||
|
sizeY = info.ysize;
|
||||||
|
endY = beginY+sizeY;
|
||||||
|
numY = info.numy;
|
||||||
|
|
||||||
|
// Prepare the buffer and load it
|
||||||
|
buf.resize(numX*numY);
|
||||||
|
|
||||||
|
data.read(&buf[0], buf.size()*sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions inherited from HeightMap:
|
||||||
|
|
||||||
|
float getHeight(int x, int y)
|
||||||
|
{
|
||||||
|
assert(x>=0 && x<numX);
|
||||||
|
assert(y>=0 && y<numY);
|
||||||
|
return getHeight(x + y*numX);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getHeight(int index)
|
||||||
|
{
|
||||||
|
assert(index >= 0 && index < buf.size());
|
||||||
|
return buf[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
float getMinX() { return beginX; }
|
||||||
|
float getMaxX() { return endX; }
|
||||||
|
float getMinY() { return beginY; }
|
||||||
|
float getMaxY() { return endY; }
|
||||||
|
|
||||||
|
int getNumX() { return numX; }
|
||||||
|
int getNumY() { return numY; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef TERRAIN_LAND_FACTORY_H
|
||||||
|
#define TERRAIN_LAND_FACTORY_H
|
||||||
|
|
||||||
|
#include <mangle/stream/stream.hpp>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
enum LandInfoGridType
|
||||||
|
{
|
||||||
|
LGT_Quadratic
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LandInfoDataType
|
||||||
|
{
|
||||||
|
LDT_Float
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandInfo
|
||||||
|
{
|
||||||
|
// Type information
|
||||||
|
LandInfoGridType grid;
|
||||||
|
LandInfoDataType data;
|
||||||
|
|
||||||
|
// Landscape size and number of vertices. Note that xsize and
|
||||||
|
// ysize may be negative, signaling a flipped landscape in that
|
||||||
|
// direction.
|
||||||
|
float xsize, ysize;
|
||||||
|
int numx, numy;
|
||||||
|
|
||||||
|
// World offset along the same x/y axes. Whether these are set or
|
||||||
|
// used depends on the client implementation.
|
||||||
|
float xoffset, yoffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* We use normal streams for data. This allows us to just pass (for
|
||||||
|
example) a file stream as height map input later, with no extra
|
||||||
|
fuzz.
|
||||||
|
*/
|
||||||
|
typedef Mangle::Stream::StreamPtr LandDataPtr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Factory class that provides streams to land data cells. Each
|
||||||
|
"cell" has a unique integer coordinate in the plane.
|
||||||
|
*/
|
||||||
|
struct LandFactory
|
||||||
|
{
|
||||||
|
// True if this factory has any data for the given grid cell.
|
||||||
|
virtual bool has(int x, int y) = 0;
|
||||||
|
|
||||||
|
// Return stream to data for this cell. Additional data about the
|
||||||
|
// landscape is returned through the LandInfo struct.
|
||||||
|
virtual LandDataPtr get(int x, int y, LandInfo &info) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1 @@
|
|||||||
|
*_test
|
@ -0,0 +1,14 @@
|
|||||||
|
GCC=g++
|
||||||
|
|
||||||
|
all: triangle_test esm_test
|
||||||
|
|
||||||
|
LIB_INC=-I../../../libs/
|
||||||
|
|
||||||
|
triangle_test: triangle_test.cpp
|
||||||
|
$(GCC) $^ -o $@
|
||||||
|
|
||||||
|
esm_test: esm_test.cpp
|
||||||
|
$(GCC) $^ -o $@ $(LIB_INC)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *_test
|
@ -0,0 +1,10 @@
|
|||||||
|
#include <iostream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "../esm_land_factory.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
cout << "under development\n";
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
under development
|
@ -0,0 +1,55 @@
|
|||||||
|
Cell types:
|
||||||
|
\ / \ /
|
||||||
|
/ \ / \
|
||||||
|
\ / \ /
|
||||||
|
/ \ / \
|
||||||
|
|
||||||
|
Full index list:
|
||||||
|
0
|
||||||
|
6
|
||||||
|
5
|
||||||
|
0
|
||||||
|
1
|
||||||
|
6
|
||||||
|
1
|
||||||
|
2
|
||||||
|
6
|
||||||
|
6
|
||||||
|
2
|
||||||
|
7
|
||||||
|
2
|
||||||
|
8
|
||||||
|
7
|
||||||
|
2
|
||||||
|
3
|
||||||
|
8
|
||||||
|
3
|
||||||
|
4
|
||||||
|
8
|
||||||
|
8
|
||||||
|
4
|
||||||
|
9
|
||||||
|
5
|
||||||
|
6
|
||||||
|
10
|
||||||
|
10
|
||||||
|
6
|
||||||
|
11
|
||||||
|
6
|
||||||
|
12
|
||||||
|
11
|
||||||
|
6
|
||||||
|
7
|
||||||
|
12
|
||||||
|
7
|
||||||
|
8
|
||||||
|
12
|
||||||
|
12
|
||||||
|
8
|
||||||
|
13
|
||||||
|
8
|
||||||
|
14
|
||||||
|
13
|
||||||
|
8
|
||||||
|
9
|
||||||
|
14
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
make || exit
|
||||||
|
|
||||||
|
mkdir -p output
|
||||||
|
|
||||||
|
PROGS=*_test
|
||||||
|
|
||||||
|
for a in $PROGS; do
|
||||||
|
if [ -f "output/$a.out" ]; then
|
||||||
|
echo "Running $a:"
|
||||||
|
./$a | diff output/$a.out -
|
||||||
|
else
|
||||||
|
echo "Creating $a.out"
|
||||||
|
./$a > "output/$a.out"
|
||||||
|
git add "output/$a.out"
|
||||||
|
fi
|
||||||
|
done
|
@ -0,0 +1,93 @@
|
|||||||
|
#include <iostream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "../triangulator.hpp"
|
||||||
|
|
||||||
|
const int X = 4;
|
||||||
|
const int Y = 4;
|
||||||
|
|
||||||
|
typedef Terrain::Triangulator<short,X,Y> Triangles4x4;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Triangles4x4 t;
|
||||||
|
|
||||||
|
cout << "Cell types:\n";
|
||||||
|
for(int y=0;y<Y;y++)
|
||||||
|
{
|
||||||
|
for(int x=0;x<X;x++)
|
||||||
|
{
|
||||||
|
if(t.cellType(x,y)) cout << "/ ";
|
||||||
|
else cout << "\\ ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "Full index list:\n";
|
||||||
|
for(int i=0; i<X*Y*3; i++)
|
||||||
|
cout << t.getData()[i] << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code we might add later:
|
||||||
|
|
||||||
|
// Get the vertex indices belonging to a given triangle
|
||||||
|
void getTriangle(int trinum, Index &p1, Index &p2, Index &p3)
|
||||||
|
{
|
||||||
|
assert(trinum >= 0 && trinum < TriNum);
|
||||||
|
trinum *= 3;
|
||||||
|
|
||||||
|
p1 = array[trinum++];
|
||||||
|
p2 = array[trinum++];
|
||||||
|
p3 = array[trinum];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get height interpolation weights for a given grid square. The
|
||||||
|
input is the grid square number (x,y) and the relative position
|
||||||
|
within that square (xrel,yrel = [0.0..1.0].) The weights are
|
||||||
|
returned as three vertex index + weight factor pairs.
|
||||||
|
|
||||||
|
A more user-friendly version for HeightMap structs is given
|
||||||
|
below.
|
||||||
|
* /
|
||||||
|
void getWeights(int x, int y, float xrel, float yrel,
|
||||||
|
Index &p1, float w1,
|
||||||
|
Index &p2, float w2,
|
||||||
|
Index &p3, float w3)
|
||||||
|
{
|
||||||
|
// Find cell index
|
||||||
|
int index = y*SizeX + x;
|
||||||
|
|
||||||
|
// First triangle in cell
|
||||||
|
index *= 2;
|
||||||
|
|
||||||
|
// The rest depends on how the cell is triangulated
|
||||||
|
if(cellType(x,y))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cell is divided as \ from 0,0 to 1,1
|
||||||
|
if(xrel < yrel)
|
||||||
|
{
|
||||||
|
// Bottom left triangle.
|
||||||
|
|
||||||
|
// Order is (0,0),(1,1),(0,1).
|
||||||
|
getTriangle(index, p1,p2,p3);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Top right triangle
|
||||||
|
|
||||||
|
// Order is (0,0),(1,0),(1,1).
|
||||||
|
getTriangle(index+1, p1,p2,p3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
@ -0,0 +1,104 @@
|
|||||||
|
#ifndef TERRAIN_TRIANGULATOR_H
|
||||||
|
#define TERRAIN_TRIANGULATOR_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
The triangulator is a simple math helper class, used for dividing a
|
||||||
|
regular square grid into alternating set of triangles. It divides a
|
||||||
|
grid like this:
|
||||||
|
|
||||||
|
+----+----+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
+----+----+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
+----+----+
|
||||||
|
|
||||||
|
into this:
|
||||||
|
|
||||||
|
+----+----+
|
||||||
|
| \ 2|3 / |
|
||||||
|
|1 \ | / 4|
|
||||||
|
+----+----+
|
||||||
|
|5 / | \ 8|
|
||||||
|
| / 6|7 \ |
|
||||||
|
+----+----+
|
||||||
|
|
||||||
|
Since the triangulation information is typically the same for all
|
||||||
|
terrains of the same size, once instance can usually be shared.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
// Index number type, number of grid cells (not vertices) in X and Y
|
||||||
|
// directions.
|
||||||
|
template <typename Index, int SizeX, int SizeY>
|
||||||
|
class Triangulator
|
||||||
|
{
|
||||||
|
// Number of triangles
|
||||||
|
static const int TriNum = SizeX * SizeY * 2;
|
||||||
|
|
||||||
|
// 3 indices per triangle
|
||||||
|
Index array[TriNum * 3];
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get raw triangle data pointer. Typically used for creating
|
||||||
|
// meshes.
|
||||||
|
const Index *getData() { return array; }
|
||||||
|
|
||||||
|
// Return whether a given cell is divided as / (true) or \
|
||||||
|
// (false).
|
||||||
|
static bool cellType(int x, int y)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && x < SizeX);
|
||||||
|
assert(y >= 0 && y < SizeY);
|
||||||
|
|
||||||
|
bool even = (x & 1) == 1;
|
||||||
|
if((y & 1) == 1) even = !even;
|
||||||
|
return even;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor sets up the index buffer
|
||||||
|
Triangulator()
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
for ( int y = 0; y < SizeX; y++ )
|
||||||
|
for ( int x = 0; x < SizeY; x++ )
|
||||||
|
{
|
||||||
|
// Get vertex indices
|
||||||
|
Index line1 = y*(SizeX+1) + x;
|
||||||
|
Index line2 = line1 + SizeX+1;
|
||||||
|
|
||||||
|
if(cellType(x,y))
|
||||||
|
{
|
||||||
|
// Top left
|
||||||
|
array[index++] = line1;
|
||||||
|
array[index++] = line1 + 1;
|
||||||
|
array[index++] = line2;
|
||||||
|
|
||||||
|
// Bottom right
|
||||||
|
array[index++] = line2;
|
||||||
|
array[index++] = line1 + 1;
|
||||||
|
array[index++] = line2 + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bottom left
|
||||||
|
array[index++] = line1;
|
||||||
|
array[index++] = line2 + 1;
|
||||||
|
array[index++] = line2;
|
||||||
|
|
||||||
|
// Top right
|
||||||
|
array[index++] = line1;
|
||||||
|
array[index++] = line1 + 1;
|
||||||
|
array[index++] = line2 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(index == TriNum*3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // Namespace
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue