nuclear@4: /* nuclear@4: Cubemapper - a program for converting panoramic images into cubemaps nuclear@4: Copyright (C) 2017 John Tsiombikas nuclear@4: nuclear@4: This program is free software: you can redistribute it and/or modify nuclear@4: it under the terms of the GNU General Public License as published by nuclear@4: the Free Software Foundation, either version 3 of the License, or nuclear@4: (at your option) any later version. nuclear@4: nuclear@4: This program is distributed in the hope that it will be useful, nuclear@4: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@4: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@4: GNU General Public License for more details. nuclear@4: nuclear@4: You should have received a copy of the GNU General Public License nuclear@4: along with this program. If not, see . nuclear@4: */ nuclear@0: #include nuclear@0: #include "meshgen.h" nuclear@0: #include "mesh.h" nuclear@0: nuclear@0: // -------- sphere -------- nuclear@0: nuclear@0: #define SURAD(u) ((u) * 2.0 * M_PI) nuclear@0: #define SVRAD(v) ((v) * M_PI) nuclear@0: nuclear@0: static Vec3 sphvec(float theta, float phi) nuclear@0: { nuclear@0: return Vec3(sin(theta) * sin(phi), nuclear@0: cos(phi), nuclear@0: cos(theta) * sin(phi)); nuclear@0: } nuclear@0: nuclear@0: void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange) nuclear@0: { nuclear@0: if(usub < 4) usub = 4; nuclear@0: if(vsub < 2) vsub = 2; nuclear@0: nuclear@0: int uverts = usub + 1; nuclear@0: int vverts = vsub + 1; nuclear@0: nuclear@0: int num_verts = uverts * vverts; nuclear@0: int num_quads = usub * vsub; nuclear@0: int num_tri = num_quads * 2; nuclear@0: nuclear@0: mesh->clear(); nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = urange / (float)(uverts - 1); nuclear@0: float dv = vrange / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; i *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter) nuclear@0: { nuclear@0: if(!iter) { nuclear@0: verts->push_back(v1); nuclear@0: verts->push_back(v2); nuclear@0: verts->push_back(v3); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: Vec3 v12 = normalize(v1 + v2); nuclear@0: Vec3 v23 = normalize(v2 + v3); nuclear@0: Vec3 v31 = normalize(v3 + v1); nuclear@0: nuclear@0: geosphere(verts, v1, v12, v31, iter - 1); nuclear@0: geosphere(verts, v2, v23, v12, iter - 1); nuclear@0: geosphere(verts, v3, v31, v23, iter - 1); nuclear@0: geosphere(verts, v12, v23, v31, iter - 1); nuclear@0: } nuclear@0: nuclear@0: void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi) nuclear@0: { nuclear@0: int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3; nuclear@0: nuclear@0: std::vector verts; nuclear@0: for(int i=0; iclear(); nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: nuclear@0: for(int i=0; iclear(); nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = urange / (float)(uverts - 1); nuclear@0: float dv = vrange / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; iclear(); nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = urange / (float)(uverts - 1); nuclear@0: float dv = vrange / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; iclear(); nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = urange / (float)(uverts - 1); nuclear@0: float dv = vrange / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; iclear(); nuclear@0: nuclear@0: int uverts = usub + 1; nuclear@0: int vverts = vsub + 1; nuclear@0: int num_verts = uverts * vverts; nuclear@0: nuclear@0: int num_quads = usub * vsub; nuclear@0: int num_tri = num_quads * 2; nuclear@0: nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = 1.0 / (float)usub; nuclear@0: float dv = 1.0 / (float)vsub; nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; iclear(); nuclear@0: nuclear@0: for(int i=0; i<6; i++) { nuclear@0: Mat4 xform, dir_xform; nuclear@0: Mesh m; nuclear@0: nuclear@0: gen_plane(&m, 1, 1, usub, vsub); nuclear@0: xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0)); nuclear@0: dir_xform = xform; nuclear@0: xform.translate(Vec3(0, 0, 0.5)); nuclear@0: m.apply_xform(xform, dir_xform); nuclear@0: nuclear@0: mesh->append(m); nuclear@0: } nuclear@0: nuclear@0: Mat4 scale; nuclear@0: scale.scaling(xsz, ysz, zsz); nuclear@0: mesh->apply_xform(scale, Mat4::identity); nuclear@0: } nuclear@0: nuclear@0: /* nuclear@0: void gen_box(Mesh *mesh, float xsz, float ysz, float zsz) nuclear@0: { nuclear@0: mesh->clear(); nuclear@0: nuclear@0: const int num_faces = 6; nuclear@0: int num_verts = num_faces * 4; nuclear@0: int num_tri = num_faces * 2; nuclear@0: nuclear@0: float x = xsz / 2.0; nuclear@0: float y = ysz / 2.0; nuclear@0: float z = zsz / 2.0; nuclear@0: nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) }; nuclear@0: nuclear@0: // front nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(0, 0, 1); nuclear@0: *tarr++ = Vec3(1, 0, 0); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(-x, -y, z); nuclear@0: *varr++ = Vec3(x, -y, z); nuclear@0: *varr++ = Vec3(x, y, z); nuclear@0: *varr++ = Vec3(-x, y, z); nuclear@0: // right nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(1, 0, 0); nuclear@0: *tarr++ = Vec3(0, 0, -1); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(x, -y, z); nuclear@0: *varr++ = Vec3(x, -y, -z); nuclear@0: *varr++ = Vec3(x, y, -z); nuclear@0: *varr++ = Vec3(x, y, z); nuclear@0: // back nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(0, 0, -1); nuclear@0: *tarr++ = Vec3(-1, 0, 0); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(x, -y, -z); nuclear@0: *varr++ = Vec3(-x, -y, -z); nuclear@0: *varr++ = Vec3(-x, y, -z); nuclear@0: *varr++ = Vec3(x, y, -z); nuclear@0: // left nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(-1, 0, 0); nuclear@0: *tarr++ = Vec3(0, 0, 1); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(-x, -y, -z); nuclear@0: *varr++ = Vec3(-x, -y, z); nuclear@0: *varr++ = Vec3(-x, y, z); nuclear@0: *varr++ = Vec3(-x, y, -z); nuclear@0: // top nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(0, 1, 0); nuclear@0: *tarr++ = Vec3(1, 0, 0); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(-x, y, z); nuclear@0: *varr++ = Vec3(x, y, z); nuclear@0: *varr++ = Vec3(x, y, -z); nuclear@0: *varr++ = Vec3(-x, y, -z); nuclear@0: // bottom nuclear@0: for(int i=0; i<4; i++) { nuclear@0: *narr++ = Vec3(0, -1, 0); nuclear@0: *tarr++ = Vec3(1, 0, 0); nuclear@0: *uvarr++ = uv[i]; nuclear@0: } nuclear@0: *varr++ = Vec3(-x, -y, -z); nuclear@0: *varr++ = Vec3(x, -y, -z); nuclear@0: *varr++ = Vec3(x, -y, z); nuclear@0: *varr++ = Vec3(-x, -y, z); nuclear@0: nuclear@0: // index array nuclear@0: static const int faceidx[] = {0, 1, 2, 0, 2, 3}; nuclear@0: for(int i=0; iclear(); nuclear@0: nuclear@0: int uverts = usub + 1; nuclear@0: int vverts = vsub + 1; nuclear@0: int num_verts = uverts * vverts; nuclear@0: nuclear@0: int num_quads = usub * vsub; nuclear@0: int num_tri = num_quads * 2; nuclear@0: nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = 1.0 / (float)(uverts - 1); nuclear@0: float dv = 1.0 / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; i 0.5 ? v - dv * 0.25 : v + dv * 0.25; nuclear@0: nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls); nuclear@0: tang = nextu - pos; nuclear@0: } nuclear@0: nuclear@0: Vec3 normal; nuclear@0: if(nfunc) { nuclear@0: normal = rev_vert(u, v, nfunc, cls); nuclear@0: } else { nuclear@0: Vec3 nextv = rev_vert(u, v + dv, rfunc, cls); nuclear@0: Vec3 bitan = nextv - pos; nuclear@0: if(length_sq(bitan) < 1e-6) { nuclear@0: nextv = rev_vert(u, v - dv, rfunc, cls); nuclear@0: bitan = pos - nextv; nuclear@0: } nuclear@0: nuclear@0: normal = cross(tang, bitan); nuclear@0: } nuclear@0: nuclear@0: *varr++ = pos; nuclear@0: *narr++ = normalize(normal); nuclear@0: *tarr++ = normalize(tang); nuclear@0: *uvarr++ = Vec2(u, v); nuclear@0: nuclear@0: if(i < usub && j < vsub) { nuclear@0: int idx = i * vverts + j; nuclear@0: nuclear@0: *idxarr++ = idx; nuclear@0: *idxarr++ = idx + vverts + 1; nuclear@0: *idxarr++ = idx + 1; nuclear@0: nuclear@0: *idxarr++ = idx; nuclear@0: *idxarr++ = idx + vverts; nuclear@0: *idxarr++ = idx + vverts + 1; nuclear@0: } nuclear@0: nuclear@0: v += dv; nuclear@0: } nuclear@0: u += du; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls) nuclear@0: { nuclear@0: Vec2 pos = sf(u, v, cls); nuclear@0: nuclear@0: float x = pos.x; nuclear@0: float y = v * height; nuclear@0: float z = pos.y; nuclear@0: nuclear@0: return Vec3(x, y, z); nuclear@0: } nuclear@0: nuclear@0: // ---- sweep shape along a path ---- nuclear@0: void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls) nuclear@0: { nuclear@0: if(!sfunc) return; nuclear@0: if(usub < 3) usub = 3; nuclear@0: if(vsub < 1) vsub = 1; nuclear@0: nuclear@0: mesh->clear(); nuclear@0: nuclear@0: int uverts = usub + 1; nuclear@0: int vverts = vsub + 1; nuclear@0: int num_verts = uverts * vverts; nuclear@0: nuclear@0: int num_quads = usub * vsub; nuclear@0: int num_tri = num_quads * 2; nuclear@0: nuclear@0: Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); nuclear@0: Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); nuclear@0: Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); nuclear@0: Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); nuclear@0: unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); nuclear@0: nuclear@0: float du = 1.0 / (float)(uverts - 1); nuclear@0: float dv = 1.0 / (float)(vverts - 1); nuclear@0: nuclear@0: float u = 0.0; nuclear@0: for(int i=0; i 0.5 ? v - dv * 0.25 : v + dv * 0.25; nuclear@0: nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls); nuclear@0: tang = nextu - pos; nuclear@0: } nuclear@0: nuclear@0: Vec3 normal; nuclear@0: Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls); nuclear@0: Vec3 bitan = nextv - pos; nuclear@0: if(length_sq(bitan) < 1e-6) { nuclear@0: nextv = sweep_vert(u, v - dv, height, sfunc, cls); nuclear@0: bitan = pos - nextv; nuclear@0: } nuclear@0: nuclear@0: normal = cross(tang, bitan); nuclear@0: nuclear@0: *varr++ = pos; nuclear@0: *narr++ = normalize(normal); nuclear@0: *tarr++ = normalize(tang); nuclear@0: *uvarr++ = Vec2(u, v); nuclear@0: nuclear@0: if(i < usub && j < vsub) { nuclear@0: int idx = i * vverts + j; nuclear@0: nuclear@0: *idxarr++ = idx; nuclear@0: *idxarr++ = idx + vverts + 1; nuclear@0: *idxarr++ = idx + 1; nuclear@0: nuclear@0: *idxarr++ = idx; nuclear@0: *idxarr++ = idx + vverts; nuclear@0: *idxarr++ = idx + vverts + 1; nuclear@0: } nuclear@0: nuclear@0: v += dv; nuclear@0: } nuclear@0: u += du; nuclear@0: } nuclear@0: }