goat3d

annotate src/mesh.cc @ 88:7941e89798e5

selections
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 15 May 2014 06:52:01 +0300
parents 9785847d52d4
children
rev   line source
nuclear@54 1 /*
nuclear@54 2 goat3d - 3D scene, character, and animation file format library.
nuclear@54 3 Copyright (C) 2013-2014 John Tsiombikas <nuclear@member.fsf.org>
nuclear@54 4
nuclear@54 5 This program is free software: you can redistribute it and/or modify
nuclear@54 6 it under the terms of the GNU Lesser General Public License as published by
nuclear@54 7 the Free Software Foundation, either version 3 of the License, or
nuclear@54 8 (at your option) any later version.
nuclear@54 9
nuclear@54 10 This program is distributed in the hope that it will be useful,
nuclear@54 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@54 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@54 13 GNU Lesser General Public License for more details.
nuclear@54 14
nuclear@54 15 You should have received a copy of the GNU Lesser General Public License
nuclear@54 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@54 17 */
nuclear@19 18 #include "goat3d_impl.h"
nuclear@1 19 #include "mesh.h"
nuclear@19 20 #include "openctm.h"
nuclear@19 21 #include "log.h"
nuclear@1 22
nuclear@47 23 using namespace g3dimpl;
nuclear@47 24
nuclear@40 25 Int4::Int4()
nuclear@40 26 {
nuclear@40 27 x = y = z = w = 0;
nuclear@40 28 }
nuclear@40 29
nuclear@40 30 Int4::Int4(int x, int y, int z, int w)
nuclear@40 31 {
nuclear@40 32 this->x = x;
nuclear@40 33 this->y = y;
nuclear@40 34 this->z = z;
nuclear@40 35 this->w = w;
nuclear@40 36 }
nuclear@40 37
nuclear@1 38 Mesh::Mesh()
nuclear@1 39 {
nuclear@8 40 material = 0;
nuclear@1 41 }
nuclear@1 42
nuclear@19 43 bool Mesh::load(const char *fname)
nuclear@19 44 {
nuclear@19 45 CTMcontext ctm = ctmNewContext(CTM_IMPORT);
nuclear@19 46
nuclear@19 47 ctmLoad(ctm, fname);
nuclear@19 48 if(ctmGetError(ctm) != CTM_NONE) {
nuclear@19 49 logmsg(LOG_ERROR, "failed to load ctm mesh: %s\n", fname);
nuclear@19 50 ctmFreeContext(ctm);
nuclear@19 51 return false;
nuclear@19 52 }
nuclear@19 53
nuclear@19 54 int vnum = ctmGetInteger(ctm, CTM_VERTEX_COUNT);
nuclear@19 55 int fnum = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT);
nuclear@19 56
nuclear@19 57 const CTMfloat *vertices = ctmGetFloatArray(ctm, CTM_VERTICES);
nuclear@19 58 if(!vertices) {
nuclear@19 59 logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no vertices found!\n", fname);
nuclear@19 60 ctmFreeContext(ctm);
nuclear@19 61 return false;
nuclear@19 62 }
nuclear@19 63
nuclear@19 64 const CTMuint *indices = ctmGetIntegerArray(ctm, CTM_INDICES);
nuclear@19 65 if(!indices) {
nuclear@19 66 logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no faces found!\n", fname);
nuclear@19 67 ctmFreeContext(ctm);
nuclear@19 68 return false;
nuclear@19 69 }
nuclear@19 70
nuclear@19 71 const CTMfloat *normals = ctmGetFloatArray(ctm, CTM_NORMALS);
nuclear@19 72 const CTMfloat *texcoords = ctmGetFloatArray(ctm, CTM_UV_MAP_1);
nuclear@19 73
nuclear@19 74 CTMenum tangent_id = ctmGetNamedAttribMap(ctm, "tangent");
nuclear@19 75 const CTMfloat *tangents = tangent_id ? ctmGetFloatArray(ctm, tangent_id) : 0;
nuclear@19 76
nuclear@19 77 CTMenum skinweight_id = ctmGetNamedAttribMap(ctm, "skin_weight");
nuclear@19 78 const CTMfloat *skinweights = skinweight_id ? ctmGetFloatArray(ctm, skinweight_id) : 0;
nuclear@19 79
nuclear@19 80 CTMenum skinmat_id = ctmGetNamedAttribMap(ctm, "skin_matrix");
nuclear@19 81 const CTMuint *skinmats = skinmat_id ? ctmGetIntegerArray(ctm, skinmat_id) : 0;
nuclear@19 82
nuclear@19 83 CTMenum color_id = ctmGetNamedAttribMap(ctm, "color");
nuclear@19 84 const CTMfloat *colors = color_id ? ctmGetFloatArray(ctm, color_id) : 0;
nuclear@19 85
nuclear@19 86 // now put everything we found into our vectors
nuclear@19 87 this->vertices = VECDATA(Vector3, vertices, vnum);
nuclear@19 88
nuclear@19 89 if(texcoords) {
nuclear@19 90 this->texcoords = VECDATA(Vector2, texcoords, vnum);
nuclear@19 91 }
nuclear@19 92 if(normals) {
nuclear@19 93 this->normals = VECDATA(Vector3, normals, vnum);
nuclear@19 94 }
nuclear@19 95 if(skinweights) {
nuclear@19 96 this->skin_weights = VECDATA(Vector4, skinweights, vnum);
nuclear@19 97 }
nuclear@19 98 if(colors) {
nuclear@19 99 this->colors = VECDATA(Vector4, colors, vnum);
nuclear@19 100 }
nuclear@19 101
nuclear@19 102 // the rest need converting
nuclear@19 103 if(tangents) {
nuclear@19 104 this->tangents.clear();
nuclear@19 105 this->tangents.resize(vnum);
nuclear@19 106
nuclear@19 107 for(int i=0; i<vnum; i++) {
nuclear@19 108 for(int j=0; j<3; j++) {
nuclear@19 109 this->tangents[i][j] = tangents[j];
nuclear@19 110 }
nuclear@19 111 tangents += 4;
nuclear@19 112 }
nuclear@19 113 }
nuclear@19 114 if(skinmats) {
nuclear@19 115 this->skin_matrices.clear();
nuclear@19 116 this->skin_matrices.resize(vnum);
nuclear@19 117
nuclear@19 118 for(int i=0; i<vnum; i++) {
nuclear@19 119 this->skin_matrices[i].x = skinmats[0];
nuclear@19 120 this->skin_matrices[i].y = skinmats[1];
nuclear@19 121 this->skin_matrices[i].z = skinmats[2];
nuclear@19 122 this->skin_matrices[i].w = skinmats[3];
nuclear@19 123 }
nuclear@19 124 }
nuclear@19 125
nuclear@19 126 // grab the face data
nuclear@19 127 this->faces.clear();
nuclear@19 128 this->faces.resize(fnum);
nuclear@19 129
nuclear@19 130 for(int i=0; i<fnum; i++) {
nuclear@19 131 for(int j=0; j<3; j++) {
nuclear@19 132 this->faces[i].v[j] = indices[j];
nuclear@19 133 }
nuclear@19 134 indices += 3;
nuclear@19 135 }
nuclear@19 136
nuclear@19 137
nuclear@19 138 ctmFreeContext(ctm);
nuclear@19 139 return true;
nuclear@19 140 }
nuclear@19 141
nuclear@19 142 bool Mesh::save(const char *fname) const
nuclear@19 143 {
nuclear@19 144 int vnum = (int)vertices.size();
nuclear@30 145 int fnum = (int)faces.size();
nuclear@30 146
nuclear@30 147 if(!vnum || !fnum) {
nuclear@30 148 return false;
nuclear@30 149 }
nuclear@19 150
nuclear@19 151 CTMcontext ctm = ctmNewContext(CTM_EXPORT);
nuclear@19 152
nuclear@19 153 // vertices, normals, and face-vertex indices
nuclear@30 154 ctmDefineMesh(ctm, &vertices[0].x, vnum, (CTMuint*)faces[0].v, fnum,
nuclear@19 155 normals.empty() ? 0 : &normals[0].x);
nuclear@19 156
nuclear@19 157 // texture coordinates
nuclear@19 158 if(!texcoords.empty()) {
nuclear@19 159 ctmAddUVMap(ctm, &texcoords[0].x, "texcoord", 0);
nuclear@19 160 }
nuclear@19 161
nuclear@19 162 // vertex colors
nuclear@19 163 if(!colors.empty()) {
nuclear@19 164 ctmAddAttribMap(ctm, &colors[0].x, "color");
nuclear@19 165 }
nuclear@19 166
nuclear@19 167 // skin weights
nuclear@19 168 if(!skin_weights.empty()) {
nuclear@19 169 ctmAddAttribMap(ctm, &skin_weights[0].x, "skin_weight");
nuclear@19 170 }
nuclear@19 171
nuclear@19 172 // if either of the non-float4 attributes are present we need to make a tmp array
nuclear@19 173 CTMfloat *attr_array = 0;
nuclear@19 174 if(!tangents.empty() || !skin_matrices.empty()) {
nuclear@19 175 attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array];
nuclear@19 176 }
nuclear@19 177
nuclear@19 178 // tangents
nuclear@19 179 if(!tangents.empty()) {
nuclear@19 180 CTMfloat *ptr = attr_array;
nuclear@19 181
nuclear@19 182 for(int i=0; i<vnum; i++) {
nuclear@19 183 *ptr++ = tangents[i].x;
nuclear@19 184 *ptr++ = tangents[i].y;
nuclear@19 185 *ptr++ = tangents[i].z;
nuclear@19 186 *ptr++ = 1.0;
nuclear@19 187 }
nuclear@19 188 ctmAddAttribMap(ctm, attr_array, "tangent");
nuclear@19 189 }
nuclear@19 190
nuclear@19 191 // skin matrix indices (4 per vertex)
nuclear@19 192 if(!skin_matrices.empty()) {
nuclear@19 193 CTMfloat *ptr = attr_array;
nuclear@19 194
nuclear@19 195 for(int i=0; i<vnum; i++) {
nuclear@19 196 *ptr++ = (float)skin_matrices[i].x;
nuclear@19 197 *ptr++ = (float)skin_matrices[i].y;
nuclear@19 198 *ptr++ = (float)skin_matrices[i].z;
nuclear@19 199 *ptr++ = (float)skin_matrices[i].w;
nuclear@19 200 }
nuclear@19 201 ctmAddAttribMap(ctm, attr_array, "skin_matrix");
nuclear@19 202 }
nuclear@19 203
nuclear@19 204 delete [] attr_array;
nuclear@19 205
nuclear@19 206 /* TODO find a way to specify the nodes participating in the skinning of this mesh
nuclear@19 207 * probably in the comment field?
nuclear@19 208 */
nuclear@19 209
nuclear@19 210 logmsg(LOG_INFO, "saving CTM mesh file: %s\n", fname);
nuclear@19 211 ctmSave(ctm, fname);
nuclear@19 212
nuclear@19 213 ctmFreeContext(ctm);
nuclear@19 214 return true;
nuclear@19 215 }
nuclear@19 216
nuclear@8 217 void Mesh::set_material(Material *mat)
nuclear@1 218 {
nuclear@8 219 material = mat;
nuclear@1 220 }
nuclear@1 221
nuclear@8 222 Material *Mesh::get_material()
nuclear@1 223 {
nuclear@8 224 return material;
nuclear@1 225 }
nuclear@1 226
nuclear@8 227 const Material *Mesh::get_material() const
nuclear@1 228 {
nuclear@8 229 return material;
nuclear@1 230 }
nuclear@77 231
nuclear@77 232 AABox Mesh::get_bounds(const Matrix4x4 &xform) const
nuclear@77 233 {
nuclear@77 234 AABox bbox;
nuclear@77 235
nuclear@77 236 for(size_t i=0; i<vertices.size(); i++) {
nuclear@77 237 Vector3 v = vertices[i].transformed(xform);
nuclear@77 238
nuclear@77 239 for(int j=0; j<3; j++) {
nuclear@77 240 if(v[j] < bbox.bmin[j]) {
nuclear@77 241 bbox.bmin[j] = v[j];
nuclear@77 242 }
nuclear@77 243 if(v[j] > bbox.bmax[j]) {
nuclear@77 244 bbox.bmax[j] = v[j];
nuclear@77 245 }
nuclear@77 246 }
nuclear@77 247 }
nuclear@77 248 return bbox;
nuclear@77 249 }