]> git.tdb.fi Git - r2c2.git/blob - source/3d/overlay.cpp
Make some internal colors darker to match linear color space
[r2c2.git] / source / 3d / overlay.cpp
1 #include <algorithm>
2 #include <cmath>
3 #include <msp/fs/path.h>
4 #include <msp/gl/framebuffer.h>
5 #include <msp/gl/immediate.h>
6 #include <msp/gl/matrix.h>
7 #include <msp/gl/renderer.h>
8 #include <msp/gl/texture2d.h>
9 #include <msp/io/print.h>
10 #include "overlay.h"
11 #include "track.h"
12 #include "tracktype.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 namespace R2C2 {
18
19 Overlay3D::Overlay3D(const GL::Font &f):
20         font(f)
21 { }
22
23 Overlay3D::~Overlay3D()
24 {
25         for(map<string, GL::Mesh *>::iterator i=graphics.begin(); i!=graphics.end(); ++i)
26                 delete i->second;
27         for(map<const Object3D *, Icon *>::iterator i=icons.begin(); i!=icons.end(); ++i)
28                 delete i->second;
29 }
30
31 void Overlay3D::set_label(const Object3D &track, const string &label)
32 {
33         get_icon(track).label = label;
34         update_icon(get_icon(track));
35 }
36
37 void Overlay3D::add_graphic(const Object3D &track, const string &grf_name)
38 {
39         const GL::Mesh *grf = get_graphic(grf_name);
40         if(!grf)
41                 return;
42
43         Icon &icon = get_icon(track);
44         if(find(icon.graphics.begin(), icon.graphics.end(), grf)==icon.graphics.end())
45                 icon.graphics.push_back(grf);
46
47         update_icon(icon);
48 }
49
50 void Overlay3D::remove_graphic(const Object3D &track, const string &grf_name)
51 {
52         const GL::Mesh *grf = get_graphic(grf_name);
53         Icon &icon = get_icon(track);
54         icon.graphics.erase(remove(icon.graphics.begin(), icon.graphics.end(), grf), icon.graphics.end());
55
56         update_icon(icon);
57 }
58
59 void Overlay3D::clear_graphics(const Object3D &track)
60 {
61         get_icon(track).graphics.clear();
62         update_icon(get_icon(track));
63 }
64
65 void Overlay3D::clear(const Object3D &track)
66 {
67         map<const Object3D *, Icon *>::iterator i = icons.find(&track);
68         if(i!=icons.end())
69         {
70                 delete i->second;
71                 icons.erase(i);
72         }
73 }
74
75 void Overlay3D::render(GL::Renderer &renderer, const GL::Tag &) const
76 {
77         unsigned fb_width = GL::Framebuffer::current()->get_width();
78         unsigned fb_height = GL::Framebuffer::current()->get_height();
79
80         GL::Renderer::Push push(renderer);
81         GL::MatrixStack::Push push_proj(GL::MatrixStack::projection());
82
83         GL::MatrixStack::projection() = GL::Matrix::scaling(2.0/fb_width, 2.0/fb_height, 1.0);
84
85         glLineWidth(1);
86
87         int size = int(font.get_native_size()+0.5);
88         float spacing = round(size*1.1)/size;
89         float baseline = round((0.5-font.get_ascent()*0.5-font.get_descent()*0.5)*size)/size;
90
91         for(map<const Object3D *, Icon *>::const_iterator i=icons.begin(); i!=icons.end(); ++i)
92         {
93                 if(!i->first->is_visible())
94                         continue;
95
96                 const Icon &icon = *i->second;
97
98                 GL::Vector3 p = renderer.get_camera()->project(i->first->get_node());
99                 p.x = int(p.x*0.5*fb_width-icon.width*size/2);
100                 p.y = int(p.y*0.5*fb_height);
101
102                 GL::Renderer::Push push2(renderer);
103                 renderer.matrix_stack() = GL::Matrix::translation(p);
104                 renderer.matrix_stack() *= GL::Matrix::scaling(size);
105
106                 icon.background.draw(renderer);
107
108                 glColor3f(0.0, 1.0, 0.0);
109                 for(vector<const GL::Mesh *>::const_iterator j=icon.graphics.begin(); j!=icon.graphics.end(); ++j)
110                 {
111                         (*j)->draw(renderer);
112                         renderer.matrix_stack() *= GL::Matrix::translation(spacing, 0, 0);
113                 }
114
115                 renderer.matrix_stack() *= GL::Matrix::translation(0, baseline, 0);
116                 renderer.set_texture(&font.get_texture());
117                 icon.text.draw(renderer);
118         }
119
120         glColor3f(1.0, 1.0, 1.0);
121 }
122
123 Overlay3D::Icon &Overlay3D::get_icon(const Object3D &track)
124 {
125         Icon *&icon = icons[&track];
126         if(!icon)
127                 icon = new Icon;
128
129         return *icon;
130 }
131
132 const GL::Mesh *Overlay3D::get_graphic(const string &name)
133 {
134         GL::Mesh *&grf = graphics[name];
135         if(!grf)
136         {
137                 grf = new GL::Mesh;
138                 try
139                 {
140                         DataFile::load(*grf, (FS::Path("icons")/(name+".mesh")).str());
141                 }
142                 catch(const exception &e)
143                 {
144                         IO::print("Error loading overlay graphic '%s': %s\n", name, e.what());
145                         delete grf;
146                         grf = 0;
147                 }
148         }
149
150         return grf;
151 }
152
153 void Overlay3D::update_icon(Icon &icon)
154 {
155         icon.background.clear();
156
157         icon.width = max(icon.graphics.size()*1.1+font.get_string_width(icon.label), 1.0);
158
159         {
160                 GL::MeshBuilder bld(icon.background);
161                 bld.color(0.05f, 0.05f, 0.05f, 0.7f);
162
163                 bld.begin(GL::TRIANGLE_FAN);
164                 bld.vertex(0.4, 0.5);
165                 bld.vertex(icon.width-0.4, 0.5);
166                 bld.vertex(icon.width-0.4, 1.2);
167                 for(int i=4; i<=12; ++i)
168                         bld.vertex(0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
169                 bld.end();
170
171                 bld.begin(GL::TRIANGLE_FAN);
172                 bld.vertex(icon.width-0.4, 0.5);
173                 bld.vertex(0.4, 0.5);
174                 bld.vertex(0.4, -0.2);
175                 for(int i=-4; i<=4; ++i)
176                         bld.vertex(icon.width-0.4+cos(i*M_PI/8)*0.7, 0.5+sin(i*M_PI/8)*0.7);
177                 bld.end();
178         }
179
180         icon.text.clear();
181
182         {
183                 GL::MeshBuilder bld(icon.text);
184                 bld.color(0.0f, 1.0f, 0.0f);
185                 font.build_string(icon.label, bld);
186         }
187 }
188
189
190 Overlay3D::Icon::Icon():
191         width(1.0),
192         background((GL::COLOR4_UBYTE, GL::VERTEX2)),
193         text((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2))
194 { }
195
196 } // namespace R2C2