1 /**************************************************************************/
2 /*  Copyright 2009 Tim Day                                                */
3 /*                                                                        */
4 /*  This file is part of Fracplanet                                       */
5 /*                                                                        */
6 /*  Fracplanet is free software: you can redistribute it and/or modify    */
7 /*  it under the terms of the GNU General Public License as published by  */
8 /*  the Free Software Foundation, either version 3 of the License, or     */
9 /*  (at your option) any later version.                                   */
10 /*                                                                        */
11 /*  Fracplanet is distributed in the hope that it will be useful,         */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
14 /*  GNU General Public License for more details.                          */
15 /*                                                                        */
16 /*  You should have received a copy of the GNU General Public License     */
17 /*  along with Fracplanet.  If not, see <http://www.gnu.org/licenses/>.   */
18 /**************************************************************************/
19 
20 #ifndef _triangle_mesh_h_
21 #define _triangle_mesh_h_
22 
23 #include "common.h"
24 #include "geometry.h"
25 #include "parameters_save.h"
26 #include "parameters_terrain.h"
27 #include "progress.h"
28 #include "random.h"
29 #include "triangle.h"
30 #include "triangle_edge.h"
31 #include "vertex.h"
32 
33 /*! \file
34   \brief Interface for class TriangleMesh.
35 */
36 
37 //! Contains vertices and triangles of a triangle mesh.
38 /*! Abstract base class because specific classes must specify a geometry.
39   Not as general-purpose as it might be due to constraints imposed by OpenGL.
40   In particular, Triangle can have no attributes (e.g normal, colour) if a single
41   OpenGL call is to be made to draw all triangles, so this information is entirely associated with Vertex.
42   Two colours can be associated with each vertex
43   (required for fracplanet application to obtain sharp coastlines),
44   and it it a requirement for subclasses to sort triangles so that all
45   those before _triangle_switch_colour use vertex colour index 0,
46   and those afterwards vertex colour index 1.
47   \todo The geometry() method is a mess.
48   It would surely be better to have a Geometry* in the base class passed in via the constructor.
49 */
50 class TriangleMesh
51 {
52 public:
53 
54   //! Constructor.
55   TriangleMesh(Progress* progress);
56 
57   //! Destructor.
58   virtual ~TriangleMesh();
59 
60   //! Accessor
set_emissive(float e)61   void set_emissive(float e)
62     {
63       _emissive=e;
64     }
65 
66   //! Accessor
emissive()67   float emissive() const
68     {
69       return _emissive;
70     }
71 
72   //! Append a vertex.
add_vertex(const Vertex & v)73   void add_vertex(const Vertex& v)
74     {
75       _vertex.push_back(v);
76     }
77 
78   //! Append a triangle.
add_triangle(const Triangle & t)79   void add_triangle(const Triangle& t)
80     {
81       _triangle.push_back(t);
82     }
83 
84   //! Accessor.
vertex(uint i)85   const Vertex& vertex(uint i) const
86     {
87       return _vertex[i];
88     }
89 
90   //! Accessor.
triangle(uint i)91   const Triangle& triangle(uint i) const
92     {
93       return _triangle[i];
94     }
95 
96   //! Access the geometry of this class (needed to abstract concepts like "mid-point" and "height").
97   virtual const Geometry& geometry() const
98     =0;
99 
100   //! Return height of a vertex.
vertex_height(uint i)101   float vertex_height(uint i) const
102     {
103       return geometry().height(vertex(i).position());
104     }
105 
106   //! Set height of a vertex.
set_vertex_height(uint i,float h)107   void set_vertex_height(uint i,float h)
108     {
109       XYZ p(vertex(i).position());
110       geometry().set_height(p,h);
111       vertex(i).position(p);
112     }
113 
114   //! Return minimum height of a triangle's vertices.
triangle_height_min(uint i)115   float triangle_height_min(uint i) const
116     {
117       const Triangle& t=triangle(i);
118       return minimum
119 	(
120 	 vertex_height(t.vertex(0)),
121 	 vertex_height(t.vertex(1)),
122 	 vertex_height(t.vertex(2))
123 	 );
124     }
125 
126   //! Return maximum height of a triangle's vertices.
triangle_height_max(uint i)127   float triangle_height_max(uint i) const
128     {
129       const Triangle& t=triangle(i);
130       return maximum
131 	(
132 	 vertex_height(t.vertex(0)),
133 	 vertex_height(t.vertex(1)),
134 	 vertex_height(t.vertex(2))
135 	 );
136     }
137 
138   //! Return mean height of a triangle's vertices.
triangle_height_average(uint i)139   float triangle_height_average(uint i) const
140     {
141       const Triangle& t=triangle(i);
142       return
143 	(
144 	 vertex_height(t.vertex(0))
145 	 +vertex_height(t.vertex(1))
146 	 +vertex_height(t.vertex(2))
147 	 )/3.0;
148     }
149 
150   //! Compute and return the normal to a triangle
151   const XYZ triangle_normal(uint i) const;
152 
153   //! Return which vertex colour to use for a triangle.
which_colour_for_triangle(uint t)154   uint which_colour_for_triangle(uint t) const
155     {
156       return (t<_triangle_switch_colour ? 0 : 1);
157     }
158 
159   //! Returns number of vertices in mesh.
vertices()160   uint vertices() const
161     {
162       return _vertex.size();
163     }
164   //! Returns number of triangles in mesh.
triangles()165   uint triangles() const
166     {
167       return _triangle.size();
168     }
169 
170   //! Returns number of triangles in mesh indexing colour[0] of vertices.
triangles_of_colour0()171   uint triangles_of_colour0() const
172     {
173       return _triangle_switch_colour;
174     }
175 
176   //! Returns number of triangles in mesh indexing colour[1] of vertices.
triangles_of_colour1()177   uint triangles_of_colour1() const
178     {
179       return triangles()-_triangle_switch_colour;
180     }
181 
182   //! (Re-)computes vertex normals.
183   void compute_vertex_normals();
184 
185   //! Perform a single subdivision pass with perturbations up to the specified size
186   void subdivide(const XYZ& variation,uint level,uint levels);
187 
188   //! Perform a number of subdivisions, possibly some unperturbed ("flat"), and halving the perturbation variation each iteration.
189   void subdivide(uint subdivisions,uint flat_subdivisions,const XYZ& variation);
190 
191   //! Dump the mesh to the file in a form suitable for use by POVRay.
192   void write_povray(std::ofstream& out,bool exclude_alternate_colour,bool double_illuminate,bool no_shadow) const;
193 
194   //! Dump the mesh to the file in a form suitable for use by Blender.
195   void write_blender(std::ofstream& out,const std::string& mesh_name,const FloatRGBA* fake_alpha) const;
196 
197  protected:
198 
199   //! The vertices of this mesh.
200   std::vector<Vertex> _vertex;
201 
202   //! The triangles of this mesh.
203   std::vector<Triangle> _triangle;
204 
205   //! The index of the triangle at which we switch to the alternate colour.
206   uint _triangle_switch_colour;
207 
208   //! The emission level for vertices with the _emissive flag set
209   float _emissive;
210 
211   //! Pointer to the progress object to which progress reports should be made.
212   Progress*const _progress;
213 
214   //! Accessor.
vertex(uint i)215   Vertex& vertex(uint i)
216     {
217       return _vertex[i];
218     }
219 
220   //! Accessor.
triangle(uint i)221   Triangle& triangle(uint i)
222     {
223       return _triangle[i];
224     }
225 
226   //! Convenience wrapper with null test.
227   void progress_start(uint steps,const std::string& info) const;
228 
229   //! Convenience wrapper with null test.
230   void progress_stall(const std::string& reason) const;
231 
232   //! Convenience wrapper with null test.
233   void progress_step(uint step) const;
234 
235   //! Convenience wrapper with null test.
236   void progress_complete(const std::string& info) const;
237 
238  private:
239 
240   //! Fake per-vertex alpha for Blender.
241   static ByteRGBA blender_alpha_workround(const ByteRGBA*,const ByteRGBA&);
242 };
243 
244 //! A single triangle lying in the z-plane.
245 class TriangleMeshFlat : virtual public TriangleMesh
246 {
247  public:
248 
249   //! Constructor.
250   TriangleMeshFlat(ParametersObject::ObjectType obj,float z,uint seed,Progress* progress);
251 
252   //! Destructor.
~TriangleMeshFlat()253   ~TriangleMeshFlat()
254     {}
255 
256   //! Returns the specific geometry.
geometry()257   virtual const Geometry& geometry() const
258     {
259       return _geometry;
260     }
261 
262  private:
263 
264   //! The specifc geometry for this mesh.
265   GeometryFlat _geometry;
266 };
267 
268 //! An icosahedron.
269 class TriangleMeshIcosahedron : virtual public TriangleMesh
270 {
271  public:
272 
273   //! Constructor.
274   TriangleMeshIcosahedron(float radius,uint seed,Progress* progress);
275 
276   //! Destructor.
~TriangleMeshIcosahedron()277   ~TriangleMeshIcosahedron()
278     {}
279 
280   //! Returns the specific geometry.
geometry()281   virtual const Geometry& geometry() const
282     {
283       return _geometry;
284     }
285 
286  private:
287 
288   //! The specifc geometry for this mesh.
289   GeometrySpherical _geometry;
290 };
291 
292 //! A subdivided icosahedron.
293 class TriangleMeshSubdividedIcosahedron : public TriangleMeshIcosahedron
294 {
295  public:
296 
297   //! Constructor.
298   TriangleMeshSubdividedIcosahedron(float radius,uint subdivisions,uint flat_subdivisions,uint seed,const XYZ& variation,Progress* progress);
299 
300   //! Destructor.
~TriangleMeshSubdividedIcosahedron()301   ~TriangleMeshSubdividedIcosahedron()
302     {}
303 };
304 
305 #endif
306