goat3dgfx
view src/curve.cc @ 33:253542d715f4
default texture
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Mar 2014 06:32:37 +0200 |
parents | 1873dfd13f2d |
children |
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 using namespace goatgfx;
10 #define DEF_THICKNESS 0.075
11 #define DEF_SEGM_SUB 3
12 #define DEF_RING_SUB 6
14 Curve::Curve()
15 {
16 thickness = DEF_THICKNESS;
17 mesh_valid = false;
18 lengths_valid = false;
20 bbox_valid = false;
22 segm_subdiv = DEF_SEGM_SUB;
23 ring_subdiv = DEF_RING_SUB;
24 }
26 Curve::Curve(const Vector3 *points, int num_points)
27 {
28 thickness = DEF_THICKNESS;
29 mesh_valid = false;
30 lengths_valid = false;
32 bbox_valid = false;
34 segm_subdiv = DEF_SEGM_SUB;
35 ring_subdiv = DEF_RING_SUB;
37 for(int i=0; i<num_points; i++) {
38 add_point(points[i]);
39 }
40 }
42 Curve::Curve(const Vector2 *points, int num_points)
43 {
44 thickness = DEF_THICKNESS;
45 mesh_valid = false;
46 lengths_valid = false;
48 bbox_valid = false;
50 segm_subdiv = DEF_SEGM_SUB;
51 ring_subdiv = DEF_RING_SUB;
53 for(int i=0; i<num_points; i++) {
54 add_point(Vector3(points[i].x, points[i].y, 0.0));
55 }
56 }
58 void Curve::set_name(const char *name)
59 {
60 this->name = name;
61 }
63 const char *Curve::get_name() const
64 {
65 return name.c_str();
66 }
68 bool Curve::empty() const
69 {
70 return cv.empty();
71 }
73 void Curve::set_thickness(float thickness)
74 {
75 this->thickness = thickness;
76 }
78 void Curve::set_subdiv(int seg, int ring)
79 {
80 if(seg < 1) seg = 1;
81 if(ring < 3) ring = 3;
83 segm_subdiv = seg;
84 ring_subdiv = ring;
85 }
87 void Curve::clear()
88 {
89 mesh_valid = false;
90 lengths_valid = false;
91 bbox_valid = false;
92 cv.clear();
93 }
95 void Curve::add_point(const Vector3 &pt)
96 {
97 cv.push_back(pt);
98 mesh_valid = false;
99 lengths_valid = false;
100 bbox_valid = false;
101 }
103 Vector3 &Curve::get_point(int idx)
104 {
105 mesh_valid = false;
106 lengths_valid = false;
107 bbox_valid = false;
108 return cv[idx];
109 }
111 const Vector3 &Curve::get_point(int idx) const
112 {
113 return cv[idx];
114 }
116 int Curve::get_count() const
117 {
118 return (int)cv.size();
119 }
121 Vector3 &Curve::operator[] (int idx)
122 {
123 return get_point(idx);
124 }
126 const Vector3 &Curve::operator[] (int idx) const
127 {
128 return get_point(idx);
129 }
131 void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const
132 {
133 if(!bbox_valid) {
134 this->bbmin = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
135 this->bbmax = -this->bbmin;
137 for(size_t i=0; i<cv.size(); i++) {
138 for(int j=0; j<3; j++) {
139 if(cv[i][j] < this->bbmin[j]) {
140 this->bbmin[j] = cv[i][j];
141 }
142 if(cv[i][j] > this->bbmax[j]) {
143 this->bbmax[j] = cv[i][j];
144 }
145 }
146 }
147 bbox_valid = true;
148 }
150 if(bbmin) *bbmin = this->bbmin;
151 if(bbmax) *bbmax = this->bbmax;
152 }
154 void Curve::normalize()
155 {
156 get_bbox(0, 0); // force validation of the bounding box
158 float len = (bbmax - bbmin).length() * 0.5;
159 if(len == 0.0) {
160 return;
161 }
163 for(size_t i=0; i<cv.size(); i++) {
164 get_point(i) /= len;
165 }
166 }
168 Vector3 Curve::get_pos(float t) const
169 {
170 if(cv.empty()) {
171 return Vector3(0, 0, 0);
172 }
173 if(cv.size() == 1 || t <= 0.0) {
174 return cv[0];
175 }
176 if(t >= 1.0) {
177 return cv.back();
178 }
180 t = reparametrize(t);
182 int numcv = (int)cv.size();
183 int idx0 = t * (numcv - 1);
184 int idx1 = idx0 + 1;
186 int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1;
187 int idx_next = idx1 >= numcv - 1 ? idx1 : idx1 + 1;
189 float dt = 1.0 / (float)(numcv - 1);
191 float t0 = (float)idx0 * dt;
192 float t1 = (float)idx1 * dt;
194 t = (t - t0) / (t1 - t0);
195 if(t < 0.0) t = 0.0;
196 if(t > 1.0) t = 1.0;
198 //return catmull_rom_spline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
199 return bspline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
200 }
202 Vector3 Curve::operator() (float t) const
203 {
204 return get_pos(t);
205 }
207 void Curve::draw() const
208 {
209 update_mesh();
210 if(!mesh_valid) {
211 return;
212 }
214 mesh.draw();
215 }
218 float Curve::reparametrize(float t) const
219 {
220 calc_cvlengths();
221 return t; // TODO
222 }
224 void Curve::calc_cvlengths() const
225 {
226 if(lengths_valid || cv.empty()) {
227 return;
228 }
230 length.clear();
231 length.resize(cv.size());
233 length[0] = 0;
234 for(size_t i=1; i<cv.size(); i++) {
235 length[i] = length[i - 1] + (cv[i] - cv[i - 1]).length();
236 }
238 lengths_valid = true;
239 }
241 void Curve::update_mesh() const
242 {
243 if(mesh_valid) return;
245 if(cv.size() < 2) {
246 return;
247 }
249 mesh.clear();
251 int nsub = segm_subdiv * (cv.size() - 1);
252 int num_rings = nsub + 1;
254 int num_verts = ring_subdiv * num_rings;
255 int num_quads = ring_subdiv * nsub;
256 int num_tri = num_quads * 2;
257 int num_idx = num_tri * 3;
259 float *varr = mesh.set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts);
260 float *narr = mesh.set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts);
261 float *tcarr = mesh.set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts);
262 unsigned int *idxarr = mesh.set_index_data(num_idx);
264 float t = 0.0;
265 float dt = 1.0 / (float)(num_rings - 1);
267 for(int i=0; i<num_rings; i++) {
268 Vector3 p = get_pos(t);
269 Vector3 dir = (get_pos(t + dt) - p).normalized();
271 Vector3 up = Vector3(0, 0, 1);
272 float updotdir = dot_product(up, dir);
273 if(1.0 - fabs(updotdir) < 1e-4) {
274 up = Vector3(0, 1, 0);
275 }
276 Vector3 right = cross_product(up, dir).normalized();
277 up = cross_product(dir, right);
279 for(int j=0; j<ring_subdiv; j++) {
280 float u = (float)j / (float)ring_subdiv * M_PI * 2.0;
281 Quaternion qrot(dir, u);
282 Vector3 v = p + right.transformed(qrot) * thickness;
284 *varr++ = v.x;
285 *varr++ = v.y;
286 *varr++ = v.z;
288 Vector3 norm = (v - p).normalized();
289 *narr++ = norm.x;
290 *narr++ = norm.y;
291 *narr++ = norm.z;
293 *tcarr++ = u;
294 *tcarr++ = t;
296 if(i < nsub) {
297 int quad = i * ring_subdiv + j;
299 int v0 = quad;
300 int v1 = i * ring_subdiv + ((j + 1) % ring_subdiv);
301 int v2 = (i + 1) * ring_subdiv + ((j + 1) % ring_subdiv);
302 int v3 = (i + 1) * ring_subdiv + j;
304 idxarr[quad * 6] = v0;
305 idxarr[quad * 6 + 1] = v1;
306 idxarr[quad * 6 + 2] = v2;
308 idxarr[quad * 6 + 3] = v0;
309 idxarr[quad * 6 + 4] = v2;
310 idxarr[quad * 6 + 5] = v3;
311 }
312 }
314 t += dt;
315 }
317 mesh_valid = true;
318 }