]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGOceanTile.cxx
Ocean tile detail work in progress
[simgear.git] / simgear / scene / tgdb / SGOceanTile.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2006-2007 Mathias Froehlich 
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #include "SGOceanTile.hxx"
27
28 #include <simgear/compiler.h>
29
30 #include <osg/Geode>
31 #include <osg/Geometry>
32 #include <osg/MatrixTransform>
33 #include <osg/StateSet>
34
35 #include <simgear/bucket/newbucket.hxx>
36 #include <simgear/math/sg_geodesy.hxx>
37 #include <simgear/math/sg_types.hxx>
38 #include <simgear/misc/texcoord.hxx>
39 #include <simgear/scene/material/mat.hxx>
40 #include <simgear/scene/material/matlib.hxx>
41
42 void fillDrawElements(int width, int height,
43                       osg::DrawElementsUShort::vector_type::iterator elements)
44 {
45     for (int j = 0; j < height - 1; j++) {
46         for (int i = 0; i < width - 1; i++) {
47             *elements++ = j * width + i;
48             *elements++ = j * width + i + 1;
49             *elements++ = (j + 1) * width + i;
50             *elements++ = (j + 1) * width + i;
51             *elements++ = j * width + i + 1;
52             *elements++ = (j + 1) * width + i + 1;
53         }
54     }
55 }
56
57 // Generate an ocean tile
58 osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib)
59 {
60   osg::StateSet *stateSet = 0;
61
62   double tex_width = 1000.0;
63   
64   // find Ocean material in the properties list
65   SGMaterial *mat = matlib->find( "Ocean" );
66   if ( mat != NULL ) {
67     // set the texture width and height values for this
68     // material
69     tex_width = mat->get_xsize();
70     
71     // set ssgState
72     stateSet = mat->get_state();
73   } else {
74     SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown use material name = Ocean");
75   }
76   
77   // Calculate center point
78   SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center());
79   
80   double clon = b.get_center_lon();
81   double clat = b.get_center_lat();
82   double height = b.get_height();
83   double width = b.get_width();
84
85   // Calculate vertices. By splitting the tile up into 4 quads on a
86   // side we avoid curvature-of-the-earth problems; the error should
87   // be less than .5 meters.
88   SGGeod geod[5][5];
89   SGVec3f normals[5][5];
90   SGVec3d rel[5][5];
91   double longInc = width * .25;
92   double latInc = height * .25;
93   double startLat = clat - height * .5;
94   double startLon = clon - width * .5;
95   for (int j = 0; j < 5; j++) {
96     double lat = startLat + j * latInc;
97     for (int i = 0; i < 5; i++) {
98       geod[i][j] = SGGeod::fromDeg(startLon + i * longInc, lat);
99       SGVec3d cart = SGVec3d::fromGeod(geod[i][j]);
100       rel[i][j] = cart - cartCenter;
101       normals[i][j] = toVec3f(normalize(cart));
102     }
103   }
104     
105   // Calculate texture coordinates
106   point_list geod_nodes;
107   geod_nodes.reserve(5 * 5);
108   int_list rectangle;
109   rectangle.reserve(5 * 5);
110   for (int j = 0; j < 5; j++) {
111     for (int i = 0; i < 5; ++i) {
112       geod_nodes.push_back(Point3D(geod[i][j].getLongitudeDeg(),
113                                    geod[i][j].getLatitudeDeg(),
114                                    geod[i][j].getElevationM()));
115       rectangle.push_back(j * 5 + i);
116     }
117   }
118   point_list texs = sgCalcTexCoords( b, geod_nodes, rectangle, 
119                                      1000.0 / tex_width );
120   
121   // Allocate osg structures
122   osg::Vec3Array *vl = new osg::Vec3Array;
123   osg::Vec3Array *nl = new osg::Vec3Array;
124   osg::Vec2Array *tl = new osg::Vec2Array;
125
126   for (int j = 0; j < 5; j++) {
127     for (int i = 0; i < 5; ++i) {
128       vl->push_back(rel[i][j].osg());
129       nl->push_back(normals[i][j].osg());
130       tl->push_back(texs[j * 5 + i].toSGVec2f().osg());
131     }
132   }
133   
134   osg::Vec4Array* cl = new osg::Vec4Array;
135   cl->push_back(osg::Vec4(1, 1, 1, 1));
136   
137   osg::Geometry* geometry = new osg::Geometry;
138   geometry->setVertexArray(vl);
139   geometry->setNormalArray(nl);
140   geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
141   geometry->setColorArray(cl);
142   geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
143   geometry->setTexCoordArray(0, tl);
144
145   osg::DrawElementsUShort* drawElements
146       = new osg::DrawElementsUShort(GL_TRIANGLES, 32 * 3);
147   fillDrawElements(5, 5, drawElements->begin());
148   geometry->addPrimitiveSet(drawElements);
149
150   osg::Geode* geode = new osg::Geode;
151   geode->setName("Ocean tile");
152   geode->addDrawable(geometry);
153   geode->setStateSet(stateSet);
154
155   osg::MatrixTransform* transform = new osg::MatrixTransform;
156   transform->setName("Ocean");
157   transform->setMatrix(osg::Matrix::translate(cartCenter.osg()));
158   transform->addChild(geode);
159   
160   return transform;
161 }