Mercurial > hg > forks > gldragon
comparison dmscene.cpp @ 61:7b138613e2fc
Rename dmmodel.* to dmscene.*
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 14 Dec 2019 14:08:51 +0200 |
parents | dmmodel.cpp@0ae1ff609626 |
children | 03aa729a9e90 |
comparison
equal
deleted
inserted
replaced
60:f645e38e3157 | 61:7b138613e2fc |
---|---|
1 // | |
2 // GLDragon - OpenGL PLY model viewer / simple benchmark | |
3 // -- Scene and model handling + PLY file parsing | |
4 // Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org> | |
5 // (C) Copyright 2019 Tecnic Software productions (TNSP) | |
6 // | |
7 // See file "COPYING" for license information. | |
8 // | |
9 #include "dmscene.h" | |
10 #include <SDL_endian.h> | |
11 | |
12 | |
13 static bool dmTextError(DMTextFileInfo &info, const std::string &msg) | |
14 { | |
15 dmError("%s on line #%d: %s\n", | |
16 msg.c_str(), info.nline, info.line.c_str()); | |
17 return false; | |
18 } | |
19 | |
20 | |
21 static bool dmSyntaxError(DMTextFileInfo &info, const std::string &msg) | |
22 { | |
23 dmError("Syntax error on line #%d: %s\n", | |
24 info.nline, msg.c_str()); | |
25 return false; | |
26 } | |
27 | |
28 | |
29 static bool dmReadLine(DMTextFileInfo &info) | |
30 { | |
31 if (!std::getline(info.file, info.line)) | |
32 return false; | |
33 | |
34 info.nline++; | |
35 | |
36 info.line = dmStrTrim(info.line); | |
37 | |
38 return true; | |
39 } | |
40 | |
41 | |
42 static DMPLYPropType dmPLYParsePropType(const std::string &name) | |
43 { | |
44 if (name == "list") | |
45 return PLY_TYPE_LIST; | |
46 else | |
47 if (name == "float" || name == "float32") | |
48 return PLY_TYPE_FLOAT; | |
49 else | |
50 if (name == "double" || name == "float64") | |
51 return PLY_TYPE_DOUBLE; | |
52 else | |
53 if (name == "uchar" || name == "uint8") | |
54 return PLY_TYPE_UINT8; | |
55 else | |
56 if (name == "int16") | |
57 return PLY_TYPE_INT16; | |
58 else | |
59 if (name == "uint16") | |
60 return PLY_TYPE_UINT16; | |
61 else | |
62 if (name == "int" || name == "int32") | |
63 return PLY_TYPE_INT32; | |
64 else | |
65 if (name == "uint" || name == "uint32") | |
66 return PLY_TYPE_UINT32; | |
67 else | |
68 return PLY_TYPE_NONE; | |
69 } | |
70 | |
71 | |
72 static bool dmPLYParsePropertyValueASCII(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval, size_t &pos) | |
73 { | |
74 size_t len = 0; | |
75 std::string val = info.line.substr(pos); | |
76 | |
77 switch (ptype) | |
78 { | |
79 case PLY_TYPE_INT8: | |
80 case PLY_TYPE_INT16: | |
81 case PLY_TYPE_INT32: | |
82 pval.v_int = std::stoi(val, &len); | |
83 break; | |
84 | |
85 case PLY_TYPE_UINT8: | |
86 case PLY_TYPE_UINT16: | |
87 case PLY_TYPE_UINT32: | |
88 pval.v_uint = std::stoi(val, &len); | |
89 break; | |
90 | |
91 case PLY_TYPE_FLOAT: | |
92 pval.v_float = std::stof(val, &len); | |
93 break; | |
94 | |
95 case PLY_TYPE_DOUBLE: | |
96 pval.v_double = std::stod(val, &len); | |
97 break; | |
98 | |
99 default: | |
100 return dmTextError(info, | |
101 "Internal error, unimplemented PLY property type"); | |
102 } | |
103 | |
104 pos += len; | |
105 | |
106 return true; | |
107 } | |
108 | |
109 | |
110 static bool dmPLYParsePropertyASCII(DMPLYFileInfo &info, DMPLYFileProperty &prop, size_t &pos) | |
111 { | |
112 switch (prop.type) | |
113 { | |
114 case PLY_TYPE_LIST: | |
115 prop.list_values.clear(); | |
116 | |
117 if (!dmPLYParsePropertyValueASCII(info, prop.list_num_type, prop.list_num_value, pos)) | |
118 return false; | |
119 | |
120 for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) | |
121 { | |
122 DMPLYPropValue pval; | |
123 if (!dmPLYParsePropertyValueASCII(info, prop.list_values_type, pval, pos)) | |
124 return false; | |
125 | |
126 prop.list_values.push_back(pval); | |
127 } | |
128 | |
129 if (prop.list_values.size() != prop.list_num_value.v_uint) | |
130 { | |
131 return dmSyntaxError(info, | |
132 "Number of property list '"+ prop.name +" values not equal to number specified"); | |
133 } | |
134 return true; | |
135 | |
136 default: | |
137 return dmPLYParsePropertyValueASCII(info, prop.type, prop.value, pos); | |
138 } | |
139 } | |
140 | |
141 | |
142 static bool dmPLYParseElementASCII(DMPLYFileInfo &info, DMPLYFileElement &element) | |
143 { | |
144 size_t nprop = 0, pos = 0; | |
145 | |
146 // Read one line | |
147 if (!dmReadLine(info)) | |
148 { | |
149 return dmTextError(info, | |
150 "Unexpected end of file"); | |
151 } | |
152 | |
153 // Skip empty lines | |
154 if (info.line.empty()) | |
155 return true; | |
156 | |
157 // Parse the properties | |
158 for (auto const prop : element.properties) | |
159 { | |
160 if (!dmPLYParsePropertyASCII(info, *prop, pos)) | |
161 return false; | |
162 | |
163 nprop++; | |
164 } | |
165 | |
166 if (nprop != element.properties.size()) | |
167 { | |
168 return dmSyntaxError(info, | |
169 "Expected N properties, got different number"); | |
170 } | |
171 | |
172 return true; | |
173 } | |
174 | |
175 | |
176 bool dmPLYReadPropertyValueBIN(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval) | |
177 { | |
178 uint8_t tmpU8; | |
179 int8_t tmpS8; | |
180 uint16_t tmpU16; | |
181 int16_t tmpS16; | |
182 uint32_t tmpU32; | |
183 int32_t tmpS32; | |
184 float tmpFloat; | |
185 | |
186 switch (ptype) | |
187 { | |
188 case PLY_TYPE_INT8: | |
189 info.file.read(reinterpret_cast<char *>(&tmpS8), 1); | |
190 pval.v_int = tmpS8; | |
191 break; | |
192 | |
193 case PLY_TYPE_UINT8: | |
194 info.file.read(reinterpret_cast<char *>(&tmpU8), 1); | |
195 pval.v_uint = tmpU8; | |
196 break; | |
197 | |
198 case PLY_TYPE_INT16: | |
199 info.file.read(reinterpret_cast<char *>(&tmpS16), 2); | |
200 tmpS16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpS16) : SDL_SwapBE16(tmpS16); | |
201 pval.v_int = tmpS16; | |
202 break; | |
203 | |
204 case PLY_TYPE_UINT16: | |
205 info.file.read(reinterpret_cast<char *>(&tmpU16), 2); | |
206 tmpU16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpU16) : SDL_SwapBE16(tmpU16); | |
207 pval.v_uint = tmpU16; | |
208 break; | |
209 | |
210 case PLY_TYPE_INT32: | |
211 info.file.read(reinterpret_cast<char *>(&tmpS32), 4); | |
212 tmpS32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpS32) : SDL_SwapBE32(tmpS32); | |
213 pval.v_int = tmpS32; | |
214 break; | |
215 | |
216 case PLY_TYPE_UINT32: | |
217 info.file.read(reinterpret_cast<char *>(&tmpU32), 4); | |
218 tmpU32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpU32) : SDL_SwapBE32(tmpU32); | |
219 pval.v_uint = tmpU32; | |
220 break; | |
221 | |
222 case PLY_TYPE_FLOAT: | |
223 info.file.read(reinterpret_cast<char *>(&tmpFloat), 4); | |
224 pval.v_float = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapFloatLE(tmpFloat) : SDL_SwapFloatBE(tmpFloat); | |
225 break; | |
226 | |
227 default: | |
228 return dmTextError(info, | |
229 "Internal error, unimplemented PLY property type"); | |
230 } | |
231 | |
232 return true; | |
233 } | |
234 | |
235 | |
236 bool dmPLYReadPropertyBIN(DMPLYFileInfo &info, DMPLYFileProperty &prop) | |
237 { | |
238 switch (prop.type) | |
239 { | |
240 case PLY_TYPE_LIST: | |
241 prop.list_values.clear(); | |
242 | |
243 if (!dmPLYReadPropertyValueBIN(info, prop.list_num_type, prop.list_num_value)) | |
244 return false; | |
245 | |
246 for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) | |
247 { | |
248 DMPLYPropValue pval; | |
249 if (!dmPLYReadPropertyValueBIN(info, prop.list_values_type, pval)) | |
250 return false; | |
251 | |
252 prop.list_values.push_back(pval); | |
253 } | |
254 | |
255 if (prop.list_values.size() != prop.list_num_value.v_uint) | |
256 { | |
257 return dmSyntaxError(info, | |
258 "Number of property list '"+ prop.name +" values not equal to number specified"); | |
259 } | |
260 return true; | |
261 | |
262 default: | |
263 return dmPLYReadPropertyValueBIN(info, prop.type, prop.value); | |
264 } | |
265 } | |
266 | |
267 | |
268 bool dmPLYReadElementBIN(DMPLYFileInfo &info, DMPLYFileElement &element) | |
269 { | |
270 size_t nprop = 0; | |
271 | |
272 for (auto const prop : element.properties) | |
273 { | |
274 if (!dmPLYReadPropertyBIN(info, *prop)) | |
275 return false; | |
276 | |
277 nprop++; | |
278 } | |
279 | |
280 if (nprop != element.properties.size()) | |
281 { | |
282 return dmSyntaxError(info, | |
283 "Expected N properties, got different number"); | |
284 } | |
285 | |
286 return true; | |
287 } | |
288 | |
289 | |
290 bool DMModel::loadFromPLY(const std::string &filename) | |
291 { | |
292 DMPLYFileInfo info; | |
293 | |
294 return loadFromPLY(filename, info); | |
295 } | |
296 | |
297 | |
298 bool DMModel::loadFromPLY(const std::string &filename, DMPLYFileInfo &info) | |
299 { | |
300 info.filename = filename; | |
301 info.nline = info.state = 0; | |
302 info.file.open(info.filename.c_str(), std::fstream::in | std::fstream::binary); | |
303 | |
304 dmMsg("Trying to read mesh from '%s'.\n", | |
305 info.filename.c_str()); | |
306 | |
307 if (!info.file.is_open()) | |
308 { | |
309 dmError("Unable to open file '%s'.\n", | |
310 info.filename.c_str()); | |
311 return false; | |
312 } | |
313 | |
314 // Parse the PLY header | |
315 while (info.state >= 0) | |
316 { | |
317 // Read one line | |
318 if (!dmReadLine(info)) | |
319 return false; | |
320 | |
321 // Skip empty lines | |
322 if (info.line.empty()) | |
323 continue; | |
324 | |
325 // Split key and value | |
326 std::vector<std::string> tokens = dmStrSplit(info.line); | |
327 std::string &key = tokens[0]; | |
328 | |
329 if (info.state == 0 && key == "ply") | |
330 { | |
331 info.state = 1; | |
332 } | |
333 else | |
334 if (info.state > 0 && key == "end_header") | |
335 { | |
336 info.state = -1; | |
337 } | |
338 else | |
339 if (info.state == 1 && key == "format") | |
340 { | |
341 if (tokens.size() < 3) | |
342 { | |
343 return dmSyntaxError(info, | |
344 "Expected value for format"); | |
345 } | |
346 | |
347 info.format = PLY_FMT_UNKNOWN; | |
348 | |
349 if (tokens[1] == "ascii") | |
350 info.format = PLY_FMT_ASCII; | |
351 else | |
352 if (tokens[1] == "binary_little_endian") | |
353 info.format = PLY_FMT_BIN_LE; | |
354 else | |
355 if (tokens[1] == "binary_big_endian") | |
356 info.format = PLY_FMT_BIN_BE; | |
357 | |
358 if (info.format == PLY_FMT_UNKNOWN || | |
359 tokens[2] != "1.0") | |
360 { | |
361 dmError("Unknown or unsupported PLY file format '%s'.\n", | |
362 (tokens[1] +" "+ tokens[2]).c_str()); | |
363 return false; | |
364 } | |
365 | |
366 info.state = 2; | |
367 } | |
368 else | |
369 if ((info.state == 2 || info.state == 3) && key == "element") | |
370 { | |
371 if (tokens.size() < 3) | |
372 { | |
373 return dmSyntaxError(info, | |
374 "Expected a value for element key"); | |
375 } | |
376 | |
377 std::string &el_name = tokens[1], &el_value = tokens[2]; | |
378 | |
379 if (info.elem_map.count(el_name)) | |
380 { | |
381 return dmSyntaxError(info, | |
382 "Element '"+ el_name +"' has already been defined"); | |
383 } | |
384 | |
385 DMPLYFileElement &elem = info.elem_map[el_name]; | |
386 info.element = &elem; | |
387 info.elements.push_back(&elem); | |
388 | |
389 elem.name = el_name; | |
390 elem.value = std::stoi(el_value); | |
391 | |
392 info.state = 3; | |
393 } | |
394 else | |
395 if (info.state == 3 && key == "property") | |
396 { | |
397 if (tokens.size() < 3) | |
398 { | |
399 return dmSyntaxError(info, | |
400 "Expected value for property"); | |
401 } | |
402 | |
403 const std::string | |
404 &pr_name = tokens.back(), | |
405 &pr_typename = tokens.at(1); | |
406 | |
407 if (!info.element) | |
408 { | |
409 // Should not happen | |
410 return dmSyntaxError(info, | |
411 "No element defined for property '"+ pr_name +"'?"); | |
412 } | |
413 | |
414 // Check if this property has been already defined | |
415 if (info.element->prop_map.count(pr_name)) | |
416 { | |
417 return dmSyntaxError(info, | |
418 "Element '"+ info.element->name + | |
419 "' already has property '"+ pr_name +"' defined?"); | |
420 } | |
421 | |
422 // Parse property information | |
423 DMPLYPropType pr_type = dmPLYParsePropType(pr_typename); | |
424 if (pr_type == PLY_TYPE_NONE) | |
425 { | |
426 return dmSyntaxError(info, | |
427 "Invalid or unsupported property type '"+ pr_typename +"'"); | |
428 } | |
429 | |
430 DMPLYFileProperty &prop = info.element->prop_map[pr_name]; | |
431 info.element->properties.push_back(&prop); | |
432 | |
433 prop.name = pr_name; | |
434 prop.type = pr_type; | |
435 | |
436 if (pr_type == PLY_TYPE_LIST) | |
437 { | |
438 // List is a special case | |
439 if (tokens.size() < 5) | |
440 { | |
441 return dmSyntaxError(info, | |
442 "Expected more values for a list property (num_type, val_type, name)"); | |
443 } | |
444 | |
445 prop.list_num_type = dmPLYParsePropType(tokens.at(2)); | |
446 prop.list_values_type = dmPLYParsePropType(tokens.at(3)); | |
447 | |
448 if (prop.list_num_type == PLY_TYPE_NONE || | |
449 prop.list_values_type == PLY_TYPE_NONE) | |
450 { | |
451 return dmSyntaxError(info, | |
452 "Invalid or unsupported property type(s)"); | |
453 } | |
454 } | |
455 } | |
456 else | |
457 if (info.state > 0 // && (key == "comment" || key == "obj_info") | |
458 ) | |
459 { | |
460 // Ignore comments | |
461 // .. and unknown keys | |
462 } | |
463 else | |
464 { | |
465 return dmSyntaxError(info, | |
466 "Unexpected key '"+ key +"'"); | |
467 } | |
468 } | |
469 | |
470 // Check header data | |
471 DMPLYFileElement *elem; | |
472 DMPLYFileProperty *prop; | |
473 if (info.state != -1 || | |
474 (elem = info.checkElem(PLY_ELEM_FACE)) == 0 || | |
475 (prop = elem->checkProp(PLY_PROP_VERTEX_INDICES)) == 0 || | |
476 prop->type != PLY_TYPE_LIST || | |
477 (elem = info.checkElem(PLY_ELEM_VERTEX)) == 0 || | |
478 (prop = elem->checkProp("x")) == 0 || prop->type != PLY_TYPE_FLOAT || | |
479 (prop = elem->checkProp("y")) == 0 || prop->type != PLY_TYPE_FLOAT || | |
480 (prop = elem->checkProp("z")) == 0 || prop->type != PLY_TYPE_FLOAT | |
481 ) | |
482 { | |
483 dmError("PLY file did not contain expected information.\n"); | |
484 return false; | |
485 } | |
486 | |
487 nvertices = info.elem_map[PLY_ELEM_VERTEX].value; | |
488 nfaces = info.elem_map[PLY_ELEM_FACE].value; | |
489 | |
490 | |
491 if (nvertices < 3 || nfaces < 1) | |
492 { | |
493 dmError("Invalid nvertices (%d) and/or nfaces (%d).\n", | |
494 nvertices, nfaces); | |
495 return false; | |
496 } | |
497 | |
498 dmMsg("Should have %d vertices, %d faces\n", | |
499 nvertices, nfaces); | |
500 | |
501 // Pre-allocate space | |
502 vertices.reserve(nvertices); | |
503 normals.reserve(nvertices); | |
504 faces.reserve(nfaces * 3); | |
505 | |
506 // Read the actual data (in order of the elements) | |
507 for (auto *element : info.elements) | |
508 for (int n = 0; n < element->value; n++) | |
509 { | |
510 switch (info.format) | |
511 { | |
512 case PLY_FMT_ASCII: | |
513 if (!dmPLYParseElementASCII(info, *element)) | |
514 return false; | |
515 break; | |
516 | |
517 default: | |
518 if (!dmPLYReadElementBIN(info, *element)) | |
519 return false; | |
520 break; | |
521 } | |
522 | |
523 // Check for specific elements | |
524 if (element->name == PLY_ELEM_FACE) | |
525 { | |
526 DMPLYFileProperty &prop = element->prop_map[PLY_PROP_VERTEX_INDICES]; | |
527 | |
528 if (prop.list_num_value.v_uint != 3) | |
529 { | |
530 return dmSyntaxError(info, | |
531 "Expected 3 vertices per face"); | |
532 } | |
533 | |
534 for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) | |
535 { | |
536 faces.push_back(prop.list_values[n].v_uint); | |
537 } | |
538 } | |
539 else | |
540 if (element->name == PLY_ELEM_VERTEX) | |
541 { | |
542 DMVector3 vert; | |
543 vert.x = element->prop_map["x"].value.v_float; | |
544 vert.y = element->prop_map["y"].value.v_float; | |
545 vert.z = element->prop_map["z"].value.v_float; | |
546 | |
547 vertices.push_back(vert); | |
548 | |
549 if (element->checkProp("nx") && | |
550 element->checkProp("ny") && | |
551 element->checkProp("nz")) | |
552 { | |
553 DMVector3 normal; | |
554 normal.x = element->prop_map["nx"].value.v_float; | |
555 normal.y = element->prop_map["ny"].value.v_float; | |
556 normal.z = element->prop_map["nz"].value.v_float; | |
557 | |
558 normals.push_back(normal); | |
559 } | |
560 } | |
561 } | |
562 | |
563 dmMsg("Found %ld vertices, %ld normals, %ld faces\n", | |
564 vertices.size(), | |
565 normals.size(), | |
566 faces.size() / 3); | |
567 | |
568 return true; | |
569 } | |
570 | |
571 | |
572 bool dmParseVector(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMVector3 &vec) | |
573 { | |
574 if (tokens.size() == offs + 1) | |
575 { | |
576 vec.x = vec.y = vec.z = std::stof(tokens[offs]); | |
577 } | |
578 else | |
579 if (tokens.size() == offs + 3) | |
580 { | |
581 vec.x = std::stof(tokens[offs]); | |
582 vec.y = std::stof(tokens[offs + 1]); | |
583 vec.z = std::stof(tokens[offs + 2]); | |
584 } | |
585 else | |
586 { | |
587 return dmSyntaxError(info, | |
588 "Expected 1/3 value vector for '"+ *info.key +"'"); | |
589 } | |
590 | |
591 return true; | |
592 } | |
593 | |
594 | |
595 bool dmParseVector(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMVector4 &vec) | |
596 { | |
597 if (tokens.size() == offs + 1) | |
598 { | |
599 vec.p.x = vec.p.y = vec.p.z = std::stof(tokens[offs]); | |
600 } | |
601 else | |
602 if (tokens.size() == offs + 3 || tokens.size() == offs + 4) | |
603 { | |
604 vec.p.x = std::stof(tokens[offs]); | |
605 vec.p.y = std::stof(tokens[offs + 1]); | |
606 vec.p.z = std::stof(tokens[offs + 2]); | |
607 | |
608 if (tokens.size() == offs + 4) | |
609 vec.p.w = std::stof(tokens[offs + 3]); | |
610 } | |
611 else | |
612 { | |
613 return dmSyntaxError(info, | |
614 "Expected 1/3/4 value vector for '"+ *info.key +"'"); | |
615 } | |
616 | |
617 return true; | |
618 } | |
619 | |
620 | |
621 bool DMSimpleScene::loadInfo(const std::string &filename) | |
622 { | |
623 DMTextFileInfo info; | |
624 DMModel *model = 0; | |
625 DMLight *light = 0; | |
626 DMVector4 *ppos = 0, *ppointAt = 0; | |
627 DMMaterial *pmat = 0; | |
628 | |
629 info.filename = filename; | |
630 info.nline = info.state = 0; | |
631 info.file.open(info.filename.c_str(), std::fstream::in | std::fstream::binary); | |
632 | |
633 dmMsg("Trying to read scene data from '%s'.\n", | |
634 info.filename.c_str()); | |
635 | |
636 if (!info.file.is_open()) | |
637 { | |
638 dmError("Unable to open file '%s'.\n", | |
639 info.filename.c_str()); | |
640 return false; | |
641 } | |
642 | |
643 while (info.state >= 0) | |
644 { | |
645 // Read one line | |
646 if (!dmReadLine(info)) | |
647 { | |
648 info.state = -1; | |
649 break; | |
650 } | |
651 | |
652 // Skip empty lines and comments | |
653 if (info.line.empty() || | |
654 info.line[0] == '#' || | |
655 info.line[0] == ';') | |
656 continue; | |
657 | |
658 // Split key and values | |
659 std::vector<std::string> tokens = dmStrSplit(info.line); | |
660 std::string key = tokens[0]; | |
661 info.key = &key; | |
662 | |
663 if (key == "model") | |
664 { | |
665 DMModel newmodel; | |
666 if (tokens.size() != 2) | |
667 { | |
668 return dmSyntaxError(info, | |
669 "Keyword model expects a filename argument"); | |
670 } | |
671 | |
672 models.push_back(newmodel); | |
673 model = &models.back(); | |
674 model->modelFile = tokens[1]; | |
675 pmat = &model->material; | |
676 info.state = 1; | |
677 } | |
678 else | |
679 if (info.state == 1 && (key == "shaderfile")) | |
680 { | |
681 if (tokens.size() != 3) | |
682 { | |
683 return dmSyntaxError(info, | |
684 "Keyword shaderfile expects shader type (fs, vs) and filename arguments"); | |
685 } | |
686 | |
687 std::string | |
688 &shtype = tokens[1], | |
689 &shfile = tokens[2]; | |
690 | |
691 if (shtype == "fs") | |
692 model->fragShaderFile = shfile; | |
693 else | |
694 if (shtype == "vs") | |
695 model->vertShaderFile = shfile; | |
696 else | |
697 { | |
698 return dmSyntaxError(info, | |
699 "Invalid shaderfile type '"+ shtype +"'"); | |
700 } | |
701 } | |
702 else | |
703 if (info.state == 1 && (key == "translate" || key == "rotate" || key == "scale")) | |
704 { | |
705 DMVector3 vec; | |
706 | |
707 if (!dmParseVector(info, tokens, 1, vec)) | |
708 return false; | |
709 | |
710 if (!model) | |
711 return false; | |
712 | |
713 if (key == "translate") | |
714 { | |
715 model->translate = vec; | |
716 model->translateSet = true; | |
717 } | |
718 else | |
719 if (key == "rotate") | |
720 { | |
721 model->rotate = vec; | |
722 model->rotateSet = true; | |
723 } | |
724 else | |
725 if (key == "scale") | |
726 { | |
727 model->scale = vec; | |
728 model->scaleSet = true; | |
729 } | |
730 } | |
731 else | |
732 if (info.state == 1 && key == "shininess") | |
733 { | |
734 if (tokens.size() != 2) | |
735 { | |
736 return dmSyntaxError(info, | |
737 "Expected argument for shininess"); | |
738 } | |
739 | |
740 model->material.shininess = std::stoi(tokens[1], 0, 0); | |
741 } | |
742 else | |
743 if (key == "light") | |
744 { | |
745 DMLight newlight; | |
746 | |
747 if (lights.size() >= 4) | |
748 { | |
749 return dmTextError(info, | |
750 "Too many lights defined (max 4)"); | |
751 } | |
752 | |
753 lights.push_back(newlight); | |
754 light = &lights.back(); | |
755 ppos = &light->position; | |
756 ppointAt = &light->pointAt; | |
757 pmat = &light->color; | |
758 info.state = 2; | |
759 } | |
760 else | |
761 if ((info.state == 1 || info.state == 2) && | |
762 (key == "ambient" || key == "diffuse" || key == "specular")) | |
763 { | |
764 DMVector4 val; | |
765 val.c.a = 1.0f; | |
766 | |
767 if (!dmParseVector(info, tokens, 1, val)) | |
768 return false; | |
769 | |
770 if (key == "ambient") | |
771 pmat->ambient = val; | |
772 else | |
773 if (key == "diffuse") | |
774 pmat->diffuse = val; | |
775 else | |
776 if (key == "specular") | |
777 pmat->specular = val; | |
778 } | |
779 else | |
780 if (key == "camera") | |
781 { | |
782 info.state = 3; | |
783 | |
784 ppos = &camera.position; | |
785 ppointAt = &camera.pointAt; | |
786 } | |
787 else | |
788 if ((info.state == 3 || info.state == 2) && | |
789 (key == "position" || key == "pos" || key == "point_at")) | |
790 { | |
791 DMVector4 vec; | |
792 vec.p.w = 0; | |
793 | |
794 if (!dmParseVector(info, tokens, 1, vec)) | |
795 return false; | |
796 | |
797 if (key == "position" || key == "pos") | |
798 *ppos = vec; | |
799 else | |
800 if (key == "point_at") | |
801 *ppointAt = vec; | |
802 } | |
803 else | |
804 { | |
805 return dmSyntaxError(info, | |
806 "Unexpected key '"+ key +"'"); | |
807 } | |
808 } | |
809 | |
810 return true; | |
811 } |