Mercurial > hg > forks > gldragon
comparison dmmodel.cpp @ 21:1404dfcee7b8
More work on scenefile and model loading support.
Can now load PLY models and simple scene definition files.
Converted dragon mesh to binary PLY format.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 22 Nov 2019 03:03:52 +0200 |
parents | a329f0216491 |
children | 03b86b9c2f29 |
comparison
equal
deleted
inserted
replaced
20:294c4c7943b5 | 21:1404dfcee7b8 |
---|---|
1 // | 1 // |
2 // | 2 // |
3 // | 3 // |
4 #include "dmmodel.h" | 4 #include "dmmodel.h" |
5 #include <SDL_endian.h> | |
5 | 6 |
6 | 7 |
7 static bool dmError(DMTextFileInfo &info, const std::string &msg) | 8 static bool dmError(DMTextFileInfo &info, const std::string &msg) |
8 { | 9 { |
9 printf("ERROR: %s on line #%d: %s\n", | 10 printf("ERROR: %s on line #%d: %s\n", |
137 { | 138 { |
138 size_t nprop = 0, pos = 0; | 139 size_t nprop = 0, pos = 0; |
139 | 140 |
140 // Read one line | 141 // Read one line |
141 if (!dmReadLine(info)) | 142 if (!dmReadLine(info)) |
142 return false; | 143 { |
144 return dmError(info, | |
145 "Unexpected end of file"); | |
146 } | |
143 | 147 |
144 // Skip empty lines | 148 // Skip empty lines |
145 if (info.line.empty()) | 149 if (info.line.empty()) |
146 return true; | 150 return true; |
147 | 151 |
164 } | 168 } |
165 | 169 |
166 | 170 |
167 bool dmPLYReadPropertyValueBIN(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval) | 171 bool dmPLYReadPropertyValueBIN(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval) |
168 { | 172 { |
169 uint8_t tmp[8]; | 173 uint8_t tmpU8; |
174 int8_t tmpS8; | |
170 uint16_t tmpU16; | 175 uint16_t tmpU16; |
171 int16_t tmpS16; | 176 int16_t tmpS16; |
172 uint32_t tmpU32; | 177 uint32_t tmpU32; |
173 int32_t tmpS32; | 178 int32_t tmpS32; |
179 float tmpFloat; | |
174 | 180 |
175 switch (ptype) | 181 switch (ptype) |
176 { | 182 { |
177 case PLY_TYPE_INT8: | 183 case PLY_TYPE_INT8: |
178 info.file.read(reinterpret_cast<char *>(&tmp), 1); | 184 info.file.read(reinterpret_cast<char *>(&tmpS8), 1); |
179 pval.v_int = (int8_t) tmp[0]; | 185 pval.v_int = tmpS8; |
180 break; | 186 break; |
181 | 187 |
182 case PLY_TYPE_UINT8: | 188 case PLY_TYPE_UINT8: |
183 info.file.read(reinterpret_cast<char *>(&tmp), 1); | 189 info.file.read(reinterpret_cast<char *>(&tmpU8), 1); |
184 pval.v_uint = (uint8_t) tmp[0]; | 190 pval.v_uint = tmpU8; |
185 break; | 191 break; |
186 | 192 |
187 case PLY_TYPE_INT16: | 193 case PLY_TYPE_INT16: |
188 info.file.read(reinterpret_cast<char *>(&tmp), 2); | 194 info.file.read(reinterpret_cast<char *>(&tmpS16), 2); |
189 tmpS16 = | 195 tmpS16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpS16) : SDL_SwapBE16(tmpS16); |
190 (tmp[0] << 8) | | |
191 (tmp[1]); | |
192 pval.v_int = tmpS16; | 196 pval.v_int = tmpS16; |
193 break; | 197 break; |
194 | 198 |
195 case PLY_TYPE_UINT16: | 199 case PLY_TYPE_UINT16: |
196 info.file.read(reinterpret_cast<char *>(&tmp), 2); | 200 info.file.read(reinterpret_cast<char *>(&tmpU16), 2); |
197 tmpU16 = | 201 tmpU16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpU16) : SDL_SwapBE16(tmpU16); |
198 (tmp[0] << 8) | | |
199 (tmp[1]); | |
200 pval.v_uint = tmpU16; | 202 pval.v_uint = tmpU16; |
201 break; | 203 break; |
202 | 204 |
203 case PLY_TYPE_INT32: | 205 case PLY_TYPE_INT32: |
204 info.file.read(reinterpret_cast<char *>(&tmp), 4); | 206 info.file.read(reinterpret_cast<char *>(&tmpS32), 4); |
205 tmpS32 = | 207 tmpS32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpS32) : SDL_SwapBE32(tmpS32); |
206 (tmp[0] << 24) | | |
207 (tmp[1] << 16) | | |
208 (tmp[2] << 8) | | |
209 (tmp[3]); | |
210 | |
211 pval.v_int = tmpS32; | 208 pval.v_int = tmpS32; |
212 break; | 209 break; |
213 | 210 |
214 case PLY_TYPE_UINT32: | 211 case PLY_TYPE_UINT32: |
215 info.file.read(reinterpret_cast<char *>(&tmp), 4); | 212 info.file.read(reinterpret_cast<char *>(&tmpU32), 4); |
216 tmpU32 = | 213 tmpU32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpU32) : SDL_SwapBE32(tmpU32); |
217 (tmp[3] << 24) | | |
218 (tmp[2] << 16) | | |
219 (tmp[1] << 8) | | |
220 (tmp[0]); | |
221 | |
222 pval.v_uint = tmpU32; | 214 pval.v_uint = tmpU32; |
223 break; | 215 break; |
224 | 216 |
225 case PLY_TYPE_FLOAT: | 217 case PLY_TYPE_FLOAT: |
226 info.file.read(reinterpret_cast<char *>(&tmp), 4); | 218 info.file.read(reinterpret_cast<char *>(&tmpFloat), 4); |
227 tmpU32 = | 219 pval.v_float = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapFloatLE(tmpFloat) : SDL_SwapFloatBE(tmpFloat); |
228 (tmp[0] << 24) | | |
229 (tmp[1] << 16) | | |
230 (tmp[2] << 8) | | |
231 (tmp[3]); | |
232 | |
233 pval.v_uint = tmpU32; | |
234 break; | 220 break; |
235 | 221 |
236 default: | 222 default: |
237 return dmError(info, | 223 return dmError(info, |
238 "Internal error, unimplemented PLY property type"); | 224 "Internal error, unimplemented PLY property type"); |
546 } | 532 } |
547 } | 533 } |
548 else | 534 else |
549 if (element->name == PLY_ELEM_VERTEX) | 535 if (element->name == PLY_ELEM_VERTEX) |
550 { | 536 { |
551 DMVertex vert; | 537 DMVector3 vert; |
552 vert.x = element->prop_map["x"].value.v_float; | 538 vert.x = element->prop_map["x"].value.v_float; |
553 vert.y = element->prop_map["y"].value.v_float; | 539 vert.y = element->prop_map["y"].value.v_float; |
554 vert.z = element->prop_map["z"].value.v_float; | 540 vert.z = element->prop_map["z"].value.v_float; |
555 | 541 |
556 vertices.push_back(vert); | 542 vertices.push_back(vert); |
557 | 543 |
558 if (element->checkProp("nx") && | 544 if (element->checkProp("nx") && |
559 element->checkProp("ny") && | 545 element->checkProp("ny") && |
560 element->checkProp("nz")) | 546 element->checkProp("nz")) |
561 { | 547 { |
562 DMVertex normal; | 548 DMVector3 normal; |
563 normal.x = element->prop_map["nx"].value.v_float; | 549 normal.x = element->prop_map["nx"].value.v_float; |
564 normal.y = element->prop_map["ny"].value.v_float; | 550 normal.y = element->prop_map["ny"].value.v_float; |
565 normal.z = element->prop_map["nz"].value.v_float; | 551 normal.z = element->prop_map["nz"].value.v_float; |
566 | 552 |
567 normals.push_back(normal); | 553 normals.push_back(normal); |
576 | 562 |
577 return true; | 563 return true; |
578 } | 564 } |
579 | 565 |
580 | 566 |
567 bool dmParseVector(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMVector3 &vec) | |
568 { | |
569 if (tokens.size() == offs + 1) | |
570 { | |
571 vec.x = vec.y = vec.z = std::stof(tokens[offs]); | |
572 } | |
573 else | |
574 if (tokens.size() == offs + 3) | |
575 { | |
576 vec.x = std::stof(tokens[offs]); | |
577 vec.y = std::stof(tokens[offs + 1]); | |
578 vec.z = std::stof(tokens[offs + 2]); | |
579 } | |
580 else | |
581 { | |
582 return dmSyntaxError(info, | |
583 "Expected 1/3 value vector for '"+ *info.key +"'"); | |
584 } | |
585 | |
586 return true; | |
587 } | |
588 | |
589 | |
590 bool dmParseVector(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMVector4 &vec) | |
591 { | |
592 vec.w = 1.0f; | |
593 | |
594 if (tokens.size() == offs + 1) | |
595 { | |
596 vec.x = vec.y = vec.z = std::stof(tokens[offs]); | |
597 } | |
598 else | |
599 if (tokens.size() == offs + 3 || tokens.size() == offs + 4) | |
600 { | |
601 vec.x = std::stof(tokens[offs]); | |
602 vec.y = std::stof(tokens[offs + 1]); | |
603 vec.z = std::stof(tokens[offs + 2]); | |
604 | |
605 if (tokens.size() == offs + 4) | |
606 vec.w = std::stof(tokens[offs + 3]); | |
607 } | |
608 else | |
609 { | |
610 return dmSyntaxError(info, | |
611 "Expected 1/3/4 value vector for '"+ *info.key +"'"); | |
612 } | |
613 | |
614 return true; | |
615 } | |
616 | |
617 | |
618 bool dmParseColor(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMColor &color) | |
619 { | |
620 color.alpha = 0xff; | |
621 | |
622 if (tokens.size() == offs + 1) | |
623 { | |
624 color.r = color.g = color.b = std::stoi(tokens[offs], 0, 0); | |
625 } | |
626 else | |
627 if (tokens.size() == offs + 3 || tokens.size() == offs + 4) | |
628 { | |
629 color.r = std::stoi(tokens[offs], 0, 0); | |
630 color.g = std::stoi(tokens[offs + 1], 0, 0); | |
631 color.b = std::stoi(tokens[offs + 2], 0, 0); | |
632 | |
633 if (tokens.size() == offs + 4) | |
634 color.alpha = std::stoi(tokens[offs + 3], 0, 0); | |
635 } | |
636 else | |
637 { | |
638 return dmSyntaxError(info, | |
639 "Expected color values <value> or <red> <green> <blue> [<alpha>] for '"+ *info.key +"'"); | |
640 } | |
641 | |
642 return true; | |
643 } | |
644 | |
645 | |
581 bool DMSimpleScene::loadInfo(const std::string &filename) | 646 bool DMSimpleScene::loadInfo(const std::string &filename) |
582 { | 647 { |
583 DMTextFileInfo info; | 648 DMTextFileInfo info; |
649 DMModel *model = 0; | |
650 DMLight *light = 0; | |
651 DMVector3 *ppos = 0, *ppointAt = 0; | |
584 | 652 |
585 info.filename = filename; | 653 info.filename = filename; |
586 info.nline = info.state = 0; | 654 info.nline = info.state = 0; |
587 info.file.open(info.filename.c_str(), std::fstream::in | std::fstream::binary); | 655 info.file.open(info.filename.c_str(), std::fstream::in | std::fstream::binary); |
588 | 656 |
611 info.line[0] == ';') | 679 info.line[0] == ';') |
612 continue; | 680 continue; |
613 | 681 |
614 // Split key and values | 682 // Split key and values |
615 std::vector<std::string> tokens = dmStrSplit(info.line); | 683 std::vector<std::string> tokens = dmStrSplit(info.line); |
616 std::string &key = tokens[0]; | 684 std::string key = tokens[0]; |
617 | 685 info.key = &key; |
618 if (key == "color") | 686 |
619 { | 687 if (key == "model") |
620 DMColor color; | 688 { |
621 color.alpha = 0xff; | 689 DMModel newmodel; |
622 | 690 if (tokens.size() != 2) |
623 if (tokens.size() == 2) | 691 { |
624 { | 692 return dmError(info, |
625 color.r = color.g = color.b = std::stoi(tokens[1], 0, 0); | 693 "Keyword model expects a filename argument"); |
626 } | 694 } |
627 else | 695 |
628 if (tokens.size() == 4 || tokens.size() == 5) | 696 models.push_back(newmodel); |
629 { | 697 model = &models.back(); |
630 color.r = std::stoi(tokens[1], 0, 0); | 698 model->modelFile = tokens[1]; |
631 color.g = std::stoi(tokens[2], 0, 0); | 699 info.state = 1; |
632 color.b = std::stoi(tokens[3], 0, 0); | 700 } |
633 | 701 else |
634 if (tokens.size() == 5) | 702 if (info.state == 1 && key == "color") |
635 color.alpha = std::stoi(tokens[4], 0, 0); | 703 { |
636 } | 704 if (!dmParseColor(info, tokens, 1, model->color)) |
637 else | 705 return false; |
638 { | 706 } |
639 return dmSyntaxError(info, | 707 else |
640 "Expected color values <value> or <red> <green> <blue> [<alpha>]"); | 708 if (info.state == 1 && (key == "translate" || key == "rotate" || key == "scale")) |
641 } | 709 { |
642 | 710 DMVector3 vec; |
643 model.color = color; | 711 |
644 } | 712 if (!dmParseVector(info, tokens, 1, vec)) |
645 else | 713 return false; |
646 if (key == "translate" || key == "rotate" || key == "scale" || | 714 |
647 key == "camera_pos" || key == "camera_at") | 715 if (!model) |
648 { | 716 return false; |
649 DMVertex vec; | |
650 | |
651 if (tokens.size() == 2) | |
652 { | |
653 vec.x = vec.y = vec.z = std::stof(tokens[1]); | |
654 } | |
655 else | |
656 if (tokens.size() == 4) | |
657 { | |
658 vec.x = std::stof(tokens[1]); | |
659 vec.y = std::stof(tokens[2]); | |
660 vec.z = std::stof(tokens[3]); | |
661 } | |
662 else | |
663 { | |
664 return dmSyntaxError(info, | |
665 "Expected vector value for '"+ key +"'"); | |
666 } | |
667 | 717 |
668 if (key == "translate") | 718 if (key == "translate") |
669 model.translate = vec; | 719 model->translate = vec; |
670 else | 720 else |
671 if (key == "rotate") | 721 if (key == "rotate") |
672 model.rotate = vec; | 722 model->rotate = vec; |
673 else | 723 else |
674 if (key == "scale") | 724 if (key == "scale") |
675 model.scale = vec; | 725 model->scale = vec; |
726 } | |
727 else | |
728 if (key == "light") | |
729 { | |
730 DMLight newlight; | |
731 | |
732 if (lights.size() >= 4) | |
733 { | |
734 printf("ERROR: Too many lights defined.\n"); | |
735 return false; | |
736 } | |
737 lights.push_back(newlight); | |
738 light = &lights.back(); | |
739 ppos = &light->pos; | |
740 ppointAt = &light->pointAt; | |
741 info.state = 2; | |
742 } | |
743 else | |
744 if (info.state == 2 && (key == "ambient" || key == "diffuse" || key == "specular")) | |
745 { | |
746 DMVector4 val; | |
747 | |
748 if (!dmParseVector(info, tokens, 1, val)) | |
749 return false; | |
750 | |
751 if (key == "ambient") | |
752 light->ambient = val; | |
676 else | 753 else |
677 if (key == "camera_pos") | 754 if (key == "diffuse") |
678 camera.pos = vec; | 755 light->diffuse = val; |
679 else | 756 else |
680 if (key == "camera_at") | 757 if (key == "specular") |
681 camera.lookAt = vec; | 758 light->specular = val; |
682 } | 759 } |
683 else | 760 else |
684 if (key == "light") | 761 if (key == "camera") |
685 { | 762 { |
686 if (tokens.size() == 4) | 763 info.state = 3; |
687 { | 764 |
688 DMVertex pos; | 765 ppos = &camera.pos; |
689 pos.x = std::stof(tokens[1]); | 766 ppointAt = &camera.pointAt; |
690 pos.y = std::stof(tokens[2]); | 767 } |
691 pos.z = std::stof(tokens[3]); | 768 else |
692 } | 769 if ((info.state == 3 || info.state == 2) && (key == "pos" || key == "point_at")) |
770 { | |
771 DMVector3 vec; | |
772 | |
773 if (!dmParseVector(info, tokens, 1, vec)) | |
774 return false; | |
775 | |
776 if (key == "pos") | |
777 *ppos = vec; | |
693 else | 778 else |
694 { | 779 if (key == "point_at") |
695 return dmSyntaxError(info, | 780 *ppointAt = vec; |
696 "Expected light definition as <x> <y> <z> "); | |
697 } | |
698 } | 781 } |
699 else | 782 else |
700 { | 783 { |
701 return dmSyntaxError(info, | 784 return dmSyntaxError(info, |
702 "Unexpected key '"+ key +"'"); | 785 "Unexpected key '"+ key +"'"); |
703 } | 786 } |
704 } | 787 } |
705 | 788 |
706 model.printInfo(); | 789 return true; |
707 | 790 } |
708 return true; | |
709 } |