3
* Copyright (C) 2003 Fabien Chereau
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
#include "landscape.h"
21
#include "init_parser.h"
23
Landscape::Landscape(float _radius) : radius(_radius), sky_brightness(1.)
28
Landscape::~Landscape()
31
Landscape* Landscape::create_from_file(const string& landscape_file, const string& section_name)
33
InitParser pd; // The landscape data ini file parser
34
pd.load(landscape_file);
36
s = pd.get_str(section_name, "type");
37
Landscape* ldscp = NULL;
40
ldscp = new LandscapeOldStyle();
42
else if (s=="spherical")
44
ldscp = new LandscapeSpherical();
46
else if (s=="fisheye")
48
ldscp = new LandscapeFisheye();
52
cerr << "Unknown landscape type: " << s << endl;
54
// to avoid making this a fatal error, will load as a fisheye
55
// if this fails, it just won't draw
56
ldscp = new LandscapeFisheye();
59
ldscp->load(landscape_file, section_name);
63
// create landscape from parameters passed in a hash (same keys as with ini file)
64
// NOTE: maptex must be full path and filename
65
Landscape* Landscape::create_from_hash(stringHash_t & param)
68
// NOTE: textures should be full filename (and path)
69
if (param["type"]=="old_style")
71
LandscapeOldStyle* ldscp = new LandscapeOldStyle();
72
ldscp->create(1, param);
75
else if (param["type"]=="spherical")
77
LandscapeSpherical* ldscp = new LandscapeSpherical();
78
ldscp->create(param["name"], 1, param["path"] + param["maptex"]);
82
{ // if (s=="fisheye")
83
LandscapeFisheye* ldscp = new LandscapeFisheye();
84
ldscp->create(param["name"], 1, param["path"] + param["maptex"], str_to_double(param["texturefov"]));
89
// Load attributes common to all landscapes
90
void Landscape::loadCommon(const string& landscape_file, const string& section_name)
92
InitParser pd; // The landscape data ini file parser
93
pd.load(landscape_file);
94
name = pd.get_str(section_name, "name");
95
author = pd.get_str(section_name, "author");
96
description = pd.get_str(section_name, "description");
99
cerr << "No valid landscape definition found for section "<< section_name << " in file " << landscape_file << ". No landscape in use." << endl;
109
string Landscape::get_file_content(const string& landscape_file)
111
InitParser pd; // The landscape data ini file parser
112
pd.load(landscape_file);
116
for (int i=0; i<pd.get_nsec();i++)
118
result += pd.get_secname(i) + '\n';
123
string Landscape::getLandscapeNames(const string& landscape_file)
125
InitParser pd; // The landscape data ini file parser
126
pd.load(landscape_file);
130
for (int i=0; i<pd.get_nsec();i++)
132
result += pd.get_str(pd.get_secname(i), "name") + '\n';
137
string Landscape::nameToKey(const string& landscape_file, const string & name)
139
InitParser pd; // The landscape data ini file parser
140
pd.load(landscape_file);
142
for (int i=0; i<pd.get_nsec();i++)
144
if (name==pd.get_str(pd.get_secname(i), "name")) return pd.get_secname(i);
150
LandscapeOldStyle::LandscapeOldStyle(float _radius) : Landscape(_radius), side_texs(NULL), sides(NULL), fog_tex(NULL), ground_tex(NULL)
153
LandscapeOldStyle::~LandscapeOldStyle()
157
for (int i=0;i<nb_side_texs;++i)
159
if (side_texs[i]) delete side_texs[i];
166
if (sides) delete [] sides;
167
if (ground_tex) delete ground_tex;
168
if (fog_tex) delete fog_tex;
172
void LandscapeOldStyle::load(const string& landscape_file, const string& section_name)
174
loadCommon(landscape_file, section_name);
176
// TODO: put values into hash and call create method to consolidate code
178
InitParser pd; // The landscape data ini file parser
179
pd.load(landscape_file);
181
string type = pd.get_str(section_name, "type");
182
if(type != "old_style")
184
cerr << "Landscape type mismatch for landscape "<< section_name << ", expected old_style, found " << type << ". No landscape in use.\n";
189
// Load sides textures
190
nb_side_texs = pd.get_int(section_name, "nbsidetex", 0);
191
side_texs = new s_texture*[nb_side_texs];
193
for (int i=0;i<nb_side_texs;++i)
195
sprintf(tmp,"tex%d",i);
196
side_texs[i] = new s_texture(pd.get_str(section_name, tmp),TEX_LOAD_TYPE_PNG_ALPHA,false);
199
// Init sides parameters
200
nb_side = pd.get_int(section_name, "nbside", 0);
201
sides = new landscape_tex_coord[nb_side];
205
for (int i=0;i<nb_side;++i)
207
sprintf(tmp,"side%d",i);
208
s = pd.get_str(section_name, tmp);
209
sscanf(s.c_str(),"tex%d:%f:%f:%f:%f",&texnum,&a,&b,&c,&d);
210
sides[i].tex = side_texs[texnum];
211
sides[i].tex_coords[0] = a;
212
sides[i].tex_coords[1] = b;
213
sides[i].tex_coords[2] = c;
214
sides[i].tex_coords[3] = d;
215
//printf("%f %f %f %f\n",a,b,c,d);
218
nb_decor_repeat = pd.get_int(section_name, "nb_decor_repeat", 1);
220
ground_tex = new s_texture(pd.get_str(section_name, "groundtex"),TEX_LOAD_TYPE_PNG_SOLID,false);
221
s = pd.get_str(section_name, "ground");
222
sscanf(s.c_str(),"groundtex:%f:%f:%f:%f",&a,&b,&c,&d);
223
ground_tex_coord.tex = ground_tex;
224
ground_tex_coord.tex_coords[0] = a;
225
ground_tex_coord.tex_coords[1] = b;
226
ground_tex_coord.tex_coords[2] = c;
227
ground_tex_coord.tex_coords[3] = d;
229
fog_tex = new s_texture(pd.get_str(section_name, "fogtex"),TEX_LOAD_TYPE_PNG_SOLID_REPEAT,false);
230
s = pd.get_str(section_name, "fog");
231
sscanf(s.c_str(),"fogtex:%f:%f:%f:%f",&a,&b,&c,&d);
232
fog_tex_coord.tex = fog_tex;
233
fog_tex_coord.tex_coords[0] = a;
234
fog_tex_coord.tex_coords[1] = b;
235
fog_tex_coord.tex_coords[2] = c;
236
fog_tex_coord.tex_coords[3] = d;
238
fog_alt_angle = pd.get_double(section_name, "fog_alt_angle", 0.);
239
fog_angle_shift = pd.get_double(section_name, "fog_angle_shift", 0.);
240
decor_alt_angle = pd.get_double(section_name, "decor_alt_angle", 0.);
241
decor_angle_shift = pd.get_double(section_name, "decor_angle_shift", 0.);
242
decor_angle_rotatez = pd.get_double(section_name, "decor_angle_rotatez", 0.);
243
ground_angle_shift = pd.get_double(section_name, "ground_angle_shift", 0.);
244
ground_angle_rotatez = pd.get_double(section_name, "ground_angle_rotatez", 0.);
245
draw_ground_first = pd.get_int(section_name, "draw_ground_first", 0);
249
// create from a hash of parameters (no ini file needed)
250
void LandscapeOldStyle::create(bool _fullpath, stringHash_t param)
252
name = param["name"];
253
valid_landscape = 1; // assume valid if got here
255
// Load sides textures
256
nb_side_texs = str_to_int(param["nbsidetex"]);
257
side_texs = new s_texture*[nb_side_texs];
260
for (int i=0;i<nb_side_texs;++i)
263
sprintf(tmp,"tex%d",i);
264
side_texs[i] = new s_texture(_fullpath, param["path"] + param[tmp],TEX_LOAD_TYPE_PNG_ALPHA, false);
268
// Init sides parameters
269
nb_side = str_to_int(param["nbside"]);
270
sides = new landscape_tex_coord[nb_side];
274
for (int i=0;i<nb_side;++i)
276
sprintf(tmp,"side%d",i);
278
sscanf(s.c_str(),"tex%d:%f:%f:%f:%f",&texnum,&a,&b,&c,&d);
279
sides[i].tex = side_texs[texnum];
280
sides[i].tex_coords[0] = a;
281
sides[i].tex_coords[1] = b;
282
sides[i].tex_coords[2] = c;
283
sides[i].tex_coords[3] = d;
284
//printf("%f %f %f %f\n",a,b,c,d);
287
nb_decor_repeat = str_to_int(param["nb_decor_repeat"], 1);
289
ground_tex = new s_texture(_fullpath, param["path"] + param["groundtex"],TEX_LOAD_TYPE_PNG_SOLID, false);
291
sscanf(s.c_str(),"groundtex:%f:%f:%f:%f",&a,&b,&c,&d);
292
ground_tex_coord.tex = ground_tex;
293
ground_tex_coord.tex_coords[0] = a;
294
ground_tex_coord.tex_coords[1] = b;
295
ground_tex_coord.tex_coords[2] = c;
296
ground_tex_coord.tex_coords[3] = d;
298
fog_tex = new s_texture(_fullpath, param["path"] + param["fogtex"],TEX_LOAD_TYPE_PNG_SOLID_REPEAT, false);
300
sscanf(s.c_str(),"fogtex:%f:%f:%f:%f",&a,&b,&c,&d);
301
fog_tex_coord.tex = fog_tex;
302
fog_tex_coord.tex_coords[0] = a;
303
fog_tex_coord.tex_coords[1] = b;
304
fog_tex_coord.tex_coords[2] = c;
305
fog_tex_coord.tex_coords[3] = d;
307
fog_alt_angle = str_to_double(param["fog_alt_angle"]);
308
fog_angle_shift = str_to_double(param["fog_angle_shift"]);
309
decor_alt_angle = str_to_double(param["decor_alt_angle"]);
310
decor_angle_shift = str_to_double(param["decor_angle_shift"]);
311
decor_angle_rotatez = str_to_double(param["decor_angle_rotatez"]);
312
ground_angle_shift = str_to_double(param["ground_angle_shift"]);
313
ground_angle_rotatez = str_to_double(param["ground_angle_rotatez"]);
314
draw_ground_first = str_to_int(param["draw_ground_first"]);
317
void LandscapeOldStyle::draw(ToneReproductor * eye, const Projector* prj, const Navigator* nav)
319
if(!valid_landscape) return;
320
if (draw_ground_first) draw_ground(eye, prj, nav);
321
draw_decor(eye, prj, nav);
322
if (!draw_ground_first) draw_ground(eye, prj, nav);
323
draw_fog(eye, prj, nav);
327
// Draw the horizon fog
328
void LandscapeOldStyle::draw_fog(ToneReproductor * eye, const Projector* prj, const Navigator* nav) const
330
if(!fog_fader.getInterstate()) return;
331
glBlendFunc(GL_ONE, GL_ONE);
333
glColor3f(fog_fader.getInterstate()*(0.1f+0.1f*sky_brightness), fog_fader.getInterstate()*(0.1f+0.1f*sky_brightness), fog_fader.getInterstate()*(0.1f+0.1f*sky_brightness));
334
glEnable(GL_TEXTURE_2D);
336
glEnable(GL_CULL_FACE);
337
glBindTexture(GL_TEXTURE_2D, fog_tex->getID());
338
prj->sCylinder(radius, radius*sinf(fog_alt_angle*M_PI/180.), 128, 1, nav->get_local_to_eye_mat() *
339
Mat4d::translation(Vec3d(0.,0.,radius*sinf(fog_angle_shift*M_PI/180.))), 1);
340
glDisable(GL_CULL_FACE);
344
// Draw the mountains with a few pieces of texture
345
void LandscapeOldStyle::draw_decor(ToneReproductor * eye, const Projector* prj, const Navigator* nav) const
347
if (!land_fader.getInterstate()) return;
348
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
349
glEnable(GL_TEXTURE_2D);
351
glColor4f(sky_brightness, sky_brightness, sky_brightness, land_fader.getInterstate());
353
int subdiv = 128/(nb_decor_repeat*nb_side);
354
if (subdiv<=0) subdiv = 1;
355
float da = (2.*M_PI)/(nb_side*subdiv*nb_decor_repeat);
356
float dz = radius * sinf(decor_alt_angle*M_PI/180.f);
357
float z = radius*sinf(ground_angle_shift*M_PI/180.);
361
// Mat4d mat = nav->get_local_to_eye_mat() * Mat4d::zrotation(decor_angle_rotatez*M_PI/180.f);
362
Mat4d mat = nav->get_local_to_eye_mat();
366
z=radius*sinf(decor_angle_shift*M_PI/180.);
368
glEnable(GL_CULL_FACE);
370
for (int n=0;n<nb_decor_repeat;++n)
372
a = 2.f*M_PI*n/nb_decor_repeat;
373
for (int i=0;i<nb_side;++i)
375
glBindTexture(GL_TEXTURE_2D, sides[i].tex->getID());
376
glBegin(GL_QUAD_STRIP);
377
for (int j=0;j<=subdiv;++j)
379
x = radius * sinf(a + da * j + da * subdiv * i + decor_angle_rotatez*M_PI/180);
380
y = radius * cosf(a + da * j + da * subdiv * i + decor_angle_rotatez*M_PI/180);
381
glNormal3f(-x, -y, 0);
382
glTexCoord2f(sides[i].tex_coords[0] + (float)j/subdiv * (sides[i].tex_coords[2]-sides[i].tex_coords[0]),
383
sides[i].tex_coords[3]);
384
prj->sVertex3(x, y, z + dz * (sides[i].tex_coords[3]-sides[i].tex_coords[1]), mat);
385
glTexCoord2f(sides[i].tex_coords[0] + (float)j/subdiv * (sides[i].tex_coords[2]-sides[i].tex_coords[0]),
386
sides[i].tex_coords[1]);
387
prj->sVertex3(x, y, z , mat);
392
glDisable(GL_CULL_FACE);
398
void LandscapeOldStyle::draw_ground(ToneReproductor * eye, const Projector* prj, const Navigator* nav) const
400
if (!land_fader.getInterstate()) return;
401
Mat4d mat = nav->get_local_to_eye_mat() * Mat4d::zrotation(ground_angle_rotatez*M_PI/180.f) * Mat4d::translation(Vec3d(0,0,radius*sinf(ground_angle_shift*M_PI/180.)));
402
glColor4f(sky_brightness, sky_brightness, sky_brightness, land_fader.getInterstate());
403
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
404
glEnable(GL_CULL_FACE);
405
glEnable(GL_TEXTURE_2D);
407
glBindTexture(GL_TEXTURE_2D, ground_tex->getID());
408
int subdiv = 128/(nb_decor_repeat*nb_side);
409
if (subdiv<=0) subdiv = 1;
410
prj->sDisk(radius,nb_side*subdiv*nb_decor_repeat,5, mat, 1);
411
glDisable(GL_CULL_FACE);
414
LandscapeFisheye::LandscapeFisheye(float _radius) : Landscape(_radius), map_tex(NULL)
417
LandscapeFisheye::~LandscapeFisheye()
419
if (map_tex) delete map_tex;
423
void LandscapeFisheye::load(const string& landscape_file, const string& section_name)
425
loadCommon(landscape_file, section_name);
427
InitParser pd; // The landscape data ini file parser
428
pd.load(landscape_file);
430
string type = pd.get_str(section_name, "type");
431
if(type != "fisheye")
433
cerr << "Landscape type mismatch for landscape "<< section_name << ", expected fisheye, found " << type << ". No landscape in use.\n";
437
create(name, 0, pd.get_str(section_name, "maptex"), pd.get_double(section_name, "texturefov", 360));
441
// create a fisheye landscape from basic parameters (no ini file needed)
442
void LandscapeFisheye::create(const string _name, bool _fullpath, const string _maptex, double _texturefov)
444
// cout << _name << " " << _fullpath << " " << _maptex << " " << _texturefov << "\n";
445
valid_landscape = 1; // assume ok...
447
map_tex = new s_texture(_fullpath,_maptex,TEX_LOAD_TYPE_PNG_ALPHA,false);
448
tex_fov = _texturefov*M_PI/180.;
452
void LandscapeFisheye::draw(ToneReproductor * eye, const Projector* prj, const Navigator* nav)
454
if(!valid_landscape) return;
455
if(!land_fader.getInterstate()) return;
457
// Normal transparency mode
458
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
460
glColor4f(sky_brightness, sky_brightness, sky_brightness, land_fader.getInterstate());
462
glEnable(GL_CULL_FACE);
463
glEnable(GL_TEXTURE_2D);
465
glBindTexture(GL_TEXTURE_2D, map_tex->getID());
466
prj->sSphere_map(radius,40,20, nav->get_local_to_eye_mat(), tex_fov, 1);
468
glDisable(GL_CULL_FACE);
472
// spherical panoramas
474
LandscapeSpherical::LandscapeSpherical(float _radius) : Landscape(_radius), map_tex(NULL)
477
LandscapeSpherical::~LandscapeSpherical()
479
if (map_tex) delete map_tex;
483
void LandscapeSpherical::load(const string& landscape_file, const string& section_name)
485
loadCommon(landscape_file, section_name);
487
InitParser pd; // The landscape data ini file parser
488
pd.load(landscape_file);
490
string type = pd.get_str(section_name, "type");
491
if(type != "spherical" )
493
cerr << "Landscape type mismatch for landscape "<< section_name << ", expected spherical, found " << type << ". No landscape in use.\n";
498
create(name, 0, pd.get_str(section_name, "maptex"));
503
// create a spherical landscape from basic parameters (no ini file needed)
504
void LandscapeSpherical::create(const string _name, bool _fullpath, const string _maptex)
506
// cout << _name << " " << _fullpath << " " << _maptex << " " << _texturefov << "\n";
507
valid_landscape = 1; // assume ok...
509
map_tex = new s_texture(_fullpath,_maptex,TEX_LOAD_TYPE_PNG_ALPHA,false);
513
void LandscapeSpherical::draw(ToneReproductor * eye, const Projector* prj, const Navigator* nav)
515
if(!valid_landscape) return;
516
if(!land_fader.getInterstate()) return;
518
// Need to flip texture usage horizontally due to glusphere convention
519
// so that left-right is consistent in source texture and rendering
520
glMatrixMode(GL_TEXTURE);
524
glTranslatef(-1,0,0);
525
glMatrixMode(GL_MODELVIEW);
527
// Normal transparency mode
528
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
530
glColor4f(sky_brightness, sky_brightness, sky_brightness, land_fader.getInterstate());
532
glEnable(GL_CULL_FACE);
533
glEnable(GL_TEXTURE_2D);
535
glBindTexture(GL_TEXTURE_2D, map_tex->getID());
537
// TODO: verify that this works correctly for custom projections
539
prj->sSphere(radius,1.0,40,20, nav->get_local_to_eye_mat(), 1);
541
glDisable(GL_CULL_FACE);
543
glMatrixMode(GL_TEXTURE);
545
glMatrixMode(GL_MODELVIEW);