00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <simgear_config.h>
00024 #endif
00025
00026 #include "SGOceanTile.hxx"
00027
00028 #include <math.h>
00029 #include <simgear/compiler.h>
00030
00031 #include <osg/Geode>
00032 #include <osg/Geometry>
00033 #include <osg/MatrixTransform>
00034 #include <osg/StateSet>
00035
00036 #include <simgear/bucket/newbucket.hxx>
00037 #include <simgear/math/sg_geodesy.hxx>
00038 #include <simgear/math/sg_types.hxx>
00039 #include <simgear/misc/texcoord.hxx>
00040 #include <simgear/scene/material/Effect.hxx>
00041 #include <simgear/scene/material/EffectGeode.hxx>
00042 #include <simgear/scene/material/mat.hxx>
00043 #include <simgear/scene/material/matlib.hxx>
00044
00045 #include <simgear/scene/util/VectorArrayAdapter.hxx>
00046
00047 using namespace simgear;
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 namespace
00062 {
00063 const int lonPoints = 5;
00064 const int latPoints = 5;
00065
00066 class OceanMesh {
00067 public:
00068 OceanMesh():
00069 geoPoints(latPoints * lonPoints + 2 * (lonPoints + latPoints)),
00070 geod_nodes(latPoints * lonPoints),
00071 vl(new osg::Vec3Array(geoPoints)),
00072 nl(new osg::Vec3Array(geoPoints)),
00073 tl(new osg::Vec2Array(geoPoints)),
00074 vlArray(*vl, lonPoints + 2, lonPoints, 1),
00075 nlArray(*nl, lonPoints + 2, lonPoints, 1),
00076 tlArray(*tl, lonPoints + 2, lonPoints, 1)
00077 {
00078 }
00079 const int geoPoints;
00080 SGGeod geod[latPoints][lonPoints];
00081 SGVec3f normals[latPoints][lonPoints];
00082 SGVec3d rel[latPoints][lonPoints];
00083
00084 point_list geod_nodes;
00085
00086 osg::Vec3Array* vl;
00087 osg::Vec3Array* nl;
00088 osg::Vec2Array* tl;
00089 VectorArrayAdapter<osg::Vec3Array> vlArray;
00090 VectorArrayAdapter<osg::Vec3Array> nlArray;
00091 VectorArrayAdapter<osg::Vec2Array> tlArray;
00092
00093 void calcMesh(const SGVec3d& cartCenter, const SGQuatd& orient,
00094 double clon, double clat,
00095 double height, double width, double tex_width);
00096 void calcApronPt(int latIdx, int lonIdx, int latInner, int lonInner,
00097 int destIdx, double tex_width);
00098 void calcApronPts(double tex_width);
00099
00100 };
00101 }
00102
00103 void OceanMesh::calcMesh(const SGVec3d& cartCenter, const SGQuatd& orient,
00104 double clon, double clat,
00105 double height, double width, double tex_width)
00106 {
00107
00108
00109
00110 double longInc = width * .25;
00111 double latInc = height * .25;
00112 double startLat = clat - height * .5;
00113 double startLon = clon - width * .5;
00114 for (int j = 0; j < latPoints; j++) {
00115 double lat = startLat + j * latInc;
00116 for (int i = 0; i < lonPoints; i++) {
00117 geod[j][i] = SGGeod::fromDeg(startLon + i * longInc, lat);
00118 SGVec3d cart = SGVec3d::fromGeod(geod[j][i]);
00119 rel[j][i] = orient.transform(cart - cartCenter);
00120 normals[j][i] = toVec3f(orient.transform(normalize(cart)));
00121 }
00122 }
00123
00124
00125 point_list geod_nodes(latPoints * lonPoints);
00126 VectorArrayAdapter<point_list> geodNodesArray(geod_nodes, lonPoints);
00127 int_list rectangle(latPoints * lonPoints);
00128 VectorArrayAdapter<int_list> rectArray(rectangle, lonPoints);
00129 for (int j = 0; j < latPoints; j++) {
00130 for (int i = 0; i < lonPoints; i++) {
00131 geodNodesArray(j, i) = Point3D(geod[j][i].getLongitudeDeg(),
00132 geod[j][i].getLatitudeDeg(),
00133 geod[j][i].getElevationM());
00134 rectArray(j, i) = j * 5 + i;
00135 }
00136 }
00137 point_list texs = sgCalcTexCoords( clat, geod_nodes, rectangle,
00138 1000.0 / tex_width );
00139 VectorArrayAdapter<point_list> texsArray(texs, lonPoints);
00140
00141 for (int j = 0; j < latPoints; j++) {
00142 for (int i = 0; i < lonPoints; ++i) {
00143 vlArray(j, i) = toOsg(rel[j][i]);
00144 nlArray(j, i) = toOsg(normals[j][i]);
00145 tlArray(j, i) = toOsg(texsArray(j, i).toSGVec2f());
00146 }
00147 }
00148
00149 }
00150
00151
00152
00153
00154
00155
00156 void OceanMesh::calcApronPt(int latIdx, int lonIdx, int latInner, int lonInner,
00157 int destIdx, double tex_width)
00158 {
00159 static const float downDist = 150.0f;
00160 static const float outDist = 40.0f;
00161
00162
00163
00164 osg::Vec3f edgePt = vlArray(latIdx, lonIdx);
00165 osg::Vec3f edgeVec;
00166 if (lonIdx == lonInner) {
00167 if (lonIdx > 0)
00168 edgeVec = vlArray(latIdx, lonIdx - 1) - edgePt;
00169 else
00170 edgeVec = edgePt - vlArray(latIdx, lonIdx + 1);
00171 if (latIdx > latInner)
00172 edgeVec = -edgeVec;
00173 } else {
00174 if (latIdx > 0)
00175 edgeVec = edgePt - vlArray(latIdx - 1, lonIdx);
00176 else
00177 edgeVec = vlArray(latIdx + 1, lonIdx) - edgePt;
00178 if (lonIdx > lonInner)
00179 edgeVec = -edgeVec;
00180 }
00181 edgeVec.normalize();
00182 osg::Vec3f outVec = nlArray(latIdx, lonIdx) ^ edgeVec;
00183 (*vl)[destIdx]
00184 = edgePt - nlArray(latIdx, lonIdx) * downDist + outVec * outDist;
00185 (*nl)[destIdx] = nlArray(latIdx, lonIdx);
00186 static const float apronDist
00187 = sqrtf(downDist * downDist + outDist * outDist);
00188 float texDelta = apronDist / tex_width;
00189 if (lonIdx == lonInner) {
00190 if (latIdx > latInner)
00191 (*tl)[destIdx]
00192 = tlArray(latIdx, lonIdx) + osg::Vec2f(0.0f, texDelta);
00193 else
00194 (*tl)[destIdx]
00195 = tlArray(latIdx, lonIdx) - osg::Vec2f(0.0f, texDelta);
00196 } else {
00197 if (lonIdx > lonInner)
00198 (*tl)[destIdx]
00199 = tlArray(latIdx, lonIdx) + osg::Vec2f(texDelta, 0.0f);
00200 else
00201 (*tl)[destIdx]
00202 = tlArray(latIdx, lonIdx) - osg::Vec2f(texDelta, 0.0f);
00203 }
00204 }
00205
00206 void OceanMesh::calcApronPts(double tex_width)
00207 {
00208 for (int i = 0; i < lonPoints; i++)
00209 calcApronPt(0, i, 1, i, i, tex_width);
00210 int topApronOffset = latPoints + (2 + lonPoints) * latPoints;
00211 for (int i = 0; i < lonPoints; i++)
00212 calcApronPt(latPoints - 1, i, latPoints - 2, i,
00213 i + topApronOffset, tex_width);
00214 for (int i = 0; i < latPoints; i++) {
00215 calcApronPt(i, 0, i, 1, lonPoints + i * (lonPoints + 2), tex_width);
00216 calcApronPt(i, lonPoints - 1, i, lonPoints - 2,
00217 lonPoints + i * (lonPoints + 2) + 1 + lonPoints, tex_width);
00218 }
00219 }
00220
00221 namespace
00222 {
00223
00224
00225 void fillDrawElementsRow(int width, short row0Start, short row1Start,
00226 osg::DrawElementsUShort::vector_type::iterator&
00227 elements)
00228 {
00229 short row0Idx = row0Start;
00230 short row1Idx = row1Start;
00231 for (int i = 0; i < width - 1; i++, row0Idx++, row1Idx++) {
00232 *elements++ = row0Idx;
00233 *elements++ = row0Idx + 1;
00234 *elements++ = row1Idx;
00235 *elements++ = row1Idx;
00236 *elements++ = row0Idx + 1;
00237 *elements++ = row1Idx + 1;
00238 }
00239 }
00240
00241 void fillDrawElementsWithApron(short height, short width,
00242 osg::DrawElementsUShort::vector_type::iterator
00243 elements)
00244 {
00245
00246 fillDrawElementsRow(width, 0, width + 1, elements);
00247 for (short i = 0; i < height - 1; i++)
00248 fillDrawElementsRow(width + 2, width + i * (width + 2),
00249 width + (i + 1) * (width + 2),
00250 elements);
00251
00252 short topApronBottom = width + (height - 1) * (width + 2) + 1;
00253 fillDrawElementsRow(width, topApronBottom, topApronBottom + width + 1,
00254 elements);
00255 }
00256 }
00257
00258 osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib)
00259 {
00260 Effect *effect = 0;
00261
00262 double tex_width = 1000.0;
00263
00264
00265 SGMaterial *mat = matlib->find( "Ocean" );
00266 if ( mat != NULL ) {
00267
00268
00269 tex_width = mat->get_xsize();
00270
00271
00272 effect = mat->get_effect();
00273 } else {
00274 SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown use material name = Ocean");
00275 }
00276 OceanMesh grid;
00277
00278 SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center());
00279 SGGeod geodPos = SGGeod::fromCart(cartCenter);
00280 SGQuatd hlOr = SGQuatd::fromLonLat(geodPos);
00281
00282 double clon = b.get_center_lon();
00283 double clat = b.get_center_lat();
00284 double height = b.get_height();
00285 double width = b.get_width();
00286
00287 grid.calcMesh(cartCenter, hlOr, clon, clat, height, width, tex_width);
00288 grid.calcApronPts(tex_width);
00289
00290 osg::Vec4Array* cl = new osg::Vec4Array;
00291 cl->push_back(osg::Vec4(1, 1, 1, 1));
00292
00293 osg::Geometry* geometry = new osg::Geometry;
00294 geometry->setVertexArray(grid.vl);
00295 geometry->setNormalArray(grid.nl);
00296 geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
00297 geometry->setColorArray(cl);
00298 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00299 geometry->setTexCoordArray(0, grid.tl);
00300
00301
00302 osg::DrawElementsUShort* drawElements
00303 = new osg::DrawElementsUShort(GL_TRIANGLES,
00304 6 * ((latPoints - 1) * (lonPoints + 1)
00305 + 2 * (latPoints - 1)));
00306 fillDrawElementsWithApron(latPoints, lonPoints, drawElements->begin());
00307 geometry->addPrimitiveSet(drawElements);
00308
00309 EffectGeode* geode = new EffectGeode;
00310 geode->setName("Ocean tile");
00311 geode->setEffect(effect);
00312 geode->addDrawable(geometry);
00313
00314 osg::MatrixTransform* transform = new osg::MatrixTransform;
00315 transform->setName("Ocean");
00316 transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))*
00317 osg::Matrix::translate(toOsg(cartCenter)));
00318 transform->addChild(geode);
00319
00320 return transform;
00321 }