Merge remote branch 'upstream/master'

actorid
Marc Zinnschlag 14 years ago
commit f620b580f0

@ -25,8 +25,9 @@ struct Land
{
// Get the grid location
esm.getSubNameIs("INTV");
esm.getT(X);
esm.getT(Y);
esm.getSubHeaderIs(8);
esm.getT<int>(X);
esm.getT<int>(Y);
esm.getHNT(flags, "DATA");

@ -23,12 +23,11 @@ namespace ESM {
struct LandTexture
{
std::string name, texture;
std::string id, texture;
int index;
void load(ESMReader &esm)
{
name = esm.getHNString("NAME");
esm.getHNT(index, "INTV");
texture = esm.getHNString("DATA");
}

@ -149,6 +149,79 @@ namespace ESMS
int getSize() { return list.size(); }
};
/* Land textures are indexed by an integer number
*/
struct LTexList : RecList
{
// TODO: For multiple ESM/ESP files we need one list per file.
std::vector<LandTexture> ltex;
int count;
LTexList() : count(0)
{
// More than enough to hold Morrowind.esm.
ltex.reserve(128);
}
int getSize() { return count; }
void load(ESMReader &esm, const std::string &id)
{
LandTexture lt;
lt.load(esm);
lt.id = id;
// Make sure we have room for the structure
if(lt.index + 1 > (int)ltex.size())
ltex.resize(lt.index+1);
// Store it
ltex[lt.index] = lt;
}
};
/* Landscapes are indexed by the X,Y coordinates of the exterior
cell they belong to.
*/
struct LandList : RecList
{
// Map containing all landscapes
typedef std::map<int, Land*> LandsCol;
typedef std::map<int, LandsCol> Lands;
Lands lands;
int count;
LandList() : count(0) {}
int getSize() { return count; }
// Find land for the given coordinates. Return null if no data.
const Land *search(int x, int y) const
{
Lands::const_iterator it = lands.find(x);
if(it==lands.end())
return NULL;
LandsCol::const_iterator it2 = it->second.find(y);
if(it2 == it->second.end())
return NULL;
return it2->second;
}
void load(ESMReader &esm, const std::string &id)
{
count++;
// Create the structure and load it. This actually skips the
// landscape data and remembers the file position for later.
Land *land = new Land;
land->load(esm);
// Store the structure
lands[land->X][land->Y] = land;
}
};
// Cells aren't simply indexed by name. Exterior cells are treated
// separately.
// TODO: case handling (cell names are case-insensitive, but they are also showen to the
@ -243,8 +316,6 @@ namespace ESMS
void load(ESMReader &esm, const std::string &id)
{
using namespace std;
count++;
// All cells have a name record, even nameless exterior cells.

@ -69,10 +69,10 @@ namespace ESMS
// Lists that need special rules
CellList cells;
RecIDListT<GameSetting> gameSettings;
//RecListT<Land> lands;
//RecListT<LandTexture> landTexts;
LandList lands;
LTexList landTexts;
ScriptListT<Script> scripts;
//RecListT<MagicEffect> magicEffects;
ScriptListT<Script> scripts;
//RecListT<Skill> skills;
//RecListT<PathGrid> pathgrids;
@ -112,12 +112,12 @@ namespace ESMS
recLists[REC_GLOB] = &globals;
recLists[REC_GMST] = &gameSettings;
recLists[REC_INGR] = &ingreds;
//recLists[REC_LAND] = &lands;
recLists[REC_LAND] = &lands;
recLists[REC_LEVC] = &creatureLists;
recLists[REC_LEVI] = &itemLists;
recLists[REC_LIGH] = &lights;
recLists[REC_LOCK] = &lockpicks;
//recLists[REC_LTEX] = &landTexts;
recLists[REC_LTEX] = &landTexts;
//recLists[REC_MGEF] = &magicEffects;
recLists[REC_MISC] = &miscItems;
recLists[REC_NPC_] = &npcs;

@ -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,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,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

@ -352,46 +352,7 @@ void genIndexData()
cache.addVertexBuffer(lev,vertList);
}
// Pregenerate triangle indices
int size = 64*64*6;
auto indList = new ushort[size];
int index = 0;
bool flag = false;
for ( int y = 0; y < 64; y++ )
{
for ( int x = 0; x < 64; x++ )
{
int line1 = y*65 + x;
int line2 = (y+1)*65 + x;
if ( flag )
{
indList[index++] = line1;
indList[index++] = line1 + 1;
indList[index++] = line2;
indList[index++] = line2;
indList[index++] = line1 + 1;
indList[index++] = line2 + 1;
}
else
{
indList[index++] = line1;
indList[index++] = line2 + 1;
indList[index++] = line2;
indList[index++] = line1;
indList[index++] = line1 + 1;
indList[index++] = line2 + 1;
}
flag = !flag; //flip tris for next time
}
flag = !flag; //flip tries for next row
}
assert(index == indList.length);
cache.setIndexBuffer(indList);
// index stuff already ported
}
void genLevel(int level, int X, int Y, ref GenLevelResult result,

Loading…
Cancel
Save