]> git.tdb.fi Git - r2c2.git/blob - source/3d/overlay.cpp
Add an overlay to display aspects of tracks
[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 }
34
35 void Overlay3D::set_label(const Track3D &track, const string &label)
36 {
37         get_icon(track).label = label;
38         update_icon(get_icon(track));
39 }
40
41 void Overlay3D::add_graphic(const Track3D &track, const string &grf_name)
42 {
43         const GL::Mesh *grf = get_graphic(grf_name);
44         if(!grf)
45                 return;
46
47         Icon &icon = get_icon(track);
48         if(find(icon.graphics.begin(), icon.graphics.end(), grf)==icon.graphics.end())
49                 icon.graphics.push_back(grf);
50
51         update_icon(icon);
52 }
53
54 void Overlay3D::remove_graphic(const Track3D &track, const string &grf_name)
55 {
56         const GL::Mesh *grf = get_graphic(grf_name);
57         Icon &icon = get_icon(track);
58         icon.graphics.erase(remove(icon.graphics.begin(), icon.graphics.end(), grf), icon.graphics.end());
59
60         update_icon(icon);
61 }
62
63 void Overlay3D::clear_graphics(const Track3D &track)
64 {
65         get_icon(track).graphics.clear();
66         update_icon(get_icon(track));
67 }
68
69 void Overlay3D::clear(const Track3D &track)
70 {
71         map<const Track3D *, Icon *>::iterator i = icons.find(&track);
72         if(i!=icons.end())
73         {
74                 delete i->second;
75                 icons.erase(i);
76         }
77 }
78
79 void Overlay3D::render(const GL::Tag &tag) const
80 {
81         if(tag==0)
82         {
83                 GL::matrix_mode(GL::PROJECTION);
84                 GL::push_matrix();
85                 GL::load_identity();
86                 GL::scale(2.0/window.get_width(), 2.0/window.get_height(), 1.0);
87                 GL::matrix_mode(GL::MODELVIEW);
88                 GL::push_matrix();
89                 GL::load_identity();
90
91                 glLineWidth(1);
92
93                 int size = int(font.get_default_size()+0.5);
94                 float spacing = round(size*1.1)/size;
95                 float baseline = round((0.5-font.get_ascent()*0.5-font.get_descent()*0.5)*size)/size;
96
97                 for(map<const Track3D *, Icon *>::const_iterator i=icons.begin(); i!=icons.end(); ++i)
98                 {
99                         const Icon &icon = *i->second;
100
101                         const Point &pos = i->first->get_track().get_position();
102                         Point minp;
103                         Point maxp;
104                         i->first->get_type().get_bounds(0, minp, maxp);
105                         float rot = i->first->get_track().get_rotation();
106                         float c = cos(rot);
107                         float s = sin(rot);
108
109                         GL::Vector3 p((minp.x+maxp.x)/2, (minp.y+maxp.y)/2, 0);
110                         p = GL::Vector3(pos.x+c*p.x-s*p.y, pos.y+s*p.x+c*p.y, pos.z+0.02);
111                         p = camera.project(p);
112
113                         GL::PushMatrix push_mat;
114                         p.x = int(p.x*0.5*window.get_width()-icon.width*size/2);
115                         p.y = int(p.y*0.5*window.get_height());
116                         GL::translate(p.x, p.y, p.z);
117                         GL::scale_uniform(size);
118
119                         icon.background.draw();
120
121                         glColor3f(0.0, 1.0, 0.0);
122                         for(vector<const GL::Mesh *>::const_iterator j=icon.graphics.begin(); j!=icon.graphics.end(); ++j)
123                         {
124                                 (*j)->draw();
125                                 GL::translate(spacing, 0, 0);
126                         }
127
128                         GL::translate(0, baseline, 0);
129                         font.draw_string(icon.label);
130                         GL::Texture::unbind();
131                 }
132
133                 GL::matrix_mode(GL::PROJECTION);
134                 GL::pop_matrix();
135                 GL::matrix_mode(GL::MODELVIEW);
136                 GL::pop_matrix();
137         }
138 }
139
140 Overlay3D::Icon &Overlay3D::get_icon(const Track3D &track)
141 {
142         Icon *&icon = icons[&track];
143         if(!icon)
144                 icon = new Icon;
145
146         return *icon;
147 }
148
149 const GL::Mesh *Overlay3D::get_graphic(const string &name)
150 {
151         GL::Mesh *&grf = graphics[name];
152         if(!grf)
153         {
154                 grf = new GL::Mesh;
155                 try
156                 {
157                         DataFile::load(*grf, (FS::Path("icons")/(name+".mesh")).str());
158                 }
159                 catch(const Exception &e)
160                 {
161                         IO::print("Error loading overlay graphic '%s': %s\n", name, e.what());
162                         delete grf;
163                         grf = 0;
164                 }
165         }
166
167         return grf;
168 }
169
170 void Overlay3D::update_icon(Icon &icon)
171 {
172         icon.background.clear();
173
174         icon.width = max(icon.graphics.size()*1.1+font.get_string_width(icon.label), 1.0);
175
176         GL::MeshBuilder bld(icon.background);
177         bld.color(0.2f, 0.2f, 0.2f, 0.7f);
178
179         bld.begin(GL::TRIANGLE_FAN);
180         bld.vertex(0.4, 0.5);
181         bld.vertex(icon.width-0.4, 0.5);
182         bld.vertex(icon.width-0.4, 1.2);
183         for(int i=4; i<=12; ++i)
184                 bld.vertex(0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
185         bld.end();
186
187         bld.begin(GL::TRIANGLE_FAN);
188         bld.vertex(icon.width-0.4, 0.5);
189         bld.vertex(0.4, 0.5);
190         bld.vertex(0.4, -0.2);
191         for(int i=-4; i<=4; ++i)
192                 bld.vertex(icon.width-0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
193         bld.end();
194 }
195
196
197 Overlay3D::Icon::Icon():
198         width(1.0),
199         background((GL::COLOR4_UBYTE, GL::VERTEX2))
200 { }
201
202 } // namespace Marklin