{"id":1050,"date":"2021-12-28T23:15:11","date_gmt":"2021-12-28T23:15:11","guid":{"rendered":"https:\/\/writingagame.com\/?p=1050"},"modified":"2022-01-01T00:17:01","modified_gmt":"2022-01-01T00:17:01","slug":"chapter-33-polygons-intersection","status":"publish","type":"post","link":"https:\/\/writingagame.com\/index.php\/2021\/12\/28\/chapter-33-polygons-intersection\/","title":{"rendered":"Chapter 33. Polygons Intersection"},"content":{"rendered":"\n<p>Just a friendly reminder: 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 <strong>existing <\/strong>textured mesh&#8217;s&nbsp;<strong>fragment<\/strong>. Like this:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/01.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In previous chapter we implemented a concept of selecting and manipulating &#8220;<em>marked vertices\/triangles groups<\/em>&#8220;. So, now we can select one (in this sample &#8211; &#8220;box_right&#8221;), duplicate it, rotate and move at our discretion. Particularly &#8211; facing us, like this:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/02.jpg\"><\/p>\n\n\n\n<p> <\/p>\n\n\n\n<p>The next task is to cut this white rectangle out of the mesh.<\/p>\n\n\n\n<p>We will scan mesh&#8217;s triangles and will build intersections between these triangles and white rectangle. Both <em>triangle <\/em>and <em>rectangle <\/em>are <strong>polygons<\/strong>. So, we are talking about <strong>Polygons Intersection<\/strong>. <\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/03.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The intersection of red triangle and white rectangle is 4-points polygon (2 triangles).<\/li><li>The intersection of left blue &#8211; is a 5-points polygon (3 triangles).<\/li><\/ul>\n\n\n\n<p>New concepts here are: <em>Polygons <\/em>and <em>Polygons Intersection<\/em>. The <em>polygon <\/em>is basically an array of <em>Polygon Ribs<\/em>.<\/p>\n\n\n\n<p>Now &#8211; 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>PolygonRib.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;Vertex01.h&quot;\n#include &lt;vector&gt;\n\nclass PolygonRib\n{\npublic:\n\tint i0;\n\tint i1;\n\tfloat* p0; \/\/rib p0\n\tfloat* p1; \/\/rib p1\n\t\/\/line equation\n\tfloat a_slope = 0; \/\/a\n\tfloat b_intercept = 0; \/\/b\n\tbool isVertical = false;\n\tfloat x_vertical = 0;\n\tbool isHorizontal = false;\n\t\/\/direction to &quot;inner&quot; side\n\tfloat xDirIn = 0;\n\tfloat yDirIn = 0;\npublic:\n\tPolygonRib(std::vector&lt;Vertex01*&gt;* pVxSrc, int idx0);\n\tstatic bool matchingLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc);\n\tstatic bool parallelLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>3. Under <em>modeler <\/em>add new C++ file <strong>PolygonRib.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;PolygonRib.h&quot;\n\nPolygonRib::PolygonRib(std::vector&lt;Vertex01*&gt;* pVxSrc, int idx0) {\n\t\/\/2 points\n\ti0 = idx0;\n\tp0 = pVxSrc-&gt;at(idx0)-&gt;aPos;\n\tint ribsN = pVxSrc-&gt;size();\n\tint idx1 = (idx0 + 1) % ribsN;\n\ti1 = idx1;\n\tp1 = pVxSrc-&gt;at(idx1)-&gt;aPos;\n\t\/\/3-rd &quot;inner&quot; ref point\n\tfloat* p2;\n\tint idx2 = (idx0 + 2) % ribsN;\n\tp2 = pVxSrc-&gt;at(idx2)-&gt;aPos;\n\t\/\/find line equation\n\tif (p0&#91;0] == p1&#91;0]) {\n\t\tisVertical = true;\n\t\tx_vertical = p0&#91;0];\n\t\t\/\/&quot;inner&quot; side\n\t\tif (p2&#91;0] &lt; x_vertical)\n\t\t\txDirIn = -1;\n\t\telse\n\t\t\txDirIn = 1;\n\t}\n\telse if (p0&#91;1] == p1&#91;1]) {\n\t\tisHorizontal = true;\n\t\ta_slope = 0;\n\t\tb_intercept = p0&#91;1];\n\t\t\/\/&quot;inner&quot; side\n\t\tif (p2&#91;1] &lt; b_intercept)\n\t\t\tyDirIn = -1;\n\t\telse\n\t\t\tyDirIn = 1;\n\t}\n\telse {\n\t\ta_slope = (p1&#91;1]-p0&#91;1]) \/ (p1&#91;0] - p0&#91;0]);\n\t\tb_intercept = p0&#91;1] - a_slope * p0&#91;0];\n\t\t\/\/&quot;inner&quot; side\n\t\tfloat y = a_slope * p2&#91;0] + b_intercept;\n\t\tif(p2&#91;1] &lt; y)\n\t\t\tyDirIn = -1;\n\t\telse\n\t\t\tyDirIn = 1;\n\t\tfloat x = (p2&#91;1] - b_intercept) \/ a_slope;\n\t\tif (p2&#91;0] &lt; x)\n\t\t\txDirIn = -1;\n\t\telse\n\t\t\txDirIn = 1;\n\t}\n}\nbool PolygonRib::matchingLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc) {\n\tif (!parallelLines(pRibFrame, pRibSrc))\n\t\treturn false;\n\tif (pRibFrame-&gt;b_intercept != pRibSrc-&gt;b_intercept)\n\t\treturn false;\n\tif (pRibFrame-&gt;x_vertical != pRibSrc-&gt;x_vertical)\n\t\treturn false;\n\treturn true;\n}\nbool PolygonRib::parallelLines(PolygonRib* pRibFrame, PolygonRib* pRibSrc) {\n\tif (pRibFrame-&gt;isVertical != pRibSrc-&gt;isVertical)\n\t\treturn false;\n\tif (pRibFrame-&gt;a_slope != pRibSrc-&gt;a_slope)\n\t\treturn false;\n\treturn true;\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>4. Under <em>modeler <\/em>add new header file <strong>Polygon.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;Vertex01.h&quot;\n#include &quot;Triangle01.h&quot;\n#include &quot;PolygonRib.h&quot;\n#include &lt;vector&gt;\n\nclass Polygon\n{\npublic:\n\tstd::vector&lt;Vertex01*&gt; vertices;\n\tstd::vector&lt;PolygonRib*&gt; ribs;\n\tstd::vector&lt;Triangle01*&gt; triangles;\n\tfloat normal&#91;3] = {0,0,0};\n\tint ribsN = 0;\n\t\/\/bounding box\n\tfloat bbMin&#91;3] = { 0,0,0 };\n\tfloat bbMax&#91;3] = { 0,0,0 };\npublic:\n\tvirtual ~Polygon() { clearAll(this); };\n\tstatic void clearAll(Polygon* pPL);\n\tstatic int addVertex(Polygon* pPL, Vertex01* pV);\n\tstatic int addVertex(Polygon* pPL, float x, float y, float z);\n\tstatic int finalizePolygon(Polygon* pPL);\n\tstatic int setTriangle(Polygon* pPL, Triangle01* pT, std::vector&lt;Vertex01*&gt;* pVxSrc);\n\tstatic int setRectangle(Polygon* pPL, float w, float h);\n\tstatic int xyIntersection(Polygon* pDst, Polygon* pFrame, Polygon* pSrc);\n\tstatic int addLinesIntersection(Polygon* pDst, Polygon* pFrame, int ribNframe, Polygon* pSrc, int ribNsrc);\n\n\tstatic bool dotFits(float* p0, PolygonRib* pPR);\n\tstatic bool dotFits(float* p0, Polygon* pPL);\n\tstatic bool correctSide(float* p0, PolygonRib* pPR);\n\tstatic int addVert(Polygon* pDst, float* p0, Vertex01* pV0, Vertex01* pV1);\n\tstatic int addVert(Polygon * pDst, float* p0, Polygon * pSrc);\n\tstatic int buildTriangles(Polygon* pPL);\n};\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>5. Under <em>modeler <\/em>add new C++ file <strong>Polygon.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;Polygon.h&quot;\n#include &quot;linmath.h&quot;\n#include &quot;utils.h&quot;\n#include &quot;platform.h&quot;\n#include &lt;algorithm&gt;\n\nextern float radians2degrees;\n\nvoid Polygon::clearAll(Polygon* pPL) {\n\tfor (int i = pPL-&gt;vertices.size() - 1; i &gt;= 0; i--)\n\t\tdelete pPL-&gt;vertices.at(i);\n\tpPL-&gt;vertices.clear();\n\n\tfor (int i = pPL-&gt;ribs.size() - 1; i &gt;= 0; i--)\n\t\tdelete pPL-&gt;ribs.at(i);\n\tpPL-&gt;ribs.clear();\n\n\tfor (int i = pPL-&gt;triangles.size() - 1; i &gt;= 0; i--)\n\t\tdelete pPL-&gt;triangles.at(i);\n\tpPL-&gt;triangles.clear();\n}\nint Polygon::addVertex(Polygon* pPL, float x, float y, float z) {\n\tVertex01* pV = new Vertex01();\n\tpV-&gt;aPos&#91;0] = x;\n\tpV-&gt;aPos&#91;1] = y;\n\tpV-&gt;aPos&#91;2] = z;\n\tpPL-&gt;vertices.push_back(pV);\n\treturn 1;\n}\nint Polygon::addVertex(Polygon* pPL, Vertex01* pV0) {\n\tVertex01* pV = new Vertex01(*pV0);\n\tpPL-&gt;vertices.push_back(pV);\n\/\/mylog(&quot;====Adding vertexs %f x %f\\n&quot;,pV-&gt;aPos&#91;0], pV-&gt;aPos&#91;1]);\n\treturn 1;\n}\nint Polygon::setTriangle(Polygon* pPL, Triangle01* pT, std::vector&lt;Vertex01*&gt;* pVxSrc) {\n\tclearAll(pPL);\n\tfor (int i = 0; i &lt; 3; i++) {\n\t\tint vN = pT-&gt;idx&#91;i];\n\t\tVertex01* pV = pVxSrc-&gt;at(vN);\n\t\taddVertex(pPL, pV);\n\t}\n\tfinalizePolygon(pPL);\n\treturn 1;\n}\nint Polygon::setRectangle(Polygon* pPL, float w, float h) {\n\tclearAll(pPL);\n\tw \/= 2;\n\th \/= 2;\n\t\/\/CCW\n\taddVertex(pPL, -w,  h, 0); \/\/NW\n\taddVertex(pPL, -w, -h, 0); \/\/SW\n\taddVertex(pPL,  w, -h, 0); \/\/SE\n\taddVertex(pPL,  w,  h, 0); \/\/NE\n\tfinalizePolygon(pPL);\n\treturn 1;\n}\nint Polygon::finalizePolygon(Polygon* pPL) {\n\tpPL-&gt;ribsN = pPL-&gt;vertices.size();\n\tfor (int i = 0; i &lt; pPL-&gt;ribsN; i++) {\n\t\tPolygonRib* pPR = new PolygonRib(&amp;pPL-&gt;vertices,i);\n\t\tpPL-&gt;ribs.push_back(pPR);\n\t}\n\t\/\/calculate polygon&#039;s normal\n\tfloat v0&#91;3];\n\tfloat v2&#91;3];\n\tfor (int i = 0; i &lt; 3; i++) {\n\t\tv0&#91;i] = pPL-&gt;vertices.at(1)-&gt;aPos&#91;i] - pPL-&gt;vertices.at(0)-&gt;aPos&#91;i];\n\t\tv2&#91;i] = pPL-&gt;vertices.at(2)-&gt;aPos&#91;i] - pPL-&gt;vertices.at(0)-&gt;aPos&#91;i];\n\t}\n\tvec3_mul_cross(pPL-&gt;normal, v0, v2);\n\tvec3_norm(pPL-&gt;normal, pPL-&gt;normal);\n\t\/\/bounding box\n\tVertex01* pV = pPL-&gt;vertices.at(0);\n\tv3copy(pPL-&gt;bbMin, pV-&gt;aPos);\n\tv3copy(pPL-&gt;bbMax, pV-&gt;aPos);\n\tfor (int vN = pPL-&gt;vertices.size() - 1; vN &gt;= 1; vN--) {\n\t\tpV = pPL-&gt;vertices.at(vN);\n\t\tfor (int i = 0; i &lt; 3; i++) {\n\t\t\tif (pPL-&gt;bbMin&#91;i] &gt; pV-&gt;aPos&#91;i])\n\t\t\t\tpPL-&gt;bbMin&#91;i] = pV-&gt;aPos&#91;i];\n\t\t\tif (pPL-&gt;bbMax&#91;i] &lt; pV-&gt;aPos&#91;i])\n\t\t\t\tpPL-&gt;bbMax&#91;i] = pV-&gt;aPos&#91;i];\n\t\t}\n\t}\n\treturn 1;\n}\nint Polygon::addLinesIntersection(Polygon* pDst, Polygon* pFrame, int ribNframe, Polygon* pSrc, int ribNsrc) {\n\tPolygonRib* pRibFrame = pFrame-&gt;ribs.at(ribNframe);\n\tPolygonRib* pRibSrc = pSrc-&gt;ribs.at(ribNsrc);\n\t\/*\nmylog(&quot;==addLinesIntersection\\n&quot;);\nmylog(&quot;  fr %f x %f to %f x %f v=%d h=%d\\n&quot;, pRibFrame-&gt;p0&#91;0], pRibFrame-&gt;p0&#91;1], pRibFrame-&gt;p1&#91;0], pRibFrame-&gt;p1&#91;1], pRibFrame-&gt;isVertical, pRibFrame-&gt;isHorizontal);\nmylog(&quot;  tr %f x %f to %f x %f v=%d h=%d\\n&quot;, pRibSrc-&gt;p0&#91;0], pRibSrc-&gt;p0&#91;1], pRibSrc-&gt;p1&#91;0], pRibSrc-&gt;p1&#91;1], pRibSrc-&gt;isVertical, pRibSrc-&gt;isHorizontal);\n*\/\n\tif (PolygonRib::matchingLines(pRibFrame, pRibSrc)) {\n\t\tVertex01* pV0 = pSrc-&gt;vertices.at(pRibSrc-&gt;i0);\n\t\tVertex01* pV1 = pSrc-&gt;vertices.at(pRibSrc-&gt;i1);\n\t\tint dstVertsN0 = pDst-&gt;vertices.size();\n\t\tif (dotFits(pRibFrame-&gt;p0, pRibSrc))\n\t\t\taddVert(pDst, pRibFrame-&gt;p0, pV0,pV1);\n\t\tif (dotFits(pRibFrame-&gt;p1, pRibSrc))\n\t\t\taddVert(pDst, pRibFrame-&gt;p1, pV0, pV1);\n\t\tif (dotFits(pRibSrc-&gt;p0, pRibFrame))\n\t\t\taddVertex(pDst, pV0);\n\t\tif (dotFits(pRibSrc-&gt;p1, pRibFrame))\n\t\t\taddVertex(pDst, pV1);\n\/\/mylog(&quot;  lines are identical\\n&quot;);\n\t\treturn pDst-&gt;vertices.size()- dstVertsN0;\n\t}\n\tif (PolygonRib::parallelLines(pRibFrame, pRibSrc)) {\n\/\/mylog(&quot;  lines are parallel\\n&quot;);\n\t\treturn 0;\n\t}\n\t\/\/find lines intersection, assuming lines are not parallel\n\tfloat x,y;\n\tif (pRibFrame-&gt;isVertical) {\n\t\tx = pRibFrame-&gt;p0&#91;0];\n\t\ty = pRibSrc-&gt;a_slope * x + pRibSrc-&gt;b_intercept;\n\t}\n\telse { \/\/pRibFrame not vertical\n\t\tif (pRibSrc-&gt;isVertical) {\n\t\t\tx = pRibSrc-&gt;p0&#91;0];\n\t\t\ty = pRibFrame-&gt;a_slope * x + pRibFrame-&gt;b_intercept;\n\t\t}\n\t\telse { \/\/both lines are &quot;normal&quot;\n\t\t\tx = (pRibSrc-&gt;b_intercept - pRibFrame-&gt;b_intercept) \/ (pRibFrame-&gt;a_slope - pRibSrc-&gt;a_slope);\n\t\t\ty = pRibFrame-&gt;a_slope * x + pRibFrame-&gt;b_intercept;\n\t\t}\n\t}\n\t\/\/check if belongs to both PolygonRibs\n\tfloat xy&#91;2];\n\txy&#91;0] = x;\n\txy&#91;1] = y;\n\tif (!dotFits(xy, pRibFrame))\n\t\treturn 0;\n\tif (!dotFits(xy, pRibSrc))\n\t\treturn 0;\n\taddVert(pDst, xy, pSrc-&gt;vertices.at(pRibSrc-&gt;i0), pSrc-&gt;vertices.at(pRibSrc-&gt;i1));\n\treturn 1;\n}\nbool Polygon::correctSide(float* p0, PolygonRib* pPR) {\n\tif (pPR-&gt;isVertical)\n\t\tif ((p0&#91;0] - pPR-&gt;x_vertical) * pPR-&gt;xDirIn &lt; 0)\n\t\t\treturn false;\n\tif (pPR-&gt;isHorizontal)\n\t\tif ((p0&#91;1] - pPR-&gt;b_intercept) * pPR-&gt;yDirIn &lt; 0)\n\t\t\treturn false;\n\tfloat y = pPR-&gt;a_slope * p0&#91;0] + pPR-&gt;b_intercept;\n\tif ((p0&#91;1] - y) * pPR-&gt;yDirIn &lt; 0)\n\t\treturn false;\n\treturn true;\n}\nint Polygon::addVert(Polygon* pDst, float* p0, Vertex01* pV0, Vertex01* pV1) {\n\tfloat d&#91;2];\n\tfor (int i = 0; i &lt; 2; i++)\n\t\td&#91;i] = pV0-&gt;aPos&#91;i] - p0&#91;i];\n\tfloat dist2v0 = v3lengthXY(d);\n\tif (dist2v0 == 0)\n\t\treturn addVertex(pDst, pV0);\n\tfor (int i = 0; i &lt; 2; i++)\n\t\td&#91;i] = pV1-&gt;aPos&#91;i] - p0&#91;i];\n\tfloat dist2v1 = v3lengthXY(d);\n\tif (dist2v1 == 0)\n\t\treturn addVertex(pDst, pV1);\n\t\/\/if here - find mid values\n\tfloat k0 = dist2v1 \/ (dist2v0 + dist2v1);\n\tfloat k1 = dist2v0 \/ (dist2v0 + dist2v1);\n\tVertex01* pVx = new Vertex01(*pV0);\n\tpVx-&gt;aPos&#91;0] = p0&#91;0];\n\tpVx-&gt;aPos&#91;1] = p0&#91;1];\n\tpVx-&gt;aPos&#91;2] = k0 * pV0-&gt;aPos&#91;2] + k1 * pV1-&gt;aPos&#91;2];\n\tfor (int i = 0; i &lt; 3; i++)\n\t\tpVx-&gt;aNormal&#91;i] = k0 * pV0-&gt;aNormal&#91;i] + k1 * pV1-&gt;aNormal&#91;i];\n\tfor (int i = 0; i &lt; 2; i++)\n\t\tpVx-&gt;aTuv&#91;i] = k0 * pV0-&gt;aTuv&#91;i] + k1 * pV1-&gt;aTuv&#91;i];\n\tfor (int i = 0; i &lt; 2; i++)\n\t\tpVx-&gt;aTuv2&#91;i] = k0 * pV0-&gt;aTuv2&#91;i] + k1 * pV1-&gt;aTuv2&#91;i];\n\taddVertex(pDst, pVx);\n\tdelete pVx;\n\treturn 0;\n}\nint Polygon::xyIntersection(Polygon* pDst, Polygon* pFrame, Polygon* pSrc) {\n\t\/\/check bounding boxes, XY only\n\tfor (int i = 0; i &lt; 2; i++) {\n\t\tif (pFrame-&gt;bbMin&#91;i] &gt; pSrc-&gt;bbMax&#91;i])\n\t\t\treturn 0;\n\t\tif (pFrame-&gt;bbMax&#91;i] &lt; pSrc-&gt;bbMin&#91;i])\n\t\t\treturn 0;\n\t}\n\t\/\/compare normals\n\tif (v3dotProduct(pFrame-&gt;normal, pSrc-&gt;normal) &lt;= 0)\n\t\treturn 0;\n\/*\nmylog(&quot;&gt;&gt;&gt;pFrame %fx%f to %fx%f to %fx%f \\n&quot;,\n\tpFrame-&gt;vertices.at(0)-&gt;aPos&#91;0], pFrame-&gt;vertices.at(0)-&gt;aPos&#91;1],\n\tpFrame-&gt;vertices.at(1)-&gt;aPos&#91;0], pFrame-&gt;vertices.at(1)-&gt;aPos&#91;1],\n\tpFrame-&gt;vertices.at(2)-&gt;aPos&#91;0], pFrame-&gt;vertices.at(2)-&gt;aPos&#91;1]\n);\nmylog(&quot;   pSrc   %fx%f to %fx%f to %fx%f \\n&quot;,\n\tpSrc-&gt;vertices.at(0)-&gt;aPos&#91;0], pSrc-&gt;vertices.at(0)-&gt;aPos&#91;1],\n\tpSrc-&gt;vertices.at(1)-&gt;aPos&#91;0], pSrc-&gt;vertices.at(1)-&gt;aPos&#91;1],\n\tpSrc-&gt;vertices.at(2)-&gt;aPos&#91;0], pSrc-&gt;vertices.at(2)-&gt;aPos&#91;1]\n);\nmylog(&quot;---SrcVerts\\n&quot;);\n*\/\n\t\/\/if here - have overlap\n\tint addedSrcVerts = 0;\n\tfor (int vN = 0; vN &lt; pSrc-&gt;ribsN; vN++) {\n\t\tVertex01* pV = pSrc-&gt;vertices.at(vN);\n\t\tif (dotFits(pV-&gt;aPos, pFrame))\n\t\t\taddedSrcVerts += addVertex(pDst, pV);\n\t}\n\tif (addedSrcVerts == pSrc-&gt;ribsN)\n\t\treturn addedSrcVerts;\n\n\/\/mylog(&quot;---FrameVerts\\n&quot;);\n\tint addedFrameVerts = 0;\n\tfor (int vN = 0; vN &lt; pFrame-&gt;ribsN; vN++) {\n\t\tVertex01* pV = pFrame-&gt;vertices.at(vN);\n\t\tif (dotFits(pV-&gt;aPos, pSrc)) {\n\t\t\tint frameVerts = addVert(pDst, pV-&gt;aPos, pSrc);\n\t\t\taddedFrameVerts += frameVerts;\n\t\t}\n\t}\n\tif (addedFrameVerts == pFrame-&gt;ribsN)\n\t\treturn addedFrameVerts;\n\n\/\/mylog(&quot;---CrossVerts\\n&quot;);\n\t\/\/check ribs intersections\n\tint addedCrossVerts = 0;\n\tfor (int ribNframe = 0; ribNframe &lt; pFrame-&gt;ribsN; ribNframe++) {\n\t\tfor (int ribNsrc = 0; ribNsrc &lt; pSrc-&gt;ribsN; ribNsrc++) {\n\t\t\tint crossVerts = addLinesIntersection(pDst, pFrame, ribNframe, pSrc, ribNsrc);\n\t\t\taddedCrossVerts += crossVerts;\n\t\t}\n\t}\n\treturn (addedSrcVerts + addedFrameVerts + addedCrossVerts);\n}\nbool Polygon::dotFits(float* p0, PolygonRib* pPR) {\n\/\/mylog(&quot;dotFits Rib %f x %f vs %f x %f to %f x %f\\n&quot;, p0&#91;0], p0&#91;1], pPR-&gt;p0&#91;0], pPR-&gt;p0&#91;1], pPR-&gt;p1&#91;0], pPR-&gt;p1&#91;1]);\n\t\/\/assuming that p0 is on the line\n\tint dir0;\n\tint dir1;\n\tif (pPR-&gt;isVertical) {\n\t\tif (pPR-&gt;p0&#91;1] == p0&#91;1])\n\t\t\treturn true;\n\t\telse if (pPR-&gt;p0&#91;1] &lt; p0&#91;1])\n\t\t\tdir0 = -1;\n\t\telse\n\t\t\tdir0 = 1;\n\n\t\tif (pPR-&gt;p1&#91;1] == p0&#91;1])\n\t\t\treturn true;\n\t\telse if (pPR-&gt;p1&#91;1] &lt; p0&#91;1])\n\t\t\tdir1 = -1;\n\t\telse\n\t\t\tdir1 = 1;\n\t}\n\telse{ \/\/&quot;normal&quot; line\n\t\tif (pPR-&gt;p0&#91;0] == p0&#91;0])\n\t\t\treturn true;\n\t\telse if (pPR-&gt;p0&#91;0] &lt; p0&#91;0])\n\t\t\tdir0 = -1;\n\t\telse\n\t\t\tdir0 = 1;\n\n\t\tif (pPR-&gt;p1&#91;0] == p0&#91;0])\n\t\t\treturn true;\n\t\telse if (pPR-&gt;p1&#91;0] &lt; p0&#91;0])\n\t\t\tdir1 = -1;\n\t\telse\n\t\t\tdir1 = 1;\n\t}\n\/\/mylog(&quot;  fits?=%d\\n&quot;, !(dir0 == dir1));\n\tif (dir0 == dir1)\n\t\treturn false;\n\treturn true;\n}\nbool Polygon::dotFits(float* p0, Polygon* pPL) {\n\/\/mylog(&quot;dotFits Polygon %f x %f\\n&quot;,p0&#91;0],p0&#91;1]);\n\n\tfor (int i = 0; i &lt; pPL-&gt;ribsN; i++)\n\t\tif (!correctSide(p0, pPL-&gt;ribs.at(i))) {\n\/\/mylog(&quot;  don&#039;t Fit side %f x %f to %f x %f\\n&quot;, pPL-&gt;ribs.at(i)-&gt;p0&#91;0], pPL-&gt;ribs.at(i)-&gt;p0&#91;1], pPL-&gt;ribs.at(i)-&gt;p1&#91;0], pPL-&gt;ribs.at(i)-&gt;p1&#91;1]);\n\t\t\treturn false;\n\t\t}\n\/\/mylog(&quot;  dotFits!\\n&quot;);\n\treturn true;\n}\nint Polygon::buildTriangles(Polygon* pPL) {\n\tint vertsN = pPL-&gt;vertices.size();\n\t\/\/mid point coords\n\tfloat p0&#91;2] = { 0,0 };\n\tfor (int vN = 0; vN &lt; vertsN; vN++) {\n\t\tfloat* p1 = pPL-&gt;vertices.at(vN)-&gt;aPos;\n\t\tp0&#91;0] += p1&#91;0];\n\t\tp0&#91;1] += p1&#91;1];\n\t}\n\tp0&#91;0] \/= vertsN;\n\tp0&#91;1] \/= vertsN;\n\tfor (int vN = 0; vN &lt; vertsN; vN++) {\n\t\tfloat* p1 = pPL-&gt;vertices.at(vN)-&gt;aPos;\n\t\tfloat v1&#91;3] ={0,0,0};\n\t\tv1&#91;0] = p1&#91;0] - p0&#91;0];\n\t\tv1&#91;1] = p1&#91;1] - p0&#91;1];\n\t\tfloat az = -atan2f(v1&#91;0], v1&#91;1]) * radians2degrees;\n\t\t\/\/aTangent is not used at this point, ok to use it to store az\n\t\tpPL-&gt;vertices.at(vN)-&gt;aTangent&#91;0] = az;\n\t}\n\t\/\/sort vertices\n\tstd::sort(pPL-&gt;vertices.begin(), pPL-&gt;vertices.end(), \n\t\t&#91;](Vertex01* pV0, Vertex01* pV1) {\n\t\treturn pV0-&gt;aTangent&#91;0] &gt; pV1-&gt;aTangent&#91;0]; });\n\t\/\/check for redundancy\n\tfor (int vN = pPL-&gt;vertices.size() - 1; vN &gt; 0; vN--) {\n\t\tVertex01* pV = pPL-&gt;vertices.at(vN);\n\t\tVertex01* pVprev = pPL-&gt;vertices.at(vN-1);\n\t\tif (pV-&gt;aTangent&#91;0] == pVprev-&gt;aTangent&#91;0]) {\n\t\t\tdelete pV;\n\t\t\tpPL-&gt;vertices.erase(pPL-&gt;vertices.begin() + vN);\n\t\t}\n\t}\n\tpPL-&gt;ribsN = pPL-&gt;vertices.size();\n\t\/\/build triangles\n\tVertex01* pV = pPL-&gt;vertices.at(0);\n\tfor (int vN = 2; vN &lt; pPL-&gt;ribsN; vN++) {\n\t\tTriangle01* pTR = new Triangle01();\n\t\tpPL-&gt;triangles.push_back(pTR);\n\t\tpTR-&gt;idx&#91;0] = 0;\n\t\tpTR-&gt;idx&#91;1] = vN;\n\t\tpTR-&gt;idx&#91;2] = vN - 1;\n\t\tpTR-&gt;subjN = pV-&gt;subjN;\n\t\tpTR-&gt;materialN = pV-&gt;materialN;\n\t\t\/\/mark\n\t\tmyStrcpy_s(pTR-&gt;marks, 124, pV-&gt;marks);\n\t}\n\treturn 1;\n}\nint Polygon::addVert(Polygon* pDst, float* p0, Polygon* pSrc) {\n\t\/\/check where horizontal line drawn through p0 crosses polygon&#039;s ribs\n\tVertex01 vx0;\n\tVertex01 vx1;\n\tint vxN = 0;\n\tfor (int ribN = 0; ribN &lt; pSrc-&gt;ribsN; ribN++) {\n\t\tPolygonRib* pPR = pSrc-&gt;ribs.at(ribN);\n\t\tif (pPR-&gt;isHorizontal)\n\t\t\tcontinue;\n\t\tfloat p1&#91;2];\n\t\tp1&#91;1] = p0&#91;1];\n\t\tif (pPR-&gt;isVertical)\n\t\t\tp1&#91;0] = pPR-&gt;x_vertical;\n\t\telse\n\t\t\tp1&#91;0] = (p1&#91;1] - pPR-&gt;b_intercept) \/ pPR-&gt;a_slope;\n\t\tif (!dotFits(p1, pPR))\n\t\t\tcontinue;\n\t\t\/\/if here - 1 intersection found\n\t\tVertex01* pVdst = &amp;vx0;\n\t\tif(vxN &gt; 0)\n\t\t\tpVdst = &amp;vx1;\n\t\tVertex01* pV0src = pSrc-&gt;vertices.at(pPR-&gt;i0);\n\t\tVertex01* pV1src = pSrc-&gt;vertices.at(pPR-&gt;i1);\n\t\tmemcpy(pVdst, pV0src, sizeof(Vertex01));\n\t\tfloat d&#91;2];\n\t\tfor (int i = 0; i &lt; 2; i++)\n\t\t\td&#91;i] = pV0src-&gt;aPos&#91;i] - p1&#91;i];\n\t\tfloat dist2v0 = v3lengthXY(d);\n\t\tif (dist2v0 == 0)\n\t\t\tmemcpy(pVdst, pV0src, sizeof(Vertex01));\n\t\telse {\n\t\t\tfor (int i = 0; i &lt; 2; i++)\n\t\t\t\td&#91;i] = pV1src-&gt;aPos&#91;i] - p1&#91;i];\n\t\t\tfloat dist2v1 = v3lengthXY(d);\n\t\t\tif (dist2v1 == 0)\n\t\t\t\tmemcpy(pVdst, pV1src, sizeof(Vertex01));\n\t\t\telse {\n\t\t\t\t\/\/if here - find mid values\n\t\t\t\tfloat k0 = dist2v1 \/ (dist2v0 + dist2v1);\n\t\t\t\tfloat k1 = dist2v0 \/ (dist2v0 + dist2v1);\n\t\t\t\tpVdst-&gt;aPos&#91;0] = p1&#91;0];\n\t\t\t\tpVdst-&gt;aPos&#91;1] = p1&#91;1];\n\t\t\t\tpVdst-&gt;aPos&#91;2] = k0 * pV0src-&gt;aPos&#91;2] + k1 * pV1src-&gt;aPos&#91;2];\n\t\t\t\tfor (int i = 0; i &lt; 3; i++)\n\t\t\t\t\tpVdst-&gt;aNormal&#91;i] = k0 * pV0src-&gt;aNormal&#91;i] + k1 * pV1src-&gt;aNormal&#91;i];\n\t\t\t\tfor (int i = 0; i &lt; 2; i++)\n\t\t\t\t\tpVdst-&gt;aTuv&#91;i] = k0 * pV0src-&gt;aTuv&#91;i] + k1 * pV1src-&gt;aTuv&#91;i];\n\t\t\t\tfor (int i = 0; i &lt; 2; i++)\n\t\t\t\t\tpVdst-&gt;aTuv2&#91;i] = k0 * pV0src-&gt;aTuv2&#91;i] + k1 * pV1src-&gt;aTuv2&#91;i];\n\t\t\t}\n\t\t}\n\t\tvxN++;\n\t\tif (vxN &gt; 1)\n\t\t\tbreak;\n\t}\n\taddVert(pDst, p0, &amp;vx0, &amp;vx1);\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>Now &#8211; model description.<\/p>\n\n\n\n<p>6. Copy following code to a <strong>Text Editor<\/strong> 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: [31]; 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;a2mesh wh=&quot;50,2&quot; all markedAs=&quot;box_right&quot; onThe=&quot;right&quot; py=24.6 az=31 \/&gt;\n\t&lt;a2mesh wh=&quot;50,2&quot; all markedAs=&quot;box_left&quot; onThe=&quot;left&quot; py=24.6 az=-31 \/&gt;\n\t&lt;a2mesh wh=&quot;53,2&quot; all markedAs=&quot;box_front&quot; py=17.8 \/&gt;\n\t&lt;a2mesh wh=&quot;6 ,2&quot; all markedAs=&quot;box_back&quot; onThe=&quot;back&quot; py=31.5 px=23.5 \/&gt;\n\t&lt;a2mesh wh=&quot;6 ,2&quot; all markedAs=&quot;box_back&quot; onThe=&quot;back&quot; py=31.5 px=-23.5 \/&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>New code starts at line 32.<\/li><li>We have here new tags &#8220;<strong>a2mesh<\/strong>&#8220;. It&#8217;s like &#8220;a&#8221; (apply), but &#8220;apply to mesh&#8221;.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>To read and to execute it we need to add new functionality to <strong>ModelLoader<\/strong>.<\/p>\n\n\n\n<p>7. Open <em>ModelLoader.h<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [45]; 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\tpModelBuilder-&gt;lockGroup(pModelBuilder);\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, ModelBuilder* pMB, 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\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<ul class=\"wp-block-list\"><li>New function here is <em>processTag_a2mesh(..)<\/em><\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>Implementation:<\/p>\n\n\n\n<p>8. Open <em>ModelLoader.cpp<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [181,182,351]; 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}\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\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\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\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, 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}\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\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\/\/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\/\/------------\n\t\/\/replace material\n\tMaterial mt;\n\tmt.setShaderType(&quot;phong&quot;);\n\tmt.uColor.setRGBA(0,255,0,255);\n\tint mtN = pMB-&gt;useMaterial(pMB, &amp;mt);\n\tfor (int i = vx2.size() - 1; i &gt;= 0; i--)\n\t\tvx2.at(i)-&gt;materialN = mtN;\n\tfor (int i = tr2.size() - 1; i &gt;= 0; i--)\n\t\ttr2.at(i)-&gt;materialN = mtN;\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<p><\/p>\n\n\n\n<p>How it works:<\/p>\n\n\n\n<p>Everything happens in <em>processTag_a2mesh(..)<\/em> (line 351).<\/p>\n\n\n\n<p>Line 355. Reading position where we are applying it to.<\/p>\n\n\n\n<p>Line 360. Cloning selected mesh.<\/p>\n\n\n\n<p>Line 369. Placing cloned mesh facing us:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/04.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Line 374. Reading sizes what we want to cut.<\/p>\n\n\n\n<p>Lines 381-390. Scanning mesh&#8217;s triangles and building intersections (line 384). Resulting intersection is stored in <em>Polygon intersection<\/em> (line 383).<\/p>\n\n\n\n<p>If intersection exists, we are building triangles (line 486) and saving result into <em>vx2 <\/em>(vertices) and <em>tr2 <\/em>(triangles) arrays (vectors) (line 388).<\/p>\n\n\n\n<p>After all triangles processed, in  <em>vx2 <\/em>\/ <em>tr2<\/em> we have our desired fragment cutted out of initial mesh&#8217;s copy:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/05.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>To make it visible after moving it back to it&#8217;s place, we are changing it&#8217;s material (lines 394-401). <\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/06.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>We&#8217;ll remove  changing material code a bit later.<\/p>\n\n\n\n<p>Line 404. Positioning cutted fragment to it&#8217;s final place.<\/p>\n\n\n\n<p>Line 406. Cloning fragment back to <strong>ModelBuilder<\/strong>. However, it has the same coordinates as original mesh, so they are overlapping each other:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/07.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>To shift it a bit out of original mesh, we have an extra command in <em>root01.txt<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;\/group sizeD=\"0.1,0,0.1\"&gt;<\/code><\/pre>\n\n\n\n<p>It&#8217;s the last one, line 38.<\/p>\n\n\n\n<p><em>ModelLoader <\/em>will translate <em>sizeD <\/em>to <em>scale<\/em>, it&#8217;s lines 327-339 in <em>ModelLoader.cpp<\/em>, function <em>fillProps_gt(..)<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>9. Build and run. Result:<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/writingagame.com\/img\/b01\/c33\/08.jpg\"><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The goal is achieved.<\/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>10. 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\"\/>\n\n\n\n<p>11. Under <em>modeler <\/em>add <strong>Existing Item<\/strong> from <em>C:\\CPP\\engine\\modeler<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Polygon.cpp<\/li><li>Polygon.h<\/li><li>PolygonRib.cpp<\/li><li>PolygonRib. 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>12. 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\"\/>\n\n\n\n<p>Our next task is to apply <em>normal map<\/em> to cutted fragments, preserving their original materials and textures.<\/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\">Just a friendly reminder: 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 existing textured mesh&#8217;s&nbsp;fragment. Like this: In previous chapter we implemented a concept of selecting and manipulating &#8220;marked vertices\/triangles groups&#8220;. So, now we can select one (in this sample &#8211; &#8220;box_right&#8221;), duplicate [&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-1050","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\/1050","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=1050"}],"version-history":[{"count":42,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/1050\/revisions"}],"predecessor-version":[{"id":1146,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/1050\/revisions\/1146"}],"wp:attachment":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/media?parent=1050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/categories?post=1050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/tags?post=1050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}