goat3d

annotate src/mesh.cc @ 40:a5c5cec3cb88

- added mesh attribute and face append functions - added Int4 constructor - continued the blender exporter - fixed a bug in clean_filename which made it produce unterminated strings - renamed clean_filename to goat3d_clean_filename and made it extern - added call to goat3d_clean_filename in the mesh XML export code to cleanup ctm filenames
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 13 Oct 2013 10:14:19 +0300
parents 0fe02696fb1e
children 498ca7ac7047
rev   line source
nuclear@19 1 #include "goat3d_impl.h"
nuclear@1 2 #include "mesh.h"
nuclear@19 3 #include "openctm.h"
nuclear@19 4 #include "log.h"
nuclear@1 5
nuclear@40 6 Int4::Int4()
nuclear@40 7 {
nuclear@40 8 x = y = z = w = 0;
nuclear@40 9 }
nuclear@40 10
nuclear@40 11 Int4::Int4(int x, int y, int z, int w)
nuclear@40 12 {
nuclear@40 13 this->x = x;
nuclear@40 14 this->y = y;
nuclear@40 15 this->z = z;
nuclear@40 16 this->w = w;
nuclear@40 17 }
nuclear@40 18
nuclear@1 19 Mesh::Mesh()
nuclear@1 20 {
nuclear@8 21 material = 0;
nuclear@1 22 }
nuclear@1 23
nuclear@19 24 bool Mesh::load(const char *fname)
nuclear@19 25 {
nuclear@19 26 CTMcontext ctm = ctmNewContext(CTM_IMPORT);
nuclear@19 27
nuclear@19 28 ctmLoad(ctm, fname);
nuclear@19 29 if(ctmGetError(ctm) != CTM_NONE) {
nuclear@19 30 logmsg(LOG_ERROR, "failed to load ctm mesh: %s\n", fname);
nuclear@19 31 ctmFreeContext(ctm);
nuclear@19 32 return false;
nuclear@19 33 }
nuclear@19 34
nuclear@19 35 int vnum = ctmGetInteger(ctm, CTM_VERTEX_COUNT);
nuclear@19 36 int fnum = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT);
nuclear@19 37
nuclear@19 38 const CTMfloat *vertices = ctmGetFloatArray(ctm, CTM_VERTICES);
nuclear@19 39 if(!vertices) {
nuclear@19 40 logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no vertices found!\n", fname);
nuclear@19 41 ctmFreeContext(ctm);
nuclear@19 42 return false;
nuclear@19 43 }
nuclear@19 44
nuclear@19 45 const CTMuint *indices = ctmGetIntegerArray(ctm, CTM_INDICES);
nuclear@19 46 if(!indices) {
nuclear@19 47 logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no faces found!\n", fname);
nuclear@19 48 ctmFreeContext(ctm);
nuclear@19 49 return false;
nuclear@19 50 }
nuclear@19 51
nuclear@19 52 const CTMfloat *normals = ctmGetFloatArray(ctm, CTM_NORMALS);
nuclear@19 53 const CTMfloat *texcoords = ctmGetFloatArray(ctm, CTM_UV_MAP_1);
nuclear@19 54
nuclear@19 55 CTMenum tangent_id = ctmGetNamedAttribMap(ctm, "tangent");
nuclear@19 56 const CTMfloat *tangents = tangent_id ? ctmGetFloatArray(ctm, tangent_id) : 0;
nuclear@19 57
nuclear@19 58 CTMenum skinweight_id = ctmGetNamedAttribMap(ctm, "skin_weight");
nuclear@19 59 const CTMfloat *skinweights = skinweight_id ? ctmGetFloatArray(ctm, skinweight_id) : 0;
nuclear@19 60
nuclear@19 61 CTMenum skinmat_id = ctmGetNamedAttribMap(ctm, "skin_matrix");
nuclear@19 62 const CTMuint *skinmats = skinmat_id ? ctmGetIntegerArray(ctm, skinmat_id) : 0;
nuclear@19 63
nuclear@19 64 CTMenum color_id = ctmGetNamedAttribMap(ctm, "color");
nuclear@19 65 const CTMfloat *colors = color_id ? ctmGetFloatArray(ctm, color_id) : 0;
nuclear@19 66
nuclear@19 67 // now put everything we found into our vectors
nuclear@19 68 this->vertices = VECDATA(Vector3, vertices, vnum);
nuclear@19 69
nuclear@19 70 if(texcoords) {
nuclear@19 71 this->texcoords = VECDATA(Vector2, texcoords, vnum);
nuclear@19 72 }
nuclear@19 73 if(normals) {
nuclear@19 74 this->normals = VECDATA(Vector3, normals, vnum);
nuclear@19 75 }
nuclear@19 76 if(skinweights) {
nuclear@19 77 this->skin_weights = VECDATA(Vector4, skinweights, vnum);
nuclear@19 78 }
nuclear@19 79 if(colors) {
nuclear@19 80 this->colors = VECDATA(Vector4, colors, vnum);
nuclear@19 81 }
nuclear@19 82
nuclear@19 83 // the rest need converting
nuclear@19 84 if(tangents) {
nuclear@19 85 this->tangents.clear();
nuclear@19 86 this->tangents.resize(vnum);
nuclear@19 87
nuclear@19 88 for(int i=0; i<vnum; i++) {
nuclear@19 89 for(int j=0; j<3; j++) {
nuclear@19 90 this->tangents[i][j] = tangents[j];
nuclear@19 91 }
nuclear@19 92 tangents += 4;
nuclear@19 93 }
nuclear@19 94 }
nuclear@19 95 if(skinmats) {
nuclear@19 96 this->skin_matrices.clear();
nuclear@19 97 this->skin_matrices.resize(vnum);
nuclear@19 98
nuclear@19 99 for(int i=0; i<vnum; i++) {
nuclear@19 100 this->skin_matrices[i].x = skinmats[0];
nuclear@19 101 this->skin_matrices[i].y = skinmats[1];
nuclear@19 102 this->skin_matrices[i].z = skinmats[2];
nuclear@19 103 this->skin_matrices[i].w = skinmats[3];
nuclear@19 104 }
nuclear@19 105 }
nuclear@19 106
nuclear@19 107 // grab the face data
nuclear@19 108 this->faces.clear();
nuclear@19 109 this->faces.resize(fnum);
nuclear@19 110
nuclear@19 111 for(int i=0; i<fnum; i++) {
nuclear@19 112 for(int j=0; j<3; j++) {
nuclear@19 113 this->faces[i].v[j] = indices[j];
nuclear@19 114 }
nuclear@19 115 indices += 3;
nuclear@19 116 }
nuclear@19 117
nuclear@19 118
nuclear@19 119 ctmFreeContext(ctm);
nuclear@19 120 return true;
nuclear@19 121 }
nuclear@19 122
nuclear@19 123 bool Mesh::save(const char *fname) const
nuclear@19 124 {
nuclear@19 125 int vnum = (int)vertices.size();
nuclear@30 126 int fnum = (int)faces.size();
nuclear@30 127
nuclear@30 128 if(!vnum || !fnum) {
nuclear@30 129 return false;
nuclear@30 130 }
nuclear@19 131
nuclear@19 132 CTMcontext ctm = ctmNewContext(CTM_EXPORT);
nuclear@19 133
nuclear@19 134 // vertices, normals, and face-vertex indices
nuclear@30 135 ctmDefineMesh(ctm, &vertices[0].x, vnum, (CTMuint*)faces[0].v, fnum,
nuclear@19 136 normals.empty() ? 0 : &normals[0].x);
nuclear@19 137
nuclear@19 138 // texture coordinates
nuclear@19 139 if(!texcoords.empty()) {
nuclear@19 140 ctmAddUVMap(ctm, &texcoords[0].x, "texcoord", 0);
nuclear@19 141 }
nuclear@19 142
nuclear@19 143 // vertex colors
nuclear@19 144 if(!colors.empty()) {
nuclear@19 145 ctmAddAttribMap(ctm, &colors[0].x, "color");
nuclear@19 146 }
nuclear@19 147
nuclear@19 148 // skin weights
nuclear@19 149 if(!skin_weights.empty()) {
nuclear@19 150 ctmAddAttribMap(ctm, &skin_weights[0].x, "skin_weight");
nuclear@19 151 }
nuclear@19 152
nuclear@19 153 // if either of the non-float4 attributes are present we need to make a tmp array
nuclear@19 154 CTMfloat *attr_array = 0;
nuclear@19 155 if(!tangents.empty() || !skin_matrices.empty()) {
nuclear@19 156 attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array];
nuclear@19 157 }
nuclear@19 158
nuclear@19 159 // tangents
nuclear@19 160 if(!tangents.empty()) {
nuclear@19 161 CTMfloat *ptr = attr_array;
nuclear@19 162
nuclear@19 163 for(int i=0; i<vnum; i++) {
nuclear@19 164 *ptr++ = tangents[i].x;
nuclear@19 165 *ptr++ = tangents[i].y;
nuclear@19 166 *ptr++ = tangents[i].z;
nuclear@19 167 *ptr++ = 1.0;
nuclear@19 168 }
nuclear@19 169 ctmAddAttribMap(ctm, attr_array, "tangent");
nuclear@19 170 }
nuclear@19 171
nuclear@19 172 // skin matrix indices (4 per vertex)
nuclear@19 173 if(!skin_matrices.empty()) {
nuclear@19 174 CTMfloat *ptr = attr_array;
nuclear@19 175
nuclear@19 176 for(int i=0; i<vnum; i++) {
nuclear@19 177 *ptr++ = (float)skin_matrices[i].x;
nuclear@19 178 *ptr++ = (float)skin_matrices[i].y;
nuclear@19 179 *ptr++ = (float)skin_matrices[i].z;
nuclear@19 180 *ptr++ = (float)skin_matrices[i].w;
nuclear@19 181 }
nuclear@19 182 ctmAddAttribMap(ctm, attr_array, "skin_matrix");
nuclear@19 183 }
nuclear@19 184
nuclear@19 185 delete [] attr_array;
nuclear@19 186
nuclear@19 187 /* TODO find a way to specify the nodes participating in the skinning of this mesh
nuclear@19 188 * probably in the comment field?
nuclear@19 189 */
nuclear@19 190
nuclear@19 191 logmsg(LOG_INFO, "saving CTM mesh file: %s\n", fname);
nuclear@19 192 ctmSave(ctm, fname);
nuclear@19 193
nuclear@19 194 ctmFreeContext(ctm);
nuclear@19 195 return true;
nuclear@19 196 }
nuclear@19 197
nuclear@8 198 void Mesh::set_material(Material *mat)
nuclear@1 199 {
nuclear@8 200 material = mat;
nuclear@1 201 }
nuclear@1 202
nuclear@8 203 Material *Mesh::get_material()
nuclear@1 204 {
nuclear@8 205 return material;
nuclear@1 206 }
nuclear@1 207
nuclear@8 208 const Material *Mesh::get_material() const
nuclear@1 209 {
nuclear@8 210 return material;
nuclear@1 211 }