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 #include "triangle_mesh_terrain.h"
21
22 #include <map>
23
24 #include "noise.h"
25
TriangleMeshTerrain(Progress * progress)26 TriangleMeshTerrain::TriangleMeshTerrain(Progress* progress)
27 :TriangleMesh(progress)
28 ,max_height(0.0)
29 {}
30
~TriangleMeshTerrain()31 TriangleMeshTerrain::~TriangleMeshTerrain()
32 {}
33
34
do_noise(const ParametersTerrain & parameters)35 void TriangleMeshTerrain::do_noise(const ParametersTerrain& parameters)
36 {
37 if (parameters.noise.terms==0 || parameters.noise.amplitude==0) return;
38
39 const uint steps=vertices();
40 uint step=0;
41
42 progress_start(100,"Noise");
43
44 MultiscaleNoise noise(parameters.seed,parameters.noise.terms,parameters.noise.amplitude_decay);
45 for (uint i=0;i<vertices();i++)
46 {
47 step++;
48 progress_step((100*step)/steps);
49
50 const float h=vertex_height(i);
51 const float p=parameters.noise.amplitude*noise(parameters.noise.frequency*vertex(i).position());
52
53 set_vertex_height(i,h+p);
54 }
55
56 progress_complete("Noise complete");
57 }
58
do_sea_level(const ParametersTerrain &)59 void TriangleMeshTerrain::do_sea_level(const ParametersTerrain& /*parameters*/)
60 {
61 // Introduce sea level
62 const uint steps=vertices()+triangles();
63 uint step=0;
64
65 progress_start(100,"Sea level");
66 {
67 std::vector<bool> sea_vertices(vertices()); // Flag vertices forced to sea level
68
69 for (uint i=0;i<vertices();i++)
70 {
71 step++;
72 progress_step((100*step)/steps);
73
74 const float m=vertex_height(i);
75
76 if (m<=0.0)
77 {
78 set_vertex_height(i,0.0);
79 sea_vertices[i]=true;
80 }
81 else if (m>max_height)
82 max_height=m;
83 }
84
85 std::vector<Triangle> land_sea[2];
86
87 for (uint i=0;i<triangles();i++)
88 {
89 step++;
90 progress_step((100*step)/steps);
91
92 const Triangle& t=triangle(i);
93 land_sea[sea_vertices[t.vertex(0)] && sea_vertices[t.vertex(1)] && sea_vertices[t.vertex(2)]].push_back(t);
94 }
95
96 _triangle_switch_colour=land_sea[0].size();
97 _triangle=land_sea[0];
98 _triangle.insert(_triangle.end(),land_sea[1].begin(),land_sea[1].end());
99 }
100 progress_complete("Sea level completed");
101 }
102
do_power_law(const ParametersTerrain & parameters)103 void TriangleMeshTerrain::do_power_law(const ParametersTerrain& parameters)
104 {
105 const uint steps=vertices();
106 uint step=0;
107
108 progress_start(100,"Power law");
109
110 for (uint i=0;i<vertices();i++)
111 {
112 step++;
113 progress_step((100*step)/steps);
114
115 const float h=vertex_height(i);
116 if (h>geometry().epsilon())
117 set_vertex_height(i,max_height*pow(h/max_height,parameters.power_law));
118 }
119
120 progress_complete("Power law completed");
121 }
122
insert_unique(std::vector<uint> & v,uint x)123 inline void insert_unique(std::vector<uint>& v,uint x)
124 {
125 if (std::find(v.begin(),v.end(),x)==v.end()) v.push_back(x);
126 }
127
do_rivers(const ParametersTerrain & parameters)128 void TriangleMeshTerrain::do_rivers(const ParametersTerrain& parameters)
129 {
130 if (parameters.rivers==0) return;
131
132 Random01 r01(parameters.rivers_seed);
133
134 std::vector<bool> is_sea_vertex(vertices());
135
136 // Used to use a vector of sets, but this saves memory and there aren't many elements to each set
137 std::vector<std::vector<uint> > vertex_neighbours(vertices());
138
139 progress_start(100,"River preparation");
140
141 const uint prep_steps=triangles();
142 uint step=0;
143
144 // Need to know each vertex's neighbours (for land vertices)
145 for (uint i=0;i<triangles_of_colour0();i++)
146 {
147 step++;
148 progress_step((100*step)/prep_steps);
149
150 const Triangle& t=triangle(i);
151 insert_unique(vertex_neighbours[t.vertex(0)],t.vertex(1));
152 insert_unique(vertex_neighbours[t.vertex(0)],t.vertex(2));
153 insert_unique(vertex_neighbours[t.vertex(1)],t.vertex(0));
154 insert_unique(vertex_neighbours[t.vertex(1)],t.vertex(2));
155 insert_unique(vertex_neighbours[t.vertex(2)],t.vertex(0));
156 insert_unique(vertex_neighbours[t.vertex(2)],t.vertex(1));
157 }
158
159 for (uint i=triangles_of_colour0();i!=triangles();i++)
160 {
161 step++;
162 progress_step((100*step)/prep_steps);
163
164 const Triangle& t=triangle(i);
165 is_sea_vertex[t.vertex(0)]=true;
166 is_sea_vertex[t.vertex(1)]=true;
167 is_sea_vertex[t.vertex(2)]=true;
168 }
169
170 progress_complete("River preparation completed");
171
172 progress_start(100,"Rivers");
173
174 const uint maximum_lake_size=(uint)(vertices()*parameters.lake_becomes_sea);
175
176 const uint steps=parameters.rivers;
177 step=0;
178
179 for (uint r=0;r<parameters.rivers;r++)
180 {
181 step++;
182 progress_step((100*step)/steps);
183
184 unsigned int last_stall_warning=0;
185
186 std::set<uint> vertices_to_add;
187 // Also track the height of vertices in the river.
188 // When a river level rise is forced we can look for upstream points to bring back into the current set
189 std::multimap<float,uint> vertices_to_add_by_height;
190
191 std::set<uint> current_vertices;
192 float current_vertices_height;
193
194 // Pick a random non sea triangle to start river
195 // Would like to use __gnu_cxx::random_sample_n but can't get it to work
196 uint source_vertex=(uint)(r01()*vertices());
197
198 // Rivers starting in the sea are skipped to keep river density independent of land area, and to avoid lock-up on all-sea planets
199 if (is_sea_vertex[source_vertex])
200 continue;
201
202 current_vertices.insert(source_vertex);
203 current_vertices_height=vertex_height(source_vertex);
204
205 while(true)
206 {
207 bool reached_sea=false;
208 std::set<uint> current_vertices_neighbours;
209
210 for (std::set<uint>::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++)
211 {
212 vertices_to_add.insert(*it);
213 vertices_to_add_by_height.insert(std::make_pair(current_vertices_height,*it));
214 reached_sea|=(is_sea_vertex[*it]);
215
216 const std::vector<uint>& neighbours=vertex_neighbours[*it];
217
218 // Only vertices NOT in the current river section are of interest
219 for (std::vector<uint>::const_iterator it_n=neighbours.begin();it_n!=neighbours.end();it_n++)
220 {
221 if (current_vertices.find(*it_n)==current_vertices.end())
222 current_vertices_neighbours.insert(*it_n);
223 }
224 }
225
226 // Find the heights of everything we could flow to
227 std::multimap<float,uint> flow_candidates;
228 for (std::set<uint>::const_iterator it=current_vertices_neighbours.begin();it!=current_vertices_neighbours.end();it++)
229 {
230 flow_candidates.insert(std::multimap<float,uint>::value_type(vertex_height(*it),*it));
231 }
232
233 if (reached_sea)
234 {
235 break;
236 }
237 else if (current_vertices.size()>=maximum_lake_size)
238 {
239 break; // Lake becomes an inland sea
240 }
241 else
242 {
243 // If there is any intersection between the current river hexes and completed rivers then we're done
244 bool meets_existing=false;
245 for (std::set<uint>::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++)
246 {
247 if (river_vertices.find(*it)!=river_vertices.end())
248 {
249 meets_existing=true;
250 break;
251 }
252 }
253 if (meets_existing)
254 {
255 break;
256 }
257 }
258
259 unsigned int num_current_vertices=0;
260 if (flow_candidates.empty()) // Not sure how this could ever happen, but just to be safe...
261 {
262 std::cerr << "Warning: Unexpected internal state: no flow candidates for a river\n";
263 break;
264 }
265 else if ((*(flow_candidates.begin())).first<current_vertices_height-geometry().epsilon()) // Can flow downhill...
266 {
267 // We just flow into ONE vertex, otherwise rivers will expand to inundate all lower terrain
268 current_vertices.clear();
269 current_vertices_height=(*(flow_candidates.begin())).first;
270 current_vertices.insert((*(flow_candidates.begin())).second);
271 num_current_vertices=1;
272 //std::cerr << "-" << current_vertices.size();
273 }
274 else if ((*(flow_candidates.begin())).first<current_vertices_height+geometry().epsilon()) // Or expand across flat...
275 {
276 // But if there are multiple candidates on the same level, flow into all of them
277 std::multimap<float,uint>::const_iterator flat_end=flow_candidates.upper_bound(current_vertices_height+geometry().epsilon());
278
279 for (std::multimap<float,uint>::const_iterator it_flat=flow_candidates.begin();it_flat!=flat_end;it_flat++)
280 {
281 current_vertices.insert((*it_flat).second);
282 }
283 num_current_vertices=current_vertices.size();
284 //std::cerr << "=" << current_vertices.size();
285 }
286 else // Otherwise the water level must rise to height of the lowest flow candidate
287 {
288 current_vertices_height=(*(flow_candidates.begin())).first+geometry().epsilon(); // Rise a bit more to avoid getting stuck due to precision.
289 const uint outflow_vertex=(*(flow_candidates.begin())).second;
290 current_vertices.insert(outflow_vertex);
291
292 // Any vertices upstream below the new height should now become part of the current set, and have their level raised.
293 std::multimap<float,uint>::iterator backflow_end=vertices_to_add_by_height.upper_bound(current_vertices_height);
294 for (std::multimap<float,uint>::iterator it=vertices_to_add_by_height.begin();it!=backflow_end;it++)
295 {
296 const uint v=(*it).second;
297 current_vertices.insert(v);
298 set_vertex_height(v,current_vertices_height);
299 }
300 vertices_to_add_by_height.erase(vertices_to_add_by_height.begin(),backflow_end);
301
302 // Raise level of everything in the working set
303 // Also count vertices rather than having .size() iterate over them again.
304 for (std::set<uint>::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++)
305 {
306 set_vertex_height(*it,current_vertices_height);
307 num_current_vertices++;
308 }
309 //std::cerr << "+" << current_vertices.size();
310 }
311
312 if (num_current_vertices>=last_stall_warning+100)
313 {
314 std::ostringstream msg;
315 msg << "Rivers (delay: " << num_current_vertices << " vertex lake)";
316 progress_stall(msg.str());
317 last_stall_warning=num_current_vertices;
318 }
319 else if (num_current_vertices+100<=last_stall_warning)
320 {
321 std::ostringstream msg;
322 msg << "Rivers: lake complete";
323 progress_stall(msg.str());
324 last_stall_warning=num_current_vertices;
325 }
326 }
327
328 river_vertices.insert(vertices_to_add.begin(),vertices_to_add.end());
329 }
330
331 progress_complete("Rivers completed");
332 }
333
do_colours(const ParametersTerrain & parameters)334 void TriangleMeshTerrain::do_colours(const ParametersTerrain& parameters)
335 {
336 const uint steps=triangles_of_colour1()+vertices();
337 uint step=0;
338
339 progress_start(100,"Colouring");
340
341 // Colour any triangles which need colouring (ie just sea)
342 ByteRGBA colour_ocean(parameters.colour_ocean);
343 ByteRGBA colour_river(parameters.colour_river);
344 if (parameters.oceans_and_rivers_emissive>0.0f)
345 {
346 colour_ocean.a=0;
347 colour_river.a=0;
348 }
349
350 for (uint i=triangles_of_colour0();i!=triangles();i++)
351 {
352 step++;
353 progress_step((100*step)/steps);
354
355 vertex(triangle(i).vertex(0)).colour(1,colour_ocean);
356 vertex(triangle(i).vertex(1)).colour(1,colour_ocean);
357 vertex(triangle(i).vertex(2)).colour(1,colour_ocean);
358
359 // For debugging, set the colour0 of those triangles to red
360 vertex(triangle(i).vertex(0)).colour(0,ByteRGBA(255,0,0,255));
361 vertex(triangle(i).vertex(1)).colour(0,ByteRGBA(255,0,0,255));
362 vertex(triangle(i).vertex(2)).colour(0,ByteRGBA(255,0,0,255));
363 }
364
365 const float treeline=0.25;
366 const float beachline=0.01;
367
368 // Colour all vertices
369 for (uint i=0;i<vertices();i++)
370 {
371 step++;
372 progress_step((100*step)/steps);
373
374 bool is_river=(river_vertices.find(i)!=river_vertices.end());
375
376 float average_slope=1.0-(geometry().up(vertex(i).position())%vertex(i).normal());
377
378 const float normalised_height=vertex_height(i)/max_height;
379
380 float snowline_here=
381 parameters.snowline_equator
382 +fabs(geometry().normalised_latitude(vertex(i).position()))*(parameters.snowline_pole-parameters.snowline_equator)
383 +parameters.snowline_slope_effect*average_slope
384 -(is_river ? parameters.snowline_glacier_effect : 0.0);
385
386 if (snowline_here>0.0)
387 snowline_here=pow(snowline_here,parameters.snowline_power_law);
388
389 if (normalised_height>snowline_here)
390 {
391 vertex(i).colour(0,parameters.colour_snow);
392 }
393 else if (is_river)
394 {
395 vertex(i).colour(0,parameters.colour_river);
396 }
397 else if (normalised_height<beachline)
398 {
399 vertex(i).colour(0,parameters.colour_shoreline);
400 }
401 else if (normalised_height<treeline)
402 {
403 const float blend=normalised_height/treeline;
404 vertex(i).colour(0,blend*parameters.colour_high+(1.0-blend)*parameters.colour_low);
405 }
406 else
407 {
408 vertex(i).colour(0,parameters.colour_high);
409 }
410 }
411
412 progress_complete("Colouring completed");
413 }
414
do_terrain(const ParametersTerrain & parameters)415 void TriangleMeshTerrain::do_terrain(const ParametersTerrain& parameters)
416 {
417 do_noise(parameters);
418 do_sea_level(parameters);
419 do_power_law(parameters);
420 do_rivers(parameters);
421 compute_vertex_normals();
422 do_colours(parameters);
423 set_emissive(parameters.oceans_and_rivers_emissive);
424 }
425
write_blender(std::ofstream & out,const ParametersSave &,const ParametersTerrain &,const std::string & mesh_name) const426 void TriangleMeshTerrain::write_blender(std::ofstream& out,const ParametersSave&,const ParametersTerrain&,const std::string& mesh_name) const
427 {
428 TriangleMesh::write_blender(out,mesh_name+".terrain",0);
429 }
430
431 namespace
432 {
lerp(float l,const T & v0,const T & v1)433 template <typename T> const T lerp(float l,const T& v0,const T& v1)
434 {
435 return (1.0f-l)*v0+l*v1;
436 }
437
fn(const XYZ & v)438 FloatRGBA fn(const XYZ& v)
439 {
440 const XYZ n(v.normalised());
441 return FloatRGBA(0.5f+0.5f*n.x,0.5f+0.5f*n.y,0.5f+0.5f*n.z,0.0f);
442 }
443
444 class ScanConvertHelper : public ScanConvertBackend
445 {
446 public:
ScanConvertHelper(Raster<ByteRGBA> & image,Raster<ushort> * dem,Raster<ByteRGBA> * normalmap,const boost::array<FloatRGBA,3> & vertex_colours,const boost::array<float,3> & vertex_heights,const boost::array<XYZ,3> & vertex_normals)447 ScanConvertHelper
448 (
449 Raster<ByteRGBA>& image,
450 Raster<ushort>* dem,
451 Raster<ByteRGBA>* normalmap,
452 const boost::array<FloatRGBA,3>& vertex_colours,
453 const boost::array<float,3>& vertex_heights,
454 const boost::array<XYZ,3>& vertex_normals
455 )
456 :ScanConvertBackend(image.width(),image.height())
457 ,_image(image)
458 ,_dem(dem)
459 ,_normalmap(normalmap)
460 ,_vertex_colours(vertex_colours)
461 ,_vertex_heights(vertex_heights)
462 ,_vertex_normals(vertex_normals)
463 {
464 if (_dem) assert(_image.width()==_dem->width() && _image.height()==_dem->height());
465 if (_normalmap) assert(_image.width()==_normalmap->width() && _image.height()==_normalmap->height());
466 }
~ScanConvertHelper()467 virtual ~ScanConvertHelper()
468 {}
469
scan_convert_backend(uint y,const ScanEdge & edge0,const ScanEdge & edge1) const470 virtual void scan_convert_backend(uint y,const ScanEdge& edge0,const ScanEdge& edge1) const
471 {
472 const FloatRGBA c0=lerp(edge0.lambda,_vertex_colours[edge0.vertex0],_vertex_colours[edge0.vertex1]);
473 const FloatRGBA c1=lerp(edge1.lambda,_vertex_colours[edge1.vertex0],_vertex_colours[edge1.vertex1]);
474 _image.scan(y,edge0.x,c0,edge1.x,c1);
475
476 if (_dem)
477 {
478 const float h0=lerp(edge0.lambda,_vertex_heights[edge0.vertex0],_vertex_heights[edge0.vertex1]);
479 const float h1=lerp(edge1.lambda,_vertex_heights[edge1.vertex0],_vertex_heights[edge1.vertex1]);
480 _dem->scan(y,edge0.x,h0,edge1.x,h1);
481 }
482 if (_normalmap)
483 {
484 const XYZ n0(lerp(edge0.lambda,_vertex_normals[edge0.vertex0],_vertex_normals[edge0.vertex1]).normalised());
485 const XYZ n1(lerp(edge1.lambda,_vertex_normals[edge1.vertex0],_vertex_normals[edge1.vertex1]).normalised());
486 _normalmap->scan<XYZ>(y,edge0.x,n0,edge1.x,n1,fn);
487 }
488 }
489
subdivide(const boost::array<XYZ,3> & v,const XYZ & m,const ScanConverter & scan_converter) const490 virtual void subdivide(const boost::array<XYZ,3>& v,const XYZ& m,const ScanConverter& scan_converter) const
491 {
492 // Subdivision pattern (into 7) avoids creating any mid-points in edges shared with other triangles.
493 const boost::array<XYZ,3> vm=
494 {{
495 (v[1]+v[2]+m)/3.0f,
496 (v[0]+v[2]+m)/3.0f,
497 (v[0]+v[1]+m)/3.0f
498 }};
499
500 //! \todo This isn't right (for correct value would need to compute barycentric coordinates of m), but it will should only affect one facet at the pole.
501 const boost::array<FloatRGBA,3> cm=
502 {{
503 0.5f*(_vertex_colours[1]+_vertex_colours[2]),
504 0.5f*(_vertex_colours[0]+_vertex_colours[2]),
505 0.5f*(_vertex_colours[0]+_vertex_colours[1])
506 }};
507 const boost::array<float,3> hm=
508 {{
509 0.5f*(_vertex_heights[1]+_vertex_heights[2]),
510 0.5f*(_vertex_heights[0]+_vertex_heights[2]),
511 0.5f*(_vertex_heights[0]+_vertex_heights[1])
512 }};
513 const boost::array<XYZ,3> nm=
514 {{
515 (_vertex_normals[1]+_vertex_normals[2]).normalised(),
516 (_vertex_normals[0]+_vertex_normals[2]).normalised(),
517 (_vertex_normals[0]+_vertex_normals[1]).normalised()
518 }};
519
520 {
521 const boost::array<XYZ,3> p={{v[0],v[1],vm[2]}};
522 const boost::array<FloatRGBA,3> c={{_vertex_colours[0],_vertex_colours[1],cm[2]}};
523 const boost::array<float,3> h={{_vertex_heights[0],_vertex_heights[1],hm[2]}};
524 const boost::array<XYZ,3> n={{_vertex_normals[0],_vertex_normals[1],nm[2]}};
525 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
526 }
527
528 {
529 const boost::array<XYZ,3> p={{v[1],v[2],vm[0]}};
530 const boost::array<FloatRGBA,3> c={{_vertex_colours[1],_vertex_colours[2],cm[0]}};
531 const boost::array<float,3> h={{_vertex_heights[1],_vertex_heights[2],hm[0]}};
532 const boost::array<XYZ,3> n={{_vertex_normals[1],_vertex_normals[2],nm[0]}};
533 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
534 }
535
536 {
537 const boost::array<XYZ,3> p={{v[2],v[0],vm[1]}};
538 const boost::array<FloatRGBA,3> c={{_vertex_colours[2],_vertex_colours[0],cm[1]}};
539 const boost::array<float,3> h={{_vertex_heights[2],_vertex_heights[0],hm[1]}};
540 const boost::array<XYZ,3> n={{_vertex_normals[2],_vertex_normals[0],nm[1]}};
541 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
542 }
543
544 {
545 const boost::array<XYZ,3> p={{v[0],vm[2],vm[1]}};
546 const boost::array<FloatRGBA,3> c={{_vertex_colours[0],cm[2],cm[1]}};
547 const boost::array<float,3> h={{_vertex_heights[0],hm[2],hm[1]}};
548 const boost::array<XYZ,3> n={{_vertex_normals[0],nm[2],nm[1]}};
549 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
550 }
551
552 {
553 const boost::array<XYZ,3> p={{v[1],vm[0],vm[2]}};
554 const boost::array<FloatRGBA,3> c={{_vertex_colours[1],cm[0],cm[2]}};
555 const boost::array<float,3> h={{_vertex_heights[1],hm[0],hm[2]}};
556 const boost::array<XYZ,3> n={{_vertex_normals[1],nm[0],nm[2]}};
557 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
558 }
559
560 {
561 const boost::array<XYZ,3> p={{v[2],vm[1],vm[0]}};
562 const boost::array<FloatRGBA,3> c={{_vertex_colours[2],cm[1],cm[0]}};
563 const boost::array<float,3> h={{_vertex_heights[2],hm[1],hm[0]}};
564 const boost::array<XYZ,3> n={{_vertex_normals[2],nm[1],nm[0]}};
565 scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n));
566 }
567
568 {
569 scan_converter.scan_convert(vm,ScanConvertHelper(_image,_dem,_normalmap,cm,hm,nm));
570 }
571
572 }
573
574 private:
575 Raster<ByteRGBA>& _image;
576 Raster<ushort>* _dem;
577 Raster<ByteRGBA>* _normalmap;
578 const boost::array<FloatRGBA,3>& _vertex_colours;
579 const boost::array<float,3>& _vertex_heights;
580 const boost::array<XYZ,3>& _vertex_normals;
581 };
582 }
583
render_texture(Raster<ByteRGBA> & image,Raster<ushort> * dem,Raster<ByteRGBA> * normal_map,bool shading,float ambient,const XYZ & illumination) const584 void TriangleMeshTerrain::render_texture
585 (
586 Raster<ByteRGBA>& image,
587 Raster<ushort>* dem,
588 Raster<ByteRGBA>* normal_map,
589 bool shading,
590 float ambient,
591 const XYZ& illumination
592 ) const
593 {
594 progress_start(100,"Generating textures");
595
596 for (uint i=0;i<triangles();i++)
597 {
598 const Triangle& t=triangle(i);
599 const boost::array<const Vertex*,3> vertices
600 ={{
601 &vertex(t.vertex(0)),
602 &vertex(t.vertex(1)),
603 &vertex(t.vertex(2)),
604 }};
605
606 const boost::array<XYZ,3> vertex_positions
607 ={{
608 vertices[0]->position(),
609 vertices[1]->position(),
610 vertices[2]->position()
611 }};
612
613 const uint which_colour=(i<triangles_of_colour0() ? 0 : 1);
614 const boost::array<FloatRGBA,3> vertex_colours
615 ={{
616 FloatRGBA(vertices[0]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[0]->normal()%illumination) : 1.0f),
617 FloatRGBA(vertices[1]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[1]->normal()%illumination) : 1.0f),
618 FloatRGBA(vertices[2]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[2]->normal()%illumination) : 1.0f)
619 }};
620 const boost::array<float,3> vertex_heights
621 ={{
622 std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[0]->position()))),
623 std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[1]->position()))),
624 std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[2]->position())))
625 }};
626 const boost::array<XYZ,3> vertex_normals
627 ={{
628 vertices[0]->normal(),
629 vertices[1]->normal(),
630 vertices[2]->normal()
631 }};
632
633 ScanConvertHelper backend(image,dem,normal_map,vertex_colours,vertex_heights,vertex_normals);
634
635 geometry().scan_convert
636 (
637 vertex_positions,
638 backend
639 );
640
641 progress_step((100*i)/(triangles()-1));
642 }
643
644 progress_complete("Texture generation completed");
645 }
646
TriangleMeshTerrainPlanet(const ParametersTerrain & parameters,Progress * progress)647 TriangleMeshTerrainPlanet::TriangleMeshTerrainPlanet(const ParametersTerrain& parameters,Progress* progress)
648 :TriangleMesh(progress)
649 ,TriangleMeshTerrain(progress)
650 ,TriangleMeshSubdividedIcosahedron(1.0+parameters.variation.z*parameters.base_height,parameters.subdivisions,parameters.subdivisions_unperturbed,parameters.seed,parameters.variation,progress)
651 {
652 do_terrain(parameters);
653 }
654
write_povray(std::ofstream & out,const ParametersSave & param_save,const ParametersTerrain & parameters_terrain) const655 void TriangleMeshTerrainPlanet::write_povray(std::ofstream& out,const ParametersSave& param_save,const ParametersTerrain& parameters_terrain) const
656 {
657 if (param_save.pov_sea_object)
658 {
659 out
660 << "sphere {<0.0,0.0,0.0>,1.0 pigment{rgb "
661 << parameters_terrain.colour_ocean.format_pov_rgb()
662 << "} finish {ambient "
663 << emissive()
664 << " diffuse "
665 << 1.0f-emissive()
666 << "}}\n";
667 }
668
669 if (param_save.pov_atmosphere)
670 {
671 out
672 << "sphere {<0.0,0.0,0.0>,1.025 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <1.0,1.0,1.0> extinction 1}}}}\n"
673 << "sphere {<0.0,0.0,0.0>,1.05 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <0.0,0.0,1.0> extinction 1}}}}\n";
674 }
675
676 TriangleMesh::write_povray(out,param_save.pov_sea_object,false,false); // Don't double illuminate. Don't no-shadow.
677 }
678
TriangleMeshTerrainFlat(const ParametersTerrain & parameters,Progress * progress)679 TriangleMeshTerrainFlat::TriangleMeshTerrainFlat(const ParametersTerrain& parameters,Progress* progress)
680 :TriangleMesh(progress)
681 ,TriangleMeshTerrain(progress)
682 ,TriangleMeshFlat(parameters.object_type,parameters.variation.z*parameters.base_height,parameters.seed,progress)
683 {
684 subdivide(parameters.subdivisions,parameters.subdivisions_unperturbed,parameters.variation);
685
686 do_terrain(parameters);
687 }
688
write_povray(std::ofstream & out,const ParametersSave & param_save,const ParametersTerrain & parameters_terrain) const689 void TriangleMeshTerrainFlat::write_povray(std::ofstream& out,const ParametersSave& param_save,const ParametersTerrain& parameters_terrain) const
690 {
691 if (param_save.pov_sea_object)
692 {
693 out
694 << "plane {<0.0,1.0,0.0>,0.0 pigment{rgb "
695 << parameters_terrain.colour_ocean.format_pov_rgb()
696 << "} finish {ambient "
697 << emissive()
698 << " diffuse "
699 << 1.0f-emissive()
700 << "}}\n";
701 }
702
703 if (param_save.pov_atmosphere)
704 {
705 out
706 << "plane {<0.0,1.0,0.0>,0.05 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <1.0,1.0,1.0> extinction 1}}}}\n"
707 << "plane {<0.0,1.0,0.0>,0.1 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <0.0,0.0,1.0> extinction 1}}}}\n";
708 }
709
710 TriangleMesh::write_povray(out,param_save.pov_sea_object,false,false); // Don't double illuminate. Don't no-shadow.
711 }
712