{"id":912,"date":"2021-12-13T19:44:09","date_gmt":"2021-12-13T19:44:09","guid":{"rendered":"https:\/\/writingagame.com\/?p=912"},"modified":"2023-05-19T19:24:32","modified_gmt":"2023-05-19T19:24:32","slug":"chapter-30-vertex-group-manipulations","status":"publish","type":"post","link":"https:\/\/writingagame.com\/index.php\/2021\/12\/13\/chapter-30-vertex-group-manipulations\/","title":{"rendered":"Chapter 30. Vertex group manipulations"},"content":{"rendered":"\n<p>Here I want to add gilded (golden) prints on the pack. For this we will need a way to modify projection&#8217;s size and position (initially defined by VirtualShape). <\/p>\n\n\n\n<p>Our new <em>root01.txt<\/em> will be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; 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,back v&quot; xywh=&quot;2,1,323,495&quot;\/&gt;\n&lt;a=&quot;right all&quot; xywh=&quot;327,1,128,495&quot;\/&gt;\n&lt;a=&quot;left all&quot; xywh=&quot;457,1,128,495&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 uTex1mask_use=&quot;tx0&quot; uTex0_use=&quot;whitenoise&quot; uTex0translateChannelN=0 uTex3_use=&quot;gold&quot; \/&gt;\n\t&lt;a=&quot;front&quot; xywh=&quot;589,415,128,94&quot; whl=&quot;20.7,16,x&quot; pxyz=&quot;0.3,6.1,x&quot; \/&gt; \/\/emblem\t\n&lt;\/group&gt; \n&lt;clone ay=180 \/&gt;\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p>1. Copy this code to a&nbsp;<strong>Text Editor<\/strong>&nbsp;and save it (overwrite) to\/as<\/p>\n\n\n\n<p><em>C:\\CPP\\a997modeler\\dt\\models\\misc\\marlboro01\\<strong>root01.txt<\/strong><\/em><\/p>\n\n\n\n<p>Please note:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In &#8220;a&#8221; tags now we have extra properties: <em>whl <\/em>(adjusted box size) and <em>pxyz <\/em>(projection&#8217;s position).<\/li>\n\n\n\n<li>&#8220;x&#8221; in sizes\/coordinates means to use default value (from VirtualShape).<\/li>\n\n\n\n<li>Also we have a new tag &#8220;clone&#8221; (the last one), which will copy\/duplicate the last closed group (in this case &#8211; gilded prints on the front side) and will place it (cloned copy) on the back side.<\/li>\n<\/ul>\n\n\n\n<p> <\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>In previous samples we used <em>gold01.bmp<\/em> texture. But for this sample it is too yellow. So I added a new one, &#8220;roman gold&#8221;:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c30\/gold02roman.jpg\"><\/p>\n\n\n\n<p>It is less yellow and more greenish.<\/p>\n\n\n\n2. Download <a href=\"https:\/\/writingagame.com\/img\/b01\/c30\/gold02roman.bmp\" download=\"\">BMP file here<\/a>\n\n\n\n<p><\/p>\n\n\n\n<p>and save it to\/as:<\/p>\n\n\n\n<p><em>C:\\CPP\\engine\\dt\\common\\img\\materials\\<strong>gold02roman.bmp<\/strong><\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>Now &#8211; SW part.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Windows<\/h2>\n\n\n\n<p>3. Start VS, open&nbsp;<em>C:\\CPP\\<em>a997modeler<\/em>\\p_windows\\p_windows.sln<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>4. Under <em>modeler <\/em>add new header file <strong>GroupTransform.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; title: ; notranslate\" title=\"\">\n#pragma once\n#include &quot;ModelBuilder.h&quot;\n\nclass GroupTransform\n{\npublic:\n\tfloat shift&#91;4] = { 0,0,0,0 };\n\tfloat spin&#91;3] = { 0,0,0 }; \/\/in degrees\npublic:\n\tint executeGroupTransform(ModelBuilder* pMB) { return executeGroupTransform(pMB, this); };\n\tstatic int executeGroupTransform(ModelBuilder* pMB, GroupTransform* pGT);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>5. Under <em>modeler <\/em>add new C++ file <strong>GroupTransform.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;GroupTransform.h&quot;\n\nint GroupTransform::executeGroupTransform(ModelBuilder* pMB, GroupTransform* pGT) {\n\tpMB-&gt;moveGroupDg(pMB, pGT-&gt;spin&#91;0], pGT-&gt;spin&#91;1], pGT-&gt;spin&#91;2], pGT-&gt;shift&#91;0], pGT-&gt;shift&#91;1], pGT-&gt;shift&#91;2]);\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>In <strong>ModelLoader <\/strong>new functionality:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>fillProps_gt(..)<\/em> &#8211; filling out <em>GroupTrandform <\/em>info.<\/li>\n\n\n\n<li><em>processTag_a(..)<\/em> is changed to accept <em>VirtualShape <\/em>adjustments and <em>GroupTrandform <\/em> instructions (which are applicable to current &#8220;a&#8221; group).<\/li>\n\n\n\n<li>added &#8220;clone&#8221; tag handling <em>processTag_clone(..)<\/em><\/li>\n<\/ul>\n\n\n\n<p>6. Open <em>ModelLoader.h<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [4,37,41]; 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\nclass ModelLoader : public XMLparser\n{\npublic:\n\tModelBuilder* pModelBuilder = NULL;\n\tbool ownModelBuilder = false;\n\tstd::vector&lt;GameSubj*&gt;* pSubjsVector = 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}\n\t\tpModelBuilder-&gt;useSubjN(subjN);\n\t};\n\tvirtual ~ModelLoader() {\n\t\tif (!ownModelBuilder)\n\t\t\treturn;\n\t\tpModelBuilder-&gt;buildDrawJobs(*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, std::string tagStr);\n\tint 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};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>7. Open <em>ModelLoader.cpp<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [171,172,173,174,253,254,255,264,265,266,271,291,292,293]; 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\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}\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\n\tpML-&gt;pModelBuilder-&gt;useMaterial(pMT);\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.find(&quot;mt_&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\treturn fillProps_mt(&amp;mt, pML-&gt;currentTag, pML);\n\t}\n\tif (pML-&gt;tagName.find(&quot;\/mt_&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\treturn 1;\n\t}\n\tif (pML-&gt;tagName.compare(&quot;\/group&quot;) == 0) {\n\t\tGroupTransform groupTransform;\n\t\tfillProps_gt(&amp;groupTransform, pML-&gt;currentTag);\n\t\tgroupTransform.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\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::fillProps_gt(GroupTransform* pGS, std::string tagStr) {\n\t\/\/position\n\tsetFloatArray(pGS-&gt;shift, 3, &quot;pxyz&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;shift&#91;0], &quot;px&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;shift&#91;1], &quot;py&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;shift&#91;2], &quot;pz&quot;, tagStr);\n\t\/\/angles\n\tsetFloatArray(pGS-&gt;spin, 3, &quot;axyz&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;spin&#91;0], &quot;ax&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;spin&#91;1], &quot;ay&quot;, tagStr);\n\tsetFloatValue(&amp;pGS-&gt;spin&#91;2], &quot;az&quot;, tagStr);\n\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\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\tsetFloatArray(xywh, 4, &quot;xywh&quot;, tagStr);\n\tstd::string flipStr = getStringValue(&quot;flip&quot;, tagStr);\n\tTexCoords tc;\n\ttc.set(texN, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\n\tsetFloatArray(xywh, 4, &quot;xywh2nm&quot;, tagStr);\n\tflipStr = getStringValue(&quot;flip2nm&quot;, tagStr);\n\tTexCoords tc2nm;\n\ttc2nm.set(pMT-&gt;uTex2nm, xywh&#91;0], xywh&#91;1], xywh&#91;2], xywh&#91;3], flipStr);\n\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\t\/\/pMB-&gt;buildFace(pMB, applyTosVector.at(aN), pMB-&gt;pCurrentVShape, &amp;tc, &amp;tc2nm);\n\t\tpMB-&gt;buildFace(pMB, applyTosVector.at(aN), pVS_a, &amp;tc, &amp;tc2nm);\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, 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\/\/cloning\n\t\tint vertsN = pMB-&gt;vertices.size() - pMB-&gt;pLastClosedGroup-&gt;fromVertexN;\n\t\tint trianglesN = pMB-&gt;triangles.size() - pMB-&gt;pLastClosedGroup-&gt;fromTriangleN;\n\t\tpMB-&gt;lockGroup(pMB);\n\t\tfor (int i = 0; i &lt; vertsN; i++) {\n\t\t\tint vN = pMB-&gt;pLastClosedGroup-&gt;fromVertexN + i;\n\t\t\tVertex01* pV = new Vertex01(*pMB-&gt;vertices.at(vN));\n\t\t\tpMB-&gt;vertices.push_back(pV);\n\t\t}\n\t\tfor (int i = 0; i &lt; trianglesN; i++) {\n\t\t\tint tN = pMB-&gt;pLastClosedGroup-&gt;fromTriangleN + i;\n\t\t\tTriangle01* pT = new Triangle01(*pMB-&gt;triangles.at(tN));\n\t\t\tfor (int n = 0; n &lt; 3; n++)\n\t\t\t\tpT-&gt;idx&#91;n] += vertsN;\n\t\t\tpMB-&gt;triangles.push_back(pT);\n\t\t}\n\t}\n\tGroupTransform groupTransform;\n\tfillProps_gt(&amp;groupTransform, pML-&gt;currentTag);\n\tgroupTransform.executeGroupTransform(pMB);\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}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p><em>ModelLoader &#8216;s<\/em> &#8220;clone&#8221; tag relies on new variable <em>pLastClosedGroup<\/em> in <em>ModelBuilder1base<\/em>.<\/p>\n\n\n\n<p>8. Open <em> <em>ModelBuilder1base<\/em>.h<\/em> and replace code by: <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [22]; 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\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&lt;GameSubj*&gt; gameSubjs) { return buildDrawJobs(this, gameSubjs); };\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};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>This new variable  <em>pLastClosedGroup<\/em>  is maintained in <em>ModelBuilder1base::releaseGroup()<\/em><\/p>\n\n\n\n<p>9. Open <em> <em>ModelBuilder1base<\/em>.cpp<\/em> and replace code by:  <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [323,324,325]; 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\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\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::useMaterial(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\tpMB-&gt;usingMaterialN = i;\n\t\t\t\treturn i;\n\t\t\t}\n\t\/\/if here - add new material to the list\n\tpMB-&gt;usingMaterialN = itemsN;\n\t\/\/create a copy of new Material and add 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\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\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\t\/\/if (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\nvoid ModelBuilder1base::lockGroup(ModelBuilder1base* pMB) {\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}\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 has-css-opacity\"\/>\n\n\n\n<p>10. Build and run.<\/p>\n\n\n\n<p><strong>Before<\/strong>:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c28\/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\/c30\/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\/gHyh_ZQPoIU?controls=0&amp;autoplay=1&amp;loop=1&amp;playlist=gHyh_ZQPoIU\" title=\"Reflection over mask\" 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; gilded.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Android<\/h2>\n\n\n\n<p>11. Close and re-open VS. Open&nbsp;<em>C:\\CPP\\a997modeler<\/em><strong><em>\\p_android\\p_android.sln<\/em>.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>12. Under&nbsp;<em><strong>modeler&nbsp;<\/strong><\/em>add&nbsp;<strong>Existing&nbsp;<\/strong>Item<\/p>\n\n\n\n<p>from&nbsp;<em>C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n<p>Files&nbsp;<em>GroupTransform.cpp<\/em>&nbsp;and&nbsp;<em> <em>GroupTransform<\/em>.h<\/em><\/p>\n\n\n\n<p><strong>Add<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>13. Turn on, unlock, plug in, allow.<\/p>\n\n\n\n<p>Build and run.<\/p>\n\n\n\n<p>Ok.<\/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 has-css-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p class=\"mb-2\">Here I want to add gilded (golden) prints on the pack. For this we will need a way to modify projection&#8217;s size and position (initially defined by VirtualShape). Our new root01.txt will be: 1. Copy this code to a&nbsp;Text Editor&nbsp;and save it (overwrite) to\/as C:\\CPP\\a997modeler\\dt\\models\\misc\\marlboro01\\root01.txt Please note: In previous samples we used gold01.bmp texture. But [&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-912","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\/912","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=912"}],"version-history":[{"count":24,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/912\/revisions"}],"predecessor-version":[{"id":1984,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/912\/revisions\/1984"}],"wp:attachment":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/media?parent=912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/categories?post=912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/tags?post=912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}