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@14
|
18 #include <stdarg.h>
|
nuclear@0
|
19 #include "goat3d.h"
|
nuclear@0
|
20 #include "goat3d_impl.h"
|
nuclear@9
|
21 #include "chunk.h"
|
nuclear@0
|
22
|
nuclear@47
|
23 using namespace g3dimpl;
|
nuclear@47
|
24
|
nuclear@0
|
25 Scene::Scene()
|
nuclear@0
|
26 : name("unnamed"), ambient(0.05, 0.05, 0.05)
|
nuclear@0
|
27 {
|
nuclear@74
|
28 goat = 0;
|
nuclear@75
|
29 bbox_valid = false;
|
nuclear@0
|
30 }
|
nuclear@0
|
31
|
nuclear@0
|
32 Scene::~Scene()
|
nuclear@0
|
33 {
|
nuclear@0
|
34 clear();
|
nuclear@0
|
35 }
|
nuclear@0
|
36
|
nuclear@0
|
37 void Scene::clear()
|
nuclear@0
|
38 {
|
nuclear@0
|
39 for(size_t i=0; i<materials.size(); i++) {
|
nuclear@0
|
40 delete materials[i];
|
nuclear@0
|
41 }
|
nuclear@0
|
42 materials.clear();
|
nuclear@0
|
43
|
nuclear@0
|
44 for(size_t i=0; i<meshes.size(); i++) {
|
nuclear@0
|
45 delete meshes[i];
|
nuclear@0
|
46 }
|
nuclear@0
|
47 meshes.clear();
|
nuclear@0
|
48
|
nuclear@0
|
49 for(size_t i=0; i<lights.size(); i++) {
|
nuclear@0
|
50 delete lights[i];
|
nuclear@0
|
51 }
|
nuclear@0
|
52 lights.clear();
|
nuclear@0
|
53
|
nuclear@0
|
54 for(size_t i=0; i<cameras.size(); i++) {
|
nuclear@0
|
55 delete cameras[i];
|
nuclear@0
|
56 }
|
nuclear@0
|
57 cameras.clear();
|
nuclear@0
|
58
|
nuclear@12
|
59 for(size_t i=0; i<nodes.size(); i++) {
|
nuclear@66
|
60 delete nodes[i];
|
nuclear@0
|
61 }
|
nuclear@12
|
62 nodes.clear();
|
nuclear@0
|
63
|
nuclear@0
|
64 name = "unnamed";
|
nuclear@75
|
65 bbox_valid = false;
|
nuclear@0
|
66 }
|
nuclear@0
|
67
|
nuclear@0
|
68 void Scene::set_name(const char *name)
|
nuclear@0
|
69 {
|
nuclear@0
|
70 this->name = name;
|
nuclear@0
|
71 }
|
nuclear@0
|
72
|
nuclear@0
|
73 const char *Scene::get_name() const
|
nuclear@0
|
74 {
|
nuclear@0
|
75 return name.c_str();
|
nuclear@0
|
76 }
|
nuclear@8
|
77
|
nuclear@8
|
78 void Scene::set_ambient(const Vector3 &amb)
|
nuclear@8
|
79 {
|
nuclear@8
|
80 ambient = amb;
|
nuclear@8
|
81 }
|
nuclear@8
|
82
|
nuclear@8
|
83 const Vector3 &Scene::get_ambient() const
|
nuclear@8
|
84 {
|
nuclear@8
|
85 return ambient;
|
nuclear@8
|
86 }
|
nuclear@8
|
87
|
nuclear@8
|
88 void Scene::add_material(Material *mat)
|
nuclear@8
|
89 {
|
nuclear@17
|
90 if(mat->name.empty()) {
|
nuclear@17
|
91 char buf[64];
|
nuclear@17
|
92 sprintf(buf, "material%04d", (int)materials.size());
|
nuclear@17
|
93 mat->name = std::string(buf);
|
nuclear@17
|
94 }
|
nuclear@8
|
95 materials.push_back(mat);
|
nuclear@8
|
96 }
|
nuclear@8
|
97
|
nuclear@8
|
98 Material *Scene::get_material(int idx) const
|
nuclear@8
|
99 {
|
nuclear@8
|
100 return idx >=0 && idx < (int)materials.size() ? materials[idx] : 0;
|
nuclear@8
|
101 }
|
nuclear@8
|
102
|
nuclear@8
|
103 Material *Scene::get_material(const char *name) const
|
nuclear@8
|
104 {
|
nuclear@8
|
105 for(size_t i=0; i<materials.size(); i++) {
|
nuclear@8
|
106 if(materials[i]->name == std::string(name)) {
|
nuclear@8
|
107 return materials[i];
|
nuclear@8
|
108 }
|
nuclear@8
|
109 }
|
nuclear@8
|
110 return 0;
|
nuclear@8
|
111 }
|
nuclear@8
|
112
|
nuclear@9
|
113 int Scene::get_material_count() const
|
nuclear@9
|
114 {
|
nuclear@9
|
115 return (int)materials.size();
|
nuclear@9
|
116 }
|
nuclear@9
|
117
|
nuclear@9
|
118
|
nuclear@8
|
119 void Scene::add_mesh(Mesh *mesh)
|
nuclear@8
|
120 {
|
nuclear@17
|
121 if(mesh->name.empty()) {
|
nuclear@17
|
122 char buf[64];
|
nuclear@17
|
123 sprintf(buf, "mesh%04d", (int)meshes.size());
|
nuclear@17
|
124 mesh->name = std::string(buf);
|
nuclear@17
|
125 }
|
nuclear@8
|
126 meshes.push_back(mesh);
|
nuclear@8
|
127 }
|
nuclear@8
|
128
|
nuclear@8
|
129 Mesh *Scene::get_mesh(int idx) const
|
nuclear@8
|
130 {
|
nuclear@8
|
131 return idx >= 0 && idx < (int)meshes.size() ? meshes[idx] : 0;
|
nuclear@8
|
132 }
|
nuclear@8
|
133
|
nuclear@8
|
134 Mesh *Scene::get_mesh(const char *name) const
|
nuclear@8
|
135 {
|
nuclear@8
|
136 for(size_t i=0; i<meshes.size(); i++) {
|
nuclear@8
|
137 if(meshes[i]->name == std::string(name)) {
|
nuclear@8
|
138 return meshes[i];
|
nuclear@8
|
139 }
|
nuclear@8
|
140 }
|
nuclear@8
|
141 return 0;
|
nuclear@8
|
142 }
|
nuclear@8
|
143
|
nuclear@9
|
144 int Scene::get_mesh_count() const
|
nuclear@9
|
145 {
|
nuclear@9
|
146 return (int)meshes.size();
|
nuclear@9
|
147 }
|
nuclear@9
|
148
|
nuclear@9
|
149
|
nuclear@8
|
150 void Scene::add_light(Light *light)
|
nuclear@8
|
151 {
|
nuclear@8
|
152 lights.push_back(light);
|
nuclear@8
|
153 }
|
nuclear@8
|
154
|
nuclear@8
|
155 Light *Scene::get_light(int idx) const
|
nuclear@8
|
156 {
|
nuclear@8
|
157 return idx >= 0 && idx < (int)lights.size() ? lights[idx] : 0;
|
nuclear@8
|
158 }
|
nuclear@8
|
159
|
nuclear@8
|
160 Light *Scene::get_light(const char *name) const
|
nuclear@8
|
161 {
|
nuclear@8
|
162 for(size_t i=0; i<lights.size(); i++) {
|
nuclear@8
|
163 if(lights[i]->name == std::string(name)) {
|
nuclear@8
|
164 return lights[i];
|
nuclear@8
|
165 }
|
nuclear@8
|
166 }
|
nuclear@8
|
167 return 0;
|
nuclear@8
|
168 }
|
nuclear@8
|
169
|
nuclear@9
|
170 int Scene::get_light_count() const
|
nuclear@9
|
171 {
|
nuclear@9
|
172 return (int)lights.size();
|
nuclear@9
|
173 }
|
nuclear@9
|
174
|
nuclear@9
|
175
|
nuclear@8
|
176 void Scene::add_camera(Camera *cam)
|
nuclear@8
|
177 {
|
nuclear@8
|
178 cameras.push_back(cam);
|
nuclear@8
|
179 }
|
nuclear@8
|
180
|
nuclear@8
|
181 Camera *Scene::get_camera(int idx) const
|
nuclear@8
|
182 {
|
nuclear@8
|
183 return idx >= 0 && idx < (int)cameras.size() ? cameras[idx] : 0;
|
nuclear@8
|
184 }
|
nuclear@8
|
185
|
nuclear@8
|
186 Camera *Scene::get_camera(const char *name) const
|
nuclear@8
|
187 {
|
nuclear@8
|
188 for(size_t i=0; i<cameras.size(); i++) {
|
nuclear@8
|
189 if(cameras[i]->name == std::string(name)) {
|
nuclear@8
|
190 return cameras[i];
|
nuclear@8
|
191 }
|
nuclear@8
|
192 }
|
nuclear@8
|
193 return 0;
|
nuclear@8
|
194 }
|
nuclear@8
|
195
|
nuclear@9
|
196 int Scene::get_camera_count() const
|
nuclear@9
|
197 {
|
nuclear@9
|
198 return (int)cameras.size();
|
nuclear@9
|
199 }
|
nuclear@9
|
200
|
nuclear@9
|
201
|
nuclear@8
|
202 void Scene::add_node(Node *node)
|
nuclear@8
|
203 {
|
nuclear@8
|
204 nodes.push_back(node);
|
nuclear@8
|
205 }
|
nuclear@8
|
206
|
nuclear@8
|
207 Node *Scene::get_node(int idx) const
|
nuclear@8
|
208 {
|
nuclear@8
|
209 return idx >= 0 && idx < (int)nodes.size() ? nodes[idx] : 0;
|
nuclear@8
|
210 }
|
nuclear@8
|
211
|
nuclear@8
|
212 Node *Scene::get_node(const char *name) const
|
nuclear@8
|
213 {
|
nuclear@8
|
214 for(size_t i=0; i<nodes.size(); i++) {
|
nuclear@8
|
215 if(strcmp(nodes[i]->get_name(), name) == 0) {
|
nuclear@8
|
216 return nodes[i];
|
nuclear@8
|
217 }
|
nuclear@8
|
218 }
|
nuclear@8
|
219 return 0;
|
nuclear@8
|
220 }
|
nuclear@8
|
221
|
nuclear@9
|
222 int Scene::get_node_count() const
|
nuclear@9
|
223 {
|
nuclear@9
|
224 return (int)nodes.size();
|
nuclear@9
|
225 }
|
nuclear@9
|
226
|
nuclear@75
|
227 const AABox &Scene::get_bounds() const
|
nuclear@75
|
228 {
|
nuclear@75
|
229 if(!bbox_valid) {
|
nuclear@75
|
230 bbox = AABox();
|
nuclear@75
|
231
|
nuclear@75
|
232 for(size_t i=0; i<nodes.size(); i++) {
|
nuclear@75
|
233 if(nodes[i]->get_parent()) {
|
nuclear@75
|
234 continue;
|
nuclear@75
|
235 }
|
nuclear@75
|
236
|
nuclear@75
|
237 bbox = aabox_union(bbox, nodes[i]->get_bounds());
|
nuclear@75
|
238 }
|
nuclear@75
|
239 bbox_valid = true;
|
nuclear@75
|
240 }
|
nuclear@75
|
241
|
nuclear@75
|
242 return bbox;
|
nuclear@75
|
243 }
|
nuclear@75
|
244
|
nuclear@50
|
245 // Scene::load is defined in goat3d_read.cc
|
nuclear@19
|
246 // Scene::loadxml is defined in goat3d_readxml.cc
|
nuclear@14
|
247 // Scene::save is defined in goat3d_write.cc
|
nuclear@19
|
248 // Scene::savexml is defined in goat3d_writexml.cc
|
nuclear@9
|
249
|
nuclear@9
|
250
|
nuclear@47
|
251 void g3dimpl::io_fprintf(goat3d_io *io, const char *fmt, ...)
|
nuclear@8
|
252 {
|
nuclear@14
|
253 va_list ap;
|
nuclear@9
|
254
|
nuclear@14
|
255 va_start(ap, fmt);
|
nuclear@14
|
256 io_vfprintf(io, fmt, ap);
|
nuclear@14
|
257 va_end(ap);
|
nuclear@14
|
258 }
|
nuclear@9
|
259
|
nuclear@9
|
260
|
nuclear@47
|
261 void g3dimpl::io_vfprintf(goat3d_io *io, const char *fmt, va_list ap)
|
nuclear@14
|
262 {
|
nuclear@14
|
263 char smallbuf[256];
|
nuclear@14
|
264 char *buf = smallbuf;
|
nuclear@14
|
265 int sz = sizeof smallbuf;
|
nuclear@9
|
266
|
nuclear@14
|
267 int retsz = vsnprintf(buf, sz - 1, fmt, ap);
|
nuclear@9
|
268
|
nuclear@14
|
269 if(retsz >= sz) {
|
nuclear@14
|
270 /* C99 mandates that snprintf with a short count should return the
|
nuclear@14
|
271 * number of characters that *would* be printed.
|
nuclear@14
|
272 */
|
nuclear@14
|
273 buf = new char[retsz + 1];
|
nuclear@9
|
274
|
nuclear@14
|
275 vsnprintf(buf, retsz, fmt, ap);
|
nuclear@9
|
276
|
nuclear@14
|
277 } else if(retsz <= 0) {
|
nuclear@14
|
278 /* SUSv2 and microsoft specify that snprintf with a short count
|
nuclear@14
|
279 * returns an arbitrary value <= 0. So let's try allocating
|
nuclear@14
|
280 * bigger and bigger arrays until we find the correct size.
|
nuclear@14
|
281 */
|
nuclear@14
|
282 sz = sizeof smallbuf;
|
nuclear@14
|
283 do {
|
nuclear@14
|
284 sz *= 2;
|
nuclear@14
|
285 if(buf != smallbuf) {
|
nuclear@14
|
286 delete [] buf;
|
nuclear@14
|
287 }
|
nuclear@14
|
288 buf = new char[sz + 1];
|
nuclear@9
|
289
|
nuclear@14
|
290 retsz = vsnprintf(buf, sz, fmt, ap);
|
nuclear@14
|
291 } while(retsz <= 0);
|
nuclear@9
|
292 }
|
nuclear@9
|
293
|
nuclear@15
|
294 io->write(buf, retsz, io->cls);
|
nuclear@9
|
295
|
nuclear@14
|
296 if(buf != smallbuf) {
|
nuclear@14
|
297 delete [] buf;
|
nuclear@9
|
298 }
|
nuclear@9
|
299
|
nuclear@9
|
300 }
|