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