Add curvature to ocean tiles.
An apron around the tile hides cracks with coastal tiles. The VectorArrayAdapter, which lives in the simgear namespace, is a useful utility class for treating vectors as 2D arrays.
This commit is contained in:
@@ -176,13 +176,19 @@ static inline Point3D basic_tex_coord( const Point3D& p,
|
|||||||
// calculate "none stretching" texture coordinates
|
// calculate "none stretching" texture coordinates
|
||||||
point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
||||||
const int_list& fan, double scale )
|
const int_list& fan, double scale )
|
||||||
|
{
|
||||||
|
return sgCalcTexCoords(b.get_center_lat(), geod_nodes, fan, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
point_list sgCalcTexCoords( double centerLat, const point_list& geod_nodes,
|
||||||
|
const int_list& fan, double scale )
|
||||||
{
|
{
|
||||||
// cout << "calculating texture coordinates for a specific fan of size = "
|
// cout << "calculating texture coordinates for a specific fan of size = "
|
||||||
// << fan.size() << endl;
|
// << fan.size() << endl;
|
||||||
|
|
||||||
// calculate perimeter based on center of this degree (not center
|
// calculate perimeter based on center of this degree (not center
|
||||||
// of bucket)
|
// of bucket)
|
||||||
double clat = (int)b.get_center_lat();
|
double clat = (int)centerLat;
|
||||||
if ( clat > 0 ) {
|
if ( clat > 0 ) {
|
||||||
clat = (int)clat + 0.5;
|
clat = (int)clat + 0.5;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -49,5 +49,8 @@
|
|||||||
point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
||||||
const int_list& fan, double scale = 1.0 );
|
const int_list& fan, double scale = 1.0 );
|
||||||
|
|
||||||
|
point_list sgCalcTexCoords( double centerLat, const point_list& geod_nodes,
|
||||||
|
const int_list& fan, double scale = 1.0 );
|
||||||
|
|
||||||
|
|
||||||
#endif // _TEXCOORD_HXX
|
#endif // _TEXCOORD_HXX
|
||||||
|
|||||||
+253
-101
@@ -1,6 +1,6 @@
|
|||||||
/* -*-c++-*-
|
/* -*-c++-*-
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2007 Mathias Froehlich
|
* Copyright (C) 2006-2007 Mathias Froehlich, Tim Moore
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "SGOceanTile.hxx"
|
#include "SGOceanTile.hxx"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include <osg/Geode>
|
#include <osg/Geode>
|
||||||
@@ -38,124 +39,275 @@
|
|||||||
#include <simgear/misc/texcoord.hxx>
|
#include <simgear/misc/texcoord.hxx>
|
||||||
#include <simgear/scene/material/mat.hxx>
|
#include <simgear/scene/material/mat.hxx>
|
||||||
#include <simgear/scene/material/matlib.hxx>
|
#include <simgear/scene/material/matlib.hxx>
|
||||||
|
#include <simgear/scene/util/VectorArrayAdapter.hxx>
|
||||||
|
|
||||||
void fillDrawElements(int width, int height,
|
using namespace simgear;
|
||||||
osg::DrawElementsUShort::vector_type::iterator elements)
|
// Ocean tile with curvature and apron to hide cracks. The cracks are
|
||||||
|
// mostly with adjoining coastal tiles that assume a flat ocean
|
||||||
|
// between corners of a tile; they also hide the micro cracks between
|
||||||
|
// adjoining ocean tiles. This is probably over-engineered, but it
|
||||||
|
// serves as a testbed for some things that will come later.
|
||||||
|
|
||||||
|
// Helper class for building and accessing the mesh. The layout of the
|
||||||
|
// points in the mesh is a little wacky. First is the bottom row of
|
||||||
|
// the points for the apron. Next is the left apron point, the points
|
||||||
|
// in the mesh, and the right apron point, for each of the rows of the
|
||||||
|
// mesh; the points for the top apron come last. This order should
|
||||||
|
// help with things like vertex caching in the OpenGL driver, though
|
||||||
|
// it may be superfluous for such a small mesh.
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
for (int j = 0; j < height - 1; j++) {
|
const int lonPoints = 5;
|
||||||
for (int i = 0; i < width - 1; i++) {
|
const int latPoints = 5;
|
||||||
*elements++ = j * width + i;
|
|
||||||
*elements++ = j * width + i + 1;
|
class OceanMesh {
|
||||||
*elements++ = (j + 1) * width + i;
|
public:
|
||||||
*elements++ = (j + 1) * width + i;
|
OceanMesh():
|
||||||
*elements++ = j * width + i + 1;
|
geoPoints(latPoints * lonPoints + 2 * (lonPoints + latPoints)),
|
||||||
*elements++ = (j + 1) * width + i + 1;
|
geod_nodes(latPoints * lonPoints),
|
||||||
|
vl(new osg::Vec3Array(geoPoints)),
|
||||||
|
nl(new osg::Vec3Array(geoPoints)),
|
||||||
|
tl(new osg::Vec2Array(geoPoints)),
|
||||||
|
vlArray(*vl, lonPoints + 2, lonPoints, 1),
|
||||||
|
nlArray(*nl, lonPoints + 2, lonPoints, 1),
|
||||||
|
tlArray(*tl, lonPoints + 2, lonPoints, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
const int geoPoints;
|
||||||
|
SGGeod geod[latPoints][lonPoints];
|
||||||
|
SGVec3f normals[latPoints][lonPoints];
|
||||||
|
SGVec3d rel[latPoints][lonPoints];
|
||||||
|
|
||||||
|
point_list geod_nodes;
|
||||||
|
|
||||||
|
osg::Vec3Array* vl;
|
||||||
|
osg::Vec3Array* nl;
|
||||||
|
osg::Vec2Array* tl;
|
||||||
|
VectorArrayAdapter<osg::Vec3Array> vlArray;
|
||||||
|
VectorArrayAdapter<osg::Vec3Array> nlArray;
|
||||||
|
VectorArrayAdapter<osg::Vec2Array> tlArray;
|
||||||
|
|
||||||
|
void calcMesh(const SGVec3d& cartCenter, double clon, double clat,
|
||||||
|
double height, double width, double tex_width);
|
||||||
|
void calcApronPt(int latIdx, int lonIdx, int latInner, int lonInner,
|
||||||
|
int destIdx, double tex_width);
|
||||||
|
void calcApronPts(double tex_width);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void OceanMesh::calcMesh(const SGVec3d& cartCenter, double clon, double clat,
|
||||||
|
double height, double width, double tex_width)
|
||||||
|
{
|
||||||
|
// Calculate vertices. By splitting the tile up into 4 quads on a
|
||||||
|
// side we avoid curvature-of-the-earth problems; the error should
|
||||||
|
// be less than .5 meters.
|
||||||
|
double longInc = width * .25;
|
||||||
|
double latInc = height * .25;
|
||||||
|
double startLat = clat - height * .5;
|
||||||
|
double startLon = clon - width * .5;
|
||||||
|
for (int j = 0; j < latPoints; j++) {
|
||||||
|
double lat = startLat + j * latInc;
|
||||||
|
for (int i = 0; i < lonPoints; i++) {
|
||||||
|
geod[j][i] = SGGeod::fromDeg(startLon + i * longInc, lat);
|
||||||
|
SGVec3d cart = SGVec3d::fromGeod(geod[j][i]);
|
||||||
|
rel[j][i] = cart - cartCenter;
|
||||||
|
normals[j][i] = toVec3f(normalize(cart));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate texture coordinates
|
||||||
|
point_list geod_nodes(latPoints * lonPoints);
|
||||||
|
VectorArrayAdapter<point_list> geodNodesArray(geod_nodes, lonPoints);
|
||||||
|
int_list rectangle(latPoints * lonPoints);
|
||||||
|
VectorArrayAdapter<int_list> rectArray(rectangle, lonPoints);
|
||||||
|
for (int j = 0; j < latPoints; j++) {
|
||||||
|
for (int i = 0; i < lonPoints; i++) {
|
||||||
|
geodNodesArray(j, i) = Point3D(geod[j][i].getLongitudeDeg(),
|
||||||
|
geod[j][i].getLatitudeDeg(),
|
||||||
|
geod[j][i].getElevationM());
|
||||||
|
rectArray(j, i) = j * 5 + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
point_list texs = sgCalcTexCoords( clat, geod_nodes, rectangle,
|
||||||
|
1000.0 / tex_width );
|
||||||
|
VectorArrayAdapter<point_list> texsArray(texs, lonPoints);
|
||||||
|
|
||||||
|
for (int j = 0; j < latPoints; j++) {
|
||||||
|
for (int i = 0; i < lonPoints; ++i) {
|
||||||
|
vlArray(j, i) = rel[j][i].osg();
|
||||||
|
nlArray(j, i) = normals[j][i].osg();
|
||||||
|
tlArray(j, i) = texsArray(j, i).toSGVec2f().osg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apron points. For each point on the edge we'll go 150
|
||||||
|
// metres "down" and 40 metres "out" to create a nice overlap. The
|
||||||
|
// texture should be applied according to this dimension. The
|
||||||
|
// normals of the apron polygons will be the same as the those of
|
||||||
|
// the points on the edge to better disguise the apron.
|
||||||
|
void OceanMesh::calcApronPt(int latIdx, int lonIdx, int latInner, int lonInner,
|
||||||
|
int destIdx, double tex_width)
|
||||||
|
{
|
||||||
|
static const float downDist = 150.0f;
|
||||||
|
static const float outDist = 40.0f;
|
||||||
|
// Get vector along edge, in the right direction to make a cross
|
||||||
|
// product with the normal vector that will point out from the
|
||||||
|
// mesh.
|
||||||
|
osg::Vec3f edgePt = vlArray(latIdx, lonIdx);
|
||||||
|
osg::Vec3f edgeVec;
|
||||||
|
if (lonIdx == lonInner) { // bottom or top edge
|
||||||
|
if (lonIdx > 0)
|
||||||
|
edgeVec = vlArray(latIdx, lonIdx - 1) - edgePt;
|
||||||
|
else
|
||||||
|
edgeVec = edgePt - vlArray(latIdx, lonIdx + 1);
|
||||||
|
if (latIdx > latInner)
|
||||||
|
edgeVec = -edgeVec; // Top edge
|
||||||
|
} else { // right or left edge
|
||||||
|
if (latIdx > 0)
|
||||||
|
edgeVec = edgePt - vlArray(latIdx - 1, lonIdx);
|
||||||
|
else
|
||||||
|
edgeVec = vlArray(latIdx + 1, lonIdx) - edgePt;
|
||||||
|
if (lonIdx > lonInner) // right edge
|
||||||
|
edgeVec = -edgeVec;
|
||||||
|
}
|
||||||
|
edgeVec.normalize();
|
||||||
|
osg::Vec3f outVec = nlArray(latIdx, lonIdx) ^ edgeVec;
|
||||||
|
(*vl)[destIdx]
|
||||||
|
= edgePt - nlArray(latIdx, lonIdx) * downDist + outVec * outDist;
|
||||||
|
(*nl)[destIdx] = nlArray(latIdx, lonIdx);
|
||||||
|
static const float apronDist
|
||||||
|
= sqrtf(downDist * downDist + outDist * outDist);
|
||||||
|
float texDelta = apronDist / tex_width;
|
||||||
|
if (lonIdx == lonInner) {
|
||||||
|
if (latIdx > latInner)
|
||||||
|
(*tl)[destIdx]
|
||||||
|
= tlArray(latIdx, lonIdx) + osg::Vec2f(0.0f, texDelta);
|
||||||
|
else
|
||||||
|
(*tl)[destIdx]
|
||||||
|
= tlArray(latIdx, lonIdx) - osg::Vec2f(0.0f, texDelta);
|
||||||
|
} else {
|
||||||
|
if (lonIdx > lonInner)
|
||||||
|
(*tl)[destIdx]
|
||||||
|
= tlArray(latIdx, lonIdx) + osg::Vec2f(texDelta, 0.0f);
|
||||||
|
else
|
||||||
|
(*tl)[destIdx]
|
||||||
|
= tlArray(latIdx, lonIdx) - osg::Vec2f(texDelta, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OceanMesh::calcApronPts(double tex_width)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < lonPoints; i++)
|
||||||
|
calcApronPt(0, i, 1, i, i, tex_width);
|
||||||
|
int topApronOffset = latPoints + (2 + lonPoints) * latPoints;
|
||||||
|
for (int i = 0; i < lonPoints; i++)
|
||||||
|
calcApronPt(latPoints - 1, i, latPoints - 2, i,
|
||||||
|
i + topApronOffset, tex_width);
|
||||||
|
for (int i = 0; i < latPoints; i++) {
|
||||||
|
calcApronPt(i, 0, i, 1, lonPoints + i * (lonPoints + 2), tex_width);
|
||||||
|
calcApronPt(i, lonPoints - 1, i, lonPoints - 2,
|
||||||
|
lonPoints + i * (lonPoints + 2) + 1 + lonPoints, tex_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Enter the vertices of triangles that fill one row of the
|
||||||
|
// mesh. The vertices are entered in counter-clockwise order.
|
||||||
|
void fillDrawElementsRow(int width, short row0Start, short row1Start,
|
||||||
|
osg::DrawElementsUShort::vector_type::iterator&
|
||||||
|
elements)
|
||||||
|
{
|
||||||
|
short row0Idx = row0Start;
|
||||||
|
short row1Idx = row1Start;
|
||||||
|
for (int i = 0; i < width - 1; i++, row0Idx++, row1Idx++) {
|
||||||
|
*elements++ = row0Idx;
|
||||||
|
*elements++ = row0Idx + 1;
|
||||||
|
*elements++ = row1Idx;
|
||||||
|
*elements++ = row1Idx;
|
||||||
|
*elements++ = row0Idx + 1;
|
||||||
|
*elements++ = row1Idx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillDrawElementsWithApron(short height, short width,
|
||||||
|
osg::DrawElementsUShort::vector_type::iterator
|
||||||
|
elements)
|
||||||
|
{
|
||||||
|
// First apron row
|
||||||
|
fillDrawElementsRow(width, 0, width + 1, elements);
|
||||||
|
for (short i = 0; i < height - 1; i++)
|
||||||
|
fillDrawElementsRow(width + 2, width + i * (width + 2),
|
||||||
|
width + (i + 1) * (width + 2),
|
||||||
|
elements);
|
||||||
|
// Last apron row
|
||||||
|
short topApronBottom = width + (height - 1) * (width + 2) + 1;
|
||||||
|
fillDrawElementsRow(width, topApronBottom, topApronBottom + width + 1,
|
||||||
|
elements);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate an ocean tile
|
|
||||||
osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib)
|
osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib)
|
||||||
{
|
{
|
||||||
osg::StateSet *stateSet = 0;
|
osg::StateSet *stateSet = 0;
|
||||||
|
|
||||||
double tex_width = 1000.0;
|
double tex_width = 1000.0;
|
||||||
|
|
||||||
// find Ocean material in the properties list
|
// find Ocean material in the properties list
|
||||||
SGMaterial *mat = matlib->find( "Ocean" );
|
SGMaterial *mat = matlib->find( "Ocean" );
|
||||||
if ( mat != NULL ) {
|
if ( mat != NULL ) {
|
||||||
// set the texture width and height values for this
|
// set the texture width and height values for this
|
||||||
// material
|
// material
|
||||||
tex_width = mat->get_xsize();
|
tex_width = mat->get_xsize();
|
||||||
|
|
||||||
// set ssgState
|
// set OSG State
|
||||||
stateSet = mat->get_state();
|
stateSet = mat->get_state();
|
||||||
} else {
|
} else {
|
||||||
SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown use material name = Ocean");
|
SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown use material name = Ocean");
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate center point
|
|
||||||
SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center());
|
|
||||||
|
|
||||||
double clon = b.get_center_lon();
|
|
||||||
double clat = b.get_center_lat();
|
|
||||||
double height = b.get_height();
|
|
||||||
double width = b.get_width();
|
|
||||||
|
|
||||||
// Calculate vertices. By splitting the tile up into 4 quads on a
|
|
||||||
// side we avoid curvature-of-the-earth problems; the error should
|
|
||||||
// be less than .5 meters.
|
|
||||||
SGGeod geod[5][5];
|
|
||||||
SGVec3f normals[5][5];
|
|
||||||
SGVec3d rel[5][5];
|
|
||||||
double longInc = width * .25;
|
|
||||||
double latInc = height * .25;
|
|
||||||
double startLat = clat - height * .5;
|
|
||||||
double startLon = clon - width * .5;
|
|
||||||
for (int j = 0; j < 5; j++) {
|
|
||||||
double lat = startLat + j * latInc;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
geod[i][j] = SGGeod::fromDeg(startLon + i * longInc, lat);
|
|
||||||
SGVec3d cart = SGVec3d::fromGeod(geod[i][j]);
|
|
||||||
rel[i][j] = cart - cartCenter;
|
|
||||||
normals[i][j] = toVec3f(normalize(cart));
|
|
||||||
}
|
}
|
||||||
}
|
OceanMesh grid;
|
||||||
|
// Calculate center point
|
||||||
// Calculate texture coordinates
|
SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center());
|
||||||
point_list geod_nodes;
|
|
||||||
geod_nodes.reserve(5 * 5);
|
|
||||||
int_list rectangle;
|
|
||||||
rectangle.reserve(5 * 5);
|
|
||||||
for (int j = 0; j < 5; j++) {
|
|
||||||
for (int i = 0; i < 5; ++i) {
|
|
||||||
geod_nodes.push_back(Point3D(geod[i][j].getLongitudeDeg(),
|
|
||||||
geod[i][j].getLatitudeDeg(),
|
|
||||||
geod[i][j].getElevationM()));
|
|
||||||
rectangle.push_back(j * 5 + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
point_list texs = sgCalcTexCoords( b, geod_nodes, rectangle,
|
|
||||||
1000.0 / tex_width );
|
|
||||||
|
|
||||||
// Allocate osg structures
|
double clon = b.get_center_lon();
|
||||||
osg::Vec3Array *vl = new osg::Vec3Array;
|
double clat = b.get_center_lat();
|
||||||
osg::Vec3Array *nl = new osg::Vec3Array;
|
double height = b.get_height();
|
||||||
osg::Vec2Array *tl = new osg::Vec2Array;
|
double width = b.get_width();
|
||||||
|
|
||||||
for (int j = 0; j < 5; j++) {
|
grid.calcMesh(cartCenter, clon, clat, height, width, tex_width);
|
||||||
for (int i = 0; i < 5; ++i) {
|
grid.calcApronPts(tex_width);
|
||||||
vl->push_back(rel[i][j].osg());
|
|
||||||
nl->push_back(normals[i][j].osg());
|
|
||||||
tl->push_back(texs[j * 5 + i].toSGVec2f().osg());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Vec4Array* cl = new osg::Vec4Array;
|
osg::Vec4Array* cl = new osg::Vec4Array;
|
||||||
cl->push_back(osg::Vec4(1, 1, 1, 1));
|
cl->push_back(osg::Vec4(1, 1, 1, 1));
|
||||||
|
|
||||||
osg::Geometry* geometry = new osg::Geometry;
|
osg::Geometry* geometry = new osg::Geometry;
|
||||||
geometry->setVertexArray(vl);
|
geometry->setVertexArray(grid.vl);
|
||||||
geometry->setNormalArray(nl);
|
geometry->setNormalArray(grid.nl);
|
||||||
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
|
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
|
||||||
geometry->setColorArray(cl);
|
geometry->setColorArray(cl);
|
||||||
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||||
geometry->setTexCoordArray(0, tl);
|
geometry->setTexCoordArray(0, grid.tl);
|
||||||
|
|
||||||
osg::DrawElementsUShort* drawElements
|
// Allocate the indices for triangles in the mesh and the apron
|
||||||
= new osg::DrawElementsUShort(GL_TRIANGLES, 32 * 3);
|
osg::DrawElementsUShort* drawElements
|
||||||
fillDrawElements(5, 5, drawElements->begin());
|
= new osg::DrawElementsUShort(GL_TRIANGLES,
|
||||||
geometry->addPrimitiveSet(drawElements);
|
6 * ((latPoints - 1) * (lonPoints + 1)
|
||||||
|
+ 2 * (latPoints - 1)));
|
||||||
|
fillDrawElementsWithApron(latPoints, lonPoints, drawElements->begin());
|
||||||
|
geometry->addPrimitiveSet(drawElements);
|
||||||
|
|
||||||
osg::Geode* geode = new osg::Geode;
|
osg::Geode* geode = new osg::Geode;
|
||||||
geode->setName("Ocean tile");
|
geode->setName("Ocean tile");
|
||||||
geode->addDrawable(geometry);
|
geode->addDrawable(geometry);
|
||||||
geode->setStateSet(stateSet);
|
geode->setStateSet(stateSet);
|
||||||
|
|
||||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||||
transform->setName("Ocean");
|
transform->setName("Ocean");
|
||||||
transform->setMatrix(osg::Matrix::translate(cartCenter.osg()));
|
transform->setMatrix(osg::Matrix::translate(cartCenter.osg()));
|
||||||
transform->addChild(geode);
|
transform->addChild(geode);
|
||||||
|
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ include_HEADERS = \
|
|||||||
SGSceneFeatures.hxx \
|
SGSceneFeatures.hxx \
|
||||||
SGSceneUserData.hxx \
|
SGSceneUserData.hxx \
|
||||||
SGStateAttributeVisitor.hxx \
|
SGStateAttributeVisitor.hxx \
|
||||||
SGTextureStateAttributeVisitor.hxx
|
SGTextureStateAttributeVisitor.hxx \
|
||||||
|
VectorArrayAdapter.hxx
|
||||||
|
|
||||||
|
|
||||||
libsgutil_a_SOURCES = \
|
libsgutil_a_SOURCES = \
|
||||||
SGEnlargeBoundingBox.cxx \
|
SGEnlargeBoundingBox.cxx \
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Tim Moore
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VECTORARRAYADAPTERHXX
|
||||||
|
#define VECTORARRAYADAPTERHXX 1
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
template <typename Vector>
|
||||||
|
class VectorArrayAdapter {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Adapter that provides 2D array access to the elements of a
|
||||||
|
* std::vector in row major order.
|
||||||
|
* @param v the vector
|
||||||
|
* @param rowStride distance from an element to the corresponding
|
||||||
|
* element in the next row.
|
||||||
|
* @param baseOffset offset of the first element of the array from the
|
||||||
|
* beginning of the vector.
|
||||||
|
* @param rowOffset offset of the first element in a row from the
|
||||||
|
* actual beginning of the row.
|
||||||
|
*/
|
||||||
|
VectorArrayAdapter(Vector& v, int rowStride, int baseOffset = 0,
|
||||||
|
int rowOffset = 0):
|
||||||
|
_v(v), _rowStride(rowStride), _baseOffset(baseOffset),
|
||||||
|
_rowOffset(rowOffset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typename Vector::value_type& operator() (int i, int j)
|
||||||
|
{
|
||||||
|
return _v[_baseOffset + i * _rowStride + _rowOffset + j];
|
||||||
|
}
|
||||||
|
const typename Vector::value_type& operator() (int i, int j) const
|
||||||
|
{
|
||||||
|
return _v[_baseOffset + i * _rowStride + _rowOffset + j];
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Vector& _v;
|
||||||
|
const int _rowStride;
|
||||||
|
const int _baseOffset;
|
||||||
|
const int _rowOffset;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user