rev |
line source |
nuclear@16
|
1 #include <string.h>
|
nuclear@16
|
2 #include <errno.h>
|
nuclear@31
|
3 #include <ctype.h>
|
nuclear@31
|
4 #include <string>
|
nuclear@16
|
5 #include "goat3d.h"
|
nuclear@16
|
6 #include "goat3d_impl.h"
|
nuclear@16
|
7 #include "log.h"
|
nuclear@16
|
8
|
nuclear@31
|
9 #ifndef _MSC_VER
|
nuclear@31
|
10 #include <alloca.h>
|
nuclear@31
|
11 #else
|
nuclear@31
|
12 #include <malloc.h>
|
nuclear@31
|
13 #endif
|
nuclear@31
|
14
|
nuclear@16
|
15 struct goat3d {
|
nuclear@16
|
16 Scene *scn;
|
nuclear@16
|
17 unsigned int flags;
|
nuclear@32
|
18 char *search_path;
|
nuclear@16
|
19 };
|
nuclear@16
|
20
|
nuclear@16
|
21 struct goat3d_material : public Material {};
|
nuclear@16
|
22 struct goat3d_mesh : public Mesh {};
|
nuclear@16
|
23 struct goat3d_light : public Light {};
|
nuclear@16
|
24 struct goat3d_camera : public Camera {};
|
nuclear@16
|
25 struct goat3d_node : public Node {};
|
nuclear@16
|
26
|
nuclear@16
|
27
|
nuclear@16
|
28 static long read_file(void *buf, size_t bytes, void *uptr);
|
nuclear@16
|
29 static long write_file(const void *buf, size_t bytes, void *uptr);
|
nuclear@16
|
30 static long seek_file(long offs, int whence, void *uptr);
|
nuclear@16
|
31
|
nuclear@16
|
32 extern "C" {
|
nuclear@16
|
33
|
nuclear@41
|
34 GOAT3DAPI struct goat3d *goat3d_create(void)
|
nuclear@16
|
35 {
|
nuclear@16
|
36 goat3d *goat = new goat3d;
|
nuclear@27
|
37 goat->flags = 0;
|
nuclear@32
|
38 goat->search_path = 0;
|
nuclear@16
|
39 goat->scn = new Scene;
|
nuclear@29
|
40
|
nuclear@29
|
41 goat3d_setopt(goat, GOAT3D_OPT_SAVEXML, 1);
|
nuclear@16
|
42 return goat;
|
nuclear@16
|
43 }
|
nuclear@16
|
44
|
nuclear@41
|
45 GOAT3DAPI void goat3d_free(struct goat3d *g)
|
nuclear@16
|
46 {
|
nuclear@32
|
47 delete g->search_path;
|
nuclear@16
|
48 delete g->scn;
|
nuclear@16
|
49 delete g;
|
nuclear@16
|
50 }
|
nuclear@16
|
51
|
nuclear@41
|
52 GOAT3DAPI void goat3d_setopt(struct goat3d *g, enum goat3d_option opt, int val)
|
nuclear@16
|
53 {
|
nuclear@16
|
54 if(val) {
|
nuclear@16
|
55 g->flags |= (1 << (int)opt);
|
nuclear@16
|
56 } else {
|
nuclear@16
|
57 g->flags &= ~(1 << (int)opt);
|
nuclear@16
|
58 }
|
nuclear@16
|
59 }
|
nuclear@16
|
60
|
nuclear@41
|
61 GOAT3DAPI int goat3d_getopt(const struct goat3d *g, enum goat3d_option opt)
|
nuclear@16
|
62 {
|
nuclear@16
|
63 return (g->flags >> (int)opt) & 1;
|
nuclear@16
|
64 }
|
nuclear@16
|
65
|
nuclear@41
|
66 GOAT3DAPI int goat3d_load(struct goat3d *g, const char *fname)
|
nuclear@16
|
67 {
|
nuclear@16
|
68 FILE *fp = fopen(fname, "rb");
|
nuclear@16
|
69 if(!fp) {
|
nuclear@16
|
70 logmsg(LOG_ERROR, "failed to open file \"%s\" for reading: %s\n", fname, strerror(errno));
|
nuclear@16
|
71 return -1;
|
nuclear@16
|
72 }
|
nuclear@16
|
73
|
nuclear@32
|
74 /* if the filename contained any directory components, keep the prefix
|
nuclear@32
|
75 * to use it as a search path for external mesh file loading
|
nuclear@32
|
76 */
|
nuclear@32
|
77 g->search_path = new char[strlen(fname) + 1];
|
nuclear@32
|
78 strcpy(g->search_path, fname);
|
nuclear@32
|
79
|
nuclear@32
|
80 char *slash = strrchr(g->search_path, '/');
|
nuclear@32
|
81 if(slash) {
|
nuclear@32
|
82 *slash = 0;
|
nuclear@32
|
83 } else {
|
nuclear@32
|
84 if((slash = strrchr(g->search_path, '\\'))) {
|
nuclear@32
|
85 *slash = 0;
|
nuclear@32
|
86 } else {
|
nuclear@32
|
87 delete [] g->search_path;
|
nuclear@32
|
88 g->search_path = 0;
|
nuclear@32
|
89 }
|
nuclear@32
|
90 }
|
nuclear@32
|
91
|
nuclear@16
|
92 int res = goat3d_load_file(g, fp);
|
nuclear@16
|
93 fclose(fp);
|
nuclear@16
|
94 return res;
|
nuclear@16
|
95 }
|
nuclear@16
|
96
|
nuclear@41
|
97 GOAT3DAPI int goat3d_save(const struct goat3d *g, const char *fname)
|
nuclear@16
|
98 {
|
nuclear@16
|
99 FILE *fp = fopen(fname, "wb");
|
nuclear@16
|
100 if(!fp) {
|
nuclear@16
|
101 logmsg(LOG_ERROR, "failed to open file \"%s\" for writing: %s\n", fname, strerror(errno));
|
nuclear@16
|
102 return -1;
|
nuclear@16
|
103 }
|
nuclear@16
|
104
|
nuclear@16
|
105 int res = goat3d_save_file(g, fp);
|
nuclear@16
|
106 fclose(fp);
|
nuclear@16
|
107 return res;
|
nuclear@16
|
108 }
|
nuclear@16
|
109
|
nuclear@41
|
110 GOAT3DAPI int goat3d_load_file(struct goat3d *g, FILE *fp)
|
nuclear@16
|
111 {
|
nuclear@16
|
112 goat3d_io io;
|
nuclear@16
|
113 io.cls = fp;
|
nuclear@16
|
114 io.read = read_file;
|
nuclear@16
|
115 io.write = write_file;
|
nuclear@16
|
116 io.seek = seek_file;
|
nuclear@16
|
117
|
nuclear@16
|
118 return goat3d_load_io(g, &io);
|
nuclear@16
|
119 }
|
nuclear@16
|
120
|
nuclear@41
|
121 GOAT3DAPI int goat3d_save_file(const struct goat3d *g, FILE *fp)
|
nuclear@16
|
122 {
|
nuclear@16
|
123 goat3d_io io;
|
nuclear@16
|
124 io.cls = fp;
|
nuclear@16
|
125 io.read = read_file;
|
nuclear@16
|
126 io.write = write_file;
|
nuclear@16
|
127 io.seek = seek_file;
|
nuclear@16
|
128
|
nuclear@16
|
129 return goat3d_save_io(g, &io);
|
nuclear@16
|
130 }
|
nuclear@16
|
131
|
nuclear@41
|
132 GOAT3DAPI int goat3d_load_io(struct goat3d *g, struct goat3d_io *io)
|
nuclear@16
|
133 {
|
nuclear@16
|
134 if(!g->scn->load(io)) {
|
nuclear@16
|
135 if(g->scn->loadxml(io)) {
|
nuclear@16
|
136 return -1;
|
nuclear@16
|
137 }
|
nuclear@16
|
138 }
|
nuclear@16
|
139 return 0;
|
nuclear@16
|
140 }
|
nuclear@16
|
141
|
nuclear@41
|
142 GOAT3DAPI int goat3d_save_io(const struct goat3d *g, struct goat3d_io *io)
|
nuclear@16
|
143 {
|
nuclear@16
|
144 if(goat3d_getopt(g, GOAT3D_OPT_SAVEXML)) {
|
nuclear@16
|
145 return g->scn->savexml(io) ? 0 : -1;
|
nuclear@16
|
146 }
|
nuclear@16
|
147 return g->scn->save(io) ? 0 : -1;
|
nuclear@16
|
148 }
|
nuclear@16
|
149
|
nuclear@41
|
150 GOAT3DAPI int goat3d_set_name(struct goat3d *g, const char *name)
|
nuclear@16
|
151 {
|
nuclear@16
|
152 g->scn->set_name(name);
|
nuclear@16
|
153 return 0;
|
nuclear@16
|
154 }
|
nuclear@16
|
155
|
nuclear@41
|
156 GOAT3DAPI const char *goat3d_get_name(const struct goat3d *g)
|
nuclear@16
|
157 {
|
nuclear@16
|
158 return g->scn->get_name();
|
nuclear@16
|
159 }
|
nuclear@16
|
160
|
nuclear@41
|
161 GOAT3DAPI void goat3d_set_ambient(struct goat3d *g, const float *amb)
|
nuclear@16
|
162 {
|
nuclear@16
|
163 g->scn->set_ambient(Vector3(amb[0], amb[1], amb[2]));
|
nuclear@16
|
164 }
|
nuclear@16
|
165
|
nuclear@41
|
166 GOAT3DAPI void goat3d_set_ambient3f(struct goat3d *g, float ar, float ag, float ab)
|
nuclear@16
|
167 {
|
nuclear@16
|
168 g->scn->set_ambient(Vector3(ar, ag, ab));
|
nuclear@16
|
169 }
|
nuclear@16
|
170
|
nuclear@41
|
171 GOAT3DAPI const float *goat3d_get_ambient(const struct goat3d *g)
|
nuclear@16
|
172 {
|
nuclear@16
|
173 return &g->scn->get_ambient().x;
|
nuclear@16
|
174 }
|
nuclear@16
|
175
|
nuclear@16
|
176 // ---- materials ----
|
nuclear@41
|
177 GOAT3DAPI void goat3d_add_mtl(struct goat3d *g, struct goat3d_material *mtl)
|
nuclear@27
|
178 {
|
nuclear@27
|
179 g->scn->add_material(mtl);
|
nuclear@27
|
180 }
|
nuclear@27
|
181
|
nuclear@41
|
182 GOAT3DAPI struct goat3d_material *goat3d_create_mtl(void)
|
nuclear@16
|
183 {
|
nuclear@16
|
184 return new goat3d_material;
|
nuclear@16
|
185 }
|
nuclear@16
|
186
|
nuclear@41
|
187 GOAT3DAPI void goat3d_destroy_mtl(struct goat3d_material *mtl)
|
nuclear@16
|
188 {
|
nuclear@16
|
189 delete mtl;
|
nuclear@16
|
190 }
|
nuclear@16
|
191
|
nuclear@41
|
192 GOAT3DAPI void goat3d_set_mtl_name(struct goat3d_material *mtl, const char *name)
|
nuclear@16
|
193 {
|
nuclear@16
|
194 mtl->name = std::string(name);
|
nuclear@16
|
195 }
|
nuclear@16
|
196
|
nuclear@41
|
197 GOAT3DAPI const char *goat3d_get_mtl_name(const struct goat3d_material *mtl)
|
nuclear@16
|
198 {
|
nuclear@16
|
199 return mtl->name.c_str();
|
nuclear@16
|
200 }
|
nuclear@16
|
201
|
nuclear@41
|
202 GOAT3DAPI void goat3d_set_mtl_attrib(struct goat3d_material *mtl, const char *attrib, const float *val)
|
nuclear@16
|
203 {
|
nuclear@16
|
204 (*mtl)[attrib].value = Vector4(val[0], val[1], val[2], val[3]);
|
nuclear@16
|
205 }
|
nuclear@16
|
206
|
nuclear@41
|
207 GOAT3DAPI void goat3d_set_mtl_attrib1f(struct goat3d_material *mtl, const char *attrib, float val)
|
nuclear@16
|
208 {
|
nuclear@16
|
209 goat3d_set_mtl_attrib4f(mtl, attrib, val, 0, 0, 1);
|
nuclear@16
|
210 }
|
nuclear@16
|
211
|
nuclear@41
|
212 GOAT3DAPI void goat3d_set_mtl_attrib3f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b)
|
nuclear@16
|
213 {
|
nuclear@16
|
214 goat3d_set_mtl_attrib4f(mtl, attrib, r, g, b, 1);
|
nuclear@16
|
215 }
|
nuclear@16
|
216
|
nuclear@41
|
217 GOAT3DAPI void goat3d_set_mtl_attrib4f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b, float a)
|
nuclear@16
|
218 {
|
nuclear@16
|
219 (*mtl)[attrib].value = Vector4(r, g, b, a);
|
nuclear@16
|
220 }
|
nuclear@16
|
221
|
nuclear@41
|
222 GOAT3DAPI const float *goat3d_get_mtl_attrib(struct goat3d_material *mtl, const char *attrib)
|
nuclear@16
|
223 {
|
nuclear@16
|
224 return &(*mtl)[attrib].value.x;
|
nuclear@16
|
225 }
|
nuclear@16
|
226
|
nuclear@41
|
227 GOAT3DAPI void goat3d_set_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib, const char *mapname)
|
nuclear@16
|
228 {
|
nuclear@40
|
229 (*mtl)[attrib].map = goat3d_clean_filename(mapname);
|
nuclear@16
|
230 }
|
nuclear@16
|
231
|
nuclear@41
|
232 GOAT3DAPI const char *goat3d_get_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib)
|
nuclear@16
|
233 {
|
nuclear@16
|
234 return (*mtl)[attrib].map.c_str();
|
nuclear@16
|
235 }
|
nuclear@16
|
236
|
nuclear@27
|
237 // ---- meshes ----
|
nuclear@41
|
238 GOAT3DAPI void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh)
|
nuclear@16
|
239 {
|
nuclear@27
|
240 g->scn->add_mesh(mesh);
|
nuclear@16
|
241 }
|
nuclear@16
|
242
|
nuclear@41
|
243 GOAT3DAPI int goat3d_get_mesh_count(struct goat3d *g)
|
nuclear@27
|
244 {
|
nuclear@27
|
245 return g->scn->get_mesh_count();
|
nuclear@27
|
246 }
|
nuclear@27
|
247
|
nuclear@41
|
248 GOAT3DAPI struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx)
|
nuclear@27
|
249 {
|
nuclear@27
|
250 return (goat3d_mesh*)g->scn->get_mesh(idx);
|
nuclear@27
|
251 }
|
nuclear@27
|
252
|
nuclear@41
|
253 GOAT3DAPI struct goat3d_mesh *goat3d_get_mesh_by_name(struct goat3d *g, const char *name)
|
nuclear@27
|
254 {
|
nuclear@27
|
255 return (goat3d_mesh*)g->scn->get_mesh(name);
|
nuclear@27
|
256 }
|
nuclear@27
|
257
|
nuclear@41
|
258 GOAT3DAPI struct goat3d_mesh *goat3d_create_mesh(void)
|
nuclear@16
|
259 {
|
nuclear@16
|
260 return new goat3d_mesh;
|
nuclear@16
|
261 }
|
nuclear@16
|
262
|
nuclear@41
|
263 GOAT3DAPI void goat3d_destroy_mesh(struct goat3d_mesh *mesh)
|
nuclear@16
|
264 {
|
nuclear@16
|
265 delete mesh;
|
nuclear@16
|
266 }
|
nuclear@16
|
267
|
nuclear@41
|
268 GOAT3DAPI void goat3d_set_mesh_name(struct goat3d_mesh *mesh, const char *name)
|
nuclear@16
|
269 {
|
nuclear@16
|
270 mesh->name = std::string(name);
|
nuclear@16
|
271 }
|
nuclear@16
|
272
|
nuclear@41
|
273 GOAT3DAPI const char *goat3d_get_mesh_name(const struct goat3d_mesh *mesh)
|
nuclear@16
|
274 {
|
nuclear@16
|
275 return mesh->name.c_str();
|
nuclear@16
|
276 }
|
nuclear@16
|
277
|
nuclear@41
|
278 GOAT3DAPI void goat3d_set_mesh_mtl(struct goat3d_mesh *mesh, struct goat3d_material *mtl)
|
nuclear@16
|
279 {
|
nuclear@16
|
280 mesh->material = mtl;
|
nuclear@16
|
281 }
|
nuclear@16
|
282
|
nuclear@41
|
283 GOAT3DAPI struct goat3d_material *goat3d_get_mesh_mtl(struct goat3d_mesh *mesh)
|
nuclear@16
|
284 {
|
nuclear@16
|
285 return (goat3d_material*)mesh->material;
|
nuclear@16
|
286 }
|
nuclear@16
|
287
|
nuclear@41
|
288 GOAT3DAPI int goat3d_get_mesh_attrib_count(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib)
|
nuclear@16
|
289 {
|
nuclear@16
|
290 return (int)mesh->vertices.size();
|
nuclear@16
|
291 }
|
nuclear@16
|
292
|
nuclear@41
|
293 GOAT3DAPI int goat3d_get_mesh_face_count(struct goat3d_mesh *mesh)
|
nuclear@16
|
294 {
|
nuclear@16
|
295 return (int)mesh->faces.size();
|
nuclear@16
|
296 }
|
nuclear@16
|
297
|
nuclear@19
|
298 // VECDATA is in goat3d_impl.h
|
nuclear@41
|
299 GOAT3DAPI void goat3d_set_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, const void *data, int vnum)
|
nuclear@16
|
300 {
|
nuclear@16
|
301 if(attrib == GOAT3D_MESH_ATTR_VERTEX) {
|
nuclear@16
|
302 mesh->vertices = VECDATA(Vector3, data, vnum);
|
nuclear@16
|
303 return;
|
nuclear@16
|
304 }
|
nuclear@16
|
305
|
nuclear@16
|
306 if(vnum != (int)mesh->vertices.size()) {
|
nuclear@16
|
307 logmsg(LOG_ERROR, "trying to set mesh attrib data with number of elements different than the vertex array\n");
|
nuclear@16
|
308 return;
|
nuclear@16
|
309 }
|
nuclear@16
|
310
|
nuclear@16
|
311 switch(attrib) {
|
nuclear@16
|
312 case GOAT3D_MESH_ATTR_NORMAL:
|
nuclear@16
|
313 mesh->normals = VECDATA(Vector3, data, vnum);
|
nuclear@16
|
314 break;
|
nuclear@16
|
315 case GOAT3D_MESH_ATTR_TANGENT:
|
nuclear@16
|
316 mesh->tangents = VECDATA(Vector3, data, vnum);
|
nuclear@16
|
317 break;
|
nuclear@16
|
318 case GOAT3D_MESH_ATTR_TEXCOORD:
|
nuclear@16
|
319 mesh->texcoords = VECDATA(Vector2, data, vnum);
|
nuclear@16
|
320 break;
|
nuclear@16
|
321 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
|
nuclear@16
|
322 mesh->skin_weights = VECDATA(Vector4, data, vnum);
|
nuclear@16
|
323 break;
|
nuclear@16
|
324 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
|
nuclear@16
|
325 mesh->skin_matrices = VECDATA(Int4, data, vnum);
|
nuclear@16
|
326 break;
|
nuclear@16
|
327 case GOAT3D_MESH_ATTR_COLOR:
|
nuclear@16
|
328 mesh->colors = VECDATA(Vector4, data, vnum);
|
nuclear@16
|
329 default:
|
nuclear@16
|
330 break;
|
nuclear@16
|
331 }
|
nuclear@16
|
332 }
|
nuclear@16
|
333
|
nuclear@41
|
334 GOAT3DAPI void goat3d_add_mesh_attrib1f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
|
nuclear@40
|
335 float val)
|
nuclear@40
|
336 {
|
nuclear@40
|
337 goat3d_add_mesh_attrib4f(mesh, attrib, val, 0, 0, 1);
|
nuclear@40
|
338 }
|
nuclear@40
|
339
|
nuclear@41
|
340 GOAT3DAPI void goat3d_add_mesh_attrib3f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
|
nuclear@40
|
341 float x, float y, float z)
|
nuclear@40
|
342 {
|
nuclear@40
|
343 goat3d_add_mesh_attrib4f(mesh, attrib, x, y, z, 1);
|
nuclear@40
|
344 }
|
nuclear@40
|
345
|
nuclear@41
|
346 GOAT3DAPI void goat3d_add_mesh_attrib4f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
|
nuclear@40
|
347 float x, float y, float z, float w)
|
nuclear@40
|
348 {
|
nuclear@40
|
349 switch(attrib) {
|
nuclear@40
|
350 case GOAT3D_MESH_ATTR_VERTEX:
|
nuclear@40
|
351 mesh->vertices.push_back(Vector3(x, y, z));
|
nuclear@40
|
352 break;
|
nuclear@40
|
353 case GOAT3D_MESH_ATTR_NORMAL:
|
nuclear@40
|
354 mesh->normals.push_back(Vector3(x, y, z));
|
nuclear@40
|
355 break;
|
nuclear@40
|
356 case GOAT3D_MESH_ATTR_TANGENT:
|
nuclear@40
|
357 mesh->tangents.push_back(Vector3(x, y, z));
|
nuclear@40
|
358 break;
|
nuclear@40
|
359 case GOAT3D_MESH_ATTR_TEXCOORD:
|
nuclear@40
|
360 mesh->texcoords.push_back(Vector2(x, y));
|
nuclear@40
|
361 break;
|
nuclear@40
|
362 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
|
nuclear@40
|
363 mesh->skin_weights.push_back(Vector4(x, y, z, w));
|
nuclear@40
|
364 break;
|
nuclear@40
|
365 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
|
nuclear@40
|
366 mesh->skin_matrices.push_back(Int4(x, y, z, w));
|
nuclear@40
|
367 break;
|
nuclear@40
|
368 case GOAT3D_MESH_ATTR_COLOR:
|
nuclear@40
|
369 mesh->colors.push_back(Vector4(x, y, z, w));
|
nuclear@40
|
370 default:
|
nuclear@40
|
371 break;
|
nuclear@40
|
372 }
|
nuclear@40
|
373 }
|
nuclear@40
|
374
|
nuclear@41
|
375 GOAT3DAPI void *goat3d_get_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib)
|
nuclear@16
|
376 {
|
nuclear@16
|
377 return goat3d_get_mesh_attrib(mesh, attrib, 0);
|
nuclear@16
|
378 }
|
nuclear@16
|
379
|
nuclear@41
|
380 GOAT3DAPI void *goat3d_get_mesh_attrib(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, int idx)
|
nuclear@16
|
381 {
|
nuclear@16
|
382 switch(attrib) {
|
nuclear@16
|
383 case GOAT3D_MESH_ATTR_VERTEX:
|
nuclear@16
|
384 return mesh->vertices.empty() ? 0 : (void*)&mesh->vertices[idx];
|
nuclear@16
|
385 case GOAT3D_MESH_ATTR_NORMAL:
|
nuclear@16
|
386 return mesh->normals.empty() ? 0 : (void*)&mesh->normals[idx];
|
nuclear@16
|
387 case GOAT3D_MESH_ATTR_TANGENT:
|
nuclear@16
|
388 return mesh->tangents.empty() ? 0 : (void*)&mesh->tangents[idx];
|
nuclear@16
|
389 case GOAT3D_MESH_ATTR_TEXCOORD:
|
nuclear@16
|
390 return mesh->texcoords.empty() ? 0 : (void*)&mesh->texcoords[idx];
|
nuclear@16
|
391 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
|
nuclear@16
|
392 return mesh->skin_weights.empty() ? 0 : (void*)&mesh->skin_weights[idx];
|
nuclear@16
|
393 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
|
nuclear@16
|
394 return mesh->skin_matrices.empty() ? 0 : (void*)&mesh->skin_matrices[idx];
|
nuclear@16
|
395 case GOAT3D_MESH_ATTR_COLOR:
|
nuclear@16
|
396 return mesh->colors.empty() ? 0 : (void*)&mesh->colors[idx];
|
nuclear@16
|
397 default:
|
nuclear@16
|
398 break;
|
nuclear@16
|
399 }
|
nuclear@16
|
400 return 0;
|
nuclear@16
|
401 }
|
nuclear@16
|
402
|
nuclear@16
|
403
|
nuclear@41
|
404 GOAT3DAPI void goat3d_set_mesh_faces(struct goat3d_mesh *mesh, const int *data, int num)
|
nuclear@16
|
405 {
|
nuclear@16
|
406 mesh->faces = VECDATA(Face, data, num);
|
nuclear@16
|
407 }
|
nuclear@16
|
408
|
nuclear@41
|
409 GOAT3DAPI void goat3d_add_mesh_face(struct goat3d_mesh *mesh, int a, int b, int c)
|
nuclear@40
|
410 {
|
nuclear@40
|
411 Face face;
|
nuclear@40
|
412 face.v[0] = a;
|
nuclear@40
|
413 face.v[1] = b;
|
nuclear@40
|
414 face.v[2] = c;
|
nuclear@40
|
415 mesh->faces.push_back(face);
|
nuclear@40
|
416 }
|
nuclear@40
|
417
|
nuclear@41
|
418 GOAT3DAPI int *goat3d_get_mesh_faces(struct goat3d_mesh *mesh)
|
nuclear@16
|
419 {
|
nuclear@16
|
420 return goat3d_get_mesh_face(mesh, 0);
|
nuclear@16
|
421 }
|
nuclear@16
|
422
|
nuclear@41
|
423 GOAT3DAPI int *goat3d_get_mesh_face(struct goat3d_mesh *mesh, int idx)
|
nuclear@16
|
424 {
|
nuclear@16
|
425 return mesh->faces.empty() ? 0 : mesh->faces[idx].v;
|
nuclear@16
|
426 }
|
nuclear@16
|
427
|
nuclear@16
|
428 // immedate mode state
|
nuclear@16
|
429 static enum goat3d_im_primitive im_prim;
|
nuclear@16
|
430 static struct goat3d_mesh *im_mesh;
|
nuclear@16
|
431 static Vector3 im_norm, im_tang;
|
nuclear@16
|
432 static Vector2 im_texcoord;
|
nuclear@16
|
433 static Vector4 im_skinw, im_color = Vector4(1, 1, 1, 1);
|
nuclear@16
|
434 static Int4 im_skinmat;
|
nuclear@16
|
435 static bool im_use[NUM_GOAT3D_MESH_ATTRIBS];
|
nuclear@16
|
436
|
nuclear@16
|
437
|
nuclear@41
|
438 GOAT3DAPI void goat3d_begin(struct goat3d_mesh *mesh, enum goat3d_im_primitive prim)
|
nuclear@16
|
439 {
|
nuclear@16
|
440 mesh->vertices.clear();
|
nuclear@16
|
441 mesh->normals.clear();
|
nuclear@16
|
442 mesh->tangents.clear();
|
nuclear@16
|
443 mesh->texcoords.clear();
|
nuclear@16
|
444 mesh->skin_weights.clear();
|
nuclear@16
|
445 mesh->skin_matrices.clear();
|
nuclear@16
|
446 mesh->colors.clear();
|
nuclear@16
|
447 mesh->faces.clear();
|
nuclear@16
|
448
|
nuclear@16
|
449 im_mesh = mesh;
|
nuclear@16
|
450 memset(im_use, 0, sizeof im_use);
|
nuclear@16
|
451
|
nuclear@16
|
452 im_prim = prim;
|
nuclear@16
|
453 }
|
nuclear@16
|
454
|
nuclear@41
|
455 GOAT3DAPI void goat3d_end(void)
|
nuclear@16
|
456 {
|
nuclear@16
|
457 switch(im_prim) {
|
nuclear@16
|
458 case GOAT3D_TRIANGLES:
|
nuclear@17
|
459 {
|
nuclear@17
|
460 int num_faces = (int)im_mesh->vertices.size() / 3;
|
nuclear@17
|
461 im_mesh->faces.resize(num_faces);
|
nuclear@17
|
462
|
nuclear@17
|
463 int vidx = 0;
|
nuclear@17
|
464 for(int i=0; i<num_faces; i++) {
|
nuclear@17
|
465 im_mesh->faces[i].v[0] = vidx++;
|
nuclear@17
|
466 im_mesh->faces[i].v[1] = vidx++;
|
nuclear@17
|
467 im_mesh->faces[i].v[2] = vidx++;
|
nuclear@17
|
468 }
|
nuclear@17
|
469 }
|
nuclear@16
|
470 break;
|
nuclear@16
|
471
|
nuclear@16
|
472 case GOAT3D_QUADS:
|
nuclear@17
|
473 {
|
nuclear@17
|
474 int num_quads = (int)im_mesh->vertices.size() / 4;
|
nuclear@17
|
475 im_mesh->faces.resize(num_quads * 2);
|
nuclear@17
|
476
|
nuclear@17
|
477 int vidx = 0;
|
nuclear@17
|
478 for(int i=0; i<num_quads; i++) {
|
nuclear@17
|
479 im_mesh->faces[i * 2].v[0] = vidx;
|
nuclear@17
|
480 im_mesh->faces[i * 2].v[1] = vidx + 1;
|
nuclear@17
|
481 im_mesh->faces[i * 2].v[2] = vidx + 2;
|
nuclear@17
|
482
|
nuclear@17
|
483 im_mesh->faces[i * 2 + 1].v[0] = vidx;
|
nuclear@17
|
484 im_mesh->faces[i * 2 + 1].v[1] = vidx + 2;
|
nuclear@17
|
485 im_mesh->faces[i * 2 + 1].v[2] = vidx + 3;
|
nuclear@17
|
486
|
nuclear@17
|
487 vidx += 4;
|
nuclear@17
|
488 }
|
nuclear@17
|
489 }
|
nuclear@16
|
490 break;
|
nuclear@16
|
491
|
nuclear@16
|
492 default:
|
nuclear@16
|
493 return;
|
nuclear@16
|
494 };
|
nuclear@16
|
495 }
|
nuclear@16
|
496
|
nuclear@41
|
497 GOAT3DAPI void goat3d_vertex3f(float x, float y, float z)
|
nuclear@16
|
498 {
|
nuclear@16
|
499 im_mesh->vertices.push_back(Vector3(x, y, z));
|
nuclear@16
|
500 if(im_use[GOAT3D_MESH_ATTR_NORMAL]) {
|
nuclear@16
|
501 im_mesh->normals.push_back(im_norm);
|
nuclear@16
|
502 }
|
nuclear@16
|
503 if(im_use[GOAT3D_MESH_ATTR_TANGENT]) {
|
nuclear@16
|
504 im_mesh->tangents.push_back(im_tang);
|
nuclear@16
|
505 }
|
nuclear@16
|
506 if(im_use[GOAT3D_MESH_ATTR_TEXCOORD]) {
|
nuclear@16
|
507 im_mesh->texcoords.push_back(im_texcoord);
|
nuclear@16
|
508 }
|
nuclear@16
|
509 if(im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT]) {
|
nuclear@16
|
510 im_mesh->skin_weights.push_back(im_skinw);
|
nuclear@16
|
511 }
|
nuclear@16
|
512 if(im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX]) {
|
nuclear@16
|
513 im_mesh->skin_matrices.push_back(im_skinmat);
|
nuclear@16
|
514 }
|
nuclear@16
|
515 if(im_use[GOAT3D_MESH_ATTR_COLOR]) {
|
nuclear@16
|
516 im_mesh->colors.push_back(im_color);
|
nuclear@16
|
517 }
|
nuclear@16
|
518 }
|
nuclear@16
|
519
|
nuclear@41
|
520 GOAT3DAPI void goat3d_normal3f(float x, float y, float z)
|
nuclear@16
|
521 {
|
nuclear@16
|
522 im_norm = Vector3(x, y, z);
|
nuclear@17
|
523 im_use[GOAT3D_MESH_ATTR_NORMAL] = true;
|
nuclear@16
|
524 }
|
nuclear@16
|
525
|
nuclear@41
|
526 GOAT3DAPI void goat3d_tangent3f(float x, float y, float z)
|
nuclear@16
|
527 {
|
nuclear@16
|
528 im_tang = Vector3(x, y, z);
|
nuclear@17
|
529 im_use[GOAT3D_MESH_ATTR_TANGENT] = true;
|
nuclear@16
|
530 }
|
nuclear@16
|
531
|
nuclear@41
|
532 GOAT3DAPI void goat3d_texcoord2f(float x, float y)
|
nuclear@16
|
533 {
|
nuclear@16
|
534 im_texcoord = Vector2(x, y);
|
nuclear@17
|
535 im_use[GOAT3D_MESH_ATTR_TEXCOORD] = true;
|
nuclear@16
|
536 }
|
nuclear@16
|
537
|
nuclear@41
|
538 GOAT3DAPI void goat3d_skin_weight4f(float x, float y, float z, float w)
|
nuclear@16
|
539 {
|
nuclear@16
|
540 im_skinw = Vector4(x, y, z, w);
|
nuclear@17
|
541 im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT] = true;
|
nuclear@16
|
542 }
|
nuclear@16
|
543
|
nuclear@41
|
544 GOAT3DAPI void goat3d_skin_matrix4i(int x, int y, int z, int w)
|
nuclear@16
|
545 {
|
nuclear@16
|
546 im_skinmat.x = x;
|
nuclear@16
|
547 im_skinmat.y = y;
|
nuclear@16
|
548 im_skinmat.z = z;
|
nuclear@16
|
549 im_skinmat.w = w;
|
nuclear@17
|
550 im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX] = true;
|
nuclear@16
|
551 }
|
nuclear@16
|
552
|
nuclear@41
|
553 GOAT3DAPI void goat3d_color3f(float x, float y, float z)
|
nuclear@16
|
554 {
|
nuclear@17
|
555 goat3d_color4f(x, y, z, 1.0f);
|
nuclear@16
|
556 }
|
nuclear@16
|
557
|
nuclear@41
|
558 GOAT3DAPI void goat3d_color4f(float x, float y, float z, float w)
|
nuclear@16
|
559 {
|
nuclear@16
|
560 im_color = Vector4(x, y, z, w);
|
nuclear@17
|
561 im_use[GOAT3D_MESH_ATTR_COLOR] = true;
|
nuclear@16
|
562 }
|
nuclear@16
|
563
|
nuclear@27
|
564 /* lights */
|
nuclear@41
|
565 GOAT3DAPI void goat3d_add_light(struct goat3d *g, struct goat3d_light *lt)
|
nuclear@16
|
566 {
|
nuclear@27
|
567 g->scn->add_light(lt);
|
nuclear@16
|
568 }
|
nuclear@16
|
569
|
nuclear@41
|
570 GOAT3DAPI int goat3d_get_light_count(struct goat3d *g)
|
nuclear@19
|
571 {
|
nuclear@27
|
572 return g->scn->get_light_count();
|
nuclear@19
|
573 }
|
nuclear@19
|
574
|
nuclear@41
|
575 GOAT3DAPI struct goat3d_light *goat3d_get_light(struct goat3d *g, int idx)
|
nuclear@19
|
576 {
|
nuclear@27
|
577 return (goat3d_light*)g->scn->get_light(idx);
|
nuclear@19
|
578 }
|
nuclear@19
|
579
|
nuclear@41
|
580 GOAT3DAPI struct goat3d_light *goat3d_get_light_by_name(struct goat3d *g, const char *name)
|
nuclear@27
|
581 {
|
nuclear@27
|
582 return (goat3d_light*)g->scn->get_light(name);
|
nuclear@27
|
583 }
|
nuclear@27
|
584
|
nuclear@27
|
585
|
nuclear@41
|
586 GOAT3DAPI struct goat3d_light *goat3d_create_light(void)
|
nuclear@27
|
587 {
|
nuclear@27
|
588 return new goat3d_light;
|
nuclear@27
|
589 }
|
nuclear@27
|
590
|
nuclear@41
|
591 GOAT3DAPI void goat3d_destroy_light(struct goat3d_light *lt)
|
nuclear@27
|
592 {
|
nuclear@27
|
593 delete lt;
|
nuclear@27
|
594 }
|
nuclear@27
|
595
|
nuclear@27
|
596
|
nuclear@27
|
597 /* cameras */
|
nuclear@41
|
598 GOAT3DAPI void goat3d_add_camera(struct goat3d *g, struct goat3d_camera *cam)
|
nuclear@27
|
599 {
|
nuclear@27
|
600 g->scn->add_camera(cam);
|
nuclear@27
|
601 }
|
nuclear@27
|
602
|
nuclear@41
|
603 GOAT3DAPI int goat3d_get_camera_count(struct goat3d *g)
|
nuclear@27
|
604 {
|
nuclear@27
|
605 return g->scn->get_camera_count();
|
nuclear@27
|
606 }
|
nuclear@27
|
607
|
nuclear@41
|
608 GOAT3DAPI struct goat3d_camera *goat3d_get_camera(struct goat3d *g, int idx)
|
nuclear@27
|
609 {
|
nuclear@27
|
610 return (goat3d_camera*)g->scn->get_camera(idx);
|
nuclear@27
|
611 }
|
nuclear@27
|
612
|
nuclear@41
|
613 GOAT3DAPI struct goat3d_camera *goat3d_get_camera_by_name(struct goat3d *g, const char *name)
|
nuclear@27
|
614 {
|
nuclear@27
|
615 return (goat3d_camera*)g->scn->get_camera(name);
|
nuclear@27
|
616 }
|
nuclear@27
|
617
|
nuclear@41
|
618 GOAT3DAPI struct goat3d_camera *goat3d_create_camera(void)
|
nuclear@27
|
619 {
|
nuclear@27
|
620 return new goat3d_camera;
|
nuclear@27
|
621 }
|
nuclear@27
|
622
|
nuclear@41
|
623 GOAT3DAPI void goat3d_destroy_camera(struct goat3d_camera *cam)
|
nuclear@27
|
624 {
|
nuclear@27
|
625 delete cam;
|
nuclear@27
|
626 }
|
nuclear@27
|
627
|
nuclear@27
|
628
|
nuclear@16
|
629
|
nuclear@25
|
630 // node
|
nuclear@41
|
631 GOAT3DAPI void goat3d_add_node(struct goat3d *g, struct goat3d_node *node)
|
nuclear@27
|
632 {
|
nuclear@27
|
633 g->scn->add_node(node);
|
nuclear@27
|
634 }
|
nuclear@27
|
635
|
nuclear@41
|
636 GOAT3DAPI int goat3d_get_node_count(struct goat3d *g)
|
nuclear@27
|
637 {
|
nuclear@27
|
638 return g->scn->get_node_count();
|
nuclear@27
|
639 }
|
nuclear@27
|
640
|
nuclear@41
|
641 GOAT3DAPI struct goat3d_node *goat3d_get_node(struct goat3d *g, int idx)
|
nuclear@27
|
642 {
|
nuclear@27
|
643 return (goat3d_node*)g->scn->get_node(idx);
|
nuclear@27
|
644 }
|
nuclear@27
|
645
|
nuclear@41
|
646 GOAT3DAPI struct goat3d_node *goat3d_get_node_by_name(struct goat3d *g, const char *name)
|
nuclear@27
|
647 {
|
nuclear@27
|
648 return (goat3d_node*)g->scn->get_node(name);
|
nuclear@27
|
649 }
|
nuclear@25
|
650
|
nuclear@41
|
651 GOAT3DAPI struct goat3d_node *goat3d_create_node(void)
|
nuclear@25
|
652 {
|
nuclear@25
|
653 return new goat3d_node;
|
nuclear@25
|
654 }
|
nuclear@25
|
655
|
nuclear@41
|
656 GOAT3DAPI void goat3d_set_node_name(struct goat3d_node *node, const char *name)
|
nuclear@25
|
657 {
|
nuclear@25
|
658 node->set_name(name);
|
nuclear@25
|
659 }
|
nuclear@25
|
660
|
nuclear@41
|
661 GOAT3DAPI const char *goat3d_get_node_name(const struct goat3d_node *node)
|
nuclear@25
|
662 {
|
nuclear@25
|
663 return node->get_name();
|
nuclear@25
|
664 }
|
nuclear@25
|
665
|
nuclear@41
|
666 GOAT3DAPI void goat3d_set_node_object(struct goat3d_node *node, enum goat3d_node_type type, void *obj)
|
nuclear@25
|
667 {
|
nuclear@25
|
668 node->set_object((Object*)obj);
|
nuclear@25
|
669 }
|
nuclear@25
|
670
|
nuclear@41
|
671 GOAT3DAPI void *goat3d_get_node_object(const struct goat3d_node *node)
|
nuclear@25
|
672 {
|
nuclear@26
|
673 return (void*)node->get_object();
|
nuclear@25
|
674 }
|
nuclear@25
|
675
|
nuclear@41
|
676 GOAT3DAPI enum goat3d_node_type goat3d_get_node_type(const struct goat3d_node *node)
|
nuclear@25
|
677 {
|
nuclear@26
|
678 const Object *obj = node->get_object();
|
nuclear@26
|
679 if(dynamic_cast<const Mesh*>(obj)) {
|
nuclear@26
|
680 return GOAT3D_NODE_MESH;
|
nuclear@26
|
681 }
|
nuclear@26
|
682 if(dynamic_cast<const Light*>(obj)) {
|
nuclear@26
|
683 return GOAT3D_NODE_LIGHT;
|
nuclear@26
|
684 }
|
nuclear@26
|
685 if(dynamic_cast<const Camera*>(obj)) {
|
nuclear@26
|
686 return GOAT3D_NODE_CAMERA;
|
nuclear@26
|
687 }
|
nuclear@26
|
688
|
nuclear@26
|
689 return GOAT3D_NODE_NULL;
|
nuclear@25
|
690 }
|
nuclear@25
|
691
|
nuclear@41
|
692 GOAT3DAPI void goat3d_add_node_child(struct goat3d_node *node, struct goat3d_node *child)
|
nuclear@25
|
693 {
|
nuclear@26
|
694 node->add_child(node);
|
nuclear@25
|
695 }
|
nuclear@25
|
696
|
nuclear@41
|
697 GOAT3DAPI int goat3d_get_node_child_count(const struct goat3d_node *node)
|
nuclear@25
|
698 {
|
nuclear@26
|
699 return node->get_children_count();
|
nuclear@25
|
700 }
|
nuclear@25
|
701
|
nuclear@41
|
702 GOAT3DAPI struct goat3d_node *goat3d_get_node_child(const struct goat3d_node *node, int idx)
|
nuclear@25
|
703 {
|
nuclear@26
|
704 return (goat3d_node*)node->get_child(idx);
|
nuclear@25
|
705 }
|
nuclear@25
|
706
|
nuclear@41
|
707 GOAT3DAPI void goat3d_set_node_position(struct goat3d_node *node, float x, float y, float z, long tmsec)
|
nuclear@25
|
708 {
|
nuclear@26
|
709 node->set_position(Vector3(x, y, z), tmsec);
|
nuclear@25
|
710 }
|
nuclear@25
|
711
|
nuclear@41
|
712 GOAT3DAPI void goat3d_set_node_rotation(struct goat3d_node *node, float qx, float qy, float qz, float qw, long tmsec)
|
nuclear@25
|
713 {
|
nuclear@26
|
714 node->set_rotation(Quaternion(qw, qx, qy, qz), tmsec);
|
nuclear@25
|
715 }
|
nuclear@25
|
716
|
nuclear@41
|
717 GOAT3DAPI void goat3d_set_node_scaling(struct goat3d_node *node, float sx, float sy, float sz, long tmsec)
|
nuclear@25
|
718 {
|
nuclear@26
|
719 node->set_scaling(Vector3(sx, sy, sz), tmsec);
|
nuclear@25
|
720 }
|
nuclear@25
|
721
|
nuclear@41
|
722 GOAT3DAPI void goat3d_set_node_pivot(struct goat3d_node *node, float px, float py, float pz)
|
nuclear@25
|
723 {
|
nuclear@26
|
724 node->set_pivot(Vector3(px, py, pz));
|
nuclear@25
|
725 }
|
nuclear@25
|
726
|
nuclear@25
|
727
|
nuclear@41
|
728 GOAT3DAPI void goat3d_get_node_position(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, long tmsec)
|
nuclear@25
|
729 {
|
nuclear@26
|
730 Vector3 pos = node->get_position(tmsec);
|
nuclear@26
|
731 *xptr = pos.x;
|
nuclear@26
|
732 *yptr = pos.y;
|
nuclear@26
|
733 *zptr = pos.z;
|
nuclear@25
|
734 }
|
nuclear@25
|
735
|
nuclear@41
|
736 GOAT3DAPI void goat3d_get_node_rotation(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, float *wptr, long tmsec)
|
nuclear@25
|
737 {
|
nuclear@26
|
738 Quaternion q = node->get_rotation(tmsec);
|
nuclear@26
|
739 *xptr = q.v.x;
|
nuclear@26
|
740 *yptr = q.v.y;
|
nuclear@26
|
741 *zptr = q.v.z;
|
nuclear@26
|
742 *wptr = q.s;
|
nuclear@25
|
743 }
|
nuclear@25
|
744
|
nuclear@41
|
745 GOAT3DAPI void goat3d_get_node_scaling(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, long tmsec)
|
nuclear@25
|
746 {
|
nuclear@26
|
747 Vector3 scale = node->get_scaling(tmsec);
|
nuclear@26
|
748 *xptr = scale.x;
|
nuclear@26
|
749 *yptr = scale.y;
|
nuclear@26
|
750 *zptr = scale.z;
|
nuclear@25
|
751 }
|
nuclear@25
|
752
|
nuclear@41
|
753 GOAT3DAPI void goat3d_get_node_pivot(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr)
|
nuclear@25
|
754 {
|
nuclear@26
|
755 Vector3 pivot = node->get_pivot();
|
nuclear@26
|
756 *xptr = pivot.x;
|
nuclear@26
|
757 *yptr = pivot.y;
|
nuclear@26
|
758 *zptr = pivot.z;
|
nuclear@25
|
759 }
|
nuclear@25
|
760
|
nuclear@25
|
761
|
nuclear@41
|
762 GOAT3DAPI void goat3d_get_node_matrix(const struct goat3d_node *node, float *matrix, long tmsec)
|
nuclear@25
|
763 {
|
nuclear@26
|
764 node->get_xform(tmsec, (Matrix4x4*)matrix);
|
nuclear@25
|
765 }
|
nuclear@25
|
766
|
nuclear@25
|
767
|
nuclear@16
|
768 } // extern "C"
|
nuclear@16
|
769
|
nuclear@16
|
770
|
nuclear@16
|
771 static long read_file(void *buf, size_t bytes, void *uptr)
|
nuclear@16
|
772 {
|
nuclear@16
|
773 return (long)fread(buf, 1, bytes, (FILE*)uptr);
|
nuclear@16
|
774 }
|
nuclear@16
|
775
|
nuclear@16
|
776 static long write_file(const void *buf, size_t bytes, void *uptr)
|
nuclear@16
|
777 {
|
nuclear@16
|
778 return (long)fwrite(buf, 1, bytes, (FILE*)uptr);
|
nuclear@16
|
779 }
|
nuclear@16
|
780
|
nuclear@16
|
781 static long seek_file(long offs, int whence, void *uptr)
|
nuclear@16
|
782 {
|
nuclear@16
|
783 if(fseek((FILE*)uptr, offs, whence) == -1) {
|
nuclear@16
|
784 return -1;
|
nuclear@16
|
785 }
|
nuclear@16
|
786 return ftell((FILE*)uptr);
|
nuclear@16
|
787 }
|
nuclear@31
|
788
|
nuclear@40
|
789 std::string goat3d_clean_filename(const char *str)
|
nuclear@31
|
790 {
|
nuclear@31
|
791 const char *last_slash = strrchr(str, '/');
|
nuclear@31
|
792 if(!last_slash) {
|
nuclear@31
|
793 last_slash = strrchr(str, '\\');
|
nuclear@31
|
794 }
|
nuclear@31
|
795
|
nuclear@31
|
796 if(last_slash) {
|
nuclear@31
|
797 str = last_slash + 1;
|
nuclear@31
|
798 }
|
nuclear@31
|
799
|
nuclear@31
|
800 char *buf = (char*)alloca(strlen(str) + 1);
|
nuclear@31
|
801 char *dest = buf;
|
nuclear@31
|
802 while(*str) {
|
nuclear@31
|
803 char c = *str++;
|
nuclear@31
|
804 *dest++ = tolower(c);
|
nuclear@31
|
805 }
|
nuclear@40
|
806 *dest = 0;
|
nuclear@31
|
807 return buf;
|
nuclear@31
|
808 }
|