3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
10 #include <msp/gl/misc.h>
11 #include "libmarklin/tracktype.h"
21 Track3D::Track3D(Track &t, unsigned q):
24 varray((GL::NORMAL3, GL::VERTEX3)),
30 void Track3D::set_quality(unsigned q)
36 void Track3D::get_bounds(float angle, Point &minp, Point &maxp) const
38 const Point &pos=track.get_position();
39 float rot=track.get_rotation();
44 minp.x=maxp.x=c*pos.x-s*pos.y;
45 minp.y=maxp.y=s*pos.x+c*pos.y;
47 float c2=cos(rot-angle);
48 float s2=sin(rot-angle);
50 for(vector<Point>::const_iterator i=border.begin(); i!=border.end(); ++i)
52 float x=c*pos.x-s*pos.y + c2*i->x-s2*i->y;
53 float y=s*pos.x+c*pos.y + s2*i->x+c2*i->y;
55 minp.x=min(minp.x, x);
56 minp.y=min(minp.y, y);
57 maxp.x=max(maxp.x, x);
58 maxp.y=max(maxp.y, y);
62 void Track3D::render() const
66 glPushName(reinterpret_cast<unsigned>(this));
69 glColor4f(0.25*color.r, 0.25*color.g, 0.25*color.b, 1);
70 glDrawElements(GL_QUADS, base_seq.size(), GL_UNSIGNED_INT, &base_seq[0]);
73 glColor4f(0.85*color.r, 0.85*color.g, 0.85*color.b, 1);
74 glDrawElements(GL_QUADS, rail_seq.size(), GL_UNSIGNED_INT, &rail_seq[0]);
81 void Track3D::render_endpoints() const
85 const vector<Endpoint> &endpoints=track.get_type().get_endpoints();
86 for(unsigned i=0; i<endpoints.size(); ++i)
88 const Endpoint &ep=endpoints[i];
89 GL::set(GL_CULL_FACE, track.get_link(i));
91 glColor4f(0.5, 0, 1, 0.5);
93 glColor4f(1, 0, 0.5, 0.5);
99 glVertex3f(ep.x-s*0.025, ep.y+c*0.025, 0);
100 glVertex3f(ep.x+s*0.025, ep.y-c*0.025, 0);
101 glVertex3f(ep.x+s*0.025, ep.y-c*0.025, 0.02);
102 glVertex3f(ep.x-s*0.025, ep.y+c*0.025, 0.02);
109 void Track3D::render_route(int route) const
114 if(route>=0 && static_cast<unsigned>(route)<route_seq.size())
115 glDrawElements(GL_QUADS, route_seq[route].size(), GL_UNSIGNED_INT, &route_seq[route][0]);
118 for(unsigned i=0; i<route_seq.size(); ++i)
119 glDrawElements(GL_QUADS, route_seq[i].size(), GL_UNSIGNED_INT, &route_seq[i][0]);
125 void Track3D::prepare_render() const
127 const Point &pos=track.get_position();
128 float rot=track.get_rotation();
131 glTranslatef(pos.x, pos.y, pos.z);
132 glRotatef(rot*180/M_PI, 0, 0, 1);
135 void Track3D::build_object()
138 RefPtr<GL::VertexArrayBuilder> builder=varray.modify();
143 route_seq.resize(track.get_type().get_n_routes());
145 const vector<TrackPart> &parts=track.get_type().get_parts();
147 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
148 build_part(*i, *builder, index);
151 void Track3D::build_part(const TrackPart &part, GL::VertexArrayBuilder &va_builder, unsigned &base_index)
153 static vector<Point> profile;
156 profile.push_back(Point(0, -0.02, 0));
157 profile.push_back(Point(0, -0.014, 0.008));
158 profile.push_back(Point(0, -0.014, 0.008));
159 profile.push_back(Point(0, 0.014, 0.008));
160 profile.push_back(Point(0, 0.014, 0.008));
161 profile.push_back(Point(0, 0.02, 0));
162 for(unsigned i=0; i<2; ++i)
164 profile.push_back(Point(0, -0.009+i*0.017, 0.008));
165 profile.push_back(Point(0, -0.009+i*0.017, 0.0103));
166 profile.push_back(Point(0, -0.009+i*0.017, 0.0103));
167 profile.push_back(Point(0, -0.008+i*0.017, 0.0103));
168 profile.push_back(Point(0, -0.008+i*0.017, 0.0103));
169 profile.push_back(Point(0, -0.008+i*0.017, 0.008));
171 profile.push_back(Point(0, -0.002, 0.012));
172 profile.push_back(Point(0, 0.002, 0.012));
174 static unsigned psize=profile.size();
176 const float &radius=part.radius;
177 const float &x=part.x;
178 const float &y=part.y;
179 const float &length=part.length;
180 const float &dir=part.dir;
185 nsegs=static_cast<unsigned>(part.length*(1<<quality))+1;
186 Point center(x-sin(dir)*radius, y+cos(dir)*radius, 0);
187 float r=fabs(radius);
188 float start=((radius<0)?M_PI:0)+dir;
189 float angle=(radius<0)?-length:length;
190 int inv=(radius<0)?-1:1;
191 for(unsigned i=0; i<=nsegs; ++i)
193 float a=start+i*angle/nsegs;
197 for(unsigned j=0; j<profile.size(); ++j)
200 float dy=profile[k+1].y-profile[k].y;
201 float dz=profile[k+1].z-profile[k].z;
202 float d=sqrt(dy*dy+dz*dz);
203 va_builder.normal(s*dz/d, -c*dz/d, dy/d);
205 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);
206 va_builder.vertex(p.x, p.y, p.z);
217 for(unsigned i=0; i<2; ++i)
219 for(unsigned j=0; j<profile.size(); ++j)
222 float dy=profile[k+1].y-profile[k].y;
223 float dz=profile[k+1].z-profile[k].z;
224 float d=sqrt(dy*dy+dz*dz);
225 va_builder.normal(s*dz/d, -c*dz/d, dy/d);
227 float len=(part.dead_end && i==1 && j>=6) ? length/2 : length;
228 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());
229 va_builder.vertex(p.x, p.y, p.z);
236 for(unsigned i=0; i<nsegs; ++i)
238 for(unsigned j=0; j<3; ++j)
240 base_seq.push_back(base_index+i*psize+j*2);
241 base_seq.push_back(base_index+(i+1)*psize+j*2);
242 base_seq.push_back(base_index+(i+1)*psize+1+j*2);
243 base_seq.push_back(base_index+i*psize+1+j*2);
245 for(unsigned j=3; j<9; ++j)
247 rail_seq.push_back(base_index+i*psize+j*2);
248 rail_seq.push_back(base_index+(i+1)*psize+j*2);
249 rail_seq.push_back(base_index+(i+1)*psize+1+j*2);
250 rail_seq.push_back(base_index+i*psize+1+j*2);
252 route_seq[part.route].push_back(base_index+i*psize+18);
253 route_seq[part.route].push_back(base_index+(i+1)*psize+18);
254 route_seq[part.route].push_back(base_index+(i+1)*psize+19);
255 route_seq[part.route].push_back(base_index+i*psize+19);
258 base_index+=(nsegs+1)*psize;
261 } // namespace Marklin