cubemapper

annotate src/meshgen.cc @ 4:2bfafdced01a

added README, COPYING, and copyright headers
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 30 Jul 2017 16:11:19 +0300
parents 8fc9e1d3aad2
children
rev   line source
nuclear@4 1 /*
nuclear@4 2 Cubemapper - a program for converting panoramic images into cubemaps
nuclear@4 3 Copyright (C) 2017 John Tsiombikas <nuclear@member.fsf.org>
nuclear@4 4
nuclear@4 5 This program is free software: you can redistribute it and/or modify
nuclear@4 6 it under the terms of the GNU General Public License as published by
nuclear@4 7 the Free Software Foundation, either version 3 of the License, or
nuclear@4 8 (at your option) any later version.
nuclear@4 9
nuclear@4 10 This program is distributed in the hope that it will be useful,
nuclear@4 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@4 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@4 13 GNU General Public License for more details.
nuclear@4 14
nuclear@4 15 You should have received a copy of the GNU General Public License
nuclear@4 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@4 17 */
nuclear@0 18 #include <stdio.h>
nuclear@0 19 #include "meshgen.h"
nuclear@0 20 #include "mesh.h"
nuclear@0 21
nuclear@0 22 // -------- sphere --------
nuclear@0 23
nuclear@0 24 #define SURAD(u) ((u) * 2.0 * M_PI)
nuclear@0 25 #define SVRAD(v) ((v) * M_PI)
nuclear@0 26
nuclear@0 27 static Vec3 sphvec(float theta, float phi)
nuclear@0 28 {
nuclear@0 29 return Vec3(sin(theta) * sin(phi),
nuclear@0 30 cos(phi),
nuclear@0 31 cos(theta) * sin(phi));
nuclear@0 32 }
nuclear@0 33
nuclear@0 34 void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
nuclear@0 35 {
nuclear@0 36 if(usub < 4) usub = 4;
nuclear@0 37 if(vsub < 2) vsub = 2;
nuclear@0 38
nuclear@0 39 int uverts = usub + 1;
nuclear@0 40 int vverts = vsub + 1;
nuclear@0 41
nuclear@0 42 int num_verts = uverts * vverts;
nuclear@0 43 int num_quads = usub * vsub;
nuclear@0 44 int num_tri = num_quads * 2;
nuclear@0 45
nuclear@0 46 mesh->clear();
nuclear@0 47 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 48 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 49 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 50 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 51 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 52
nuclear@0 53 float du = urange / (float)(uverts - 1);
nuclear@0 54 float dv = vrange / (float)(vverts - 1);
nuclear@0 55
nuclear@0 56 float u = 0.0;
nuclear@0 57 for(int i=0; i<uverts; i++) {
nuclear@0 58 float theta = u * 2.0 * M_PI;
nuclear@0 59
nuclear@0 60 float v = 0.0;
nuclear@0 61 for(int j=0; j<vverts; j++) {
nuclear@0 62 float phi = v * M_PI;
nuclear@0 63
nuclear@0 64 Vec3 pos = sphvec(theta, phi);
nuclear@0 65
nuclear@0 66 *varr++ = pos * rad;
nuclear@0 67 *narr++ = pos;
nuclear@0 68 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
nuclear@0 69 *uvarr++ = Vec2(u * urange, v * vrange);
nuclear@0 70
nuclear@0 71 if(i < usub && j < vsub) {
nuclear@0 72 int idx = i * vverts + j;
nuclear@0 73 *idxarr++ = idx;
nuclear@0 74 *idxarr++ = idx + 1;
nuclear@0 75 *idxarr++ = idx + vverts + 1;
nuclear@0 76
nuclear@0 77 *idxarr++ = idx;
nuclear@0 78 *idxarr++ = idx + vverts + 1;
nuclear@0 79 *idxarr++ = idx + vverts;
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 v += dv;
nuclear@0 83 }
nuclear@0 84 u += du;
nuclear@0 85 }
nuclear@0 86 }
nuclear@0 87
nuclear@0 88 // ------ geosphere ------
nuclear@0 89 #define PHI 1.618034
nuclear@0 90
nuclear@0 91 static Vec3 icosa_pt[] = {
nuclear@0 92 Vec3(PHI, 1, 0),
nuclear@0 93 Vec3(-PHI, 1, 0),
nuclear@0 94 Vec3(PHI, -1, 0),
nuclear@0 95 Vec3(-PHI, -1, 0),
nuclear@0 96 Vec3(1, 0, PHI),
nuclear@0 97 Vec3(1, 0, -PHI),
nuclear@0 98 Vec3(-1, 0, PHI),
nuclear@0 99 Vec3(-1, 0, -PHI),
nuclear@0 100 Vec3(0, PHI, 1),
nuclear@0 101 Vec3(0, -PHI, 1),
nuclear@0 102 Vec3(0, PHI, -1),
nuclear@0 103 Vec3(0, -PHI, -1)
nuclear@0 104 };
nuclear@0 105 enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
nuclear@0 106 static int icosa_idx[] = {
nuclear@0 107 P11, P31, P21,
nuclear@0 108 P11, P22, P33,
nuclear@0 109 P13, P21, P32,
nuclear@0 110 P13, P34, P22,
nuclear@0 111 P12, P23, P31,
nuclear@0 112 P12, P33, P24,
nuclear@0 113 P14, P32, P23,
nuclear@0 114 P14, P24, P34,
nuclear@0 115
nuclear@0 116 P11, P33, P31,
nuclear@0 117 P12, P31, P33,
nuclear@0 118 P13, P32, P34,
nuclear@0 119 P14, P34, P32,
nuclear@0 120
nuclear@0 121 P21, P13, P11,
nuclear@0 122 P22, P11, P13,
nuclear@0 123 P23, P12, P14,
nuclear@0 124 P24, P14, P12,
nuclear@0 125
nuclear@0 126 P31, P23, P21,
nuclear@0 127 P32, P21, P23,
nuclear@0 128 P33, P22, P24,
nuclear@0 129 P34, P24, P22
nuclear@0 130 };
nuclear@0 131
nuclear@0 132 static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
nuclear@0 133 {
nuclear@0 134 if(!iter) {
nuclear@0 135 verts->push_back(v1);
nuclear@0 136 verts->push_back(v2);
nuclear@0 137 verts->push_back(v3);
nuclear@0 138 return;
nuclear@0 139 }
nuclear@0 140
nuclear@0 141 Vec3 v12 = normalize(v1 + v2);
nuclear@0 142 Vec3 v23 = normalize(v2 + v3);
nuclear@0 143 Vec3 v31 = normalize(v3 + v1);
nuclear@0 144
nuclear@0 145 geosphere(verts, v1, v12, v31, iter - 1);
nuclear@0 146 geosphere(verts, v2, v23, v12, iter - 1);
nuclear@0 147 geosphere(verts, v3, v31, v23, iter - 1);
nuclear@0 148 geosphere(verts, v12, v23, v31, iter - 1);
nuclear@0 149 }
nuclear@0 150
nuclear@0 151 void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
nuclear@0 152 {
nuclear@0 153 int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
nuclear@0 154
nuclear@0 155 std::vector<Vec3> verts;
nuclear@0 156 for(int i=0; i<num_tri; i++) {
nuclear@0 157 Vec3 v[3];
nuclear@0 158
nuclear@0 159 for(int j=0; j<3; j++) {
nuclear@0 160 int vidx = icosa_idx[i * 3 + j];
nuclear@0 161 v[j] = normalize(icosa_pt[vidx]);
nuclear@0 162 }
nuclear@0 163
nuclear@0 164 if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
nuclear@0 165 continue;
nuclear@0 166 }
nuclear@0 167
nuclear@0 168 geosphere(&verts, v[0], v[1], v[2], subdiv);
nuclear@0 169 }
nuclear@0 170
nuclear@0 171 int num_verts = (int)verts.size();
nuclear@0 172
nuclear@0 173 mesh->clear();
nuclear@0 174 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 175 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 176 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 177 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 178
nuclear@0 179 for(int i=0; i<num_verts; i++) {
nuclear@0 180 *varr++ = verts[i] * rad;
nuclear@0 181 *narr++ = verts[i];
nuclear@0 182
nuclear@0 183 float theta = atan2(verts[i].z, verts[i].x);
nuclear@0 184 float phi = acos(verts[i].y);
nuclear@0 185
nuclear@0 186 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
nuclear@0 187
nuclear@0 188 float u = 0.5 * theta / M_PI + 0.5;
nuclear@0 189 float v = phi / M_PI;
nuclear@0 190 *uvarr++ = Vec2(u, v);
nuclear@0 191 }
nuclear@0 192 }
nuclear@0 193
nuclear@0 194 // -------- torus -----------
nuclear@0 195 static Vec3 torusvec(float theta, float phi, float mr, float rr)
nuclear@0 196 {
nuclear@0 197 theta = -theta;
nuclear@0 198
nuclear@0 199 float rx = -cos(phi) * rr + mr;
nuclear@0 200 float ry = sin(phi) * rr;
nuclear@0 201 float rz = 0.0;
nuclear@0 202
nuclear@0 203 float x = rx * sin(theta) + rz * cos(theta);
nuclear@0 204 float y = ry;
nuclear@0 205 float z = -rx * cos(theta) + rz * sin(theta);
nuclear@0 206
nuclear@0 207 return Vec3(x, y, z);
nuclear@0 208 }
nuclear@0 209
nuclear@0 210 void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange)
nuclear@0 211 {
nuclear@0 212 if(usub < 4) usub = 4;
nuclear@0 213 if(vsub < 2) vsub = 2;
nuclear@0 214
nuclear@0 215 int uverts = usub + 1;
nuclear@0 216 int vverts = vsub + 1;
nuclear@0 217
nuclear@0 218 int num_verts = uverts * vverts;
nuclear@0 219 int num_quads = usub * vsub;
nuclear@0 220 int num_tri = num_quads * 2;
nuclear@0 221
nuclear@0 222 mesh->clear();
nuclear@0 223 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 224 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 225 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 226 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 227 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 228
nuclear@0 229 float du = urange / (float)(uverts - 1);
nuclear@0 230 float dv = vrange / (float)(vverts - 1);
nuclear@0 231
nuclear@0 232 float u = 0.0;
nuclear@0 233 for(int i=0; i<uverts; i++) {
nuclear@0 234 float theta = u * 2.0 * M_PI;
nuclear@0 235
nuclear@0 236 float v = 0.0;
nuclear@0 237 for(int j=0; j<vverts; j++) {
nuclear@0 238 float phi = v * 2.0 * M_PI;
nuclear@0 239
nuclear@0 240 Vec3 pos = torusvec(theta, phi, mainrad, ringrad);
nuclear@0 241 Vec3 cent = torusvec(theta, phi, mainrad, 0.0);
nuclear@0 242
nuclear@0 243 *varr++ = pos;
nuclear@0 244 *narr++ = (pos - cent) / ringrad;
nuclear@0 245
nuclear@0 246 Vec3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad);
nuclear@0 247 Vec3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad);
nuclear@0 248
nuclear@0 249 *tarr++ = normalize(pnext - pprev);
nuclear@0 250 *uvarr++ = Vec2(u * urange, v * vrange);
nuclear@0 251
nuclear@0 252 if(i < usub && j < vsub) {
nuclear@0 253 int idx = i * vverts + j;
nuclear@0 254 *idxarr++ = idx;
nuclear@0 255 *idxarr++ = idx + 1;
nuclear@0 256 *idxarr++ = idx + vverts + 1;
nuclear@0 257
nuclear@0 258 *idxarr++ = idx;
nuclear@0 259 *idxarr++ = idx + vverts + 1;
nuclear@0 260 *idxarr++ = idx + vverts;
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 v += dv;
nuclear@0 264 }
nuclear@0 265 u += du;
nuclear@0 266 }
nuclear@0 267 }
nuclear@0 268
nuclear@0 269
nuclear@0 270 // -------- cylinder --------
nuclear@0 271
nuclear@0 272 static Vec3 cylvec(float theta, float height)
nuclear@0 273 {
nuclear@0 274 return Vec3(sin(theta), height, cos(theta));
nuclear@0 275 }
nuclear@0 276
nuclear@0 277 void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
nuclear@0 278 {
nuclear@0 279 if(usub < 4) usub = 4;
nuclear@0 280 if(vsub < 1) vsub = 1;
nuclear@0 281
nuclear@0 282 int uverts = usub + 1;
nuclear@0 283 int vverts = vsub + 1;
nuclear@0 284
nuclear@0 285 int num_body_verts = uverts * vverts;
nuclear@0 286 int num_body_quads = usub * vsub;
nuclear@0 287 int num_body_tri = num_body_quads * 2;
nuclear@0 288
nuclear@0 289 int capvverts = capsub ? capsub + 1 : 0;
nuclear@0 290 int num_cap_verts = uverts * capvverts;
nuclear@0 291 int num_cap_quads = usub * capsub;
nuclear@0 292 int num_cap_tri = num_cap_quads * 2;
nuclear@0 293
nuclear@0 294 int num_verts = num_body_verts + num_cap_verts * 2;
nuclear@0 295 int num_tri = num_body_tri + num_cap_tri * 2;
nuclear@0 296
nuclear@0 297 mesh->clear();
nuclear@0 298 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 299 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 300 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 301 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 302 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 303
nuclear@0 304 float du = urange / (float)(uverts - 1);
nuclear@0 305 float dv = vrange / (float)(vverts - 1);
nuclear@0 306
nuclear@0 307 float u = 0.0;
nuclear@0 308 for(int i=0; i<uverts; i++) {
nuclear@0 309 float theta = SURAD(u);
nuclear@0 310
nuclear@0 311 float v = 0.0;
nuclear@0 312 for(int j=0; j<vverts; j++) {
nuclear@0 313 float y = (v - 0.5) * height;
nuclear@0 314 Vec3 pos = cylvec(theta, y);
nuclear@0 315
nuclear@0 316 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
nuclear@0 317 *narr++ = Vec3(pos.x, 0.0, pos.z);
nuclear@0 318 *tarr++ = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
nuclear@0 319 *uvarr++ = Vec2(u * urange, v * vrange);
nuclear@0 320
nuclear@0 321 if(i < usub && j < vsub) {
nuclear@0 322 int idx = i * vverts + j;
nuclear@0 323
nuclear@0 324 *idxarr++ = idx;
nuclear@0 325 *idxarr++ = idx + vverts + 1;
nuclear@0 326 *idxarr++ = idx + 1;
nuclear@0 327
nuclear@0 328 *idxarr++ = idx;
nuclear@0 329 *idxarr++ = idx + vverts;
nuclear@0 330 *idxarr++ = idx + vverts + 1;
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 v += dv;
nuclear@0 334 }
nuclear@0 335 u += du;
nuclear@0 336 }
nuclear@0 337
nuclear@0 338
nuclear@0 339 // now the cap!
nuclear@0 340 if(!capsub) {
nuclear@0 341 return;
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 dv = 1.0 / (float)(capvverts - 1);
nuclear@0 345
nuclear@0 346 u = 0.0;
nuclear@0 347 for(int i=0; i<uverts; i++) {
nuclear@0 348 float theta = SURAD(u);
nuclear@0 349
nuclear@0 350 float v = 0.0;
nuclear@0 351 for(int j=0; j<capvverts; j++) {
nuclear@0 352 float r = v * rad;
nuclear@0 353
nuclear@0 354 Vec3 pos = cylvec(theta, height / 2.0) * r;
nuclear@0 355 pos.y = height / 2.0;
nuclear@0 356 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
nuclear@0 357
nuclear@0 358 *varr++ = pos;
nuclear@0 359 *narr++ = Vec3(0, 1, 0);
nuclear@0 360 *tarr++ = tang;
nuclear@0 361 *uvarr++ = Vec2(u * urange, v);
nuclear@0 362
nuclear@0 363 pos.y = -height / 2.0;
nuclear@0 364 *varr++ = pos;
nuclear@0 365 *narr++ = Vec3(0, -1, 0);
nuclear@0 366 *tarr++ = -tang;
nuclear@0 367 *uvarr++ = Vec2(u * urange, v);
nuclear@0 368
nuclear@0 369 if(i < usub && j < capsub) {
nuclear@0 370 unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
nuclear@0 371
nuclear@0 372 unsigned int vidx[4] = {
nuclear@0 373 idx,
nuclear@0 374 idx + capvverts * 2,
nuclear@0 375 idx + (capvverts + 1) * 2,
nuclear@0 376 idx + 2
nuclear@0 377 };
nuclear@0 378
nuclear@0 379 *idxarr++ = vidx[0];
nuclear@0 380 *idxarr++ = vidx[2];
nuclear@0 381 *idxarr++ = vidx[1];
nuclear@0 382 *idxarr++ = vidx[0];
nuclear@0 383 *idxarr++ = vidx[3];
nuclear@0 384 *idxarr++ = vidx[2];
nuclear@0 385
nuclear@0 386 *idxarr++ = vidx[0] + 1;
nuclear@0 387 *idxarr++ = vidx[1] + 1;
nuclear@0 388 *idxarr++ = vidx[2] + 1;
nuclear@0 389 *idxarr++ = vidx[0] + 1;
nuclear@0 390 *idxarr++ = vidx[2] + 1;
nuclear@0 391 *idxarr++ = vidx[3] + 1;
nuclear@0 392 }
nuclear@0 393
nuclear@0 394 v += dv;
nuclear@0 395 }
nuclear@0 396 u += du;
nuclear@0 397 }
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 // -------- cone --------
nuclear@0 401
nuclear@0 402 static Vec3 conevec(float theta, float y, float height)
nuclear@0 403 {
nuclear@0 404 float scale = 1.0 - y / height;
nuclear@0 405 return Vec3(sin(theta) * scale, y, cos(theta) * scale);
nuclear@0 406 }
nuclear@0 407
nuclear@0 408 void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
nuclear@0 409 {
nuclear@0 410 if(usub < 4) usub = 4;
nuclear@0 411 if(vsub < 1) vsub = 1;
nuclear@0 412
nuclear@0 413 int uverts = usub + 1;
nuclear@0 414 int vverts = vsub + 1;
nuclear@0 415
nuclear@0 416 int num_body_verts = uverts * vverts;
nuclear@0 417 int num_body_quads = usub * vsub;
nuclear@0 418 int num_body_tri = num_body_quads * 2;
nuclear@0 419
nuclear@0 420 int capvverts = capsub ? capsub + 1 : 0;
nuclear@0 421 int num_cap_verts = uverts * capvverts;
nuclear@0 422 int num_cap_quads = usub * capsub;
nuclear@0 423 int num_cap_tri = num_cap_quads * 2;
nuclear@0 424
nuclear@0 425 int num_verts = num_body_verts + num_cap_verts;
nuclear@0 426 int num_tri = num_body_tri + num_cap_tri;
nuclear@0 427
nuclear@0 428 mesh->clear();
nuclear@0 429 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 430 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 431 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 432 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 433 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 434
nuclear@0 435 float du = urange / (float)(uverts - 1);
nuclear@0 436 float dv = vrange / (float)(vverts - 1);
nuclear@0 437
nuclear@0 438 float u = 0.0;
nuclear@0 439 for(int i=0; i<uverts; i++) {
nuclear@0 440 float theta = SURAD(u);
nuclear@0 441
nuclear@0 442 float v = 0.0;
nuclear@0 443 for(int j=0; j<vverts; j++) {
nuclear@0 444 float y = v * height;
nuclear@0 445 Vec3 pos = conevec(theta, y, height);
nuclear@0 446
nuclear@0 447 Vec3 tang = normalize(conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height));
nuclear@0 448 Vec3 bitang = normalize(conevec(theta, y + 0.1, height) - pos);
nuclear@0 449
nuclear@0 450 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
nuclear@0 451 *narr++ = cross(tang, bitang);
nuclear@0 452 *tarr++ = tang;
nuclear@0 453 *uvarr++ = Vec2(u * urange, v * vrange);
nuclear@0 454
nuclear@0 455 if(i < usub && j < vsub) {
nuclear@0 456 int idx = i * vverts + j;
nuclear@0 457
nuclear@0 458 *idxarr++ = idx;
nuclear@0 459 *idxarr++ = idx + vverts + 1;
nuclear@0 460 *idxarr++ = idx + 1;
nuclear@0 461
nuclear@0 462 *idxarr++ = idx;
nuclear@0 463 *idxarr++ = idx + vverts;
nuclear@0 464 *idxarr++ = idx + vverts + 1;
nuclear@0 465 }
nuclear@0 466
nuclear@0 467 v += dv;
nuclear@0 468 }
nuclear@0 469 u += du;
nuclear@0 470 }
nuclear@0 471
nuclear@0 472
nuclear@0 473 // now the bottom cap!
nuclear@0 474 if(!capsub) {
nuclear@0 475 return;
nuclear@0 476 }
nuclear@0 477
nuclear@0 478 dv = 1.0 / (float)(capvverts - 1);
nuclear@0 479
nuclear@0 480 u = 0.0;
nuclear@0 481 for(int i=0; i<uverts; i++) {
nuclear@0 482 float theta = SURAD(u);
nuclear@0 483
nuclear@0 484 float v = 0.0;
nuclear@0 485 for(int j=0; j<capvverts; j++) {
nuclear@0 486 float r = v * rad;
nuclear@0 487
nuclear@0 488 Vec3 pos = conevec(theta, 0.0, height) * r;
nuclear@0 489 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
nuclear@0 490
nuclear@0 491 *varr++ = pos;
nuclear@0 492 *narr++ = Vec3(0, -1, 0);
nuclear@0 493 *tarr++ = tang;
nuclear@0 494 *uvarr++ = Vec2(u * urange, v);
nuclear@0 495
nuclear@0 496 if(i < usub && j < capsub) {
nuclear@0 497 unsigned int idx = num_body_verts + i * capvverts + j;
nuclear@0 498
nuclear@0 499 unsigned int vidx[4] = {
nuclear@0 500 idx,
nuclear@0 501 idx + capvverts,
nuclear@0 502 idx + (capvverts + 1),
nuclear@0 503 idx + 1
nuclear@0 504 };
nuclear@0 505
nuclear@0 506 *idxarr++ = vidx[0];
nuclear@0 507 *idxarr++ = vidx[1];
nuclear@0 508 *idxarr++ = vidx[2];
nuclear@0 509 *idxarr++ = vidx[0];
nuclear@0 510 *idxarr++ = vidx[2];
nuclear@0 511 *idxarr++ = vidx[3];
nuclear@0 512 }
nuclear@0 513
nuclear@0 514 v += dv;
nuclear@0 515 }
nuclear@0 516 u += du;
nuclear@0 517 }
nuclear@0 518 }
nuclear@0 519
nuclear@0 520
nuclear@0 521 // -------- plane --------
nuclear@0 522
nuclear@0 523 void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
nuclear@0 524 {
nuclear@0 525 gen_heightmap(mesh, width, height, usub, vsub, 0);
nuclear@0 526 }
nuclear@0 527
nuclear@0 528
nuclear@0 529 // ----- heightmap ------
nuclear@0 530
nuclear@0 531 void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
nuclear@0 532 {
nuclear@0 533 if(usub < 1) usub = 1;
nuclear@0 534 if(vsub < 1) vsub = 1;
nuclear@0 535
nuclear@0 536 mesh->clear();
nuclear@0 537
nuclear@0 538 int uverts = usub + 1;
nuclear@0 539 int vverts = vsub + 1;
nuclear@0 540 int num_verts = uverts * vverts;
nuclear@0 541
nuclear@0 542 int num_quads = usub * vsub;
nuclear@0 543 int num_tri = num_quads * 2;
nuclear@0 544
nuclear@0 545 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 546 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 547 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 548 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 549 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 550
nuclear@0 551 float du = 1.0 / (float)usub;
nuclear@0 552 float dv = 1.0 / (float)vsub;
nuclear@0 553
nuclear@0 554 float u = 0.0;
nuclear@0 555 for(int i=0; i<uverts; i++) {
nuclear@0 556 float v = 0.0;
nuclear@0 557 for(int j=0; j<vverts; j++) {
nuclear@0 558 float x = (u - 0.5) * width;
nuclear@0 559 float y = (v - 0.5) * height;
nuclear@0 560 float z = hf ? hf(u, v, hfdata) : 0.0;
nuclear@0 561
nuclear@0 562 Vec3 normal = Vec3(0, 0, 1);
nuclear@0 563 if(hf) {
nuclear@0 564 float u1z = hf(u + du, v, hfdata);
nuclear@0 565 float v1z = hf(u, v + dv, hfdata);
nuclear@0 566
nuclear@0 567 Vec3 tang = Vec3(du * width, 0, u1z - z);
nuclear@0 568 Vec3 bitan = Vec3(0, dv * height, v1z - z);
nuclear@0 569 normal = normalize(cross(tang, bitan));
nuclear@0 570 }
nuclear@0 571
nuclear@0 572 *varr++ = Vec3(x, y, z);
nuclear@0 573 *narr++ = normal;
nuclear@0 574 *tarr++ = Vec3(1, 0, 0);
nuclear@0 575 *uvarr++ = Vec2(u, v);
nuclear@0 576
nuclear@0 577 if(i < usub && j < vsub) {
nuclear@0 578 int idx = i * vverts + j;
nuclear@0 579
nuclear@0 580 *idxarr++ = idx;
nuclear@0 581 *idxarr++ = idx + vverts + 1;
nuclear@0 582 *idxarr++ = idx + 1;
nuclear@0 583
nuclear@0 584 *idxarr++ = idx;
nuclear@0 585 *idxarr++ = idx + vverts;
nuclear@0 586 *idxarr++ = idx + vverts + 1;
nuclear@0 587 }
nuclear@0 588
nuclear@0 589 v += dv;
nuclear@0 590 }
nuclear@0 591 u += du;
nuclear@0 592 }
nuclear@0 593 }
nuclear@0 594
nuclear@0 595 // ----- box ------
nuclear@0 596 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub)
nuclear@0 597 {
nuclear@0 598 static const float face_angles[][2] = {
nuclear@0 599 {0, 0},
nuclear@0 600 {M_PI / 2.0, 0},
nuclear@0 601 {M_PI, 0},
nuclear@0 602 {3.0 * M_PI / 2.0, 0},
nuclear@0 603 {0, M_PI / 2.0},
nuclear@0 604 {0, -M_PI / 2.0}
nuclear@0 605 };
nuclear@0 606
nuclear@0 607 if(usub < 1) usub = 1;
nuclear@0 608 if(vsub < 1) vsub = 1;
nuclear@0 609
nuclear@0 610 mesh->clear();
nuclear@0 611
nuclear@0 612 for(int i=0; i<6; i++) {
nuclear@0 613 Mat4 xform, dir_xform;
nuclear@0 614 Mesh m;
nuclear@0 615
nuclear@0 616 gen_plane(&m, 1, 1, usub, vsub);
nuclear@0 617 xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0));
nuclear@0 618 dir_xform = xform;
nuclear@0 619 xform.translate(Vec3(0, 0, 0.5));
nuclear@0 620 m.apply_xform(xform, dir_xform);
nuclear@0 621
nuclear@0 622 mesh->append(m);
nuclear@0 623 }
nuclear@0 624
nuclear@0 625 Mat4 scale;
nuclear@0 626 scale.scaling(xsz, ysz, zsz);
nuclear@0 627 mesh->apply_xform(scale, Mat4::identity);
nuclear@0 628 }
nuclear@0 629
nuclear@0 630 /*
nuclear@0 631 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
nuclear@0 632 {
nuclear@0 633 mesh->clear();
nuclear@0 634
nuclear@0 635 const int num_faces = 6;
nuclear@0 636 int num_verts = num_faces * 4;
nuclear@0 637 int num_tri = num_faces * 2;
nuclear@0 638
nuclear@0 639 float x = xsz / 2.0;
nuclear@0 640 float y = ysz / 2.0;
nuclear@0 641 float z = zsz / 2.0;
nuclear@0 642
nuclear@0 643 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 644 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 645 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 646 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 647 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 648
nuclear@0 649 static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) };
nuclear@0 650
nuclear@0 651 // front
nuclear@0 652 for(int i=0; i<4; i++) {
nuclear@0 653 *narr++ = Vec3(0, 0, 1);
nuclear@0 654 *tarr++ = Vec3(1, 0, 0);
nuclear@0 655 *uvarr++ = uv[i];
nuclear@0 656 }
nuclear@0 657 *varr++ = Vec3(-x, -y, z);
nuclear@0 658 *varr++ = Vec3(x, -y, z);
nuclear@0 659 *varr++ = Vec3(x, y, z);
nuclear@0 660 *varr++ = Vec3(-x, y, z);
nuclear@0 661 // right
nuclear@0 662 for(int i=0; i<4; i++) {
nuclear@0 663 *narr++ = Vec3(1, 0, 0);
nuclear@0 664 *tarr++ = Vec3(0, 0, -1);
nuclear@0 665 *uvarr++ = uv[i];
nuclear@0 666 }
nuclear@0 667 *varr++ = Vec3(x, -y, z);
nuclear@0 668 *varr++ = Vec3(x, -y, -z);
nuclear@0 669 *varr++ = Vec3(x, y, -z);
nuclear@0 670 *varr++ = Vec3(x, y, z);
nuclear@0 671 // back
nuclear@0 672 for(int i=0; i<4; i++) {
nuclear@0 673 *narr++ = Vec3(0, 0, -1);
nuclear@0 674 *tarr++ = Vec3(-1, 0, 0);
nuclear@0 675 *uvarr++ = uv[i];
nuclear@0 676 }
nuclear@0 677 *varr++ = Vec3(x, -y, -z);
nuclear@0 678 *varr++ = Vec3(-x, -y, -z);
nuclear@0 679 *varr++ = Vec3(-x, y, -z);
nuclear@0 680 *varr++ = Vec3(x, y, -z);
nuclear@0 681 // left
nuclear@0 682 for(int i=0; i<4; i++) {
nuclear@0 683 *narr++ = Vec3(-1, 0, 0);
nuclear@0 684 *tarr++ = Vec3(0, 0, 1);
nuclear@0 685 *uvarr++ = uv[i];
nuclear@0 686 }
nuclear@0 687 *varr++ = Vec3(-x, -y, -z);
nuclear@0 688 *varr++ = Vec3(-x, -y, z);
nuclear@0 689 *varr++ = Vec3(-x, y, z);
nuclear@0 690 *varr++ = Vec3(-x, y, -z);
nuclear@0 691 // top
nuclear@0 692 for(int i=0; i<4; i++) {
nuclear@0 693 *narr++ = Vec3(0, 1, 0);
nuclear@0 694 *tarr++ = Vec3(1, 0, 0);
nuclear@0 695 *uvarr++ = uv[i];
nuclear@0 696 }
nuclear@0 697 *varr++ = Vec3(-x, y, z);
nuclear@0 698 *varr++ = Vec3(x, y, z);
nuclear@0 699 *varr++ = Vec3(x, y, -z);
nuclear@0 700 *varr++ = Vec3(-x, y, -z);
nuclear@0 701 // bottom
nuclear@0 702 for(int i=0; i<4; i++) {
nuclear@0 703 *narr++ = Vec3(0, -1, 0);
nuclear@0 704 *tarr++ = Vec3(1, 0, 0);
nuclear@0 705 *uvarr++ = uv[i];
nuclear@0 706 }
nuclear@0 707 *varr++ = Vec3(-x, -y, -z);
nuclear@0 708 *varr++ = Vec3(x, -y, -z);
nuclear@0 709 *varr++ = Vec3(x, -y, z);
nuclear@0 710 *varr++ = Vec3(-x, -y, z);
nuclear@0 711
nuclear@0 712 // index array
nuclear@0 713 static const int faceidx[] = {0, 1, 2, 0, 2, 3};
nuclear@0 714 for(int i=0; i<num_faces; i++) {
nuclear@0 715 for(int j=0; j<6; j++) {
nuclear@0 716 *idxarr++ = faceidx[j] + i * 4;
nuclear@0 717 }
nuclear@0 718 }
nuclear@0 719 }
nuclear@0 720 */
nuclear@0 721
nuclear@0 722 static inline Vec3 rev_vert(float u, float v, Vec2 (*rf)(float, float, void*), void *cls)
nuclear@0 723 {
nuclear@0 724 Vec2 pos = rf(u, v, cls);
nuclear@0 725
nuclear@0 726 float angle = u * 2.0 * M_PI;
nuclear@0 727 float x = pos.x * cos(angle);
nuclear@0 728 float y = pos.y;
nuclear@0 729 float z = pos.x * sin(angle);
nuclear@0 730
nuclear@0 731 return Vec3(x, y, z);
nuclear@0 732 }
nuclear@0 733
nuclear@0 734 // ------ surface of revolution -------
nuclear@0 735 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls)
nuclear@0 736 {
nuclear@0 737 gen_revol(mesh, usub, vsub, rfunc, 0, cls);
nuclear@0 738 }
nuclear@0 739
nuclear@0 740 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*),
nuclear@0 741 Vec2 (*nfunc)(float, float, void*), void *cls)
nuclear@0 742 {
nuclear@0 743 if(!rfunc) return;
nuclear@0 744 if(usub < 3) usub = 3;
nuclear@0 745 if(vsub < 1) vsub = 1;
nuclear@0 746
nuclear@0 747 mesh->clear();
nuclear@0 748
nuclear@0 749 int uverts = usub + 1;
nuclear@0 750 int vverts = vsub + 1;
nuclear@0 751 int num_verts = uverts * vverts;
nuclear@0 752
nuclear@0 753 int num_quads = usub * vsub;
nuclear@0 754 int num_tri = num_quads * 2;
nuclear@0 755
nuclear@0 756 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 757 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 758 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 759 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 760 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 761
nuclear@0 762 float du = 1.0 / (float)(uverts - 1);
nuclear@0 763 float dv = 1.0 / (float)(vverts - 1);
nuclear@0 764
nuclear@0 765 float u = 0.0;
nuclear@0 766 for(int i=0; i<uverts; i++) {
nuclear@0 767 float v = 0.0;
nuclear@0 768 for(int j=0; j<vverts; j++) {
nuclear@0 769 Vec3 pos = rev_vert(u, v, rfunc, cls);
nuclear@0 770
nuclear@0 771 Vec3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
nuclear@0 772 Vec3 tang = nextu - pos;
nuclear@0 773 if(length_sq(tang) < 1e-6) {
nuclear@0 774 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
nuclear@0 775 nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
nuclear@0 776 tang = nextu - pos;
nuclear@0 777 }
nuclear@0 778
nuclear@0 779 Vec3 normal;
nuclear@0 780 if(nfunc) {
nuclear@0 781 normal = rev_vert(u, v, nfunc, cls);
nuclear@0 782 } else {
nuclear@0 783 Vec3 nextv = rev_vert(u, v + dv, rfunc, cls);
nuclear@0 784 Vec3 bitan = nextv - pos;
nuclear@0 785 if(length_sq(bitan) < 1e-6) {
nuclear@0 786 nextv = rev_vert(u, v - dv, rfunc, cls);
nuclear@0 787 bitan = pos - nextv;
nuclear@0 788 }
nuclear@0 789
nuclear@0 790 normal = cross(tang, bitan);
nuclear@0 791 }
nuclear@0 792
nuclear@0 793 *varr++ = pos;
nuclear@0 794 *narr++ = normalize(normal);
nuclear@0 795 *tarr++ = normalize(tang);
nuclear@0 796 *uvarr++ = Vec2(u, v);
nuclear@0 797
nuclear@0 798 if(i < usub && j < vsub) {
nuclear@0 799 int idx = i * vverts + j;
nuclear@0 800
nuclear@0 801 *idxarr++ = idx;
nuclear@0 802 *idxarr++ = idx + vverts + 1;
nuclear@0 803 *idxarr++ = idx + 1;
nuclear@0 804
nuclear@0 805 *idxarr++ = idx;
nuclear@0 806 *idxarr++ = idx + vverts;
nuclear@0 807 *idxarr++ = idx + vverts + 1;
nuclear@0 808 }
nuclear@0 809
nuclear@0 810 v += dv;
nuclear@0 811 }
nuclear@0 812 u += du;
nuclear@0 813 }
nuclear@0 814 }
nuclear@0 815
nuclear@0 816
nuclear@0 817 static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls)
nuclear@0 818 {
nuclear@0 819 Vec2 pos = sf(u, v, cls);
nuclear@0 820
nuclear@0 821 float x = pos.x;
nuclear@0 822 float y = v * height;
nuclear@0 823 float z = pos.y;
nuclear@0 824
nuclear@0 825 return Vec3(x, y, z);
nuclear@0 826 }
nuclear@0 827
nuclear@0 828 // ---- sweep shape along a path ----
nuclear@0 829 void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls)
nuclear@0 830 {
nuclear@0 831 if(!sfunc) return;
nuclear@0 832 if(usub < 3) usub = 3;
nuclear@0 833 if(vsub < 1) vsub = 1;
nuclear@0 834
nuclear@0 835 mesh->clear();
nuclear@0 836
nuclear@0 837 int uverts = usub + 1;
nuclear@0 838 int vverts = vsub + 1;
nuclear@0 839 int num_verts = uverts * vverts;
nuclear@0 840
nuclear@0 841 int num_quads = usub * vsub;
nuclear@0 842 int num_tri = num_quads * 2;
nuclear@0 843
nuclear@0 844 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
nuclear@0 845 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
nuclear@0 846 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
nuclear@0 847 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
nuclear@0 848 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
nuclear@0 849
nuclear@0 850 float du = 1.0 / (float)(uverts - 1);
nuclear@0 851 float dv = 1.0 / (float)(vverts - 1);
nuclear@0 852
nuclear@0 853 float u = 0.0;
nuclear@0 854 for(int i=0; i<uverts; i++) {
nuclear@0 855 float v = 0.0;
nuclear@0 856 for(int j=0; j<vverts; j++) {
nuclear@0 857 Vec3 pos = sweep_vert(u, v, height, sfunc, cls);
nuclear@0 858
nuclear@0 859 Vec3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls);
nuclear@0 860 Vec3 tang = nextu - pos;
nuclear@0 861 if(length_sq(tang) < 1e-6) {
nuclear@0 862 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
nuclear@0 863 nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls);
nuclear@0 864 tang = nextu - pos;
nuclear@0 865 }
nuclear@0 866
nuclear@0 867 Vec3 normal;
nuclear@0 868 Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls);
nuclear@0 869 Vec3 bitan = nextv - pos;
nuclear@0 870 if(length_sq(bitan) < 1e-6) {
nuclear@0 871 nextv = sweep_vert(u, v - dv, height, sfunc, cls);
nuclear@0 872 bitan = pos - nextv;
nuclear@0 873 }
nuclear@0 874
nuclear@0 875 normal = cross(tang, bitan);
nuclear@0 876
nuclear@0 877 *varr++ = pos;
nuclear@0 878 *narr++ = normalize(normal);
nuclear@0 879 *tarr++ = normalize(tang);
nuclear@0 880 *uvarr++ = Vec2(u, v);
nuclear@0 881
nuclear@0 882 if(i < usub && j < vsub) {
nuclear@0 883 int idx = i * vverts + j;
nuclear@0 884
nuclear@0 885 *idxarr++ = idx;
nuclear@0 886 *idxarr++ = idx + vverts + 1;
nuclear@0 887 *idxarr++ = idx + 1;
nuclear@0 888
nuclear@0 889 *idxarr++ = idx;
nuclear@0 890 *idxarr++ = idx + vverts;
nuclear@0 891 *idxarr++ = idx + vverts + 1;
nuclear@0 892 }
nuclear@0 893
nuclear@0 894 v += dv;
nuclear@0 895 }
nuclear@0 896 u += du;
nuclear@0 897 }
nuclear@0 898 }