goat3d

view src/mesh.cc @ 84:022b13ed975b

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