goat3dgfx

diff src/curve.cc @ 0:1873dfd13f2d

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 14 Nov 2013 05:27:09 +0200
parents
children 7d6b667821cf
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/curve.cc	Thu Nov 14 05:27:09 2013 +0200
     1.3 @@ -0,0 +1,316 @@
     1.4 +#include <float.h>
     1.5 +#include <assert.h>
     1.6 +#include "curve.h"
     1.7 +#include "opengl.h"
     1.8 +#include "shader.h"
     1.9 +#include "logger.h"
    1.10 +
    1.11 +#define DEF_THICKNESS	0.075
    1.12 +#define DEF_SEGM_SUB	3
    1.13 +#define DEF_RING_SUB	6
    1.14 +
    1.15 +Curve::Curve()
    1.16 +{
    1.17 +	thickness = DEF_THICKNESS;
    1.18 +	mesh_valid = false;
    1.19 +	lengths_valid = false;
    1.20 +
    1.21 +	bbox_valid = false;
    1.22 +
    1.23 +	segm_subdiv = DEF_SEGM_SUB;
    1.24 +	ring_subdiv = DEF_RING_SUB;
    1.25 +}
    1.26 +
    1.27 +Curve::Curve(const Vector3 *points, int num_points)
    1.28 +{
    1.29 +	thickness = DEF_THICKNESS;
    1.30 +	mesh_valid = false;
    1.31 +	lengths_valid = false;
    1.32 +
    1.33 +	bbox_valid = false;
    1.34 +
    1.35 +	segm_subdiv = DEF_SEGM_SUB;
    1.36 +	ring_subdiv = DEF_RING_SUB;
    1.37 +
    1.38 +	for(int i=0; i<num_points; i++) {
    1.39 +		add_point(points[i]);
    1.40 +	}
    1.41 +}
    1.42 +
    1.43 +Curve::Curve(const Vector2 *points, int num_points)
    1.44 +{
    1.45 +	thickness = DEF_THICKNESS;
    1.46 +	mesh_valid = false;
    1.47 +	lengths_valid = false;
    1.48 +
    1.49 +	bbox_valid = false;
    1.50 +
    1.51 +	segm_subdiv = DEF_SEGM_SUB;
    1.52 +	ring_subdiv = DEF_RING_SUB;
    1.53 +
    1.54 +	for(int i=0; i<num_points; i++) {
    1.55 +		add_point(Vector3(points[i].x, points[i].y, 0.0));
    1.56 +	}
    1.57 +}
    1.58 +
    1.59 +void Curve::set_name(const char *name)
    1.60 +{
    1.61 +	this->name = name;
    1.62 +}
    1.63 +
    1.64 +const char *Curve::get_name() const
    1.65 +{
    1.66 +	return name.c_str();
    1.67 +}
    1.68 +
    1.69 +bool Curve::empty() const
    1.70 +{
    1.71 +	return cv.empty();
    1.72 +}
    1.73 +
    1.74 +void Curve::set_thickness(float thickness)
    1.75 +{
    1.76 +	this->thickness = thickness;
    1.77 +}
    1.78 +
    1.79 +void Curve::set_subdiv(int seg, int ring)
    1.80 +{
    1.81 +	if(seg < 1) seg = 1;
    1.82 +	if(ring < 3) ring = 3;
    1.83 +
    1.84 +	segm_subdiv = seg;
    1.85 +	ring_subdiv = ring;
    1.86 +}
    1.87 +
    1.88 +void Curve::clear()
    1.89 +{
    1.90 +	mesh_valid = false;
    1.91 +	lengths_valid = false;
    1.92 +	bbox_valid = false;
    1.93 +	cv.clear();
    1.94 +}
    1.95 +
    1.96 +void Curve::add_point(const Vector3 &pt)
    1.97 +{
    1.98 +	cv.push_back(pt);
    1.99 +	mesh_valid = false;
   1.100 +	lengths_valid = false;
   1.101 +	bbox_valid = false;
   1.102 +}
   1.103 +
   1.104 +Vector3 &Curve::get_point(int idx)
   1.105 +{
   1.106 +	mesh_valid = false;
   1.107 +	lengths_valid = false;
   1.108 +	bbox_valid = false;
   1.109 +	return cv[idx];
   1.110 +}
   1.111 +
   1.112 +const Vector3 &Curve::get_point(int idx) const
   1.113 +{
   1.114 +	return cv[idx];
   1.115 +}
   1.116 +
   1.117 +int Curve::get_count() const
   1.118 +{
   1.119 +	return (int)cv.size();
   1.120 +}
   1.121 +
   1.122 +Vector3 &Curve::operator[] (int idx)
   1.123 +{
   1.124 +	return get_point(idx);
   1.125 +}
   1.126 +
   1.127 +const Vector3 &Curve::operator[] (int idx) const
   1.128 +{
   1.129 +	return get_point(idx);
   1.130 +}
   1.131 +
   1.132 +void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const
   1.133 +{
   1.134 +	if(!bbox_valid) {
   1.135 +		this->bbmin = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
   1.136 +		this->bbmax = -this->bbmin;
   1.137 +
   1.138 +		for(size_t i=0; i<cv.size(); i++) {
   1.139 +			for(int j=0; j<3; j++) {
   1.140 +				if(cv[i][j] < this->bbmin[j]) {
   1.141 +					this->bbmin[j] = cv[i][j];
   1.142 +				}
   1.143 +				if(cv[i][j] > this->bbmax[j]) {
   1.144 +					this->bbmax[j] = cv[i][j];
   1.145 +				}
   1.146 +			}
   1.147 +		}
   1.148 +		bbox_valid = true;
   1.149 +	}
   1.150 +
   1.151 +	if(bbmin) *bbmin = this->bbmin;
   1.152 +	if(bbmax) *bbmax = this->bbmax;
   1.153 +}
   1.154 +
   1.155 +void Curve::normalize()
   1.156 +{
   1.157 +	get_bbox(0, 0);	// force validation of the bounding box
   1.158 +
   1.159 +	float len = (bbmax - bbmin).length() * 0.5;
   1.160 +	if(len == 0.0) {
   1.161 +		return;
   1.162 +	}
   1.163 +
   1.164 +	for(size_t i=0; i<cv.size(); i++) {
   1.165 +		get_point(i) /= len;
   1.166 +	}
   1.167 +}
   1.168 +
   1.169 +Vector3 Curve::get_pos(float t) const
   1.170 +{
   1.171 +	if(cv.empty()) {
   1.172 +		return Vector3(0, 0, 0);
   1.173 +	}
   1.174 +	if(cv.size() == 1 || t <= 0.0) {
   1.175 +		return cv[0];
   1.176 +	}
   1.177 +	if(t >= 1.0) {
   1.178 +		return cv.back();
   1.179 +	}
   1.180 +
   1.181 +	t = reparametrize(t);
   1.182 +
   1.183 +	int numcv = (int)cv.size();
   1.184 +	int idx0 = t * (numcv - 1);
   1.185 +	int idx1 = idx0 + 1;
   1.186 +
   1.187 +	int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1;
   1.188 +	int idx_next = idx1 >= numcv - 1 ? idx1 : idx1 + 1;
   1.189 +
   1.190 +	float dt = 1.0 / (float)(numcv - 1);
   1.191 +
   1.192 +	float t0 = (float)idx0 * dt;
   1.193 +	float t1 = (float)idx1 * dt;
   1.194 +
   1.195 +	t = (t - t0) / (t1 - t0);
   1.196 +	if(t < 0.0) t = 0.0;
   1.197 +	if(t > 1.0) t = 1.0;
   1.198 +
   1.199 +	//return catmull_rom_spline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
   1.200 +	return bspline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
   1.201 +}
   1.202 +
   1.203 +Vector3 Curve::operator() (float t) const
   1.204 +{
   1.205 +	return get_pos(t);
   1.206 +}
   1.207 +
   1.208 +void Curve::draw() const
   1.209 +{
   1.210 +	update_mesh();
   1.211 +	if(!mesh_valid) {
   1.212 +		return;
   1.213 +	}
   1.214 +
   1.215 +	mesh.draw();
   1.216 +}
   1.217 +
   1.218 +
   1.219 +float Curve::reparametrize(float t) const
   1.220 +{
   1.221 +	calc_cvlengths();
   1.222 +	return t;	// TODO
   1.223 +}
   1.224 +
   1.225 +void Curve::calc_cvlengths() const
   1.226 +{
   1.227 +	if(lengths_valid || cv.empty()) {
   1.228 +		return;
   1.229 +	}
   1.230 +
   1.231 +	length.clear();
   1.232 +	length.resize(cv.size());
   1.233 +
   1.234 +	length[0] = 0;
   1.235 +	for(size_t i=1; i<cv.size(); i++) {
   1.236 +		length[i] = length[i - 1] + (cv[i] - cv[i - 1]).length();
   1.237 +	}
   1.238 +
   1.239 +	lengths_valid = true;
   1.240 +}
   1.241 +
   1.242 +void Curve::update_mesh() const
   1.243 +{
   1.244 +	if(mesh_valid) return;
   1.245 +
   1.246 +	if(cv.size() < 2) {
   1.247 +		return;
   1.248 +	}
   1.249 +
   1.250 +	mesh.clear();
   1.251 +
   1.252 +	int nsub = segm_subdiv * (cv.size() - 1);
   1.253 +	int num_rings = nsub + 1;
   1.254 +
   1.255 +	int num_verts = ring_subdiv * num_rings;
   1.256 +	int num_quads = ring_subdiv * nsub;
   1.257 +	int num_tri = num_quads * 2;
   1.258 +	int num_idx = num_tri * 3;
   1.259 +
   1.260 +	float *varr = mesh.set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts);
   1.261 +	float *narr = mesh.set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts);
   1.262 +	float *tcarr = mesh.set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts);
   1.263 +	unsigned int *idxarr = mesh.set_index_data(num_idx);
   1.264 +
   1.265 +	float t = 0.0;
   1.266 +	float dt = 1.0 / (float)(num_rings - 1);
   1.267 +
   1.268 +	for(int i=0; i<num_rings; i++) {
   1.269 +		Vector3 p = get_pos(t);
   1.270 +		Vector3 dir = (get_pos(t + dt) - p).normalized();
   1.271 +
   1.272 +		Vector3 up = Vector3(0, 0, 1);
   1.273 +		float updotdir = dot_product(up, dir);
   1.274 +		if(1.0 - fabs(updotdir) < 1e-4) {
   1.275 +			up = Vector3(0, 1, 0);
   1.276 +		}
   1.277 +		Vector3 right = cross_product(up, dir).normalized();
   1.278 +		up = cross_product(dir, right);
   1.279 +
   1.280 +		for(int j=0; j<ring_subdiv; j++) {
   1.281 +			float u = (float)j / (float)ring_subdiv * M_PI * 2.0;
   1.282 +			Quaternion qrot(dir, u);
   1.283 +			Vector3 v = p + right.transformed(qrot) * thickness;
   1.284 +
   1.285 +			*varr++ = v.x;
   1.286 +			*varr++ = v.y;
   1.287 +			*varr++ = v.z;
   1.288 +
   1.289 +			Vector3 norm = (v - p).normalized();
   1.290 +			*narr++ = norm.x;
   1.291 +			*narr++ = norm.y;
   1.292 +			*narr++ = norm.z;
   1.293 +
   1.294 +			*tcarr++ = u;
   1.295 +			*tcarr++ = t;
   1.296 +
   1.297 +			if(i < nsub) {
   1.298 +				int quad = i * ring_subdiv + j;
   1.299 +
   1.300 +				int v0 = quad;
   1.301 +				int v1 = i * ring_subdiv + ((j + 1) % ring_subdiv);
   1.302 +				int v2 = (i + 1) * ring_subdiv + ((j + 1) % ring_subdiv);
   1.303 +				int v3 = (i + 1) * ring_subdiv + j;
   1.304 +
   1.305 +				idxarr[quad * 6] = v0;
   1.306 +				idxarr[quad * 6 + 1] = v1;
   1.307 +				idxarr[quad * 6 + 2] = v2;
   1.308 +
   1.309 +				idxarr[quad * 6 + 3] = v0;
   1.310 +				idxarr[quad * 6 + 4] = v2;
   1.311 +				idxarr[quad * 6 + 5] = v3;
   1.312 +			}
   1.313 +		}
   1.314 +
   1.315 +		t += dt;
   1.316 +	}
   1.317 +
   1.318 +	mesh_valid = true;
   1.319 +}