]> git.tdb.fi Git - r2c2.git/blob - source/3d/overlay.cpp
Fix memory leaks and other bad stuff
[r2c2.git] / source / 3d / overlay.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <algorithm>
9 #include <cmath>
10 #include <msp/fs/path.h>
11 #include <msp/gl/matrix.h>
12 #include <msp/gl/texture.h>
13 #include <msp/io/print.h>
14 #include "overlay.h"
15 #include "track.h"
16 #include "tracktype.h"
17
18 using namespace std;
19 using namespace Msp;
20
21 namespace Marklin {
22
23 Overlay3D::Overlay3D(const Graphics::Window &w, const GL::Camera &c, const GL::Font &f):
24         window(w),
25         camera(c),
26         font(f)
27 { }
28
29 Overlay3D::~Overlay3D()
30 {
31         for(map<string, GL::Mesh *>::iterator i=graphics.begin(); i!=graphics.end(); ++i)
32                 delete i->second;
33         for(map<const Track3D *, Icon *>::iterator i=icons.begin(); i!=icons.end(); ++i)
34                 delete i->second;
35 }
36
37 void Overlay3D::set_label(const Track3D &track, const string &label)
38 {
39         get_icon(track).label = label;
40         update_icon(get_icon(track));
41 }
42
43 void Overlay3D::add_graphic(const Track3D &track, const string &grf_name)
44 {
45         const GL::Mesh *grf = get_graphic(grf_name);
46         if(!grf)
47                 return;
48
49         Icon &icon = get_icon(track);
50         if(find(icon.graphics.begin(), icon.graphics.end(), grf)==icon.graphics.end())
51                 icon.graphics.push_back(grf);
52
53         update_icon(icon);
54 }
55
56 void Overlay3D::remove_graphic(const Track3D &track, const string &grf_name)
57 {
58         const GL::Mesh *grf = get_graphic(grf_name);
59         Icon &icon = get_icon(track);
60         icon.graphics.erase(remove(icon.graphics.begin(), icon.graphics.end(), grf), icon.graphics.end());
61
62         update_icon(icon);
63 }
64
65 void Overlay3D::clear_graphics(const Track3D &track)
66 {
67         get_icon(track).graphics.clear();
68         update_icon(get_icon(track));
69 }
70
71 void Overlay3D::clear(const Track3D &track)
72 {
73         map<const Track3D *, Icon *>::iterator i = icons.find(&track);
74         if(i!=icons.end())
75         {
76                 delete i->second;
77                 icons.erase(i);
78         }
79 }
80
81 void Overlay3D::render(const GL::Tag &tag) const
82 {
83         if(tag==0)
84         {
85                 GL::matrix_mode(GL::PROJECTION);
86                 GL::push_matrix();
87                 GL::load_identity();
88                 GL::scale(2.0/window.get_width(), 2.0/window.get_height(), 1.0);
89                 GL::matrix_mode(GL::MODELVIEW);
90                 GL::push_matrix();
91                 GL::load_identity();
92
93                 glLineWidth(1);
94
95                 int size = int(font.get_default_size()+0.5);
96                 float spacing = round(size*1.1)/size;
97                 float baseline = round((0.5-font.get_ascent()*0.5-font.get_descent()*0.5)*size)/size;
98
99                 for(map<const Track3D *, Icon *>::const_iterator i=icons.begin(); i!=icons.end(); ++i)
100                 {
101                         const Icon &icon = *i->second;
102
103                         const Point &pos = i->first->get_track().get_position();
104                         Point minp;
105                         Point maxp;
106                         i->first->get_type().get_bounds(0, minp, maxp);
107                         float rot = i->first->get_track().get_rotation();
108                         float c = cos(rot);
109                         float s = sin(rot);
110
111                         GL::Vector3 p((minp.x+maxp.x)/2, (minp.y+maxp.y)/2, 0);
112                         p = GL::Vector3(pos.x+c*p.x-s*p.y, pos.y+s*p.x+c*p.y, pos.z+0.02);
113                         p = camera.project(p);
114
115                         GL::PushMatrix push_mat;
116                         p.x = int(p.x*0.5*window.get_width()-icon.width*size/2);
117                         p.y = int(p.y*0.5*window.get_height());
118                         GL::translate(p.x, p.y, p.z);
119                         GL::scale_uniform(size);
120
121                         icon.background.draw();
122
123                         glColor3f(0.0, 1.0, 0.0);
124                         for(vector<const GL::Mesh *>::const_iterator j=icon.graphics.begin(); j!=icon.graphics.end(); ++j)
125                         {
126                                 (*j)->draw();
127                                 GL::translate(spacing, 0, 0);
128                         }
129
130                         GL::translate(0, baseline, 0);
131                         font.draw_string(icon.label);
132                         GL::Texture::unbind();
133                 }
134
135                 GL::matrix_mode(GL::PROJECTION);
136                 GL::pop_matrix();
137                 GL::matrix_mode(GL::MODELVIEW);
138                 GL::pop_matrix();
139         }
140 }
141
142 Overlay3D::Icon &Overlay3D::get_icon(const Track3D &track)
143 {
144         Icon *&icon = icons[&track];
145         if(!icon)
146                 icon = new Icon;
147
148         return *icon;
149 }
150
151 const GL::Mesh *Overlay3D::get_graphic(const string &name)
152 {
153         GL::Mesh *&grf = graphics[name];
154         if(!grf)
155         {
156                 grf = new GL::Mesh;
157                 try
158                 {
159                         DataFile::load(*grf, (FS::Path("icons")/(name+".mesh")).str());
160                 }
161                 catch(const Exception &e)
162                 {
163                         IO::print("Error loading overlay graphic '%s': %s\n", name, e.what());
164                         delete grf;
165                         grf = 0;
166                 }
167         }
168
169         return grf;
170 }
171
172 void Overlay3D::update_icon(Icon &icon)
173 {
174         icon.background.clear();
175
176         icon.width = max(icon.graphics.size()*1.1+font.get_string_width(icon.label), 1.0);
177
178         GL::MeshBuilder bld(icon.background);
179         bld.color(0.2f, 0.2f, 0.2f, 0.7f);
180
181         bld.begin(GL::TRIANGLE_FAN);
182         bld.vertex(0.4, 0.5);
183         bld.vertex(icon.width-0.4, 0.5);
184         bld.vertex(icon.width-0.4, 1.2);
185         for(int i=4; i<=12; ++i)
186                 bld.vertex(0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
187         bld.end();
188
189         bld.begin(GL::TRIANGLE_FAN);
190         bld.vertex(icon.width-0.4, 0.5);
191         bld.vertex(0.4, 0.5);
192         bld.vertex(0.4, -0.2);
193         for(int i=-4; i<=4; ++i)
194                 bld.vertex(icon.width-0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
195         bld.end();
196 }
197
198
199 Overlay3D::Icon::Icon():
200         width(1.0),
201         background((GL::COLOR4_UBYTE, GL::VERTEX2))
202 { }
203
204 } // namespace Marklin