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 }
|