1 #include <msp/gl/renderer.h>
2 #include "libr2c2/terraintype.h"
10 unsigned Terrain3D::surface_indices[] =
16 unsigned Terrain3D::wall_indices[] =
22 Terrain3D::Terrain3D(Layout3D &l, Terrain &t):
25 mesh((GL::VERTEX3, GL::NORMAL3)),
26 tech(layout.get_catalogue().get<GL::Technique>("terrain.tech"))
28 terrain.signal_size_changed.connect(sigc::mem_fun(this, &Terrain3D::size_changed));
29 terrain.signal_tile_changed.connect(sigc::bind<2>(sigc::mem_fun(this, &Terrain3D::tile_changed), true));
33 layout.get_scene().add(*this);
36 Terrain3D::~Terrain3D()
38 layout.get_scene().remove(*this);
41 Vector Terrain3D::get_node() const
43 float ts = terrain.get_type().get_tile_size();
44 return terrain.get_position()+Vector(terrain.get_width()*ts/2, terrain.get_height()*ts/2, 0);
47 void Terrain3D::create_mesh()
51 GL::MeshBuilder bld(mesh);
52 unsigned width = terrain.get_width();
53 unsigned height = terrain.get_height();
54 bld.begin(GL::TRIANGLES);
55 for(unsigned y=0; y<height; ++y)
56 for(unsigned x=0; x<width; ++x)
58 const Terrain::Tile &tile = terrain.get_tile(x, y);
60 gather_nodes(x, y, nodes);
62 const unsigned *indices = surface_indices+tile.secondary_axis*6;
63 build_triangle(bld, nodes, indices);
64 build_triangle(bld, nodes, indices+3);
68 build_triangle(bld, nodes, wall_indices);
69 build_triangle(bld, nodes, wall_indices+3);
74 build_triangle(bld, nodes, wall_indices+6);
75 build_triangle(bld, nodes, wall_indices+9);
81 void Terrain3D::gather_nodes(unsigned x, unsigned y, Vector *nodes)
83 const Terrain::Tile &tile = terrain.get_tile(x, y);
84 float ts = terrain.get_type().get_tile_size();
86 for(unsigned i=0; i<4; ++i)
87 nodes[i] = Vector((x+i%2)*ts, (y+i/2)*ts, tile.nodes[i].elevation);
89 if(x+1<terrain.get_width())
91 const Terrain::Tile &neighbor = terrain.get_tile(x+1, y);
92 nodes[4] = Vector((x+1)*ts, y*ts, neighbor.nodes[0].elevation);
93 nodes[5] = Vector((x+1)*ts, (y+1)*ts, neighbor.nodes[2].elevation);
96 if(y+1<terrain.get_height())
98 const Terrain::Tile &neighbor = terrain.get_tile(x, y+1);
99 nodes[6] = Vector(x*ts, (y+1)*ts, neighbor.nodes[0].elevation);
100 nodes[7] = Vector((x+1)*ts, (y+1)*ts, neighbor.nodes[1].elevation);
104 void Terrain3D::build_triangle(GL::PrimitiveBuilder &bld, const Vector *nodes, const unsigned *indices)
106 bld.normal(normalize(cross(nodes[indices[1]]-nodes[indices[0]], nodes[indices[2]]-nodes[indices[0]])));
107 for(unsigned i=0; i<3; ++i)
108 bld.vertex(nodes[indices[i]]);
111 void Terrain3D::update_triangle(unsigned offset, const Vector *nodes, const unsigned *indices)
113 const GL::VertexFormat &format = mesh.get_vertices().get_format();
114 unsigned position_offset = format.offset(GL::VERTEX3);
115 unsigned normal_offset = format.offset(GL::NORMAL3);
117 Vector normal = normalize(cross(nodes[indices[1]]-nodes[indices[0]], nodes[indices[2]]-nodes[indices[0]]));
118 for(unsigned i=0; i<3; ++i)
120 float *vertex = mesh.modify_vertex(offset+i);
121 for(unsigned j=0; j<3; ++j)
123 vertex[position_offset+j] = nodes[indices[i]][j];
124 vertex[normal_offset+j] = normal[j];
129 void Terrain3D::size_changed(unsigned, unsigned)
134 void Terrain3D::tile_changed(unsigned x, unsigned y, bool propagate)
137 gather_nodes(x, y, nodes);
139 unsigned base = y*(terrain.get_width()*18-6);
140 if(y+1==terrain.get_height())
145 const Terrain::Tile &tile = terrain.get_tile(x, y);
146 const unsigned *indices = surface_indices+tile.secondary_axis*6;
147 update_triangle(base, nodes, indices);
148 update_triangle(base+3, nodes, indices+3);
150 if(x+1<terrain.get_width())
153 update_triangle(base, nodes, wall_indices);
154 update_triangle(base+3, nodes, wall_indices+3);
157 if(y+1<terrain.get_height())
160 update_triangle(base, nodes, wall_indices+6);
161 update_triangle(base+3, nodes, wall_indices+9);
167 tile_changed(x-1, y, false);
169 tile_changed(x, y-1, false);
173 void Terrain3D::render(GL::Renderer &renderer, const GL::Tag &tag) const
175 if(!tech.has_pass(tag))
178 GL::Renderer::Push push(renderer);
180 renderer.matrix_stack() *= matrix;
182 const GL::RenderPass &pass = tech.get_pass(tag);
183 renderer.set_material(pass.get_material());
184 renderer.set_texturing(pass.get_texturing());
185 renderer.set_shader_program(pass.get_shader_program(), pass.get_shader_data());