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