3 #include <msp/gl/misc.h>
4 #include "libmarklin/tracktype.h"
14 Track3D::Track3D(Track &t, unsigned q):
17 varray((GL::NORMAL3, GL::VERTEX3)),
23 void Track3D::set_quality(unsigned q)
29 void Track3D::get_bounds(float angle, Point &minp, Point &maxp) const
31 const Point &pos=track.get_position();
32 float rot=track.get_rotation();
37 minp.x=maxp.x=c*pos.x-s*pos.y;
38 minp.y=maxp.y=s*pos.x+c*pos.y;
40 float c2=cos(rot-angle);
41 float s2=sin(rot-angle);
43 for(vector<Point>::const_iterator i=border.begin(); i!=border.end(); ++i)
45 float x=c*pos.x-s*pos.y + c2*i->x-s2*i->y;
46 float y=s*pos.x+c*pos.y + s2*i->x+c2*i->y;
48 minp.x=min(minp.x, x);
49 minp.y=min(minp.y, y);
50 maxp.x=max(maxp.x, x);
51 maxp.y=max(maxp.y, y);
55 void Track3D::render() const
59 glPushName(reinterpret_cast<unsigned>(this));
62 glColor4f(0.25*color.r, 0.25*color.g, 0.25*color.b, 1);
63 glDrawElements(GL_QUADS, base_seq.size(), GL_UNSIGNED_INT, &base_seq[0]);
66 glColor4f(0.85*color.r, 0.85*color.g, 0.85*color.b, 1);
67 glDrawElements(GL_QUADS, rail_seq.size(), GL_UNSIGNED_INT, &rail_seq[0]);
74 void Track3D::render_endpoints() const
78 const vector<Endpoint> &endpoints=track.get_type().get_endpoints();
79 for(unsigned i=0; i<endpoints.size(); ++i)
81 const Endpoint &ep=endpoints[i];
82 GL::set(GL_CULL_FACE, track.get_link(i));
84 glColor4f(0.5, 0, 1, 0.5);
86 glColor4f(1, 0, 0.5, 0.5);
92 glVertex3f(ep.x-s*0.025, ep.y+c*0.025, 0);
93 glVertex3f(ep.x+s*0.025, ep.y-c*0.025, 0);
94 glVertex3f(ep.x+s*0.025, ep.y-c*0.025, 0.02);
95 glVertex3f(ep.x-s*0.025, ep.y+c*0.025, 0.02);
102 void Track3D::render_route(int route) const
107 if(route>=0 && static_cast<unsigned>(route)<route_seq.size())
108 glDrawElements(GL_QUADS, route_seq[route].size(), GL_UNSIGNED_INT, &route_seq[route][0]);
111 for(unsigned i=0; i<route_seq.size(); ++i)
112 glDrawElements(GL_QUADS, route_seq[i].size(), GL_UNSIGNED_INT, &route_seq[i][0]);
118 void Track3D::prepare_render() const
120 const Point &pos=track.get_position();
121 float rot=track.get_rotation();
124 glTranslatef(pos.x, pos.y, pos.z);
125 glRotatef(rot*180/M_PI, 0, 0, 1);
128 void Track3D::build_object()
131 RefPtr<GL::VertexArrayBuilder> builder=varray.modify();
136 route_seq.resize(track.get_type().get_n_routes());
138 const vector<TrackPart> &parts=track.get_type().get_parts();
140 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
141 build_part(*i, *builder, index);
144 void Track3D::build_part(const TrackPart &part, GL::VertexArrayBuilder &va_builder, unsigned &base_index)
146 static vector<Point> profile;
149 profile.push_back(Point(0, -0.02, 0));
150 profile.push_back(Point(0, -0.014, 0.008));
151 profile.push_back(Point(0, -0.014, 0.008));
152 profile.push_back(Point(0, 0.014, 0.008));
153 profile.push_back(Point(0, 0.014, 0.008));
154 profile.push_back(Point(0, 0.02, 0));
155 for(unsigned i=0; i<2; ++i)
157 profile.push_back(Point(0, -0.009+i*0.017, 0.008));
158 profile.push_back(Point(0, -0.009+i*0.017, 0.0103));
159 profile.push_back(Point(0, -0.009+i*0.017, 0.0103));
160 profile.push_back(Point(0, -0.008+i*0.017, 0.0103));
161 profile.push_back(Point(0, -0.008+i*0.017, 0.0103));
162 profile.push_back(Point(0, -0.008+i*0.017, 0.008));
164 profile.push_back(Point(0, -0.002, 0.012));
165 profile.push_back(Point(0, 0.002, 0.012));
167 static unsigned psize=profile.size();
169 const float &radius=part.radius;
170 const float &x=part.x;
171 const float &y=part.y;
172 const float &length=part.length;
173 const float &dir=part.dir;
178 nsegs=static_cast<unsigned>(part.length*(1<<quality))+1;
179 Point center(x-sin(dir)*radius, y+cos(dir)*radius, 0);
180 float r=fabs(radius);
181 float start=((radius<0)?M_PI:0)+dir;
182 float angle=(radius<0)?-length:length;
183 int inv=(radius<0)?-1:1;
184 for(unsigned i=0; i<=nsegs; ++i)
186 float a=start+i*angle/nsegs;
190 for(unsigned j=0; j<profile.size(); ++j)
193 float dy=profile[k+1].y-profile[k].y;
194 float dz=profile[k+1].z-profile[k].z;
195 float d=sqrt(dy*dy+dz*dz);
196 va_builder.normal(s*dz/d, -c*dz/d, dy/d);
198 Point p(center.x+s*(r-profile[j].y*inv), center.y-c*(r-profile[j].y*inv), profile[j].z+i*track.get_slope()/nsegs);
199 va_builder.vertex(p.x, p.y, p.z);
210 for(unsigned i=0; i<2; ++i)
212 for(unsigned j=0; j<profile.size(); ++j)
215 float dy=profile[k+1].y-profile[k].y;
216 float dz=profile[k+1].z-profile[k].z;
217 float d=sqrt(dy*dy+dz*dz);
218 va_builder.normal(s*dz/d, -c*dz/d, dy/d);
220 float len=(part.dead_end && i==1 && j>=6) ? length/2 : length;
221 Point p(x+c*len*i-s*profile[j].y, y+s*len*i+c*profile[j].y, profile[j].z+i*track.get_slope());
222 va_builder.vertex(p.x, p.y, p.z);
229 for(unsigned i=0; i<nsegs; ++i)
231 for(unsigned j=0; j<3; ++j)
233 base_seq.push_back(base_index+i*psize+j*2);
234 base_seq.push_back(base_index+(i+1)*psize+j*2);
235 base_seq.push_back(base_index+(i+1)*psize+1+j*2);
236 base_seq.push_back(base_index+i*psize+1+j*2);
238 for(unsigned j=3; j<9; ++j)
240 rail_seq.push_back(base_index+i*psize+j*2);
241 rail_seq.push_back(base_index+(i+1)*psize+j*2);
242 rail_seq.push_back(base_index+(i+1)*psize+1+j*2);
243 rail_seq.push_back(base_index+i*psize+1+j*2);
245 route_seq[part.route].push_back(base_index+i*psize+18);
246 route_seq[part.route].push_back(base_index+(i+1)*psize+18);
247 route_seq[part.route].push_back(base_index+(i+1)*psize+19);
248 route_seq[part.route].push_back(base_index+i*psize+19);
251 base_index+=(nsegs+1)*psize;
254 } // namespace Marklin