{"id":1120,"date":"2021-12-31T19:46:26","date_gmt":"2021-12-31T19:46:26","guid":{"rendered":"https:\/\/writingagame.com\/?p=1120"},"modified":"2021-12-31T22:42:20","modified_gmt":"2021-12-31T22:42:20","slug":"chapter-34-adjusting-material","status":"publish","type":"post","link":"https:\/\/writingagame.com\/index.php\/2021\/12\/31\/chapter-34-adjusting-material\/","title":{"rendered":"Chapter 34. Adjusting Material"},"content":{"rendered":"\n<p>We are STILL trying to &#8220;draw&#8221; the joint (slit) between the pack and the lid, as a small&nbsp;<em>normal map<\/em>&nbsp;applied to&nbsp;<strong>existing&nbsp;<\/strong>textured mesh&#8217;s&nbsp;<strong>fragment<\/strong>.<\/p>\n\n\n\n<p>At this point we do have fragments with their own &#8220;native&#8221; Materials. In the last sample we just replaced them (Materials) by Phong green. Instead we need to use <strong>native <\/strong>Materials, but with added <em>normal map<\/em>. So, we need a way to <strong>adjust <\/strong><em>existing <\/em>materials.<\/p>\n\n\n\n<p>Implementation:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Windows<\/h2>\n\n\n\n<p>1. Start VS, open&nbsp;<em>C:\\CPP\\a997modeler\\p_windows\\p_windows.sln<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>2. Under <em>modeler <\/em>add new header file <strong>MaterialAdjust.h<\/strong><\/p>\n\n\n\n<p>Location: <em>C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n<p>Code:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [2,4]; title: ; notranslate\" title=\"\">\n#pragma once\n#include &quot;Material.h&quot;\n\nclass MaterialAdjust : public Material\n{\npublic:\n\tbool b_shaderType = false;\n\tbool b_primitiveType = false;\n\tbool b_uColor = false;\n\tbool b_uTex0 = false;\n\tbool b_uTex1mask = false;\n\tbool b_uTex2nm = false;\n\tbool b_uTex3 = false;\n\tbool b_uTex1alphaChannelN = false;\n\tbool b_uTex1alphaNegative = false;\n\tbool b_uTex0translateChannelN = false;\n\n\tbool b_uAlphaBlending = false;\n\tbool b_uAlphaFactor = false;\n\tbool b_uAmbient = false;\n\t\/\/specular light parameters\n\tbool b_uSpecularIntencity = false;\n\tbool b_uSpecularMinDot = false;\n\tbool b_uSpecularPowerOf = false;\npublic:\n\tstatic int adjust(Material* pMT, MaterialAdjust* pMA);\n\n\tstatic int setWhat2adjust(MaterialAdjust* pMA, std::string tagStr);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Please note: it inherits <strong>Material <\/strong>class.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>3. Under <em>modeler <\/em>add new C++ file <strong>MaterialAdjust.cpp<\/strong><\/p>\n\n\n\n<p>Location: <em>C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n<p>Code:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;MaterialAdjust.h&quot;\n\nint MaterialAdjust::adjust(Material* pMT, MaterialAdjust* pMA) {\n\tif (pMA-&gt;b_shaderType)\n\t\tpMT-&gt;setShaderType(pMA-&gt;shaderType);\n\tif (pMA-&gt;b_primitiveType)\n\t\tpMT-&gt;primitiveType = pMA-&gt;primitiveType;\n\tif (pMA-&gt;b_uColor) {\n\t\tmemcpy(&amp;pMT-&gt;uColor, &amp;pMA-&gt;uColor, sizeof(MyColor));\n\t\tpMT-&gt;uTex0 = -1;\n\t}\n\tif (pMA-&gt;b_uTex0) {\n\t\tpMT-&gt;uTex0 = pMA-&gt;uTex0;\n\t\tpMT-&gt;uColor.setUint32(0);\n\t}\n\tif (pMA-&gt;b_uTex1mask)\n\t\tpMT-&gt;uTex1mask = pMA-&gt;uTex1mask;\n\tif (pMA-&gt;b_uTex2nm)\n\t\tpMT-&gt;uTex2nm = pMA-&gt;uTex2nm;\n\tif (pMA-&gt;b_uTex3)\n\t\tpMT-&gt;uTex3 = pMA-&gt;uTex3;\n\tif (pMA-&gt;b_uTex1alphaChannelN)\n\t\tpMT-&gt;uTex1alphaChannelN = pMA-&gt;uTex1alphaChannelN;\n\tif (pMA-&gt;b_uTex1alphaNegative)\n\t\tpMT-&gt;uTex1alphaNegative = pMA-&gt;uTex1alphaNegative;\n\tif (pMA-&gt;b_uTex0translateChannelN)\n\t\tpMT-&gt;uTex0translateChannelN = pMA-&gt;uTex0translateChannelN;\n\tif (pMA-&gt;b_uAlphaBlending)\n\t\tpMT-&gt;uAlphaBlending = pMA-&gt;uAlphaBlending;\n\tif (pMA-&gt;b_uAlphaFactor)\n\t\tpMT-&gt;uAlphaFactor = pMA-&gt;uAlphaFactor;\n\tif (pMA-&gt;b_uAmbient)\n\t\tpMT-&gt;uAmbient = pMA-&gt;uAmbient;\n\tif (pMA-&gt;b_uSpecularIntencity)\n\t\tpMT-&gt;uSpecularIntencity = pMA-&gt;uSpecularIntencity;\n\tif (pMA-&gt;b_uSpecularMinDot)\n\t\tpMT-&gt;uSpecularMinDot = pMA-&gt;uSpecularMinDot;\n\tif (pMA-&gt;b_uSpecularPowerOf)\n\t\tpMT-&gt;uSpecularPowerOf = pMA-&gt;uSpecularPowerOf;\n\treturn 1;\n}\nint MaterialAdjust::setWhat2adjust(MaterialAdjust* pMA, std::string tagStr) {\n\tif (tagStr.find(&quot;uTex0&quot;) != std::string::npos)\n\t\tif(pMA-&gt;uTex0 &gt;= 0)\n\t\t\tpMA-&gt;b_uTex0 = true;\n\tif (tagStr.find(&quot;uTex1mask&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uTex1mask = true;\n\tif (tagStr.find(&quot;uTex2nm&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uTex2nm = true;\n\tif (tagStr.find(&quot;uTex3&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uTex3 = true;\n\tif (tagStr.find(&quot;mt_type&quot;) != std::string::npos)\n\t\tpMA-&gt;b_shaderType = true;\n\tif (tagStr.find(&quot;uColor&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uColor = true;\n\tif (tagStr.find(&quot;primitiveType&quot;) != std::string::npos)\n\t\tpMA-&gt;b_primitiveType = true;\n\tif (tagStr.find(&quot;uTex1alphaChannelN&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uTex1alphaChannelN = true;\n\tif (tagStr.find(&quot;uTex0translateChannelN&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uTex0translateChannelN = true;\n\tif (tagStr.find(&quot;uAlphaBlending&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uAlphaBlending = true;\n\tif (tagStr.find(&quot;uAlphaFactor&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uAlphaFactor = true;\n\tif (tagStr.find(&quot;uAmbient&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uAmbient = true;\n\tif (tagStr.find(&quot;uSpecularIntencity&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uSpecularIntencity = true;\n\tif (tagStr.find(&quot;uSpecularMinDot&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uSpecularMinDot = true;\n\tif (tagStr.find(&quot;uSpecularPowerOf&quot;) != std::string::npos)\n\t\tpMA-&gt;b_uSpecularPowerOf = true;\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p>Please note: this class has all inherited functionality from <em>Material <\/em>class plus 2 new functions:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>setWhat2adjust(..)<\/em> which checks given tag and marks what Material&#8217;s properties need to be adjusted (overwritten).<\/li><li>and <em>adjust(..)<\/em> which actually adjusts given Material&#8217;s properties.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>In  <em>root01.txt<\/em> we have a new tag now:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;mt_adjust uTex2nm_use=\"tx0\" &gt;<\/code><\/pre>\n\n\n\n<p>4. Copy following code to a&nbsp;<strong>Text Editor<\/strong>&nbsp;and save (overwrite) it to\/as<\/p>\n\n\n\n<p><em>C:\\CPP\\<strong>a997modeler<\/strong>\\dt\\models\\misc\\marlboro01\\<strong>root01.txt<\/strong><\/em><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; highlight: [33,39]; title: ; notranslate\" title=\"\">\n&lt;texture_as=&quot;tx0&quot; src=&quot;marlboro03small.png&quot; ckey=&quot;#00ff00&quot;\/&gt;\n&lt;mt_type=&quot;phong&quot; uTex0_use=&quot;tx0&quot; \/&gt;\n&lt;vs=&quot;box_tank&quot; whl=&quot;53,83,21&quot; ext=1 sectR=1 \/&gt;\n&lt;a=&quot;front v&quot; xywh=&quot;2,1,323,495&quot; mark=&quot;box_front&quot;\/&gt;\n&lt;a=&quot;back v&quot;  xywh=&quot;2,1,323,495&quot; mark=&quot;box_back&quot;\/&gt;\n&lt;a=&quot;right all&quot; xywh=&quot;327,1,128,495&quot; mark=&quot;box_right&quot;\/&gt;\n&lt;a=&quot;left all&quot; xywh=&quot;457,1,128,495&quot; mark=&quot;box_left&quot;\/&gt;\n&lt;a=&quot;top&quot; xywh=&quot;588,1,323,133&quot;\/&gt;\n&lt;a=&quot;bottom&quot; xywh=&quot;587,136,324,134&quot;\/&gt;\n\/\/golden prints\n&lt;vs=&quot;box&quot; whl=&quot;55.1,85.1,23.1&quot; \/&gt;\n&lt;texture_as=&quot;whitenoise&quot; src=&quot;\/dt\/common\/img\/whitenoise\/wn64_blur3.bmp&quot;\/&gt;\n&lt;texture_as=&quot;gold&quot; src=&quot;\/dt\/common\/img\/materials\/gold02roman.bmp&quot; \/&gt;\n&lt;mt_type=&quot;mirror&quot; uAlphaBlending uTex1mask_use=&quot;tx0&quot; uTex1alphaChannelN=1 uTex0_use=&quot;whitenoise&quot; uTex0translateChannelN=0 uTex3_use=&quot;gold&quot; \/&gt;\n\/\/side golden prints\n&lt;a=&quot;right&quot; xywh=&quot;342,12,101,10&quot; whl=&quot;x,1.8,18.1&quot; pxyz=&quot;x,39.8, -0.3&quot; \/&gt; \/\/Please do not litter\n&lt;a=&quot;right&quot; xywh=&quot;339,144,105,89&quot; whl=&quot;x,15.35,18.9&quot; pxyz=&quot;x,10.3,-0.12&quot; \/&gt; \/\/For special offers...\n&lt;a=&quot;left&quot; xywh=&quot;475,15,95,48&quot; whl=&quot;x,8.4,17&quot; pxyz=&quot;x,36, 0.3&quot; \/&gt; \/\/Underage sale...\n\/\/front prints\n&lt;group&gt;\n\t\/\/bottom golden print &quot;20 class a...&quot;\n\t&lt;a=&quot;front&quot; xywh=&quot;20,498,289,13&quot; whl=&quot;47.5,2,x&quot; pxyz=&quot;1,-36,x&quot; \/&gt;\n\t\/\/blazon\/emblem\n\t&lt;mt_type=&quot;mirror&quot; uAlphaBlending uTex2nm_use=&quot;tx0&quot; uTex0_use=&quot;whitenoise&quot; uTex0translateChannelN=0 uTex3_use=&quot;gold&quot; \/&gt;\n\t&lt;a=&quot;front&quot; xywh2nm=&quot;589,415,128,94&quot; whl=&quot;20.7,16,x&quot; pxyz=&quot;0.3,6.1,x&quot; \/&gt; \/\/emblem\n\t\/\/&quot;Marlboro\n\t&lt;mt_type=&quot;phong&quot; uAlphaBlending uTex2nm_use=&quot;tx0&quot; uColor=&quot;#1E211E&quot; \/&gt;\n\t&lt;a=&quot;front&quot; xywh2nm=&quot;590,275,301,136&quot; whl=&quot;49.2,23.3,x&quot; pxyz=&quot;0.21,-18,x&quot; \/&gt; \/\/marlboro\n&lt;\/group&gt; \n&lt;clone ay=180 \/&gt;\n\/\/joint (slit) between the pack and the lid\n&lt;group&gt;\n\t&lt;mt_adjust uTex2nm_use=&quot;tx0&quot; &gt;\n\t\t&lt;a2mesh wh=&quot;50,1&quot; xywh2nm=&quot;582,497,1,4&quot; all markedAs=&quot;box_right&quot; onThe=&quot;right&quot; py=24.6 az=31 \/&gt;\n\t\t&lt;a2mesh wh=&quot;50,1&quot; xywh2nm=&quot;582,497,1,4&quot; all markedAs=&quot;box_left&quot;  onThe=&quot;left&quot;  py=24.6 az=-31 \/&gt;\n\t\t&lt;a2mesh wh=&quot;53,1&quot; xywh2nm=&quot;582,497,1,4&quot; all markedAs=&quot;box_front&quot;               py=17.8 \/&gt;\n\t\t&lt;a2mesh wh=&quot;6 ,1&quot; xywh2nm=&quot;582,497,1,4&quot; all markedAs=&quot;box_back&quot;  onThe=&quot;back&quot;  py=31.5 px=23.5 \/&gt;\n\t\t&lt;a2mesh wh=&quot;6 ,1&quot; xywh2nm=&quot;582,497,1,4&quot; all markedAs=&quot;box_back&quot;  onThe=&quot;back&quot;  py=31.5 px=-23.5 \/&gt;\n\t&lt;\/mt_adjust&gt; \n&lt;\/group sizeD=&quot;0.1,0,0.1&quot;&gt; \n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Please note: in <em>a2mesh <\/em>tags now we have a new property <em>xywh2nm<\/em> &#8211; texture coordinates for <em>normal map<\/em>.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>Now &#8211; reading and executing new tags\/properties:<\/p>\n\n\n\n<p>5. Open&nbsp;<em>ModelLoader.h<\/em>&nbsp;and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#pragma once\n#include &quot;XMLparser.h&quot;\n#include &quot;ModelBuilder.h&quot;\n#include &quot;GroupTransform.h&quot;\n#include &quot;MaterialAdjust.h&quot;\n\nclass ModelLoader : public XMLparser\n{\npublic:\n\tModelBuilder* pModelBuilder = NULL;\n\tbool ownModelBuilder = false;\n\tstd::vector&lt;GameSubj*&gt;* pSubjsVector = NULL;\n\tMaterialAdjust* pMaterialAdjust = NULL;\npublic:\n\tModelLoader(std::vector&lt;GameSubj*&gt;* 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\tpModelBuilder-&gt;lockGroup(pModelBuilder);\n\t\t}\n\t\tpModelBuilder-&gt;useSubjN(pModelBuilder,subjN);\n\t};\n\tvirtual ~ModelLoader() {\n\t\tif (!ownModelBuilder)\n\t\t\treturn;\n\t\tpModelBuilder-&gt;buildDrawJobs(pModelBuilder, *pSubjsVector);\n\t\tdelete pModelBuilder;\n\t};\n\tstatic int processTag_a(ModelLoader* pML); \/\/apply\n\tstatic int setValueFromIntHashMap(int* pInt, std::map&lt;std::string, int&gt; 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_vs(VirtualShape* pVS, std::string tagStr); \/\/virtual shape\n\tstatic int fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML); \/\/Material\n\tstatic int fillProps_gt(GroupTransform* pGS, ModelBuilder* pMB, std::string tagStr);\n\tvirtual int processTag() { return processTag(this); };\n\tstatic int processTag(ModelLoader* pML);\n\tstatic int loadModel(std::vector&lt;GameSubj*&gt;* pSubjsVector0, std::string sourceFile, std::string subjClass);\n\tstatic int processTag_clone(ModelLoader* pML);\n\tstatic int addMark(char* marks, std::string newMark);\n\tstatic int processTag_do(ModelLoader* pML);\n\tstatic int processTag_a2mesh(ModelLoader* pML);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>6.  Open&nbsp;<em>ModelLoader.cpp<\/em>&nbsp;and replace code by: <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [411]; title: ; notranslate\" title=\"\">\n#include &quot;ModelLoader.h&quot;\n#include &quot;platform.h&quot;\n#include &quot;TheGame.h&quot;\n#include &quot;DrawJob.h&quot;\n#include &quot;Texture.h&quot;\n#include &quot;utils.h&quot;\n#include &quot;Polygon.h&quot;\n\nextern TheGame theGame;\n\nint ModelLoader::loadModel(std::vector&lt;GameSubj*&gt;* pSubjsVector0, std::string sourceFile, std::string subjClass) {\n\t\/\/returns element&#039;s (Subj) number or -1\n\tint subjN = pSubjsVector0-&gt;size();\n\tGameSubj* pGS = theGame.newGameSubj(subjClass);\n\tpSubjsVector0-&gt;push_back(pGS);\n\t\/\/pGS-&gt;djStartN = DrawJob::drawJobs.size();\n\tModelLoader* pML = new ModelLoader(pSubjsVector0, subjN, NULL, sourceFile);\n\tprocessSource(pML);\n\tdelete pML;\n\t\/\/pGS-&gt;djTotalN = DrawJob::drawJobs.size() - pGS-&gt;djStartN;\n\treturn subjN;\n}\n\nint ModelLoader::setValueFromIntHashMap(int* pInt, std::map&lt;std::string, int&gt; 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(&quot;ERROR in ModelLoader::setValueFromIntMap, %s not found, %s\\n&quot;, varName.c_str(), tagStr.c_str());\n\t\treturn -1;\n\t}\n\t*pInt = intHashMap&#91;getStringValue(varName, tagStr)];\n\treturn 1;\n}\nint ModelLoader::setTexture(ModelLoader* pML, int* pInt, std::string txName) {\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tstd::string varName = txName + &quot;_use&quot;;\n\tif (setValueFromIntHashMap(pInt, pMB-&gt;texturesHashMap, varName, pML-&gt;currentTag) == 0) {\n\t\t\/\/the texture is not in hash table\n\t\tvarName = txName + &quot;_src&quot;;\n\t\tif (varExists(varName, pML-&gt;currentTag)) {\n\t\t\tstd::string txFile = getStringValue(varName, pML-&gt;currentTag);\n\t\t\tvarName = txName + &quot;_ckey&quot;;\n\t\t\tunsigned int intCkey = 0;\n\t\t\tsetUintColorValue(&amp;intCkey, varName, pML-&gt;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, &amp;pMT-&gt;uTex0, &quot;uTex0&quot;);\n\tsetTexture(pML, &amp;pMT-&gt;uTex1mask, &quot;uTex1mask&quot;);\n\tsetTexture(pML, &amp;pMT-&gt;uTex2nm, &quot;uTex2nm&quot;);\n\tsetTexture(pML, &amp;pMT-&gt;uTex3, &quot;uTex3&quot;);\n\treturn 1;\n}\nint ModelLoader::fillProps_mt(Material* pMT, std::string tagStr, ModelLoader* pML) {\n\tsetCharsValue(pMT-&gt;shaderType, 20, &quot;mt_type&quot;, tagStr);\n\tsetMaterialTextures(pML, pMT);\n\t\/\/color\n\tif (varExists(&quot;uColor&quot;, tagStr)) {\n\t\tunsigned int uintColor = 0;\n\t\tsetUintColorValue(&amp;uintColor, &quot;uColor&quot;, tagStr);\n\t\tpMT-&gt;uColor.setUint32(uintColor);\n\t}\n\t\/\/mylog(&quot;mt.uTex0=%d, mt.uTex1mask=%d\\n&quot;, mt.uTex0, mt.uTex1mask);\n\tif (varExists(&quot;primitiveType&quot;, tagStr)) {\n\t\tstd::string str0 = getStringValue(&quot;primitiveType&quot;, tagStr);\n\t\tif (str0.compare(&quot;GL_POINTS&quot;) == 0) pMT-&gt;primitiveType = GL_POINTS;\n\t\telse if (str0.compare(&quot;GL_LINES&quot;) == 0) pMT-&gt;primitiveType = GL_LINES;\n\t\telse if (str0.compare(&quot;GL_LINE_STRIP&quot;) == 0) pMT-&gt;primitiveType = GL_LINE_STRIP;\n\t\telse if (str0.compare(&quot;GL_LINE_LOOP&quot;) == 0) pMT-&gt;primitiveType = GL_LINE_LOOP;\n\t\telse if (str0.compare(&quot;GL_TRIANGLE_STRIP&quot;) == 0) pMT-&gt;primitiveType = GL_TRIANGLE_STRIP;\n\t\telse if (str0.compare(&quot;GL_TRIANGLE_FAN&quot;) == 0) pMT-&gt;primitiveType = GL_TRIANGLE_FAN;\n\t\telse pMT-&gt;primitiveType = GL_TRIANGLES;\n\t}\n\tsetIntValue(&amp;pMT-&gt;uTex1alphaChannelN, &quot;uTex1alphaChannelN&quot;, tagStr);\n\tsetIntValue(&amp;pMT-&gt;uTex0translateChannelN, &quot;uTex0translateChannelN&quot;, tagStr);\n\tsetIntBoolValue(&amp;pMT-&gt;uAlphaBlending, &quot;uAlphaBlending&quot;, tagStr);\n\tsetFloatValue(&amp;pMT-&gt;uAlphaFactor, &quot;uAlphaFactor&quot;, tagStr);\n\tsetFloatValue(&amp;pMT-&gt;uAmbient, &quot;uAmbient&quot;, tagStr);\n\tsetFloatValue(&amp;pMT-&gt;uSpecularIntencity, &quot;uSpecularIntencity&quot;, tagStr);\n\tsetFloatValue(&amp;pMT-&gt;uSpecularMinDot, &quot;uSpecularMinDot&quot;, tagStr);\n\tsetFloatValue(&amp;pMT-&gt;uSpecularPowerOf, &quot;uSpecularPowerOf&quot;, tagStr);\n\treturn 1;\n}\nint ModelLoader::processTag(ModelLoader* pML) {\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tif (pML-&gt;tagName.compare(&quot;texture_as&quot;) == 0) {\n\t\t\/\/saves texture N in texturesMap under given name\n\t\tstd::string keyName = getStringValue(&quot;texture_as&quot;, pML-&gt;currentTag);\n\t\tif (pMB-&gt;texturesHashMap.find(keyName) != pMB-&gt;texturesHashMap.end())\n\t\t\treturn pMB-&gt;texturesHashMap&#91;keyName];\n\t\telse { \/\/add new\n\t\t\tstd::string txFile = getStringValue(&quot;src&quot;, pML-&gt;currentTag);\n\t\t\tunsigned int intCkey = 0;\n\t\t\tsetUintColorValue(&amp;intCkey, &quot;ckey&quot;, pML-&gt;currentTag);\n\t\t\tint txN = Texture::loadTexture(buildFullPath(pML, txFile), intCkey);\n\t\t\tpMB-&gt;texturesHashMap&#91;keyName] = txN;\n\t\t\t\/\/mylog(&quot;%s=%d\\n&quot;, keyName.c_str(), pMB-&gt;texturesMap&#91;keyName]);\n\t\t\treturn txN;\n\t\t}\n\t}\n\tif (pML-&gt;tagName.compare(&quot;mt_type&quot;) == 0) {\n\t\t\/\/sets current material\n\t\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\t\tif (!pML-&gt;closedTag) {\n\t\t\t\/\/save previous material in stack\n\t\t\tif (pMB-&gt;usingMaterialN &gt;= 0)\n\t\t\t\tpMB-&gt;materialsStack.push_back(pMB-&gt;usingMaterialN);\n\t\t}\n\t\tMaterial mt;\n\t\tfillProps_mt(&amp;mt, pML-&gt;currentTag, pML);\n\t\tpMB-&gt;usingMaterialN = pMB-&gt;getMaterialN(pMB, &amp;mt);\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;\/mt_type&quot;) == 0) {\n\t\t\/\/restore previous material\n\t\tif (pMB-&gt;materialsStack.size() &gt; 0) {\n\t\t\tpMB-&gt;usingMaterialN = pMB-&gt;materialsStack.back();\n\t\t\tpMB-&gt;materialsStack.pop_back();\n\t\t}\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;vs&quot;) == 0) {\n\t\t\/\/sets virtual shape\n\t\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\t\tif (pML-&gt;closedTag) {\n\t\t\tif (pMB-&gt;pCurrentVShape != NULL)\n\t\t\t\tdelete pMB-&gt;pCurrentVShape;\n\t\t}\n\t\telse { \/\/open tag\n\t\t\t\/\/save previous vshape in stack\n\t\t\tif (pMB-&gt;pCurrentVShape != NULL)\n\t\t\t\tpMB-&gt;vShapesStack.push_back(pMB-&gt;pCurrentVShape);\n\t\t}\n\t\tpMB-&gt;pCurrentVShape = new VirtualShape();\n\t\tfillProps_vs(pMB-&gt;pCurrentVShape, pML-&gt;currentTag);\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;\/vs&quot;) == 0) {\n\t\t\/\/restore previous virtual shape\n\t\tif (pMB-&gt;vShapesStack.size() &gt; 0) {\n\t\t\tif (pMB-&gt;pCurrentVShape != NULL)\n\t\t\t\tdelete(pMB-&gt;pCurrentVShape);\n\t\t\tpMB-&gt;pCurrentVShape = pMB-&gt;vShapesStack.back();\n\t\t\tpMB-&gt;vShapesStack.pop_back();\n\t\t}\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;group&quot;) == 0) {\n\t\tstd::string notAllowed&#91;] = { &quot;pxyz&quot;,&quot;axyz&quot;,&quot;align&quot;,&quot;headTo&quot; };\n\t\tint notAllowedLn = sizeof(notAllowed) \/ sizeof(notAllowed&#91;0]);\n\t\tfor (int i = 0; i &lt; notAllowedLn; i++)\n\t\t\tif (varExists(notAllowed&#91;i], pML-&gt;currentTag)) {\n\t\t\t\tmylog(&quot;ERROR in ModelLoader::processTag: use %s in &lt;\/group&gt;: %s\\n&quot;, notAllowed&#91;i].c_str(), pML-&gt;currentTag.c_str());\n\t\t\t\treturn -1;\n\t\t\t}\n\t\tpMB-&gt;lockGroup(pMB);\n\t\t\/\/mark\n\t\tif (varExists(&quot;mark&quot;, pML-&gt;currentTag))\n\t\t\taddMark(pMB-&gt;pCurrentGroup-&gt;marks, getStringValue(&quot;mark&quot;, pML-&gt;currentTag));\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;\/group&quot;) == 0) {\n\t\tGroupTransform gt;\n\t\tfillProps_gt(&amp;gt, pMB, pML-&gt;currentTag);\n\t\tgt.executeGroupTransform(pMB);\n\n\t\tpMB-&gt;releaseGroup(pMB);\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;a&quot;) == 0)\n\t\treturn processTag_a(pML); \/\/apply \n\tif (pML-&gt;tagName.compare(&quot;clone&quot;) == 0)\n\t\treturn processTag_clone(pML);\n\tif (pML-&gt;tagName.compare(&quot;\/clone&quot;) == 0)\n\t\treturn processTag_clone(pML);\n\tif (pML-&gt;tagName.compare(&quot;do&quot;) == 0)\n\t\treturn processTag_do(pML);\n\tif (pML-&gt;tagName.compare(&quot;a2mesh&quot;) == 0)\n\t\treturn processTag_a2mesh(pML);\n\tif (pML-&gt;tagName.compare(&quot;mt_adjust&quot;) == 0) {\n\t\tif (pML-&gt;pMaterialAdjust != NULL)\n\t\t\tmylog(&quot;ERROR in ModelLoader::processTag %s, pMaterialAdjust is still busy. File: %s\\n&quot;, pML-&gt;currentTag.c_str(), pML-&gt;fullPath.c_str());\n\t\tpML-&gt;pMaterialAdjust = new (MaterialAdjust);\n\t\tfillProps_mt(pML-&gt;pMaterialAdjust, pML-&gt;currentTag, pML);\n\t\tpML-&gt;pMaterialAdjust-&gt;setWhat2adjust(pML-&gt;pMaterialAdjust, pML-&gt;currentTag);\n\t\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;\/mt_adjust&quot;) == 0) {\n\t\tif (pML-&gt;pMaterialAdjust != NULL) {\n\t\t\tdelete pML-&gt;pMaterialAdjust;\n\t\t\tpML-&gt;pMaterialAdjust = NULL;\n\t\t}\n\t\treturn 1;\n\t}\n\n\t\/\/mylog(&quot;%s, %s \/group?=%d\\n&quot;,pML-&gt;currentTag.c_str(), pML-&gt;tagName.c_str(), (pML-&gt;tagName.compare(&quot;\/group&quot;) == 0));\n\tmylog(&quot;ERROR in ModelLoader::processTag, unhandled tag %s, file %s\\n&quot;, pML-&gt;currentTag.c_str(), pML-&gt;fullPath.c_str());\n\treturn -1;\n}\nint ModelLoader::fillProps_vs(VirtualShape* pVS, std::string tagStr) {\n\t\/\/sets virtual shape\n\tsetCharsValue(pVS-&gt;shapeType, 20, &quot;vs&quot;, tagStr);\n\tsetFloatArray(pVS-&gt;whl, 3, &quot;whl&quot;, tagStr);\n\t\/\/extensions\n\tfloat ext;\n\tif (varExists(&quot;ext&quot;, tagStr)) {\n\t\tsetFloatValue(&amp;ext, &quot;ext&quot;, tagStr);\n\t\tpVS-&gt;setExt(ext);\n\t}\n\tif (varExists(&quot;extX&quot;, tagStr)) {\n\t\tsetFloatValue(&amp;ext, &quot;extX&quot;, tagStr);\n\t\tpVS-&gt;setExtX(ext);\n\t}\n\tif (varExists(&quot;extY&quot;, tagStr)) {\n\t\tsetFloatValue(&amp;ext, &quot;extY&quot;, tagStr);\n\t\tpVS-&gt;setExtY(ext);\n\t}\n\tif (varExists(&quot;extZ&quot;, tagStr)) {\n\t\tsetFloatValue(&amp;ext, &quot;extZ&quot;, tagStr);\n\t\tpVS-&gt;setExtZ(ext);\n\t}\n\tsetFloatValue(&amp;pVS-&gt;extU, &quot;extU&quot;, tagStr);\n\tsetFloatValue(&amp;pVS-&gt;extD, &quot;extD&quot;, tagStr);\n\tsetFloatValue(&amp;pVS-&gt;extL, &quot;extL&quot;, tagStr);\n\tsetFloatValue(&amp;pVS-&gt;extR, &quot;extR&quot;, tagStr);\n\tsetFloatValue(&amp;pVS-&gt;extF, &quot;extF&quot;, tagStr);\n\tsetFloatValue(&amp;pVS-&gt;extB, &quot;extB&quot;, tagStr);\n\t\/\/sections\n\tsetIntValue(&amp;pVS-&gt;sectionsR, &quot;sectR&quot;, tagStr);\n\tsetIntValue(&amp;pVS-&gt;sections&#91;0], &quot;sectX&quot;, tagStr);\n\tsetIntValue(&amp;pVS-&gt;sections&#91;1], &quot;sectY&quot;, tagStr);\n\tsetIntValue(&amp;pVS-&gt;sections&#91;2], &quot;sectZ&quot;, tagStr);\n\n\t\/\/mylog(&quot;pVS-&gt;shapeType=%s whl=%fx%fx%f\\n&quot;, pVS-&gt;shapeType, pVS-&gt;whl&#91;0], pVS-&gt;whl&#91;1], pVS-&gt;whl&#91;2]);\n\treturn 1;\n}\nint ModelLoader::processTag_a(ModelLoader* pML) {\n\t\/\/apply\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tstd::string tagStr = pML-&gt;currentTag;\n\tpMB-&gt;lockGroup(pMB);\n\t\/\/mark\n\tif (varExists(&quot;mark&quot;, tagStr))\n\t\taddMark(pMB-&gt;pCurrentGroup-&gt;marks, getStringValue(&quot;mark&quot;, tagStr));\n\n\tstd::vector&lt;std::string&gt; applyTosVector = splitString(pML-&gt;getStringValue(&quot;a&quot;, tagStr), &quot;,&quot;);\n\tMaterial* pMT = pMB-&gt;materialsList.at(pMB-&gt;usingMaterialN);\n\tint texN = pMT-&gt;uTex1mask;\n\tif (texN &lt; 0)\n\t\ttexN = pMT-&gt;uTex0;\n\tfloat xywh&#91;4] = { 0,0,1,1 };\n\tTexCoords* pTC = NULL;\n\tif (varExists(&quot;xywh&quot;, tagStr)) {\n\t\tsetFloatArray(xywh, 4, &quot;xywh&quot;, tagStr);\n\t\tstd::string flipStr = getStringValue(&quot;flip&quot;, tagStr);\n\t\tTexCoords tc;\n\t\ttc.set(texN, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\t\tpTC = &amp;tc;\n\t}\n\tTexCoords* pTC2nm = NULL;\n\tif (varExists(&quot;xywh2nm&quot;, tagStr)) {\n\t\tsetFloatArray(xywh, 4, &quot;xywh2nm&quot;, tagStr);\n\t\tstd::string flipStr = getStringValue(&quot;flip2nm&quot;, tagStr);\n\t\tTexCoords tc2nm;\n\t\ttc2nm.set(pMT-&gt;uTex2nm, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\t\tpTC2nm = &amp;tc2nm;\n\t}\n\t\/\/adjusted VirtualShape\n\tVirtualShape* pVS_a = new VirtualShape(*pMB-&gt;pCurrentVShape);\n\tfillProps_vs(pVS_a, tagStr);\n\n\tfor (int aN = 0; aN &lt; (int)applyTosVector.size(); aN++) {\n\t\tpMB-&gt;buildFace(pMB, applyTosVector.at(aN), pVS_a, pTC, pTC2nm);\n\t}\n\tdelete pVS_a;\n\t\/\/mylog(&quot;vertsN=%d\\n&quot;,pMB-&gt;vertices.size());\n\n\tGroupTransform GT_a;\n\tfillProps_gt(&amp;GT_a, pMB, tagStr);\n\tGT_a.executeGroupTransform(pMB);\n\n\tpMB-&gt;releaseGroup(pMB);\n\treturn 1;\n}\nint ModelLoader::processTag_clone(ModelLoader* pML) {\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tif (pML-&gt;tagName.compare(&quot;clone&quot;) == 0) {\n\t\t\/\/mark what to clone\n\t\tGroupTransform gt;\n\t\tgt.pGroup = pMB-&gt;pLastClosedGroup;\n\t\tgt.flagSelection(&amp;gt, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles);\n\n\t\t\/\/cloning\n\t\tpMB-&gt;lockGroup(pMB);\n\t\tgt.cloneFlagged(pMB, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles);\n\t}\n\tGroupTransform gt;\n\tfillProps_gt(&amp;gt, pMB, pML-&gt;currentTag);\n\tgt.executeGroupTransform(pMB);\n\n\tif (pML-&gt;tagName.compare(&quot;\/clone&quot;) == 0 || pML-&gt;closedTag) {\n\t\tpMB-&gt;releaseGroup(pMB);\n\t}\n\treturn 1;\n}\nint ModelLoader::addMark(char* marks, std::string newMark) {\n\tif (newMark.empty())\n\t\treturn 0;\n\tstd::string allMarks;\n\tallMarks.assign(marks);\n\tallMarks.append(&quot;&lt;&quot; + newMark + &quot;&gt;&quot;);\n\tmyStrcpy_s(marks, 124, allMarks.c_str());\n\treturn 1;\n}\nint ModelLoader::fillProps_gt(GroupTransform* pGT, ModelBuilder* pMB, std::string tagStr) {\n\tpGT-&gt;pGroup = pMB-&gt;pCurrentGroup;\n\t\/\/position\n\tsetFloatArray(pGT-&gt;shift, 3, &quot;pxyz&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;shift&#91;0], &quot;px&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;shift&#91;1], &quot;py&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;shift&#91;2], &quot;pz&quot;, tagStr);\n\t\/\/angles\n\tsetFloatArray(pGT-&gt;spin, 3, &quot;axyz&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;spin&#91;0], &quot;ax&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;spin&#91;1], &quot;ay&quot;, tagStr);\n\tsetFloatValue(&amp;pGT-&gt;spin&#91;2], &quot;az&quot;, tagStr);\n\t\/\/scale\n\tsetFloatArray(pGT-&gt;scale, 3, &quot;scale&quot;, tagStr);\n\n\tpGT-&gt;onThe = getStringValue(&quot;onThe&quot;, tagStr);\n\tpGT-&gt;allign = getStringValue(&quot;allign&quot;, tagStr);\n\tpGT-&gt;headZto = getStringValue(&quot;headZto&quot;, tagStr);\n\t\/\/limit to\n\tif (varExists(&quot;all&quot;, tagStr))\n\t\tpGT-&gt;pGroup = NULL;\n\tif (varExists(&quot;lastClosedGroup&quot;, tagStr))\n\t\tpGT-&gt;pGroup = pMB-&gt;pLastClosedGroup;\n\tif (varExists(&quot;markedAs&quot;, tagStr))\n\t\tpGT-&gt;limit2mark(pGT, getStringValue(&quot;markedAs&quot;, tagStr));\n\tsetFloatArray(pGT-&gt;pMin, 3, &quot;xyzMin&quot;, tagStr);\n\tsetFloatArray(pGT-&gt;pMax, 3, &quot;xyzMax&quot;, tagStr);\n\n\tif (varExists(&quot;sizeD&quot;, tagStr)) { \/\/re-size\n\t\tfloat sizeD&#91;3];\n\t\tsetFloatArray(sizeD, 3, &quot;sizeD&quot;, tagStr);\n\t\t\/\/bounding box\n\t\tpGT-&gt;flagSelection(pGT, &amp;pMB-&gt;vertices, NULL);\n\t\tfloat bbMin&#91;3];\n\t\tfloat bbMax&#91;3];\n\t\tpGT-&gt;buildBoundingBoxFlagged(bbMin, bbMax, &amp;pMB-&gt;vertices);\n\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\tfloat size = bbMax&#91;i] - bbMin&#91;i];\n\t\t\tpGT-&gt;scale&#91;i] = (size + sizeD&#91;i]) \/ size;\n\t\t}\n\t}\n\treturn 1;\n}\nint ModelLoader::processTag_do(ModelLoader* pML) {\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tGroupTransform gt;\n\tfillProps_gt(&amp;gt, pMB, pML-&gt;currentTag);\n\tgt.flagSelection(&amp;gt, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles);\n\tgt.transformFlagged(&amp;gt, &amp;pMB-&gt;vertices);\n\treturn 1;\n}\nint ModelLoader::processTag_a2mesh(ModelLoader* pML) {\n\tModelBuilder* pMB = pML-&gt;pModelBuilder;\n\tstd::string tagStr = pML-&gt;currentTag;\n\tGroupTransform gt;\n\tfillProps_gt(&amp;gt, pMB, pML-&gt;currentTag);\n\tgt.flagSelection(&amp;gt, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles);\n\t\/\/clone a copy\n\tstd::vector&lt;Vertex01*&gt; vx1;\n\tstd::vector&lt;Triangle01*&gt; tr1;\n\tgt.cloneFlagged(NULL, &amp;vx1, &amp;tr1, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles);\n\t\/\/ build transform and inverted martrices\n\tmat4x4 transformMatrix;\n\tgt.buildTransformMatrix(&amp;gt, &amp;transformMatrix);\n\tmat4x4 transformMatrixInverted;\n\tmat4x4_invert(transformMatrixInverted, transformMatrix);\n\t\/\/move\/rotate cloned\n\tgt.flagAll(&amp;vx1, &amp;tr1);\n\t\/\/gt.transformFlagged(&amp;pMB-&gt;vertices, &amp;transformMatrixInverted);\n\tgt.transformFlaggedMx(&amp;vx1, &amp;transformMatrixInverted);\n\n\t\/\/gt.cloneFlagged(pMB, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles, &amp;vx1, &amp;tr1);\n\n\tfloat wh&#91;2];\n\tsetFloatArray(wh, 2, &quot;wh&quot;, tagStr);\n\tPolygon frame;\n\tframe.setRectangle(&amp;frame, wh&#91;0], wh&#91;1]);\n\t\/\/destination arrays\n\tstd::vector&lt;Vertex01*&gt; vx2;\n\tstd::vector&lt;Triangle01*&gt; tr2;\n\tPolygon triangle;\n\tfor (int i = tr1.size() - 1; i &gt;= 0; i--) {\n\t\ttriangle.setTriangle(&amp;triangle, tr1.at(i), &amp;vx1);\n\t\tPolygon intersection;\n\t\tint pointsN = Polygon::xyIntersection(&amp;intersection, &amp;frame, &amp;triangle);\n\t\tif (pointsN &gt; 2) {\n\t\t\tPolygon::buildTriangles(&amp;intersection);\n\t\t\tGroupTransform::flagAll(&amp;intersection.vertices, &amp;intersection.triangles);\n\t\t\tGroupTransform::cloneFlagged(NULL, &amp;vx2, &amp;tr2, &amp;intersection.vertices, &amp;intersection.triangles);\n\t\t}\n\t}\n\tgt.flagAll(&amp;vx2, &amp;tr2);\n\t\/\/at this point we have cutted fragment facing us\n\tint vxTotal = vx2.size();\n\tint trTotal = tr2.size();\n\t\/\/apply adjusted material ?\n\tif (pML-&gt;pMaterialAdjust != NULL) {\n\t\t\/\/scan vertices to find new (unupdated) material\n\t\tint materialNsrc = -1; \/\/which N to replace\n\t\tint materialNdst = -1; \/\/replace by N \n\t\tfor (int vN = 0; vN &lt; vxTotal; vN++) {\n\t\t\tVertex01* pV = vx2.at(vN);\n\t\t\tif (pV-&gt;flag &lt; 0)\n\t\t\t\tcontinue;\n\t\t\tif (materialNsrc == pV-&gt;materialN)\n\t\t\t\tcontinue;\n\t\t\t\/\/have new material\n\t\t\tmaterialNsrc = pV-&gt;materialN;\n\t\t\tMaterial mt;\n\t\t\tMaterial* pMt0 = pMB-&gt;materialsList.at(materialNsrc);\n\t\t\tmemcpy(&amp;mt, pMt0, sizeof(Material));\n\t\t\t\/\/modify material\n\t\t\tMaterialAdjust::adjust(&amp;mt, pML-&gt;pMaterialAdjust);\n\t\t\tmaterialNdst = pMB-&gt;getMaterialN(pMB, &amp;mt);\n\t\t\tif (materialNsrc != materialNdst) {\n\t\t\t\t\/\/replace mtN in vx and tr arrays\n\t\t\t\tfor (int vN2 = vN; vN2 &lt; vxTotal; vN2++) {\n\t\t\t\t\tVertex01* pV2 = vx2.at(vN2);\n\t\t\t\t\tif (pV2-&gt;flag &lt; 0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (materialNsrc == pV2-&gt;materialN)\n\t\t\t\t\t\tpV2-&gt;materialN = materialNdst;\n\t\t\t\t}\n\t\t\t\tfor (int tN2 = 0; tN2 &lt; trTotal; tN2++) {\n\t\t\t\t\tTriangle01* pT2 = tr2.at(tN2);\n\t\t\t\t\tif (pT2-&gt;flag &lt; 0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (materialNsrc == pT2-&gt;materialN)\n\t\t\t\t\t\tpT2-&gt;materialN = materialNdst;\n\t\t\t\t}\n\t\t\t\tmaterialNsrc = materialNdst;\n\t\t\t}\n\t\t}\n\t}\n\telse { \/\/ pML-&gt;pMaterialAdjust == NULL, use pMB-&gt;usingMaterialN\n\t\tfor (int vN2 = 0; vN2 &lt; vxTotal; vN2++) {\n\t\t\tVertex01* pV2 = vx2.at(vN2);\n\t\t\tif (pV2-&gt;flag &lt; 0)\n\t\t\t\tcontinue;\n\t\t\tpV2-&gt;materialN = pMB-&gt;usingMaterialN;\n\t\t}\n\t\tfor (int tN2 = 0; tN2 &lt; trTotal; tN2++) {\n\t\t\tTriangle01* pT2 = tr2.at(tN2);\n\t\t\tif (pT2-&gt;flag &lt; 0)\n\t\t\t\tcontinue;\n\t\t\tpT2-&gt;materialN = pMB-&gt;usingMaterialN;\n\t\t}\n\t}\n\t\/\/apply xywh\/2nm ?\n\tif (varExists(&quot;xywh&quot;, tagStr) || varExists(&quot;xywh2nm&quot;, tagStr)) {\n\t\tMaterial* pMT = pMB-&gt;materialsList.at(vx2.at(0)-&gt;materialN);\n\t\tfloat xywh&#91;4] = { 0,0,1,1 };\n\t\tTexCoords* pTC = NULL;\n\t\tif (varExists(&quot;xywh&quot;, tagStr)) {\n\t\t\tsetFloatArray(xywh, 4, &quot;xywh&quot;, tagStr);\n\t\t\tstd::string flipStr = getStringValue(&quot;flip&quot;, tagStr);\n\t\t\tint texN = pMT-&gt;uTex1mask;\n\t\t\tif (texN &lt; 0)\n\t\t\t\ttexN = pMT-&gt;uTex0;\n\t\t\tTexCoords tc;\n\t\t\ttc.set(texN, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\t\t\tpTC = &amp;tc;\n\t\t}\n\t\tTexCoords* pTC2nm = NULL;\n\n\t\tif (varExists(&quot;xywh2nm&quot;, tagStr)) {\n\t\t\tsetFloatArray(xywh, 4, &quot;xywh2nm&quot;, tagStr);\n\t\t\tstd::string flipStr = getStringValue(&quot;flip2nm&quot;, tagStr);\n\t\t\tTexCoords tc2nm;\n\t\t\ttc2nm.set(pMT-&gt;uTex2nm, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\t\t\tpTC2nm = &amp;tc2nm;\n\t\t}\n\t\tpMB-&gt;applyTexture2flagged(&amp;vx2, &quot;front&quot;, pTC, false);\n\t\tpMB-&gt;applyTexture2flagged(&amp;vx2, &quot;front&quot;, pTC2nm, true);\n\t}\n\t\/\/move\/rotate\n\tgt.transformFlaggedMx(&amp;vx2, &amp;transformMatrix);\n\t\/\/clone back to modelBuilder arrays\n\tgt.cloneFlagged(pMB, &amp;pMB-&gt;vertices, &amp;pMB-&gt;triangles, &amp;vx2, &amp;tr2);\n\n\t\/\/clear memory\n\tfor (int i = vx1.size() - 1; i &gt;= 0; i--)\n\t\tdelete vx1.at(i);\n\tvx1.clear();\n\tfor (int i = tr1.size() - 1; i &gt;= 0; i--)\n\t\tdelete tr1.at(i);\n\ttr1.clear();\n\tfor (int i = vx2.size() - 1; i &gt;= 0; i--)\n\t\tdelete vx2.at(i);\n\tvx2.clear();\n\tfor (int i = tr2.size() - 1; i &gt;= 0; i--)\n\t\tdelete tr2.at(i);\n\ttr2.clear();\n\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>New code is in function <em>processTag_a2mesh(..)<\/em> from line 411.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>New <em>ModelLoader <\/em>requires some new functionality in <em>ModelBuilder <\/em>class.<\/p>\n\n\n\n<p>7. Open  <em>ModelBuilder1base.h<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [35]; title: ; notranslate\" title=\"\">\n#pragma once\n#include &lt;string&gt;\n#include &lt;vector&gt;\n#include &quot;Vertex01.h&quot;\n#include &quot;Triangle01.h&quot;\n#include &quot;VirtualShape.h&quot;\n#include &quot;Group01.h&quot;\n#include &quot;Material.h&quot;\n#include &quot;GameSubj.h&quot;\n#include &lt;map&gt;\n\nclass ModelBuilder1base\n{\npublic:\n\tstd::vector&lt;Vertex01*&gt; vertices;\n\tstd::vector&lt;Triangle01*&gt; triangles;\n\tstd::vector&lt;int&gt; subjNumbersList;\n\tint usingSubjN = -1;\n\n\tstd::vector&lt;Group01*&gt; groupsStack;\n\tGroup01* pCurrentGroup = NULL;\n\tGroup01* pLastClosedGroup = NULL;\n\t\n\tstd::vector&lt;VirtualShape*&gt; vShapesStack;\n\tVirtualShape* pCurrentVShape = NULL;\n\n\tstd::vector&lt;Material*&gt; materialsList;\n\tint usingMaterialN = -1;\n\tstd::vector&lt;int&gt; materialsStack;\n\n\tstd::map&lt;std::string, int&gt; texturesHashMap;\npublic:\n\tvirtual ~ModelBuilder1base();\n\tstatic int useSubjN(ModelBuilder1base* pMB, int subjN);\n\tstatic int getMaterialN(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\tstatic int buildDrawJobs(ModelBuilder1base* pMB, std::vector&lt;GameSubj*&gt; gameSubjs);\n\tstatic int rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector&lt;Vertex01*&gt; allVertices, std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles);\n\tstatic int buildSingleDrawJob(Material* pMT, std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles);\n\tstatic int moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ);\n\tstatic int calculateTangentSpace(std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>New function here is  <em>getMaterialN(..) <\/em><\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>8. Open <em>ModelBuilder1base.cpp<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [58]; title: ; notranslate\" title=\"\">\n#include &quot;ModelBuilder1base.h&quot;\n#include &quot;platform.h&quot;\n#include &quot;utils.h&quot;\n#include &quot;DrawJob.h&quot;\n#include &quot;Shader.h&quot;\n\nextern float degrees2radians;\n\nModelBuilder1base::~ModelBuilder1base() {\n\treleaseGroup(this);\n\n\t\/\/clear all vectors\n\tint itemsN = vertices.size();\n\tfor (int i = 0; i &lt; itemsN; i++)\n\t\tdelete vertices.at(i);\n\tvertices.clear();\n\n\titemsN = triangles.size();\n\tfor (int i = 0; i &lt; itemsN; i++)\n\t\tdelete triangles.at(i);\n\ttriangles.clear();\n\n\titemsN = vShapesStack.size();\n\tfor (int i = 0; i &lt; itemsN; i++)\n\t\tdelete vShapesStack.at(i);\n\tvShapesStack.clear();\n\n\titemsN = groupsStack.size();\n\tfor (int i = 0; i &lt; itemsN; i++)\n\t\tdelete groupsStack.at(i);\n\tgroupsStack.clear();\n\tif (pCurrentGroup != NULL)\n\t\tdelete pCurrentGroup;\n\tif (pLastClosedGroup != NULL)\n\t\tdelete pLastClosedGroup;\n\n\titemsN = materialsList.size();\n\tfor (int i = 0; i &lt; itemsN; i++)\n\t\tdelete materialsList.at(i);\n\tmaterialsList.clear();\n\n\tsubjNumbersList.clear();\n}\nint ModelBuilder1base::useSubjN(ModelBuilder1base* pMB, int subjN) {\n\tpMB-&gt;usingSubjN = subjN;\n\tint itemsN = pMB-&gt;subjNumbersList.size();\n\tbool newN = true;\n\tif (itemsN &gt; 0)\n\t\tfor (int i = 0; i &lt; itemsN; i++)\n\t\t\tif (pMB-&gt;subjNumbersList.at(i) == subjN) {\n\t\t\t\tnewN = false;\n\t\t\t\tbreak;\n\t\t\t}\n\tif (newN)\n\t\tpMB-&gt;subjNumbersList.push_back(subjN);\n\treturn subjN;\n}\nint ModelBuilder1base::getMaterialN(ModelBuilder1base* pMB, Material* pMT) {\n\tint itemsN = pMB-&gt;materialsList.size();\n\tif (itemsN &gt; 0)\n\t\tfor (int i = 0; i &lt; itemsN; i++)\n\t\t\tif (memcmp(pMB-&gt;materialsList.at(i), pMT, sizeof(Material)) == 0) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\/\/if here - add new material to the list\n\tMaterial* pMTnew = new Material(*pMT);\n\tpMB-&gt;materialsList.push_back(pMTnew);\n\treturn itemsN;\n}\nint ModelBuilder1base::add2triangles(ModelBuilder1base* pMB, int nNW, int nNE, int nSW, int nSE, int n) {\n\t\/\/indexes: NorthWest, NorthEast, SouthWest,SouthEast\n\tif (n % 2 == 0) { \/\/even number\n\t\taddTriangle(pMB, nNW, nSW, nNE);\n\t\taddTriangle(pMB, nNE, nSW, nSE);\n\t}\n\telse { \/\/odd number\n\t\taddTriangle(pMB, nNW, nSE, nNE);\n\t\taddTriangle(pMB, nNW, nSW, nSE);\n\t}\n\treturn pMB-&gt;triangles.size() - 1;\n}\nint ModelBuilder1base::addTriangle(ModelBuilder1base* pMB, int i0, int i1, int i2) {\n\tTriangle01* pTR = new Triangle01();\n\tpMB-&gt;triangles.push_back(pTR);\n\tpTR-&gt;idx&#91;0] = i0;\n\tpTR-&gt;idx&#91;1] = i1;\n\tpTR-&gt;idx&#91;2] = i2;\n\tpTR-&gt;subjN = pMB-&gt;usingSubjN;\n\tpTR-&gt;materialN = pMB-&gt;usingMaterialN;\n\t\/\/mark\n\tif (pMB-&gt;pCurrentGroup != NULL)\n\t\tif (strcmp(pMB-&gt;pCurrentGroup-&gt;marks, &quot;&quot;) != 0)\n\t\t\tmyStrcpy_s(pTR-&gt;marks, 124, pMB-&gt;pCurrentGroup-&gt;marks);\n\treturn pMB-&gt;triangles.size() - 1;\n}\nint ModelBuilder1base::addVertex(ModelBuilder1base* pMB, float kx, float ky, float kz, float nx, float ny, float nz) {\n\tVertex01* pVX = new Vertex01();\n\tpMB-&gt;vertices.push_back(pVX);\n\tpVX-&gt;aPos&#91;0] = kx;\n\tpVX-&gt;aPos&#91;1] = ky;\n\tpVX-&gt;aPos&#91;2] = kz;\n\t\/\/normal\n\tpVX-&gt;aNormal&#91;0] = nx;\n\tpVX-&gt;aNormal&#91;1] = ny;\n\tpVX-&gt;aNormal&#91;2] = nz;\n\tpVX-&gt;subjN = pMB-&gt;usingSubjN;\n\tpVX-&gt;materialN = pMB-&gt;usingMaterialN;\n\t\/\/mark\n\tif (pMB-&gt;pCurrentGroup != NULL)\n\t\tif (strcmp(pMB-&gt;pCurrentGroup-&gt;marks, &quot;&quot;) != 0)\n\t\t\tmyStrcpy_s(pVX-&gt;marks, 124, pMB-&gt;pCurrentGroup-&gt;marks);\n\n\treturn pMB-&gt;vertices.size() - 1;\n}\nint ModelBuilder1base::buildDrawJobs(ModelBuilder1base* pMB, std::vector&lt;GameSubj*&gt; gameSubjs) {\n\tint totalSubjsN = pMB-&gt;subjNumbersList.size();\n\tif (totalSubjsN &lt; 1) {\n\t\tpMB-&gt;subjNumbersList.push_back(-1);\n\t\ttotalSubjsN = 1;\n\t}\n\tint totalMaterialsN = pMB-&gt;materialsList.size();\n\tif (totalSubjsN &lt; 2 &amp;&amp; totalMaterialsN &lt; 2) {\n\t\t\/\/simple single DrawJob\n\t\tMaterial* pMT = pMB-&gt;materialsList.at(0);\n\t\tGameSubj* pGS = NULL;\n\t\tint gsN = pMB-&gt;subjNumbersList.at(0);\n\t\tif (gsN &gt;= 0)\n\t\t\tpGS = gameSubjs.at(gsN);\n\t\tif (pGS != NULL)\n\t\t\tpGS-&gt;djStartN = DrawJob::drawJobs.size();\n\t\tbuildSingleDrawJob(pMT, pMB-&gt;vertices, pMB-&gt;triangles);\n\t\tif (pGS != NULL)\n\t\t\tpGS-&gt;djTotalN = DrawJob::drawJobs.size() - pGS-&gt;djStartN;\n\t\treturn 1;\n\t}\n\tint totalVertsN = pMB-&gt;vertices.size();\n\tint totalTrianglesN = pMB-&gt;triangles.size();\n\t\/\/clear flags\n\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(vN);\n\t\tpVX-&gt;flag = 0;\n\t}\n\tfor (int tN = 0; tN &lt; totalTrianglesN; tN++) {\n\t\tTriangle01* pTR = pMB-&gt;triangles.at(tN);\n\t\tpTR-&gt;flag = 0;\n\t}\n\tint addedDJs = 0;\n\tfor (int sN = 0; sN &lt; totalSubjsN; sN++) {\n\t\tGameSubj* pGS = NULL;\n\t\tint gsN = pMB-&gt;subjNumbersList.at(sN);\n\t\tif (gsN &gt;= 0)\n\t\t\tpGS = gameSubjs.at(gsN);\n\t\tif (pGS != NULL)\n\t\t\tpGS-&gt;djStartN = DrawJob::drawJobs.size();\n\t\tfor (int mtN = 0; mtN &lt; totalMaterialsN; mtN++) {\n\t\t\tMaterial* pMT = pMB-&gt;materialsList.at(mtN);\n\t\t\tstd::vector&lt;Vertex01*&gt; useVertices;\n\t\t\tstd::vector&lt;Triangle01*&gt; useTriangles;\n\t\t\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\t\t\tVertex01* pVX = pMB-&gt;vertices.at(vN);\n\t\t\t\tif (pVX-&gt;flag != 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pVX-&gt;subjN != gsN)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pVX-&gt;materialN != mtN)\n\t\t\t\t\tcontinue;\n\t\t\t\t\/\/if here - make a copy\n\t\t\t\tVertex01* pVX2 = new Vertex01(*pVX);\n\t\t\t\tuseVertices.push_back(pVX2);\n\t\t\t\tpVX2-&gt;altN = vN;\n\t\t\t\tpVX-&gt;flag = 1;\n\t\t\t\tif (pVX-&gt;endOfSequence &gt; 0) {\n\t\t\t\t\trearrangeArraysForDrawJob(pMB, pMB-&gt;vertices, useVertices, useTriangles);\n\t\t\t\t\tbuildSingleDrawJob(pMT, useVertices, useTriangles);\n\t\t\t\t\taddedDJs++;\n\t\t\t\t\t\/\/clear and proceed to next sequence\n\t\t\t\t\tint useVerticesN = useVertices.size();\n\t\t\t\t\tfor (int i = 0; i &lt; useVerticesN; i++)\n\t\t\t\t\t\tdelete useVertices.at(i);\n\t\t\t\t\tuseVertices.clear();\n\t\t\t\t}\n\t\t\t}\n\t\t\tint useVerticesN = useVertices.size();\n\t\t\tif (useVerticesN &lt; 1)\n\t\t\t\tcontinue; \/\/to next material\n\t\t\t\/\/pick triangles\n\t\t\tfor (int tN = 0; tN &lt; totalTrianglesN; tN++) {\n\t\t\t\tTriangle01* pTR = pMB-&gt;triangles.at(tN);\n\t\t\t\tif (pTR-&gt;flag != 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pTR-&gt;subjN != gsN)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pTR-&gt;materialN != mtN)\n\t\t\t\t\tcontinue;\n\t\t\t\t\/\/if here - make a copy\n\t\t\t\tTriangle01* pTR2 = new Triangle01(*pTR);\n\t\t\t\tuseTriangles.push_back(pTR2);\n\t\t\t\tpTR-&gt;flag = 1;\n\t\t\t}\n\t\t\trearrangeArraysForDrawJob(pMB, pMB-&gt;vertices, useVertices, useTriangles);\n\t\t\tbuildSingleDrawJob(pMT, useVertices, useTriangles);\n\t\t\taddedDJs++;\n\t\t\t\/\/clear all for next material\n\t\t\tfor (int i = 0; i &lt; useVerticesN; i++)\n\t\t\t\tdelete useVertices.at(i);\n\t\t\tuseVertices.clear();\n\t\t\tint useTrianglesN = useTriangles.size();\n\t\t\tfor (int i = 0; i &lt; useTrianglesN; i++)\n\t\t\t\tdelete useTriangles.at(i);\n\t\t\tuseTriangles.clear();\n\t\t}\n\t\tif (pGS != NULL)\n\t\t\tpGS-&gt;djTotalN = DrawJob::drawJobs.size() - pGS-&gt;djStartN;\n\t}\n\treturn addedDJs;\n}\n\nint ModelBuilder1base::buildSingleDrawJob(Material* pMT, std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles) {\n\tint totalVertsN = useVertices.size();\n\tif (totalVertsN &lt; 1)\n\t\treturn 0;\n\tif (pMT-&gt;uTex2nm &gt;= 0)\n\t\tcalculateTangentSpace(useVertices, useTriangles);\n\tpMT-&gt;pickShaderNumber();\n\tDrawJob* pDJ = new DrawJob();\n\t\/\/copy material to DJ\n\tmemcpy(&amp;pDJ-&gt;mt, pMT, sizeof(Material));\n\t\/\/calculate VBO element size (stride) and variables offsets in VBO\n\tint VBOid = DrawJob::newBufferId();\n\tint stride = 0;\n\tpDJ-&gt;setDesirableOffsets(&amp;stride, pDJ-&gt;mt.shaderN, VBOid);\n\t\/\/create an array for VBO\n\tint bufferSize = totalVertsN * stride;\n\tfloat* vertsBuffer = new float&#91;bufferSize];\n\t\/\/fill vertsBuffer\n\tShader* pSh = Shader::shaders.at(pDJ-&gt;mt.shaderN);\n\tint floatSize = sizeof(float);\n\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\tVertex01* pVX = useVertices.at(vN);\n\t\tint idx = vN * stride \/ floatSize;\n\t\t\/\/pick data from vertex and move to the buffer\n\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aPos.offset \/ floatSize], pVX-&gt;aPos, 3 * floatSize);\n\t\tif (pSh-&gt;l_aNormal &gt;= 0) \/\/normal\n\t\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aNormal.offset \/ floatSize], pVX-&gt;aNormal, 3 * floatSize);\n\t\tif (pSh-&gt;l_aTuv &gt;= 0) \/\/attribute TUV (texture coordinates)\n\t\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aTuv.offset \/ floatSize], pVX-&gt;aTuv, 2 * floatSize);\n\t\tif (pSh-&gt;l_aTuv2 &gt;= 0) \/\/attribute TUV2 (normal maps)\n\t\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aTuv2.offset \/ floatSize], pVX-&gt;aTuv2, 2 * floatSize);\n\t\tif (pSh-&gt;l_aTangent &gt;= 0)\n\t\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aTangent.offset \/ floatSize], pVX-&gt;aTangent, 3 * floatSize);\n\t\tif (pSh-&gt;l_aBinormal &gt;= 0)\n\t\t\tmemcpy(&amp;vertsBuffer&#91;idx + pDJ-&gt;aBinormal.offset \/ floatSize], pVX-&gt;aBinormal, 3 * floatSize);\n\t}\n\t\/\/buffer is ready, create VBO\n\tglBindBuffer(GL_ARRAY_BUFFER, VBOid);\n\tglBufferData(GL_ARRAY_BUFFER, bufferSize * floatSize, vertsBuffer, GL_STATIC_DRAW);\n\tdelete&#91;] vertsBuffer;\n\tpDJ-&gt;pointsN = totalVertsN;\n\n\tint totalTrianglesN = useTriangles.size();\n\tif (totalTrianglesN &gt; 0) {\n\t\t\/\/create EBO\n\t\tint totalIndexesN = totalTrianglesN * 3;\n\t\t\/\/create buffer\n\t\tGLushort* indexBuffer = new GLushort&#91;totalIndexesN];\n\t\tfor (int tN = 0; tN &lt; totalTrianglesN; tN++) {\n\t\t\tTriangle01* pTR = useTriangles&#91;tN];\n\t\t\tint idx = tN * 3;\n\t\t\tindexBuffer&#91;idx] = (GLushort)pTR-&gt;idx&#91;0];\n\t\t\tindexBuffer&#91;idx + 1] = (GLushort)pTR-&gt;idx&#91;1];\n\t\t\tindexBuffer&#91;idx + 2] = (GLushort)pTR-&gt;idx&#91;2];\n\t\t}\n\t\t\/\/buffer is ready, create IBO\n\t\tpDJ-&gt;glEBOid = DrawJob::newBufferId();\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pDJ-&gt;glEBOid);\n\t\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndexesN * sizeof(GLushort), indexBuffer, GL_STATIC_DRAW);\n\t\tdelete&#91;] indexBuffer;\n\t\tpDJ-&gt;pointsN = totalIndexesN;\n\t}\n\t\/\/create and fill vertex attributes array (VAO)\n\tpDJ-&gt;buildVAO();\n\treturn 1;\n}\n\nint ModelBuilder1base::rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector&lt;Vertex01*&gt; allVertices, std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles) {\n\tint totalTrianglesN = useTriangles.size();\n\tif (totalTrianglesN &lt; 1)\n\t\treturn 0;\n\tint totalVerticesN = useVertices.size();\n\t\/\/save new vertices order in original vertices array\n\t\/\/since triangles indices refer to original vertices order\n\tfor (int i = 0; i &lt; totalVerticesN; i++) {\n\t\tVertex01* pVX1 = useVertices.at(i);\n\t\tVertex01* pVX0 = allVertices.at(pVX1-&gt;altN);\n\t\tpVX0-&gt;altN = i;\n\t}\n\t\/\/replace triangle original indices by new numbers saved in original vertices altN\n\tfor (int tN = 0; tN &lt; totalTrianglesN; tN++) {\n\t\tTriangle01* pTR = useTriangles.at(tN);\n\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\tVertex01* pVX0 = allVertices.at(pTR-&gt;idx&#91;i]);\n\t\t\tpTR-&gt;idx&#91;i] = pVX0-&gt;altN;\n\t\t}\n\t}\n\treturn 1;\n}\n\nint ModelBuilder1base::moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ) {\n\t\/\/moves and rotates vertex group\n\t\/\/rotation angles are set in degrees\n\tmat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };\n\tmat4x4_translate(transformMatrix, kX, kY, kZ);\n\t\/\/rotation order: Z-X-Y\n\tif (aY != 0) mat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * aY);\n\tif (aX != 0) mat4x4_rotate_X(transformMatrix, transformMatrix, degrees2radians * aX);\n\tif (aZ != 0) mat4x4_rotate_Z(transformMatrix, transformMatrix, degrees2radians * aZ);\n\n\tint vertsN = pMB-&gt;vertices.size();\n\tfor (int i = pMB-&gt;pCurrentGroup-&gt;fromVertexN; i &lt; vertsN; i++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(i);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aPos, transformMatrix, pVX-&gt;aPos, 1);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aNormal, transformMatrix, pVX-&gt;aNormal, 0);\n\t}\n\treturn 1;\n}\n\nint ModelBuilder1base::calculateTangentSpace(std::vector&lt;Vertex01*&gt; useVertices, std::vector&lt;Triangle01*&gt; useTriangles) {\n\tint totalVertsN = useVertices.size();\n\tif (totalVertsN &lt; 1)\n\t\treturn 0;\n\tint totalTrianglesN = useTriangles.size();\n\t\/\/assuming that GL_TRIANGLES\n\t\/\/clear flags\n\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\tVertex01* pV = useVertices.at(vN);\n\t\tpV-&gt;flag = 0;\n\t}\n\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\tVertex01* pVX = useVertices.at(vN);\n\t\tif (pVX-&gt;flag != 0)\n\t\t\tcontinue;\n\t\tTriangle01* pT = NULL;\n\t\tfor (int tN = 0; tN &lt; totalTrianglesN; tN++) {\n\t\t\tpT = useTriangles.at(tN);\n\t\t\tbool haveTriangle = false;\n\t\t\tfor (int i = 0; i &lt; 3; i++)\n\t\t\t\tif (pT-&gt;idx&#91;i] == vN) {\n\t\t\t\t\thaveTriangle = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (haveTriangle)\n\t\t\t\tbreak;\n\t\t}\n\t\tVertex01* pV&#91;3];\n\t\tfor (int i = 0; i &lt; 3; i++)\n\t\t\tpV&#91;i] = useVertices.at(pT-&gt;idx&#91;i]);\n\n\t\tfloat dPos1&#91;3];\n\t\tfloat dPos2&#91;3];\n\t\tfloat dUV1&#91;2];\n\t\tfloat dUV2&#91;2];\n\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\tdPos1&#91;i] = pV&#91;1]-&gt;aPos&#91;i] - pV&#91;0]-&gt;aPos&#91;i];\n\t\t\tdPos2&#91;i] = pV&#91;2]-&gt;aPos&#91;i] - pV&#91;0]-&gt;aPos&#91;i];\n\t\t}\n\t\tfor (int i = 0; i &lt; 2; i++) {\n\t\t\tdUV1&#91;i] = pV&#91;1]-&gt;aTuv2&#91;i] - pV&#91;0]-&gt;aTuv2&#91;i];\n\t\t\tdUV2&#91;i] = pV&#91;2]-&gt;aTuv2&#91;i] - pV&#91;0]-&gt;aTuv2&#91;i];\n\t\t}\n\n\t\tfloat tangent&#91;3];\n\t\tfloat binormal&#91;3];\n\t\tfloat divider = dUV1&#91;0] * dUV2&#91;1] - dUV1&#91;1] * dUV2&#91;0];\n\t\tif (divider == 0) {\n\t\t\tv3set(tangent, 1, 0, 0);\n\t\t\tv3set(binormal, 0, -1, 0);\n\t\t}\n\t\telse {\n\t\t\tfloat r = 1.0f \/ divider;\n\t\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\t\ttangent&#91;i] = (dPos1&#91;i] * dUV2&#91;1] - dPos2&#91;i] * dUV1&#91;1]) * r;\n\t\t\t\tbinormal&#91;i] = -(dPos2&#91;i] * dUV1&#91;0] - dPos1&#91;i] * dUV2&#91;0]) * r;\n\t\t\t}\n\t\t\tvec3_norm(tangent, tangent);\n\t\t\tvec3_norm(binormal, binormal);\n\t\t}\n\t\t\/\/add to all 3 vertices\n\t\tfor (int n = 0; n &lt; 3; n++) {\n\t\t\tif (pV&#91;n]-&gt;flag &gt; 0)\n\t\t\t\tcontinue;\n\t\t\tv3copy(pV&#91;n]-&gt;aTangent, tangent);\n\t\t\tv3copy(pV&#91;n]-&gt;aBinormal, binormal);\n\t\t\tpV&#91;n]-&gt;flag = 1;\n\t\t}\n\t}\n\t\/\/normalize tangent and binormal around normal\n\tfor (int vN = 0; vN &lt; totalVertsN; vN++) {\n\t\tVertex01* pV = useVertices.at(vN);\n\t\tfloat v3out&#91;3];\n\t\t\/\/tangent\n\t\tvec3_mul_cross(v3out, pV-&gt;aNormal, pV-&gt;aBinormal);\n\t\tif (v3dotProduct(pV-&gt;aTangent, v3out) &lt; 0)\n\t\t\tv3inverse(v3out);\n\t\tv3copy(pV-&gt;aTangent, v3out);\n\t\t\/\/binormal\n\t\tvec3_mul_cross(v3out, pV-&gt;aNormal, pV-&gt;aTangent);\n\t\tif (v3dotProduct(pV-&gt;aBinormal, v3out) &lt; 0)\n\t\t\tv3inverse(v3out);\n\t\tv3copy(pV-&gt;aBinormal, v3out);\n\t}\n\treturn 1;\n}\nvoid ModelBuilder1base::lockGroup(ModelBuilder1base* pMB) {\n\tGroup01* pPrevGroup = pMB-&gt;pCurrentGroup;\n\tif (pMB-&gt;pCurrentGroup != NULL)\n\t\tpMB-&gt;groupsStack.push_back(pMB-&gt;pCurrentGroup);\n\tpMB-&gt;pCurrentGroup = new Group01();\n\tpMB-&gt;pCurrentGroup-&gt;fromVertexN = pMB-&gt;vertices.size();\n\tpMB-&gt;pCurrentGroup-&gt;fromTriangleN = pMB-&gt;triangles.size();\n\t\/\/marks\n\tif(pPrevGroup != NULL)\n\t\tif (strcmp(pPrevGroup-&gt;marks, &quot;&quot;) != 0)\n\t\t\tmyStrcpy_s(pMB-&gt;pCurrentGroup-&gt;marks, 124, pPrevGroup-&gt;marks);\n}\nvoid ModelBuilder1base::releaseGroup(ModelBuilder1base* pMB) {\n\tif (pMB-&gt;pLastClosedGroup != NULL)\n\t\tdelete pMB-&gt;pLastClosedGroup;\n\tpMB-&gt;pLastClosedGroup = pMB-&gt;pCurrentGroup;\n\n\tif (pMB-&gt;groupsStack.size() &gt; 0) {\n\t\tpMB-&gt;pCurrentGroup = pMB-&gt;groupsStack.back();\n\t\tpMB-&gt;groupsStack.pop_back();\n\t}\n\telse\n\t\tpMB-&gt;pCurrentGroup = NULL;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>9. Open <em>ModelBuilder.h<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [16]; title: ; notranslate\" title=\"\">\n#pragma once\n#include &quot;ModelBuilder1base.h&quot;\n#include &quot;TexCoords.h&quot;\n\nclass ModelBuilder : public ModelBuilder1base\n{\npublic:\n\tvirtual ~ModelBuilder();\n\tstatic int buildFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC = NULL, TexCoords* pTC2nm = NULL);\n\tstatic int buildBoxFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC = NULL, TexCoords* pTC2nm = NULL);\n\tstatic int buildBoxFacePlain(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS);\n\tstatic int buildBoxFaceTank(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS);\n\tstatic int cylinderWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo);\n\tstatic int capWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo);\n\tstatic int groupApplyTexture(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, TexCoords* pTC2nm = NULL);\n\tstatic int applyTexture2flagged(std::vector&lt;Vertex01*&gt;* pVX, std::string applyTo, TexCoords* pTC, bool isNormalMap);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>New function here is <em>applyTexture2flagged(..)<\/em><\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>10.  Open <em>ModelBuilder.cpp<\/em> and replace code by: <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [454]; title: ; notranslate\" title=\"\">\n#include &quot;ModelBuilder.h&quot;\n#include &quot;platform.h&quot;\n#include &quot;utils.h&quot;\n#include &quot;DrawJob.h&quot;\n#include &quot;Shader.h&quot;\n\nextern float degrees2radians;\n\nModelBuilder::~ModelBuilder() {\n}\n\nint ModelBuilder::buildFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC, TexCoords* pTC2nm) {\n\tif (strstr(pVS-&gt;shapeType, &quot;box&quot;) == pVS-&gt;shapeType)\n\t\treturn buildBoxFace(pMB, applyTo, pVS, pTC, pTC2nm);\n\treturn -1;\n}\nint ModelBuilder::buildBoxFace(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS, TexCoords* pTC, TexCoords* pTC2nm) {\n\t\/\/this code is for simple box\n\tVirtualShape vs; \/\/face VS, \n\tmat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };\n\tvs.sectionsR = pVS-&gt;sectionsR;\n\t\/\/rotate desirable side to face us. \n\tif (applyTo.find(&quot;front&quot;) == 0) {\n\t\t\/\/Side &lt;front&gt; is facing us as is.\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;0];\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;1];\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;0];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;1];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extF;\n\t\tvs.extL = pVS-&gt;extL;\n\t\tvs.extR = pVS-&gt;extR;\n\t\tvs.extU = pVS-&gt;extU;\n\t\tvs.extD = pVS-&gt;extD;\n\t\t\/\/define how to move\/place generated face back to the VirtualShape\n\t\t\/\/just shift closer to us by length\/2\n\t\tmat4x4_translate(transformMatrix, 0, 0, pVS-&gt;whl&#91;2] \/ 2);\n\t}\n\telse if (applyTo.find(&quot;back&quot;) == 0) {\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;0];\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;1];\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;0];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;1];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extB;\n\t\tvs.extL = pVS-&gt;extR;\n\t\tvs.extR = pVS-&gt;extL;\n\t\tvs.extU = pVS-&gt;extU;\n\t\tvs.extD = pVS-&gt;extD;\n\t\t\/\/rotate 180 degrees around Y and shift farther from us by half-length\n\t\tmat4x4_translate(transformMatrix, 0, 0, -pVS-&gt;whl&#91;2] \/ 2);\n\t\tmat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 180);\n\t}\n\telse if (applyTo.find(&quot;left&quot;) == 0) {\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;2]; \/\/width = original length\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;1];\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;2];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;1];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extL;\n\t\tvs.extL = pVS-&gt;extB;\n\t\tvs.extR = pVS-&gt;extF;\n\t\tvs.extU = pVS-&gt;extU;\n\t\tvs.extD = pVS-&gt;extD;\n\t\t\/\/rotate -90 degrees around Y (CW) and shift half-width to the left\n\t\tmat4x4_translate(transformMatrix, -pVS-&gt;whl&#91;0] \/ 2, 0, 0);\n\t\tmat4x4_rotate_Y(transformMatrix, transformMatrix, -degrees2radians * 90);\n\t}\n\telse if (applyTo.find(&quot;right&quot;) == 0) {\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;2]; \/\/width = original length\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;1];\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;2];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;1];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extR;\n\t\tvs.extL = pVS-&gt;extF;\n\t\tvs.extR = pVS-&gt;extB;\n\t\tvs.extU = pVS-&gt;extU;\n\t\tvs.extD = pVS-&gt;extD;\n\t\t\/\/rotate +90 degrees around Y (CCW) and shift half-width to the right\n\t\tmat4x4_translate(transformMatrix, pVS-&gt;whl&#91;0] \/ 2, 0, 0);\n\t\tmat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 90);\n\t}\n\telse if (applyTo.find(&quot;top&quot;) == 0) {\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;0];\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;2]; \/\/height = original length\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;0];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;2];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extU;\n\t\tvs.extL = pVS-&gt;extR;\n\t\tvs.extR = pVS-&gt;extL;\n\t\tvs.extU = pVS-&gt;extF;\n\t\tvs.extD = pVS-&gt;extB;\n\t\t\/\/rotate -90 degrees around X (CW) and 180 around Y, and shift half-height up\n\t\tmat4x4_translate(transformMatrix, 0, pVS-&gt;whl&#91;1] \/ 2, 0);\n\t\tmat4x4_rotate_Y(transformMatrix, transformMatrix, degrees2radians * 180);\n\t\tmat4x4_rotate_X(transformMatrix, transformMatrix, -degrees2radians * 90);\n\t}\n\telse if (applyTo.find(&quot;bottom&quot;) == 0) {\n\t\tvs.whl&#91;0] = pVS-&gt;whl&#91;0];\n\t\tvs.whl&#91;1] = pVS-&gt;whl&#91;2]; \/\/height = original length\n\t\tvs.sections&#91;0] = pVS-&gt;sections&#91;0];\n\t\tvs.sections&#91;1] = pVS-&gt;sections&#91;2];\n\t\t\/\/extensions\n\t\tvs.extF = pVS-&gt;extD;\n\t\tvs.extL = pVS-&gt;extL;\n\t\tvs.extR = pVS-&gt;extR;\n\t\tvs.extU = pVS-&gt;extF;\n\t\tvs.extD = pVS-&gt;extB;\n\t\t\/\/rotate 90 around X (CCW) and shift half-height down\n\t\tmat4x4_translate(transformMatrix, 0, -pVS-&gt;whl&#91;1] \/ 2, 0);\n\t\tmat4x4_rotate_X(transformMatrix, transformMatrix, degrees2radians * 90);\n\t}\n\tlockGroup(pMB);\n\t\/\/create vertices\n\tif (strstr(pVS-&gt;shapeType, &quot;tank&quot;) != nullptr)\n\t\tbuildBoxFaceTank(pMB, applyTo, &amp;vs);\n\telse\n\t\tbuildBoxFacePlain(pMB, applyTo, &amp;vs);\n\n\tgroupApplyTexture(pMB, &quot;front&quot;, pTC, pTC2nm);\n\n\t\/\/move face to it&#039;s place (apply transform matrix)\n\tint vertsN = pMB-&gt;vertices.size();\n\tfor (int i = pMB-&gt;pCurrentGroup-&gt;fromVertexN; i &lt; vertsN; i++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(i);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aPos, transformMatrix, pVX-&gt;aPos, 1);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aNormal, transformMatrix, pVX-&gt;aNormal, 0);\n\t}\n\treleaseGroup(pMB);\n\treturn 1;\n}\nint ModelBuilder::buildBoxFacePlain(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS) {\n\tif (pVS-&gt;whl&#91;0] == 0 || pVS-&gt;whl&#91;1] == 0)\n\t\treturn 0;\n\t\/\/create vertices\n\tint sectionsX = pVS-&gt;sections&#91;0];\n\tint sectionsY = pVS-&gt;sections&#91;1];\n\tint pointsX = sectionsX + 1;\n\tint pointsY = sectionsY + 1;\n\tfloat stepX = pVS-&gt;whl&#91;0] \/ sectionsX;\n\tfloat stepY = pVS-&gt;whl&#91;1] \/ sectionsY;\n\tfloat kY = pVS-&gt;whl&#91;1] \/ 2;\n\tfor (int iy = 0; iy &lt; pointsY; iy++) {\n\t\tfloat kX = -pVS-&gt;whl&#91;0] \/ 2;\n\t\tfor (int ix = 0; ix &lt; pointsX; ix++) {\n\t\t\tint nSE = addVertex(pMB, kX, kY, pVS-&gt;extF, 0, 0, 1); \/\/vertex number on south-east\n\t\t\tif (iy &gt; 0 &amp;&amp; ix &gt; 0) {\n\t\t\t\t\/\/add 2 triangles\n\t\t\t\tint nSW = nSE - 1; \/\/vertex number south-west\n\t\t\t\tint nNE = nSE - pointsX; \/\/north-east\n\t\t\t\tint nNW = nSW - pointsX; \/\/north-west\n\t\t\t\tadd2triangles(pMB, nNW, nNE, nSW, nSE, iy + ix);\n\t\t\t}\n\t\t\tkX += stepX;\n\t\t}\n\t\tkY -= stepY;\n\t}\n\treturn 1;\n}\nint ModelBuilder::buildBoxFaceTank(ModelBuilder* pMB, std::string applyTo, VirtualShape* pVS) {\n\t\/\/for diamond effect - sectionsRad=1, don&#039;t merge normals\n\tbool drawMiddle = true;\n\t\/\/edges\n\tbool drawTop = false;\n\tbool drawBottom = false;\n\tbool drawLeft = false;\n\tbool drawRight = false;\n\t\/\/corners\n\tbool drawTopLeft = false;\n\tbool drawTopRight = false;\n\tbool drawBottomLeft = false;\n\tbool drawBottomRight = false;\n\tif (pVS-&gt;extF == 0 || applyTo.find(&quot; all&quot;) != std::string::npos) {\n\t\tdrawTop = true;\n\t\tdrawBottom = true;\n\t\tdrawLeft = true;\n\t\tdrawRight = true;\n\t\tdrawTopLeft = true;\n\t\tdrawTopRight = true;\n\t\tdrawBottomLeft = true;\n\t\tdrawBottomRight = true;\n\t}\n\telse if (applyTo.find(&quot; h&quot;) != std::string::npos) {\n\t\tdrawLeft = true;\n\t\tdrawRight = true;\n\t}\n\telse if (applyTo.find(&quot; v&quot;) != std::string::npos) {\n\t\tdrawTop = true;\n\t\tdrawBottom = true;\n\t}\n\tif (applyTo.find(&quot; no&quot;) != std::string::npos) {\n\t\tif (applyTo.find(&quot; noM&quot;) != std::string::npos) {\n\t\t\t\/\/middle\n\t\t\tif (applyTo.find(&quot; noMrow&quot;) != std::string::npos) {\n\t\t\t\tdrawMiddle = false;\n\t\t\t\tdrawLeft = false;\n\t\t\t\tdrawRight = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noMcol&quot;) != std::string::npos) {\n\t\t\t\tdrawMiddle = false;\n\t\t\t\tdrawTop = false;\n\t\t\t\tdrawBottom = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noMid&quot;) != std::string::npos)\n\t\t\t\tdrawMiddle = false;\n\t\t}\n\t\tif (applyTo.find(&quot; noN&quot;) != std::string::npos) {\n\t\t\t\/\/north\n\t\t\tif (applyTo.find(&quot; noNrow&quot;) != std::string::npos) {\n\t\t\t\tdrawTop = false;\n\t\t\t\tdrawTopLeft = false;\n\t\t\t\tdrawTopRight = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noNedge&quot;) != std::string::npos)\n\t\t\t\tdrawTop = false;\n\t\t\tif (applyTo.find(&quot; noNW&quot;) != std::string::npos)\n\t\t\t\tdrawTopLeft = false;\n\t\t\tif (applyTo.find(&quot; noNE&quot;) != std::string::npos)\n\t\t\t\tdrawTopRight = false;\n\t\t}\n\t\tif (applyTo.find(&quot; noS&quot;) != std::string::npos) {\n\t\t\t\/\/south\n\t\t\tif (applyTo.find(&quot; noSrow&quot;) != std::string::npos) {\n\t\t\t\tdrawBottom = false;\n\t\t\t\tdrawBottomLeft = false;\n\t\t\t\tdrawBottomRight = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noSedge&quot;) != std::string::npos)\n\t\t\t\tdrawBottom = false;\n\t\t\tif (applyTo.find(&quot; noSW&quot;) != std::string::npos)\n\t\t\t\tdrawBottomLeft = false;\n\t\t\tif (applyTo.find(&quot; noSE&quot;) != std::string::npos)\n\t\t\t\tdrawBottomRight = false;\n\t\t}\n\t\tif (applyTo.find(&quot; noW&quot;) != std::string::npos) {\n\t\t\t\/\/west\n\t\t\tif (applyTo.find(&quot; noWcol&quot;) != std::string::npos) {\n\t\t\t\tdrawLeft = false;\n\t\t\t\tdrawTopLeft = false;\n\t\t\t\tdrawBottomLeft = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noWedge&quot;) != std::string::npos)\n\t\t\t\tdrawLeft = false;\n\t\t}\n\t\tif (applyTo.find(&quot; noE&quot;) != std::string::npos) {\n\t\t\t\/\/east\n\t\t\tif (applyTo.find(&quot; noEcol&quot;) != std::string::npos) {\n\t\t\t\tdrawRight = false;\n\t\t\t\tdrawTopRight = false;\n\t\t\t\tdrawBottomRight = false;\n\t\t\t}\n\t\t\tif (applyTo.find(&quot; noEedge&quot;) != std::string::npos)\n\t\t\t\tdrawRight = false;\n\t\t}\n\t}\n\tlockGroup(pMB);\n\t\/\/middle\n\tif (pVS-&gt;whl&#91;0] &gt; 0 &amp;&amp; pVS-&gt;whl&#91;1] &gt; 0 &amp;&amp; drawMiddle) {\n\t\tbuildBoxFacePlain(pMB, applyTo, pVS);\n\t}\n\tVirtualShape vs;\n\t\/\/edges\n\t\/\/vs.type.assign(&quot;cylinder&quot;);\n\tvs.sectionsR = pVS-&gt;sectionsR;\n\tif (pVS-&gt;whl&#91;0] &gt; 0) {\n\t\tvs.sections&#91;2] = pVS-&gt;sections&#91;0]; \/\/cylinder Z sections n\n\t\tvs.whl&#91;2] = pVS-&gt;whl&#91;0]; \/\/cylinder length Z\n\t\tvs.whl&#91;0] = pVS-&gt;extF * 2; \/\/cylinder diameter X\n\t\tif (pVS-&gt;extU &gt; 0 &amp;&amp; drawTop) {\n\t\t\tvs.whl&#91;1] = pVS-&gt;extU * 2; \/\/cylinder diameter Y\n\t\t\tlockGroup(pMB);\n\t\t\tcylinderWrap(pMB, &amp;vs, 0, 90);\n\t\t\t\/\/rotate -90 degrees around Y and shift up\n\t\t\tmoveGroupDg(pMB, 0, -90, 0, 0, pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t\tif (pVS-&gt;extD &gt; 0 &amp;&amp; drawBottom) {\n\t\t\tvs.whl&#91;1] = pVS-&gt;extD * 2; \/\/cylinder diameter Y\n\t\t\tlockGroup(pMB);\n\t\t\tcylinderWrap(pMB, &amp;vs, -90, 0);\n\t\t\t\/\/rotate -90 degrees around Y and shift down\n\t\t\tmoveGroupDg(pMB, 0, -90, 0, 0, -pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t}\n\tif (pVS-&gt;whl&#91;1] &gt; 0) {\n\t\tvs.sections&#91;2] = pVS-&gt;sections&#91;1]; \/\/cylinder Z sections n\n\t\tvs.whl&#91;2] = pVS-&gt;whl&#91;1]; \/\/cylinder length Z\n\t\tvs.whl&#91;1] = pVS-&gt;extF * 2; \/\/cylinder diameter Y\n\t\tif (pVS-&gt;extL &gt; 0 &amp;&amp; drawLeft) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extL * 2; \/\/cylinder diameter X\n\t\t\tlockGroup(pMB);\n\t\t\tcylinderWrap(pMB, &amp;vs, 90, 180);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 90, 0, 0, -pVS-&gt;whl&#91;0] * 0.5f, 0, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t\tif (pVS-&gt;extR &gt; 0 &amp;&amp; drawRight) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extR * 2; \/\/cylinder diameter X\n\t\t\tlockGroup(pMB);\n\t\t\tcylinderWrap(pMB, &amp;vs, 0, 90);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 90, 0, 0, pVS-&gt;whl&#91;0] * 0.5f, 0, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t}\n\t\/\/corners\n\t\/\/vs.type.assign(&quot;cap&quot;);\n\tvs.sectionsR = pVS-&gt;sectionsR;\n\tvs.sections&#91;2] = pVS-&gt;sectionsR;\n\tvs.whl&#91;2] = pVS-&gt;extF;\n\tif (pVS-&gt;extU &gt; 0) {\n\t\t\/\/top corners\n\t\tvs.whl&#91;1] = pVS-&gt;extU * 2;\n\t\tif (pVS-&gt;extL &gt; 0 &amp;&amp; drawTopLeft) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extL * 2;\n\t\t\tlockGroup(pMB);\n\t\t\tcapWrap(pMB, &amp;vs, 90, 180);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 0, 0, 0, -pVS-&gt;whl&#91;0] * 0.5f, pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t\tif (pVS-&gt;extR &gt; 0 &amp;&amp; drawTopRight) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extR * 2;\n\t\t\tlockGroup(pMB);\n\t\t\tcapWrap(pMB, &amp;vs, 0, 90);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 0, 0, 0, pVS-&gt;whl&#91;0] * 0.5f, pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\n\t\t}\n\t}\n\tif (pVS-&gt;extD &gt; 0) {\n\t\t\/\/bottom corners\n\t\tvs.whl&#91;1] = pVS-&gt;extD * 2;\n\t\tif (pVS-&gt;extL &gt; 0 &amp;&amp; drawBottomLeft) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extL * 2;\n\t\t\tlockGroup(pMB);\n\t\t\tcapWrap(pMB, &amp;vs, -180, -90);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 0, 0, 0, -pVS-&gt;whl&#91;0] * 0.5f, -pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t\tif (pVS-&gt;extR &gt; 0 &amp;&amp; drawBottomRight) {\n\t\t\tvs.whl&#91;0] = pVS-&gt;extR * 2;\n\t\t\tlockGroup(pMB);\n\t\t\tcapWrap(pMB, &amp;vs, -90, 0);\n\t\t\t\/\/rotate 90 degrees around Y and shift left\n\t\t\tmoveGroupDg(pMB, 0, 0, 0, pVS-&gt;whl&#91;0] * 0.5f, -pVS-&gt;whl&#91;1] * 0.5f, 0);\n\t\t\treleaseGroup(pMB);\n\t\t}\n\t}\n\tif (pVS-&gt;extF == 0) {\n\t\tint vertsN = pMB-&gt;vertices.size();\n\t\tfor (int i = pMB-&gt;pCurrentGroup-&gt;fromVertexN; i &lt; vertsN; i++) {\n\t\t\tVertex01* pVX = pMB-&gt;vertices.at(i);\n\t\t\t\/\/normal\n\t\t\tv3set(pVX-&gt;aNormal, 0, 0, 1);\n\t\t}\n\t}\n\treleaseGroup(pMB);\n\treturn 1;\n}\n\nint ModelBuilder::cylinderWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo) {\n\t\/\/ angleFrom\/To - in degrees\n\tlockGroup(pMB);\n\tfloat stepZ = pVS-&gt;whl&#91;2] \/ pVS-&gt;sections&#91;2];\n\tfloat stepDg = (angleTo - angleFrom) \/ pVS-&gt;sectionsR; \/\/in degrees\n\tfor (int nz = 0; nz &lt;= pVS-&gt;sections&#91;2]; nz++) {\n\t\tfloat kz = stepZ * nz - pVS-&gt;whl&#91;2] * 0.5f;\n\t\tfor (int rpn = 0; rpn &lt;= pVS-&gt;sectionsR; rpn++) {\n\t\t\t\/\/ rpn - radial point number\n\t\t\tfloat angleRd = (angleFrom + stepDg * rpn) * degrees2radians;\n\t\t\tfloat kx = cosf(angleRd);\n\t\t\tfloat ky = sinf(angleRd);\n\t\t\tint nSE = addVertex(pMB, kx, ky, kz, kx, ky, 0);\n\t\t\tif (nz &gt; 0 &amp;&amp; rpn &gt; 0) {\n\t\t\t\tint nSW = nSE - 1;\n\t\t\t\tint nNW = nSW - pVS-&gt;sectionsR - 1;\n\t\t\t\tint nNE = nSE - pVS-&gt;sectionsR - 1;\n\t\t\t\tadd2triangles(pMB, nNE, nNW, nSE, nSW, nz + rpn);\n\t\t\t}\n\t\t}\n\t}\n\t\/\/scale to desirable diameters\n\tmat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };\n\tmat4x4_scale_aniso(transformMatrix, transformMatrix, pVS-&gt;whl&#91;0] * 0.5f, pVS-&gt;whl&#91;1] * 0.5f, 1);\n\tint vertsN = pMB-&gt;vertices.size();\n\tfor (int i = pMB-&gt;pCurrentGroup-&gt;fromVertexN; i &lt; vertsN; i++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(i);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aPos, transformMatrix, pVX-&gt;aPos, 1);\n\t}\n\treleaseGroup(pMB);\n\treturn 1;\n}\nint ModelBuilder::capWrap(ModelBuilder* pMB, VirtualShape* pVS, float angleFrom, float angleTo) {\n\t\/\/ angleFrom\/To - in degrees\n\tlockGroup(pMB);\n\t\/\/center point\n\tint n0 = addVertex(pMB, 0, 0, 1, 0, 0, 1);\n\tfloat stepZdg = 90.0f \/ pVS-&gt;sections&#91;2]; \/\/in degrees\n\tfloat stepRdg = (angleTo - angleFrom) \/ pVS-&gt;sectionsR; \/\/in degrees\n\tfor (int nz = 1; nz &lt;= pVS-&gt;sections&#91;2]; nz++) {\n\t\tfloat angleZrd = stepZdg * nz * degrees2radians;\n\t\tfloat kz = cosf(angleZrd);\n\t\tfloat R = sinf(angleZrd);\n\t\tfor (int rpn = 0; rpn &lt;= pVS-&gt;sectionsR; rpn++) {\n\t\t\t\/\/ rpn - radial point number\n\t\t\tfloat angleRd = (angleFrom + stepRdg * rpn) * degrees2radians;\n\t\t\tfloat kx = cosf(angleRd) * R;\n\t\t\tfloat ky = sinf(angleRd) * R;\n\t\t\tint nSE = addVertex(pMB, kx, ky, kz, kx, ky, kz);\n\t\t\tif (rpn &gt; 0) {\n\t\t\t\tif (nz == 1) {\n\t\t\t\t\tint nSW = nSE - 1;\n\t\t\t\t\taddTriangle(pMB, n0, nSW, nSE);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tint nSW = nSE - 1;\n\t\t\t\t\tint nNW = nSW - pVS-&gt;sectionsR - 1;\n\t\t\t\t\tint nNE = nSE - pVS-&gt;sectionsR - 1;\n\t\t\t\t\tadd2triangles(pMB, nNW, nNE, nSW, nSE, nz + rpn);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\/\/scale to desirable diameters\n\tmat4x4 transformMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };\n\tmat4x4_scale_aniso(transformMatrix, transformMatrix, pVS-&gt;whl&#91;0] * 0.5f, pVS-&gt;whl&#91;1] * 0.5f, pVS-&gt;whl&#91;2]);\n\tint vertsN = pMB-&gt;vertices.size();\n\tfor (int i = pMB-&gt;pCurrentGroup-&gt;fromVertexN; i &lt; vertsN; i++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(i);\n\t\tmat4x4_mul_vec4plus(pVX-&gt;aPos, transformMatrix, pVX-&gt;aPos, 1);\n\t}\n\treleaseGroup(pMB);\n\treturn 1;\n}\nint ModelBuilder::groupApplyTexture(ModelBuilder* pMB, std::string applyTo, TexCoords* pTC, TexCoords* pTC2nm) {\n\tint vertsN = pMB-&gt;vertices.size();\n\tfor (int vN = 0; vN &lt; vertsN; vN++) {\n\t\tVertex01* pVX = pMB-&gt;vertices.at(vN);\n\t\tif(vN &lt; pMB-&gt;pCurrentGroup-&gt;fromVertexN)\n\t\t\tpVX-&gt;flag = -1;\n\t\telse\n\t\t\tpVX-&gt;flag = 0;\n\t}\n\tapplyTexture2flagged(&amp;pMB-&gt;vertices, applyTo, pTC, false);\n\tapplyTexture2flagged(&amp;pMB-&gt;vertices, applyTo, pTC2nm, true);\n\treturn 1;\n}\nint ModelBuilder::applyTexture2flagged(std::vector&lt;Vertex01*&gt;* pVerts, std::string applyTo, TexCoords* pTC, bool isNormalMap) {\n\tif (pTC == NULL)\n\t\treturn 0;\n\tfloat posMin&#91;3];\n\tfloat posMax&#91;3];\n\tfloat posRange&#91;3];\n\tfor (int i = 0; i &lt; 3; i++) {\n\t\tposMin&#91;i] = 1000000;\n\t\tposMax&#91;i] = -1000000;\n\t}\n\tint vertsN = pVerts-&gt;size();\n\tfor (int vN = 0; vN &lt; vertsN; vN++) {\n\t\tVertex01* pVX = pVerts-&gt;at(vN);\n\t\tif (pVX-&gt;flag &lt; 0) \/\/ignore\n\t\t\tcontinue;\n\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\tif (posMin&#91;i] &gt; pVX-&gt;aPos&#91;i])\n\t\t\t\tposMin&#91;i] = pVX-&gt;aPos&#91;i];\n\t\t\tif (posMax&#91;i] &lt; pVX-&gt;aPos&#91;i])\n\t\t\t\tposMax&#91;i] = pVX-&gt;aPos&#91;i];\n\t\t}\n\t}\n\t\/\/here we have coordinates range\n\tfor (int i = 0; i &lt; 3; i++)\n\t\tposRange&#91;i] = posMax&#91;i] - posMin&#91;i];\n\t\/\/for &quot;front&quot;\n\tint xRateIndex = 0;\n\tbool xRateInverse = false;\n\tint yRateIndex = 1;\n\tbool yRateInverse = true;\n\tif (applyTo.find(&quot;front&quot;) == 0)\n\t\t; \/\/do nothing\n\telse if (applyTo.find(&quot;back&quot;) == 0)\n\t\txRateInverse = true;\n\telse if (applyTo.find(&quot;left&quot;) == 0)\n\t\txRateIndex = 2;\n\telse if (applyTo.find(&quot;right&quot;) == 0) {\n\t\txRateIndex = 2;\n\t\txRateInverse = true;\n\t}\n\telse if (applyTo.find(&quot;top&quot;) == 0) {\n\t\txRateInverse = true;\n\t\tyRateIndex = 2;\n\t}\n\telse if (applyTo.find(&quot;bottom&quot;) == 0)\n\t\tyRateIndex = 2;\n\n\tfloat xRate = 0;\n\tfloat yRate = 0;\n\tfloat tuvRange&#91;2];\n\ttuvRange&#91;0] = pTC-&gt;tuvBottomRight&#91;0] - pTC-&gt;tuvTopLeft&#91;0];\n\ttuvRange&#91;1] = pTC-&gt;tuvBottomRight&#91;1] - pTC-&gt;tuvTopLeft&#91;1];\n\tfor (int vN = 0; vN &lt; vertsN; vN++) {\n\t\tVertex01* pVX = pVerts-&gt;at(vN);\n\t\tif (pVX-&gt;flag &lt; 0) \/\/ignore\n\t\t\tcontinue;\n\t\tif (posRange&#91;xRateIndex] == 0)\n\t\t\txRate = 0;\n\t\telse {\n\t\t\txRate = (pVX-&gt;aPos&#91;xRateIndex] - posMin&#91;xRateIndex]) \/ posRange&#91;xRateIndex];\n\t\t\tif (xRateInverse)\n\t\t\t\txRate = 1.0f - xRate;\n\t\t}\n\t\tif (posRange&#91;yRateIndex] == 0)\n\t\t\tyRate = 0;\n\t\telse {\n\t\t\tyRate = (pVX-&gt;aPos&#91;yRateIndex] - posMin&#91;yRateIndex]) \/ posRange&#91;yRateIndex];\n\t\t\tif (yRateInverse)\n\t\t\t\tyRate = 1.0f - yRate;\n\t\t}\n\t\tfloat* pTuv = pVX-&gt;aTuv;\n\t\tif(isNormalMap)\n\t\t\tpTuv = pVX-&gt;aTuv2;\n\t\tpTuv&#91;0] = pTC-&gt;tuvTopLeft&#91;0] + tuvRange&#91;0] * xRate;\n\t\tpTuv&#91;1] = pTC-&gt;tuvTopLeft&#91;1] + tuvRange&#91;1] * yRate;\n\t}\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>11. Build and run. Result:<\/p>\n\n\n\n<p><strong>Before:<\/strong><\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c31\/01.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>After:<\/strong><\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c34\/01.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<iframe loading=\"lazy\" width=\"100%\" height=\"400\" src=\"https:\/\/www.youtube.com\/embed\/qUy-FMBQnGs?controls=0&amp;autoplay=1&amp;loop=1&amp;playlist=qUy-FMBQnGs\" title=\"Mesh's fragments\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"><\/iframe>\n\n\n\n<p><\/p>\n\n\n\n<p>Now &#8211; with slit.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Android<\/h2>\n\n\n\n<p>12. Close and re-start VS. Open&nbsp;<em>C:\\CPP\\a997modeler\\p_android\\p_android.sln<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>13. &nbsp;Under&nbsp;<em>modeler&nbsp;<\/em>add&nbsp;<strong>Existing Item<\/strong>&nbsp;from&nbsp;<em>C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>MaterialAdjust.cpp<\/li><li>MaterialAdjust.h<\/li><\/ul>\n\n\n\n<p><strong>Add<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>14. Switch on, unlock, plug in, allow.<\/p>\n\n\n\n<p>Build and run. Works.<\/p>\n\n\n\n<p>VS top menu&nbsp;<em>-&gt; Debug -&gt; Stop Debugging<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p class=\"mb-2\">We are STILL trying to &#8220;draw&#8221; the joint (slit) between the pack and the lid, as a small&nbsp;normal map&nbsp;applied to&nbsp;existing&nbsp;textured mesh&#8217;s&nbsp;fragment. At this point we do have fragments with their own &#8220;native&#8221; Materials. In the last sample we just replaced them (Materials) by Phong green. Instead we need to use native Materials, but with added [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-1120","post","type-post","status-publish","format-standard","hentry","category-cross-platform-3d"],"_links":{"self":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/1120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/comments?post=1120"}],"version-history":[{"count":22,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/1120\/revisions"}],"predecessor-version":[{"id":1145,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/1120\/revisions\/1145"}],"wp:attachment":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/media?parent=1120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/categories?post=1120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/tags?post=1120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}