goat3dgfx

view src/curve.cc @ 13:25bf39105c82

lalal
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 27 Nov 2013 08:08:59 +0200
parents
children 7d6b667821cf
line source
1 #include <float.h>
2 #include <assert.h>
3 #include "curve.h"
4 #include "opengl.h"
5 #include "shader.h"
6 #include "logger.h"
8 #define DEF_THICKNESS 0.075
9 #define DEF_SEGM_SUB 3
10 #define DEF_RING_SUB 6
12 Curve::Curve()
13 {
14 thickness = DEF_THICKNESS;
15 mesh_valid = false;
16 lengths_valid = false;
18 bbox_valid = false;
20 segm_subdiv = DEF_SEGM_SUB;
21 ring_subdiv = DEF_RING_SUB;
22 }
24 Curve::Curve(const Vector3 *points, int num_points)
25 {
26 thickness = DEF_THICKNESS;
27 mesh_valid = false;
28 lengths_valid = false;
30 bbox_valid = false;
32 segm_subdiv = DEF_SEGM_SUB;
33 ring_subdiv = DEF_RING_SUB;
35 for(int i=0; i<num_points; i++) {
36 add_point(points[i]);
37 }
38 }
40 Curve::Curve(const Vector2 *points, int num_points)
41 {
42 thickness = DEF_THICKNESS;
43 mesh_valid = false;
44 lengths_valid = false;
46 bbox_valid = false;
48 segm_subdiv = DEF_SEGM_SUB;
49 ring_subdiv = DEF_RING_SUB;
51 for(int i=0; i<num_points; i++) {
52 add_point(Vector3(points[i].x, points[i].y, 0.0));
53 }
54 }
56 void Curve::set_name(const char *name)
57 {
58 this->name = name;
59 }
61 const char *Curve::get_name() const
62 {
63 return name.c_str();
64 }
66 bool Curve::empty() const
67 {
68 return cv.empty();
69 }
71 void Curve::set_thickness(float thickness)
72 {
73 this->thickness = thickness;
74 }
76 void Curve::set_subdiv(int seg, int ring)
77 {
78 if(seg < 1) seg = 1;
79 if(ring < 3) ring = 3;
81 segm_subdiv = seg;
82 ring_subdiv = ring;
83 }
85 void Curve::clear()
86 {
87 mesh_valid = false;
88 lengths_valid = false;
89 bbox_valid = false;
90 cv.clear();
91 }
93 void Curve::add_point(const Vector3 &pt)
94 {
95 cv.push_back(pt);
96 mesh_valid = false;
97 lengths_valid = false;
98 bbox_valid = false;
99 }
101 Vector3 &Curve::get_point(int idx)
102 {
103 mesh_valid = false;
104 lengths_valid = false;
105 bbox_valid = false;
106 return cv[idx];
107 }
109 const Vector3 &Curve::get_point(int idx) const
110 {
111 return cv[idx];
112 }
114 int Curve::get_count() const
115 {
116 return (int)cv.size();
117 }
119 Vector3 &Curve::operator[] (int idx)
120 {
121 return get_point(idx);
122 }
124 const Vector3 &Curve::operator[] (int idx) const
125 {
126 return get_point(idx);
127 }
129 void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const
130 {
131 if(!bbox_valid) {
132 this->bbmin = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
133 this->bbmax = -this->bbmin;
135 for(size_t i=0; i<cv.size(); i++) {
136 for(int j=0; j<3; j++) {
137 if(cv[i][j] < this->bbmin[j]) {
138 this->bbmin[j] = cv[i][j];
139 }
140 if(cv[i][j] > this->bbmax[j]) {
141 this->bbmax[j] = cv[i][j];
142 }
143 }
144 }
145 bbox_valid = true;
146 }
148 if(bbmin) *bbmin = this->bbmin;
149 if(bbmax) *bbmax = this->bbmax;
150 }
152 void Curve::normalize()
153 {
154 get_bbox(0, 0); // force validation of the bounding box
156 float len = (bbmax - bbmin).length() * 0.5;
157 if(len == 0.0) {
158 return;
159 }
161 for(size_t i=0; i<cv.size(); i++) {
162 get_point(i) /= len;
163 }
164 }
166 Vector3 Curve::get_pos(float t) const
167 {
168 if(cv.empty()) {
169 return Vector3(0, 0, 0);
170 }
171 if(cv.size() == 1 || t <= 0.0) {
172 return cv[0];
173 }
174 if(t >= 1.0) {
175 return cv.back();
176 }
178 t = reparametrize(t);
180 int numcv = (int)cv.size();
181 int idx0 = t * (numcv - 1);
182 int idx1 = idx0 + 1;
184 int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1;
185 int idx_next = idx1 >= numcv - 1 ? idx1 : idx1 + 1;
187 float dt = 1.0 / (float)(numcv - 1);
189 float t0 = (float)idx0 * dt;
190 float t1 = (float)idx1 * dt;
192 t = (t - t0) / (t1 - t0);
193 if(t < 0.0) t = 0.0;
194 if(t > 1.0) t = 1.0;
196 //return catmull_rom_spline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
197 return bspline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
198 }
200 Vector3 Curve::operator() (float t) const
201 {
202 return get_pos(t);
203 }
205 void Curve::draw() const
206 {
207 update_mesh();
208 if(!mesh_valid) {
209 return;
210 }
212 mesh.draw();
213 }
216 float Curve::reparametrize(float t) const
217 {
218 calc_cvlengths();
219 return t; // TODO
220 }
222 void Curve::calc_cvlengths() const
223 {
224 if(lengths_valid || cv.empty()) {
225 return;
226 }
228 length.clear();
229 length.resize(cv.size());
231 length[0] = 0;
232 for(size_t i=1; i<cv.size(); i++) {
233 length[i] = length[i - 1] + (cv[i] - cv[i - 1]).length();
234 }
236 lengths_valid = true;
237 }
239 void Curve::update_mesh() const
240 {
241 if(mesh_valid) return;
243 if(cv.size() < 2) {
244 return;
245 }
247 mesh.clear();
249 int nsub = segm_subdiv * (cv.size() - 1);
250 int num_rings = nsub + 1;
252 int num_verts = ring_subdiv * num_rings;
253 int num_quads = ring_subdiv * nsub;
254 int num_tri = num_quads * 2;
255 int num_idx = num_tri * 3;
257 float *varr = mesh.set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts);
258 float *narr = mesh.set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts);
259 float *tcarr = mesh.set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts);
260 unsigned int *idxarr = mesh.set_index_data(num_idx);
262 float t = 0.0;
263 float dt = 1.0 / (float)(num_rings - 1);
265 for(int i=0; i<num_rings; i++) {
266 Vector3 p = get_pos(t);
267 Vector3 dir = (get_pos(t + dt) - p).normalized();
269 Vector3 up = Vector3(0, 0, 1);
270 float updotdir = dot_product(up, dir);
271 if(1.0 - fabs(updotdir) < 1e-4) {
272 up = Vector3(0, 1, 0);
273 }
274 Vector3 right = cross_product(up, dir).normalized();
275 up = cross_product(dir, right);
277 for(int j=0; j<ring_subdiv; j++) {
278 float u = (float)j / (float)ring_subdiv * M_PI * 2.0;
279 Quaternion qrot(dir, u);
280 Vector3 v = p + right.transformed(qrot) * thickness;
282 *varr++ = v.x;
283 *varr++ = v.y;
284 *varr++ = v.z;
286 Vector3 norm = (v - p).normalized();
287 *narr++ = norm.x;
288 *narr++ = norm.y;
289 *narr++ = norm.z;
291 *tcarr++ = u;
292 *tcarr++ = t;
294 if(i < nsub) {
295 int quad = i * ring_subdiv + j;
297 int v0 = quad;
298 int v1 = i * ring_subdiv + ((j + 1) % ring_subdiv);
299 int v2 = (i + 1) * ring_subdiv + ((j + 1) % ring_subdiv);
300 int v3 = (i + 1) * ring_subdiv + j;
302 idxarr[quad * 6] = v0;
303 idxarr[quad * 6 + 1] = v1;
304 idxarr[quad * 6 + 2] = v2;
306 idxarr[quad * 6 + 3] = v0;
307 idxarr[quad * 6 + 4] = v2;
308 idxarr[quad * 6 + 5] = v3;
309 }
310 }
312 t += dt;
313 }
315 mesh_valid = true;
316 }