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