Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the antispam-bee domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/ruwritingagame/public_html/wp-includes/functions.php on line 6131

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902
{"id":832,"date":"2021-12-12T02:01:44","date_gmt":"2021-12-12T02:01:44","guid":{"rendered":"https:\/\/writingagame.com\/?p=832"},"modified":"2022-02-04T02:33:11","modified_gmt":"2022-02-04T02:33:11","slug":"chapter-28-model-loader","status":"publish","type":"post","link":"https:\/\/writingagame.ru\/index.php\/2021\/12\/12\/chapter-28-model-loader\/","title":{"rendered":"\u0413\u043b\u0430\u0432\u0430 28. \u0417\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \/ Model Loader"},"content":{"rendered":"\n

\u041d\u0430\u0448\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 – \u0432\u044b\u043d\u0435\u0441\u0442\u0438 (\u0443\u0431\u0440\u0430\u0442\u044c) \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b TheGame <\/em>\u043a\u043b\u0430\u0441\u0441\u0430.<\/p>\n\n\n\n

\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u043e\u043f\u0438\u0441\u0430\u0442\u0435\u043b\u044c<\/em> (text descriptor<\/em>) \u043c\u043e\u0434\u0435\u043b\u0438, XML \u0444\u043e\u0440\u043c\u0430\u0442 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u043c. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u044d\u043a\u0437\u0435\u0448\u043d\u0438\u043a\u0430, \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \/dt<\/strong>. \u0415\u0449\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0445 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c, \u0447\u0438\u0442\u0430\u0442\u044c, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438 \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 3D \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. <\/p>\n\n\n\n

\u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c FileLoader <\/strong>\u043a\u043b\u0430\u0441\u0441. \u041d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0430\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c XML txt \u0444\u0430\u0439\u043b\u044b. \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0433\u043e XMLParser<\/strong>. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0447\u0430\u0441\u0442\u044c \u0434\u0432\u0438\u0436\u043a\u0430 (engine<\/em>).<\/p>\n\n\n\n

1. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c VS, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c\u00a0C:\\CPP\\a997modeler<\/em>\\p_windows\\p_windows.sln<\/em>.<\/p>\n\n\n\n


\n\n\n\n

2. \u041f\u043e\u0434 xEngine<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c header file XMLParser.h<\/strong><\/p>\n\n\n\n

Location: C:\\CPP\\engine<\/em> <\/p>\n\n\n\n

\u041a\u043e\u0434:<\/p>\n\n\n

\n#pragma once\n#include "FileLoader.h"\n\nclass XMLparser : public FileLoader\n{\npublic:\n\tchar* readFrom;\n\tstd::string currentTag = "";\n\tint tagLength = 0;\n\tstd::string tagName = "";\n\tbool closedTag = false; \/\/ > or \/>\npublic:\n\tXMLparser(std::string filePath) : FileLoader(filePath) { removeComments(this); readFrom = pData; };\n\tstatic int removeComments(XMLparser* pXP);\n\tstatic int processSource(XMLparser* pXP);\n\tint nextTag() { return nextTag(this); }; \/\/returns 0 if no more tags, 1 - tag extractedb\n\tstatic bool nextTag(XMLparser* pXP); \/\/returns 0 if no more tags, 1 - tag extractedb\n\tstatic int nameEndsAt(std::string varName, std::string tag);\n\tvirtual int processTag() { return 1; };\n\tstatic std::string buildFullPath(XMLparser* pXP, std::string filePath);\n\n\tstatic bool varExists(std::string varName, std::string tag);\n\tstatic std::string getStringValue(std::string varName, std::string tag);\n\tstatic int setCharsValue(char* pChars, int charsLength, std::string varName, std::string tag);\n\tstatic int setIntValue(int* pInt, std::string varName, std::string tag);\n\tstatic int setFloatValue(float* pFloat, std::string varName, std::string tag);\n\tstatic int setIntArray(int* pInts, int arrayLength, std::string varName, std::string tag);\n\tstatic int setFloatArray(float* pFloats, int arrayLength, std::string varName, std::string tag);\n\tstatic int setUintColorValue(unsigned int* pInt, std::string varName, std::string tag);\n\tstatic int setIntBoolValue(int* pInt, std::string varName, std::string tag);\n};\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n

\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u043e\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 FileLoader<\/em>.<\/p>\n\n\n\n


\n\n\n\n

3. \u041f\u043e\u0434 xEngine<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0439 C++ file XMLParser.cpp<\/strong> <\/p>\n\n\n\n

Location: C:\\CPP\\engine<\/em><\/p>\n\n\n\n

\u041a\u043e\u0434:<\/p>\n\n\n

\n#include "XMLparser.h"\n#include "platform.h"\n#include "utils.h"\n#include "MyColor.h"\n#include <vector>\n\nextern std::string filesRoot;\n\nint XMLparser::removeComments(XMLparser* pXP) {\n\t\/\/find all occurances of "\/*"\n\tstd::vector<char*> commentsStarts;\n\t\/\/ \/* comments *\/\n\tchar* scanFrom = pXP->pData;\n\twhile (1) {\n\t\tchar* commentStarts = strstr(scanFrom, "\/*");\n\t\tif (commentStarts == NULL)\n\t\t\tbreak;\n\t\tcommentsStarts.push_back(commentStarts);\n\t\tscanFrom = commentStarts + 2;\n\t}\n\t\/\/here we have a list of \/* comments *\/\n\twhile(commentsStarts.size() > 0){\n\t\t\/\/get last comment\n\t\tchar* commentStarts = commentsStarts.back();\n\t\tcommentsStarts.pop_back();\n\t\tchar* commentEnds = strstr(commentStarts, "*\/");\n\t\tint commentLength = (int)(commentEnds - commentStarts) + 2;\n\t\t\/\/shift text left\n\t\tmyStrcpy_s(commentStarts, pXP->dataSize - (int)(commentStarts - pXP->pData), commentStarts + commentLength);\n\t\tpXP->dataSize -= commentLength;\n\/\/mylog("======\\n%s----------\\n", pXP->pData);\n\t}\n\t\/\/ \/\/line comments\n\tscanFrom = pXP->pData;\n\twhile (1) {\n\t\tchar* commentStarts = strstr(scanFrom, "\/\/");\n\t\tif (commentStarts == NULL)\n\t\t\tbreak;\n\t\tchar* commentEnds = strstr(commentStarts, "\\n");\n\t\tint commentLength = (int)(commentEnds - commentStarts) + 1;\n\t\t\/\/shift text left\n\t\tmyStrcpy_s(commentStarts, pXP->dataSize - (int)(commentStarts - pXP->pData), commentStarts + commentLength);\n\t\tpXP->dataSize -= commentLength;\n\t\tscanFrom = commentStarts;\n\/\/mylog("======\\n%s----------\\n", pXP->pData);\n\t}\n\t\/\/ <!-- comments -->\n\tscanFrom = pXP->pData;\n\twhile (1) {\n\t\tchar* commentStarts = strstr(scanFrom, "<!--");\n\t\tif (commentStarts == NULL)\n\t\t\tbreak;\n\t\tcommentsStarts.push_back(commentStarts);\n\t\tscanFrom = commentStarts + 4;\n\t}\n\t\/\/here we have a list of <!-- comments -->\n\twhile (commentsStarts.size() > 0) {\n\t\t\/\/get last comment\n\t\tchar* commentStarts = commentsStarts.back();\n\t\tcommentsStarts.pop_back();\n\t\tchar* commentEnds = strstr(commentStarts, "-->");\n\t\tint commentLength = (int)(commentEnds - commentStarts) + 3;\n\t\t\/\/shift text left\n\t\tmyStrcpy_s(commentStarts, pXP->dataSize - (int)(commentStarts - pXP->pData), commentStarts + commentLength);\n\t\tpXP->dataSize -= commentLength;\n\/\/mylog("======\\n%s----------\\n", pXP->pData);\n\t}\n\treturn 1;\n}\nbool XMLparser::nextTag(XMLparser* pXP) {\n\t\/\/returns 0 if no more tags, 1 - tag extracted\n\tchar* tagStarts = strstr(pXP->readFrom, "<");\n\tif (tagStarts == NULL)\n\t\treturn false;\n\tpXP->readFrom++;\n\tchar* tagEnds = strstr(pXP->readFrom, ">");\n\tif (tagEnds == NULL)\n\t\treturn false;\n\tpXP->readFrom = tagEnds + 1;\n\tpXP->tagLength = (int)(tagEnds - tagStarts) + 1;\n\tpXP->currentTag.assign(tagStarts, pXP->tagLength);\n\treturn true;\n} \nint XMLparser::nameEndsAt(std::string varName, std::string tag) {\n\tint scanFrom = 0;\n\tint nameLength = varName.length();\n\tstd::string optsBefore = "< ";\n\tstd::string optsAfter = " =\/>\\n";\n\twhile (1) {\n\t\tint varStartsAt = tag.find(varName, scanFrom);\n\t\tif (varStartsAt == std::string::npos)\n\t\t\treturn -1;\n\t\tscanFrom = varStartsAt + nameLength;\n\t\tchar charBefore = tag.at(varStartsAt - 1);\n\t\tif (optsBefore.find(charBefore) == std::string::npos)\n\t\t\tcontinue;\n\t\tchar charAfter = tag.at(scanFrom);\n\t\tif (optsAfter.find(charAfter) == std::string::npos)\n\t\t\tcontinue;\n\t\treturn scanFrom;\n\t}\n}\nint XMLparser::processSource(XMLparser* pXP) {\n\twhile (pXP->nextTag()) {\n\t\t\/\/extract tagName\n\t\tint nameStart = pXP->currentTag.find_first_not_of(" <");\n\t\tint nameEnd = pXP->currentTag.find_first_of(" =\/>\\n", nameStart+1);\n\t\tpXP->tagName = pXP->currentTag.substr(nameStart, (nameEnd - nameStart));\n\t\t\/\/open\/closed tag\n\t\tchar lastChar = pXP->currentTag.at(pXP->tagLength - 2);\n\t\tpXP->closedTag = (lastChar == '\/');\n\/\/mylog("[%s] [%s] closed=%d nameStart=%d nameEnd=%d\\n", pXP->currentTag.c_str(), pXP->tagName.c_str(), pXP->closedTag, nameStart, nameEnd);\n\t\tpXP->processTag();\n\t}\n\treturn 1;\n}\nstd::string XMLparser::buildFullPath(XMLparser* pXP, std::string filePath) {\n\tif (filePath.at(0) != '\/')\n\t\tfilePath = pXP->inAppFolder + filePath;\n\treturn (filesRoot + filePath);\n}\n\nstd::string XMLparser::getStringValue(std::string varName, std::string tag) {\n\t\/\/returns std::string\n\tint valueStartsAt = nameEndsAt(varName, tag);\n\tif (valueStartsAt < 0)\n\t\treturn ""; \/\/var not found\n\tvalueStartsAt = tag.find_first_not_of(" ", valueStartsAt);\n\tchar c = tag.at(valueStartsAt);\n\tif (c != '=')\n\t\treturn ""; \/\/var exists, but value not set\n\tvalueStartsAt = tag.find_first_not_of(" ", valueStartsAt + 1);\n\tc = tag.at(valueStartsAt);\n\tstd::string optsQuote = "\\"'";\n\tint valueEndsAt = 0;\n\tif (optsQuote.find(c) != std::string::npos) {\n\t\t\/\/the value is in quotes\n\t\tvalueStartsAt++;\n\t\tvalueEndsAt = tag.find(c, valueStartsAt);\n\t}\n\telse { \/\/value not quoted\n\t\tvalueEndsAt = tag.find_first_of(" \/>\\n", valueStartsAt);\n\t}\n\treturn tag.substr(valueStartsAt, valueEndsAt - valueStartsAt);\n}\n\nbool XMLparser::varExists(std::string varName, std::string tag) {\n\tint valueStartsAt = nameEndsAt(varName, tag);\n\tif (valueStartsAt < 0)\n\t\treturn false; \/\/var not found\n\treturn true;\n}\nint XMLparser::setCharsValue(char* pChars, int charsLength, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string val = getStringValue(varName, tag);\n\tmyStrcpy_s(pChars, charsLength, (char*)val.c_str());\n\treturn 1;\n}\nint XMLparser::setIntValue(int* pInt, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string val = getStringValue(varName, tag);\n\t*pInt = stoi(val);\n\treturn 1;\n}\nint XMLparser::setFloatValue(float* pFloat, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string val = getStringValue(varName, tag);\n\t*pFloat = stof(val);\n\treturn 1;\n}\nint XMLparser::setFloatArray(float* pFloats, int arrayLength, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string valuesString = getStringValue(varName, tag);\n\tstd::vector<std::string> valuesVector = splitString(valuesString, ",");\n\tint valsN = valuesVector.size();\n\tif (valsN != arrayLength) {\n\t\tmylog("ERROR in XMLparser::getFloatArray, %s, %s\\n", varName.c_str(), tag.c_str());\n\t\treturn -1;\n\t}\n\tfor (int i = 0; i < valsN; i++) {\n\t\tif (valuesVector.at(i).compare("x") != 0)\n\t\t\tpFloats[i] = stof(valuesVector.at(i));\n\t}\n\treturn 1;\n}int XMLparser::setIntArray(int* pInts, int arrayLength, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string valuesString = getStringValue(varName, tag);\n\tstd::vector<std::string> valuesVector = splitString(valuesString, ",");\n\tint valsN = valuesVector.size();\n\tif (valsN != arrayLength) {\n\t\tmylog("ERROR in XMLparser::getIntArray, %s, %s\\n", varName.c_str(), tag.c_str());\n\t\treturn -1;\n\t}\n\tfor (int i = 0; i < valsN; i++) {\n\t\tif(valuesVector.at(i).compare("x") != 0)\n\t\t\tpInts[i] = stoi(valuesVector.at(i));\n\t}\n\treturn 1;\n}\nint XMLparser::setUintColorValue(unsigned int* pInt, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tMyColor clr;\n\tstd::string val = getStringValue(varName, tag);\n\tif (val.at(0) == '#') {\n\t\t\/\/the value is in HTML HEX format (like #ff0000)\n\t\tint r = std::stoi(val.substr(1, 2), nullptr, 16);\n\t\tint g = std::stoi(val.substr(3, 2), nullptr, 16);\n\t\tint b = std::stoi(val.substr(5, 2), nullptr, 16);\n\t\tint a = 255;\n\t\tif (val.size() > 7)\n\t\t\ta = std::stoi(val.substr(7, 2), nullptr, 16);\n\t\tclr.setRGBA(r, g, b, a);\n\t}\n\telse if (val.find(",") > 0) {\n\t\t\/\/the value is an array of ints (?)\n\t\tstd::vector<std::string> valuesVector = splitString(val, ",");\n\t\tint r = std::stoi(valuesVector[0]);\n\t\tint g = std::stoi(valuesVector[1]);\n\t\tint b = std::stoi(valuesVector[2]);\n\t\tint a = 255;\n\t\tif (valuesVector.size() > 3)\n\t\t\ta = std::stoi(valuesVector[3]);\n\t\tclr.setRGBA(r, g, b, a);\n\t}\n\telse {\n\t\tmylog("ERROR in XMLparser::setUintColorValue: unhandled Color format %s\\n",tag.c_str());\n\t\treturn -1;\n\t}\n\t*pInt = clr.getUint32();\n\treturn 1;\n}\nint XMLparser::setIntBoolValue(int* pInt, std::string varName, std::string tag) {\n\tif (!varExists(varName, tag))\n\t\treturn 0; \/\/var not found\n\tstd::string val = getStringValue(varName, tag);\n\tif (val.compare("") == 0) *pInt = 1;\n\telse if (val.compare("1") == 0) *pInt = 1;\n\telse if (val.compare("0") == 0) *pInt = 0;\n\telse if (val.compare("yes") == 0) *pInt = 1;\n\telse if (val.compare("no") == 0) *pInt = 0;\n\telse if (val.compare("true") == 0) *pInt = 1;\n\telse if (val.compare("false") == 0) *pInt = 0;\n\telse {\n\t\tmylog("ERROR in XMLparser::setIntBoolValue, %s=%s in %s\\n",varName.c_str(),val.c_str(),tag.c_str());\n\t\treturn -1;\n\t}\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n

\u041a\u043b\u0430\u0441\u0441 XMLParser <\/strong>\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 xml\/txt \u0444\u0430\u0439\u043b, \u0443\u0431\u0435\u0440\u0435\u0442 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b, \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0435\u0433\u043e \u0442\u0430\u0433-\u0437\u0430-\u0442\u0430\u0433\u043e\u043c \u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e<\/strong> \u0444\u0443\u043d\u043a\u0446\u0438\u044e processTag()<\/em> \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f<\/em> \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0430\u043c XMLParser <\/em>\u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u0447\u0442\u043e <\/strong>\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c\u0438 \u0442\u0430\u0433\u0430\u043c\u0438. \u0411\u0443\u0434\u0435\u0442 \u0437\u043d\u0430\u0442\u044c \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 <\/em>\u043a\u043b\u0430\u0441\u0441 ModelLoader<\/strong>, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0432\u043e\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 processTag()<\/em>.<\/p>\n\n\n\n

\u0422\u0430\u043a\u0436\u0435 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 XMLParser <\/strong>\u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0442\u0430\u0433\u043e\u0432, \u0438\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438 \u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n\n\n\n


\n\n\n\n

\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 XMLParser<\/em>, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441 ModelLoader<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 XML descriptor \u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0432 ModelBuilder<\/em>-\u0435. \u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0442\u044c modeler<\/em><\/strong>-\u0443.<\/p>\n\n\n\n

4. \u041f\u043e\u0434 modeler <\/em>\u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0439 header file ModelLoader.h<\/strong> <\/p>\n\n\n\n

Location: C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n

\u041a\u043e\u0434:<\/p>\n\n\n

\n#pragma once\n#include "XMLparser.h"\n#include "ModelBuilder.h"\n\nclass ModelLoader : public XMLparser\n{\npublic:\n\tModelBuilder* pModelBuilder = NULL;\n\tbool ownModelBuilder = false;\n\tstd::vector<GameSubj*>* pSubjsVector = NULL;\npublic:\n\tModelLoader(std::vector<GameSubj*>* pSubjsVector0, int subjN, ModelBuilder* pMB, std::string filePath) : XMLparser(filePath) {\n\t\tpSubjsVector = pSubjsVector0;\n\t\tif (pMB != NULL) {\n\t\t\townModelBuilder = false;\n\t\t\tpModelBuilder = pMB;\n\t\t}\n\t\telse {\n\t\t\townModelBuilder = true;\n\t\t\tpModelBuilder = new ModelBuilder();\n\t\t}\n\t\tpModelBuilder->useSubjN(subjN);\n\t};\n\tvirtual ~ModelLoader() {\n\t\tif (!ownModelBuilder)\n\t\t\treturn;\n\t\tpModelBuilder->buildDrawJobs(*pSubjsVector);\n\t\tdelete pModelBuilder;\n\t};\n\tstatic int fillProps_vs(VirtualShape* pVS, std::string tagStr); \/\/virtual shape\n\tstatic int processTag_a(ModelLoader* pML); \/\/apply\n\tstatic int setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr);\n\tstatic int setTexture(ModelLoader* pML, int* pInt, std::string txName);\n\tstatic int setMaterialTextures(ModelLoader* pML, Material* pMT);\n\tstatic int fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML); \/\/Material\n\tint processTag() { return processTag(this); };\n\tstatic int processTag(ModelLoader* pML);\n\tstatic int loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass);\n};\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n

\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u043e\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 XMLParser<\/em> \u043a\u043b\u0430\u0441\u0441.<\/p>\n\n\n\n


\n\n\n\n

5. \u041f\u043e\u0434 modeler <\/em>\u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0439 C++ file ModelLoader.cpp<\/strong> <\/p>\n\n\n\n

Location: C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n

\u041a\u043e\u0434:<\/p>\n\n\n

\n#include "ModelLoader.h"\n#include "platform.h"\n#include "TheGame.h"\n#include "DrawJob.h"\n#include "Texture.h"\n#include "utils.h"\n\nextern TheGame theGame;\n\nint ModelLoader::loadModel(std::vector<GameSubj*>* pSubjsVector0, std::string sourceFile, std::string subjClass) {\n\t\/\/returns element's (Subj) number or -1\n\tint subjN = pSubjsVector0->size();\n\tGameSubj* pGS = theGame.newGameSubj(subjClass);\n\tpSubjsVector0->push_back(pGS);\n\t\/\/pGS->djStartN = DrawJob::drawJobs.size();\n\tModelLoader* pML = new ModelLoader(pSubjsVector0, subjN, NULL, sourceFile);\n\tprocessSource(pML);\n\tdelete pML;\n\t\/\/pGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;\n\treturn subjN;\n}\nint ModelLoader::processTag_a(ModelLoader* pML) {\n\t\/\/apply\n\tModelBuilder* pMB = pML->pModelBuilder;\n\tstd::string tagStr = pML->currentTag;\n\tpMB->lockGroup(pMB);\n\n\tstd::vector<std::string> applyTosVector = splitString(pML->getStringValue("a", tagStr), ",");\n\tMaterial* pMT = pMB->materialsList.at(pMB->usingMaterialN);\n\tint texN = pMT->uTex1mask;\n\tif (texN < 0)\n\t\ttexN = pMT->uTex0;\n\tfloat xywh[4] = { 0,0,1,1 };\n\tsetFloatArray(xywh, 4, "xywh", tagStr);\n\tstd::string flipStr = getStringValue("flip", tagStr);\n\tTexCoords tc;\n\ttc.set(texN, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);\n\n\tsetFloatArray(xywh, 4, "xywh2nm", tagStr);\n\tflipStr = getStringValue("flip2nm", tagStr);\n\tTexCoords tc2nm;\n\ttc2nm.set(pMT->uTex2nm, xywh[0], xywh[1], xywh[2], xywh[3], flipStr);\n\n\tfor (int aN = 0; aN < (int)applyTosVector.size(); aN++) {\n\t\tpMB->buildFace(pMB, applyTosVector.at(aN), pMB->pCurrentVShape, &tc, &tc2nm);\n\t}\n\t\/\/mylog("vertsN=%d\\n",pMB->vertices.size());\n\n\tpMB->releaseGroup(pMB);\n\treturn 1;\n}\nint ModelLoader::setValueFromIntHashMap(int* pInt, std::map<std::string, int> intHashMap, std::string varName, std::string tagStr) {\n\tif (!varExists(varName, tagStr))\n\t\treturn 0;\n\tstd::string str0 = getStringValue(varName, tagStr);\n\tif (intHashMap.find(str0) == intHashMap.end()) {\n\t\tmylog("ERROR in ModelLoader::setValueFromIntMap, %s not found, %s\\n", varName.c_str(), tagStr.c_str());\n\t\treturn -1;\n\t}\n\t*pInt = intHashMap[getStringValue(varName, tagStr)];\n\treturn 1;\n}\nint ModelLoader::setTexture(ModelLoader* pML, int* pInt, std::string txName) {\n\tModelBuilder* pMB = pML->pModelBuilder;\n\tstd::string varName = txName + "_use";\n\tif (setValueFromIntHashMap(pInt, pMB->texturesHashMap, varName, pML->currentTag) == 0) {\n\t\t\/\/the texture is not in hash table\n\t\tvarName = txName + "_src";\n\t\tif (varExists(varName, pML->currentTag)) {\n\t\t\tstd::string txFile = getStringValue(varName, pML->currentTag);\n\t\t\tvarName = txName + "_ckey";\n\t\t\tunsigned int intCkey = 0;\n\t\t\tsetUintColorValue(&intCkey, varName, pML->currentTag);\n\t\t\t*pInt = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);\n\t\t}\n\t}\n\treturn 1;\n}\nint ModelLoader::setMaterialTextures(ModelLoader* pML, Material* pMT) {\n\tsetTexture(pML, &pMT->uTex0, "uTex0");\n\tsetTexture(pML, &pMT->uTex1mask, "uTex1mask");\n\tsetTexture(pML, &pMT->uTex2nm, "uTex2nm");\n\tsetTexture(pML, &pMT->uTex3, "uTex3");\n\treturn 1;\n}\nint ModelLoader::fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML) {\n\tsetCharsValue(pMT->shaderType, 20, "mt_type", tagStr);\n\tsetMaterialTextures(pML, pMT);\n\t\/\/color\n\tif (varExists("uColor", tagStr)) {\n\t\tunsigned int uintColor = 0;\n\t\tsetUintColorValue(&uintColor, "uColor", tagStr);\n\t\tpMT->uColor.setUint32(uintColor);\n\t}\n\t\/\/mylog("mt.uTex0=%d, mt.uTex1mask=%d\\n", mt.uTex0, mt.uTex1mask);\n\tif (varExists("primitiveType", tagStr)) {\n\t\tstd::string str0 = getStringValue("primitiveType", tagStr);\n\t\tif (str0.compare("GL_POINTS") == 0) pMT->primitiveType = GL_POINTS;\n\t\telse if (str0.compare("GL_LINES") == 0) pMT->primitiveType = GL_LINES;\n\t\telse if (str0.compare("GL_LINE_STRIP") == 0) pMT->primitiveType = GL_LINE_STRIP;\n\t\telse if (str0.compare("GL_LINE_LOOP") == 0) pMT->primitiveType = GL_LINE_LOOP;\n\t\telse if (str0.compare("GL_TRIANGLE_STRIP") == 0) pMT->primitiveType = GL_TRIANGLE_STRIP;\n\t\telse if (str0.compare("GL_TRIANGLE_FAN") == 0) pMT->primitiveType = GL_TRIANGLE_FAN;\n\t\telse pMT->primitiveType = GL_TRIANGLES;\n\t}\n\tsetIntValue(&pMT->uTex1alphaChannelN, "uTex1alphaChannelN", tagStr);\n\tsetIntValue(&pMT->uTex0translateChannelN, "uTex0translateChannelN", tagStr);\n\tsetIntBoolValue(&pMT->uAlphaBlending, "uAlphaBlending", tagStr);\n\tsetFloatValue(&pMT->uAlphaFactor, "uAlphaFactor", tagStr);\n\tsetFloatValue(&pMT->uAmbient, "uAmbient", tagStr);\n\tsetFloatValue(&pMT->uSpecularIntencity, "uSpecularIntencity", tagStr);\n\tsetFloatValue(&pMT->uSpecularMinDot, "uSpecularMinDot", tagStr);\n\tsetFloatValue(&pMT->uSpecularPowerOf, "uSpecularPowerOf", tagStr);\n\n\tpML->pModelBuilder->useMaterial(pMT);\n\treturn 1;\n}\nint ModelLoader::processTag(ModelLoader* pML) {\n\tModelBuilder* pMB = pML->pModelBuilder;\n\tif (pML->tagName.compare("texture_as") == 0) {\n\t\t\/\/saves texture N in texturesMap under given name\n\t\tstd::string keyName = getStringValue("texture_as", pML->currentTag);\n\t\tif (pMB->texturesHashMap.find(keyName) != pMB->texturesHashMap.end())\n\t\t\treturn pMB->texturesHashMap[keyName];\n\t\telse { \/\/add new\n\t\t\tstd::string txFile = getStringValue("src", pML->currentTag);\n\t\t\tunsigned int intCkey = 0;\n\t\t\tsetUintColorValue(&intCkey, "ckey", pML->currentTag);\n\t\t\tint txN = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);\n\t\t\tpMB->texturesHashMap[keyName] = txN;\n\t\t\t\/\/mylog("%s=%d\\n", keyName.c_str(), pMB->texturesMap[keyName]);\n\t\t\treturn txN;\n\t\t}\n\t}\n\tif (pML->tagName.find("mt_") == 0) {\n\t\t\/\/sets current material\n\t\tModelBuilder* pMB = pML->pModelBuilder;\n\t\tif (!pML->closedTag) {\n\t\t\t\/\/save previous material in stack\n\t\t\tif (pMB->usingMaterialN >= 0)\n\t\t\t\tpMB->materialsStack.push_back(pMB->usingMaterialN);\n\t\t}\n\t\tMaterial mt;\n\t\treturn fillProps_mt(&mt, pML->currentTag, pML);\n\t}\n\tif (pML->tagName.find("\/mt_") == 0) {\n\t\t\/\/restore previous material\n\t\tif (pMB->materialsStack.size() > 0) {\n\t\t\tpMB->usingMaterialN = pMB->materialsStack.back();\n\t\t\tpMB->materialsStack.pop_back();\n\t\t}\n\t\treturn 1;\n\t}\n\tif (pML->tagName.compare("vs") == 0) {\n\t\t\/\/sets virtual shape\n\t\tModelBuilder* pMB = pML->pModelBuilder;\n\t\tif (pML->closedTag) {\n\t\t\tif (pMB->pCurrentVShape != NULL)\n\t\t\t\tdelete pMB->pCurrentVShape;\n\t\t}\n\t\telse { \/\/open tag\n\t\t\t\/\/save previous vshape in stack\n\t\t\tif (pMB->pCurrentVShape != NULL)\n\t\t\t\tpMB->vShapesStack.push_back(pMB->pCurrentVShape);\n\t\t}\n\t\tpMB->pCurrentVShape = new VirtualShape();\n\t\tfillProps_vs(pMB->pCurrentVShape, pML->currentTag);\n\t\treturn 1;\n\t}\n\tif (pML->tagName.compare("\/vs") == 0) {\n\t\t\/\/restore previous virtual shape\n\t\tif (pMB->vShapesStack.size() > 0) {\n\t\t\tif (pMB->pCurrentVShape != NULL)\n\t\t\t\tdelete(pMB->pCurrentVShape);\n\t\t\tpMB->pCurrentVShape = pMB->vShapesStack.back();\n\t\t\tpMB->vShapesStack.pop_back();\n\t\t}\n\t\treturn 1;\n\t}\n\tif (pML->tagName.compare("group") == 0) {\n\t\tstd::string notAllowed[] = { "pxyz","axyz","align","headTo" };\n\t\tint notAllowedLn = sizeof(notAllowed) \/ sizeof(notAllowed[0]);\n\t\tfor (int i = 0; i < notAllowedLn; i++)\n\t\t\tif (varExists(notAllowed[i], pML->currentTag)) {\n\t\t\t\tmylog("ERROR in ModelLoader::processTag: use %s in <\/group>: %s\\n", notAllowed[i].c_str(), pML->currentTag.c_str());\n\t\t\t\treturn -1;\n\t\t\t}\n\t\tpMB->lockGroup(pMB);\n\t\treturn 1;\n\t}\n\t\/\/mylog("%s, %s \/group?=%d\\n",pML->currentTag.c_str(), pML->tagName.c_str(), (pML->tagName.compare("\/group") == 0));\n\tif (pML->tagName.compare("\/group") == 0) {\n\t\tpMB->releaseGroup(pMB);\n\t\treturn 1;\n\t}\n\tif (pML->tagName.compare("a") == 0)\n\t\treturn processTag_a(pML); \/\/apply \n\n\tmylog("ERROR in ModelLoader::processTag, unhandled tag %s, file %s\\n", pML->currentTag.c_str(), pML->fullPath.c_str());\n\treturn -1;\n}\nint ModelLoader::fillProps_vs(VirtualShape* pVS, std::string tagStr) {\n\t\/\/sets virtual shape\n\tsetCharsValue(pVS->shapeType, 20, "vs", tagStr);\n\tsetFloatArray(pVS->whl, 3, "whl", tagStr);\n\t\/\/extensions\n\tfloat ext;\n\tif (varExists("ext", tagStr)) {\n\t\tsetFloatValue(&ext, "ext", tagStr);\n\t\tpVS->setExt(ext);\n\t}\n\tif (varExists("extX", tagStr)) {\n\t\tsetFloatValue(&ext, "extX", tagStr);\n\t\tpVS->setExtX(ext);\n\t}\n\tif (varExists("extY", tagStr)) {\n\t\tsetFloatValue(&ext, "extY", tagStr);\n\t\tpVS->setExtY(ext);\n\t}\n\tif (varExists("extZ", tagStr)) {\n\t\tsetFloatValue(&ext, "extZ", tagStr);\n\t\tpVS->setExtZ(ext);\n\t}\n\tsetFloatValue(&pVS->extU, "extU", tagStr);\n\tsetFloatValue(&pVS->extD, "extD", tagStr);\n\tsetFloatValue(&pVS->extL, "extL", tagStr);\n\tsetFloatValue(&pVS->extR, "extR", tagStr);\n\tsetFloatValue(&pVS->extF, "extF", tagStr);\n\tsetFloatValue(&pVS->extB, "extB", tagStr);\n\t\/\/sections\n\tsetIntValue(&pVS->sectionsR, "sectR", tagStr);\n\tsetIntValue(&pVS->sections[0], "sectX", tagStr);\n\tsetIntValue(&pVS->sections[1], "sectY", tagStr);\n\tsetIntValue(&pVS->sections[2], "sectZ", tagStr);\n\n\t\/\/mylog("pVS->shapeType=%s whl=%fx%fx%f\\n", pVS->shapeType, pVS->whl[0], pVS->whl[1], pVS->whl[2]);\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n


\n\n\n\n

\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u043e \u0441\u043b\u0435\u0433\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c ModelBuilder1base<\/strong>.<\/p>\n\n\n\n

6. \u0417\u0430\u043c\u0435\u043d\u0438\u043c ModelBuilder1base.h<\/em> \u043a\u043e\u0434 \u043d\u0430:<\/p>\n\n\n

\n#pragma once\n#include <string>\n#include <vector>\n#include "Vertex01.h"\n#include "Triangle01.h"\n#include "VirtualShape.h"\n#include "Group01.h"\n#include "Material.h"\n#include "GameSubj.h"\n#include <map>\n\nclass ModelBuilder1base\n{\npublic:\n\tstd::vector<Vertex01*> vertices;\n\tstd::vector<Triangle01*> triangles;\n\tstd::vector<int> subjNumbersList;\n\tint usingSubjN = -1;\n\n\tstd::vector<Group01*> groupsStack;\n\tGroup01* pCurrentGroup = NULL;\n\n\tstd::vector<VirtualShape*> vShapesStack;\n\tVirtualShape* pCurrentVShape = NULL;\n\n\tstd::vector<Material*> materialsList;\n\tint usingMaterialN = -1;\n\tstd::vector<int> materialsStack;\n\n\tstd::map<std::string, int> texturesHashMap;\npublic:\n\tvirtual ~ModelBuilder1base();\n\tint useSubjN(int subjN) { return useSubjN(this, subjN); };\n\tstatic int useSubjN(ModelBuilder1base* pMB, int subjN);\n\tint useMaterial(Material* pMT) { return useMaterial(this, pMT); };\n\tstatic int useMaterial(ModelBuilder1base* pMB, Material* pMT);\n\tstatic void lockGroup(ModelBuilder1base* pMB);\n\tstatic void releaseGroup(ModelBuilder1base* pMB);\n\tstatic int addVertex(ModelBuilder1base* pMB, float kx, float ky, float kz, float nx, float ny, float nz);\n\tstatic int add2triangles(ModelBuilder1base* pMB, int nNW, int nNE, int nSW, int nSE, int n);\n\tstatic int addTriangle(ModelBuilder1base* pMB, int n0, int n1, int n2);\n\tint buildDrawJobs(std::vector<GameSubj*> gameSubjs) { return buildDrawJobs(this, gameSubjs); };\n\tstatic int buildDrawJobs(ModelBuilder1base* pMB, std::vector<GameSubj*> gameSubjs);\n\tstatic int rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector<Vertex01*> allVertices, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);\n\tstatic int buildSingleDrawJob(Material* pMT, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);\n\tstatic int moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ);\n};\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n

\u0412\u0430\u0436\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/p>\n\n\n\n