\n\/\/#version 320 es\nprecision lowp float;\nuniform mat4 uMVP; \/\/ transform matrix (Model-View-Projection)\nuniform mat3 uMV3x3; \/\/ Model-View matrix (for calculating normals into eye space)\n\nin vec3 aPos; \/\/ position attribute (x,y,z)\nin vec3 aNormal; \/\/ normal attribute (x,y,z)\n\n\/\/normal map\nin vec3 aTangent;\nin vec3 aBinormal;\nin vec2 aTuv2; \/\/attribute TUV2 (texture coordinates)\nout vec2 vTuv2; \/\/varying TUV2 (pass to fragment shader)\nuniform vec3 uVectorToLight;\nuniform vec3 uHalfVector;\nout vec3 tbnVectorToLight;\nout vec3 tbnHalfVector;\n#if defined(MIRROR)\n\tout vec2 vScreenPosition01;\n\tout mat3 inversedTBN;\n#endif\n#if defined(USE_TUV0)\n\tin vec2 aTuv; \/\/attribute TUV (texture coordinates)\n\tout vec2 vTuv; \/\/varying TUV (pass to fragment shader)\n#endif\n\nvoid main(void) { \n\tgl_Position = uMVP * vec4(aPos, 1.0);\n#if defined(USE_TUV0)\n\tvTuv = aTuv;\n#endif\n\n\tvTuv2 = aTuv2;\n\n\t\/\/ Transform the normal's orientation into eye space. \n\tvec3 N = uMV3x3 * aNormal;\n\tvec3 T = uMV3x3 * aTangent;\n\tvec3 B = uMV3x3 * aBinormal;\n\t\/\/build TBN matrix\n\tmat3 TBN = mat3(\n\t\t\tT[0],B[0],N[0],\n\t\t\tT[1],B[1],N[1],\n\t\t\tT[2],B[2],N[2]\n\t\t\t);\n\ttbnVectorToLight = TBN * uVectorToLight;\n\ttbnHalfVector = TBN * uHalfVector;\n#if defined(MIRROR)\n\tvScreenPosition01[0] = (gl_Position[0]\/gl_Position[3])*0.1;\n\tvScreenPosition01[1] = -(gl_Position[1]\/gl_Position[3])*0.1;\n\tinversedTBN = inverse(TBN);\n#endif\n}\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\n\n\n\nFragment shader<\/strong>:<\/p>\n\n\n\n2. \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0438\u0436\u0435\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440<\/strong> \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c to\/as<\/p>\n\n\n\nC:\\CPP\\engine\\dt\\shaders\\nm_f<\/strong>.txt<\/em><\/p>\n\n\n\n\/\/#version 320 es\nprecision lowp float;\nout vec4 FragColor; \/\/output pixel color\nuniform float uAlphaFactor; \/\/for semi-transparency\nuniform int uAlphaBlending; \/\/for semi-transparency\n\nin vec2 vTuv2;\nuniform sampler2D uTex2nm;\nin vec3 tbnVectorToLight;\nin vec3 tbnHalfVector;\n\n#if defined(USE_TEX0)\n\tuniform sampler2D uTex0; \/\/texture id\n\tuniform sampler2D uTex3; \/\/translate texture id\n\tuniform int uTex0translateChannelN;\n#else\n\tuniform vec4 uColor;\n#endif\n#if defined(USE_TUV0)\n\tin vec2 vTuv; \/\/varying TUV (passed from vertex shader)\n#endif\n#if defined(OVERMASK)\n\tuniform sampler2D uTex1mask; \/\/texture id\n\tuniform int uTex1alphaChannelN;\n\tuniform int uTex1alphaNegative;\n#endif\n#if defined(MIRROR)\n\tin vec2 vScreenPosition01;\n\tin mat3 inversedTBN;\n#endif\nuniform float uAmbient;\nuniform float uSpecularIntencity;\nuniform float uSpecularMinDot;\nuniform float uSpecularPowerOf;\n\nvoid main(void) {\n\tvec4 tbnNormal4 = texture(uTex2nm, vTuv2);\n\tfloat alpha = tbnNormal4.a;\n\n\tif(alpha < 0.5){\n\t\tif(uAlphaBlending > 0){\n\t\t\tif(alpha == 0.0){\n\t\t\t\tdiscard;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse{ \/\/no AlphaBlending\n\t\t\tdiscard;\n\t\t\treturn;\n\t\t}\n\t}\n\t\/\/black?\n\tif(tbnNormal4.b < 0.4){\n\t\tFragColor = vec4(0.0,0.0,0.0,alpha);\n\t\treturn;\n\t}\n\t\n\tvec4 outColor;\n#if defined(OVERMASK)\n\toutColor = texture(uTex1mask, vTuv);\n\tfloat alpha2 = outColor[uTex1alphaChannelN];\n\tif(uTex1alphaNegative > 0)\n\t\talpha2 = 1.0 - alpha2;\n\tif(alpha2 < 1.0){\n\t\talpha *= alpha2;\n\t\tif(alpha < 0.5){\n\t\t\tif(uAlphaBlending > 0){\n\t\t\t\tif(alpha == 0.0){\n\t\t\t\t\tdiscard;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse{ \/\/no AlphaBlending\n\t\t\t\tdiscard;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\tvec3 vNormalNormal = normalize(vec3(tbnNormal4) * 2.0 - 1.0);\n\n#if defined(USE_TEX0)\n\t#if defined(MIRROR)\n\t\tvec3 inversedNormal = normalize(inversedTBN * vNormalNormal);\n\t\tvec2 vTuvMirror;\n\t\tvTuvMirror[0] = (vScreenPosition01[0]+inversedNormal[0]*0.4)+0.5;\n\t\tvTuvMirror[1] = -(vScreenPosition01[1]+inversedNormal[1]*0.4)+0.5;\n\t\toutColor = texture(uTex0, vTuvMirror);\n\t#else\n\t\toutColor = texture(uTex0, vTuv);\n\t#endif\n\tif(uTex0translateChannelN >= 0){ \/\/translate channel\n\t\tvec2 tuv3;\n\t\ttuv3[0] = outColor[uTex0translateChannelN];\n\t\ttuv3[1] = 0.0;\n\t\toutColor = texture(uTex3, tuv3);\n\t}\n\tFragColor = outColor;\n#else\n\tFragColor = uColor;\n#endif\n\tif(FragColor.a != 1.0){\n\t\talpha *= FragColor.a;\n\t\tif(alpha < 0.5){\n\t\t\tif(uAlphaBlending > 0){\n\t\t\t\tif(alpha == 0.0){\n\t\t\t\t\tdiscard;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse{ \/\/no AlphaBlending\n\t\t\t\tdiscard;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tif(uAmbient<1.0){\n\t\t \/\/ Calculate the dot product of the light vector and vertex normal. If the normal and light vector are\n\t\t \/\/ pointing in the same direction then it will get max illumination.\n\t\t float directionalLightIntencity = dot(vNormalNormal, normalize(tbnVectorToLight));\n\t\t\n\t\t \/\/ count ambient component\n\t\t directionalLightIntencity += uAmbient;\n\t\t if(directionalLightIntencity < uAmbient)\n\t\t\tdirectionalLightIntencity = uAmbient;\n\n\t\t \/\/ Multiply the color by the lightIntencity illumination level to get final output color.\n\t\t FragColor *= directionalLightIntencity;\n\t}\n\tif(uSpecularIntencity>0.0){\n\t\t\/\/specular light\n\t\t\/\/ INTENSITY OF THE SPECULAR LIGHT\n\t\t\/\/ DOT PRODUCT OF NORMAL VECTOR AND THE HALF VECTOR TO THE POWER OF THE SPECULAR HARDNESS\n\t\tfloat dotProduct = dot(vNormalNormal, normalize(tbnHalfVector));\n\n\t\tif(dotProduct>uSpecularMinDot){\n\t\t\tfloat specularIntencity = pow(dotProduct, uSpecularPowerOf) * uSpecularIntencity;\t\t\n\t\t\tif(specularIntencity > uSpecularIntencity)\n\t\t\t\tspecularIntencity = uSpecularIntencity;\n\t\t\tFragColor += specularIntencity;\n\t\t}\n\t}\n\tif(uAlphaFactor != 1.0)\n\t\talpha *= uAlphaFactor;\t\n\tFragColor.a = alpha;\n}\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\n\n\n\n\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 root01.txt<\/strong>:<\/p>\n\n\n\n3. \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0438\u0436\u0435\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440<\/strong> \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c (overwrite) to\/as<\/p>\n\n\n\nC:\\CPP\\a997modeler<\/strong>\\dt\\models\\misc\\marlboro01\\root01.txt<\/strong><\/em><\/p>\n\n\n\n<texture_as="tx0" src="marlboro03small.png" ckey="#00ff00"\/>\n<mt_type="phong" uTex0_use="tx0" \/>\n<vs="box_tank" whl="53,83,21" ext=1 sectR=1 \/>\n<a="front v,back v" xywh="2,1,323,495"\/>\n<a="right all" xywh="327,1,128,495"\/>\n<a="left all" xywh="457,1,128,495"\/>\n<a="top" xywh="588,1,323,133"\/>\n<a="bottom" xywh="587,136,324,134"\/>\n\/\/golden prints\n<vs="box" whl="55.1,85.1,23.1" \/>\n<texture_as="whitenoise" src="\/dt\/common\/img\/whitenoise\/wn64_blur3.bmp"\/>\n<texture_as="gold" src="\/dt\/common\/img\/materials\/gold02roman.bmp" \/>\n<mt_type="mirror" uAlphaBlending uTex1mask_use="tx0" uTex1alphaChannelN=1 uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" \/>\n\/\/side golden prints\n<a="right" xywh="342,12,101,10" whl="x,1.8,18.1" pxyz="x,39.8, -0.3" \/> \/\/Please do not litter\n<a="right" xywh="339,144,105,89" whl="x,15.35,18.9" pxyz="x,10.3,-0.12" \/> \/\/For special offers...\n<a="left" xywh="475,15,95,48" whl="x,8.4,17" pxyz="x,36, 0.3" \/> \/\/Underage sale...\n\/\/front prints\n<group>\n\t\/\/bottom golden print "20 class a..."\n\t<a="front" xywh="20,498,289,13" whl="47.5,2,x" pxyz="1,-36,x" \/>\n\t\/\/blazon\/emblem\n\t<mt_type="mirror" uAlphaBlending uTex2nm_use="tx0" uTex0_use="whitenoise" uTex0translateChannelN=0 uTex3_use="gold" \/>\n\t<a="front" xywh2nm="589,415,128,94" whl="20.7,16,x" pxyz="0.3,6.1,x" \/> \/\/emblem\n\t\/\/"Marlboro\n\t<mt_type="phong" uAlphaBlending uTex2nm_use="tx0" uColor="#1E211E" \/>\n\t<a="front" xywh2nm="590,275,301,136" whl="49.2,23.3,x" pxyz="0.21,-18,x" \/> \/\/marlboro\n<\/group> \n<clone ay=180 \/>\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435:<\/p>\n\n\n\n
- \u041d\u043e\u0432\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0434\u043b\u044f \u0433\u0435\u0440\u0431\u0430 (\u0441\u0442\u0440\u043e\u043a\u0430 23): \u0412\u043c\u0435\u0441\u0442\u043e \u043c\u0430\u0441\u043a\u0438 uTex1mask <\/em>\u043c\u044b \u0437\u0430\u0434\u0430\u0435\u043c Normal Map<\/strong> uTex2nm_use=”tx0″<\/em> <\/li>
- \u0412 \u0442\u0430\u0433\u0435 “a” \u0434\u043b\u044f \u0433\u0435\u0440\u0431\u0430 (\u0441\u0442\u0440\u043e\u043a\u0430 24) \u043c\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u041d\u0415 xywh<\/em>, \u0430 xywh2nm<\/em> (\u0442\u043e\u0442 \u0436\u0435 xywh, \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f normal map)<\/li>
- Material \u0434\u043b\u044f \u043f\u0440\u0438\u043d\u0442\u0430 “Marlboro” (\u0441\u0442\u0440\u043e\u043a\u0430 26): Phong \u0441 uColor \u0438 \u0441 Normal Map<\/li><\/ul>\n\n\n\n
\n\n\n\n\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c.<\/p>\n\n\n\n
Windows<\/h2>\n\n\n\n
4. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c VS, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c\u00a0C:\\CPP\\a997modeler<\/em>\\p_windows\\p_windows.sln<\/em>.<\/p>\n\n\n\n
\n\n\n\n\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u043d\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432.<\/p>\n\n\n\n
5. \u0417\u0430\u043c\u0435\u043d\u0438\u043c Shader.cpp<\/em> \u043a\u043e\u0434 \u043d\u0430:<\/p>\n\n\n\n#include "Shader.h"\n#include "platform.h"\n#include "utils.h"\n#include "FileLoader.h"\n\nextern std::string filesRoot;\n\n\/\/static array (vector) of all loaded shaders\nstd::vector<Shader*> Shader::shaders;\n\nint Shader::loadShaders() {\n FileLoader* pFLvertex = new FileLoader("\/dt\/shaders\/phong_v.txt");\n FileLoader* pFLfragment = new FileLoader("\/dt\/shaders\/phong_f.txt");\n loadShadersGroup("flat", "FLAT; COLOR | TEXTURE; NONE | OVERMASK", pFLvertex->pData, pFLfragment->pData);\n loadShadersGroup("phong", "PHONG; COLOR | TEXTURE; NONE | OVERMASK", pFLvertex->pData, pFLfragment->pData);\n loadShadersGroup("mirror", "PHONG;MIRROR; NONE | OVERMASK", pFLvertex->pData, pFLfragment->pData);\n delete pFLvertex;\n delete pFLfragment;\n \/\/Normal Maps\n pFLvertex = new FileLoader("\/dt\/shaders\/nm_v.txt");\n pFLfragment = new FileLoader("\/dt\/shaders\/nm_f.txt");\n loadShadersGroup("phong", "COLOR | TEXTURE; NONE | OVERMASK", pFLvertex->pData, pFLfragment->pData);\n loadShadersGroup("mirror", "MIRROR; NONE | OVERMASK", pFLvertex->pData, pFLfragment->pData);\n delete pFLvertex;\n delete pFLfragment;\n return 1;\n}\nint Shader::buildShaderObjectFromFiles(std::string filePathVertexS, std::string filePathFragmentS) {\n \/\/create shader object\n Shader* pSh = new Shader();\n shaders.push_back(pSh);\n pSh->GLid = linkShaderProgramFromFiles((filesRoot + filePathVertexS).c_str(), (filesRoot + filePathFragmentS).c_str());\n \/\/common variables. If not presented, = -1;\n fillLocations(pSh);\n\n return (shaders.size() - 1);\n}\nint Shader::fillLocations(Shader* pSh) {\n \/\/common variables. If not presented, = -1;\n \/\/attributes\n pSh->l_aPos = glGetAttribLocation(pSh->GLid, "aPos"); \/\/attribute position (3D coordinates)\n pSh->l_aNormal = glGetAttribLocation(pSh->GLid, "aNormal"); \/\/attribute normal (3D vector)\n pSh->l_aTangent = glGetAttribLocation(pSh->GLid, "aTangent"); \/\/for normal map\n pSh->l_aBinormal = glGetAttribLocation(pSh->GLid, "aBinormal"); \/\/for normal map\n pSh->l_aTuv = glGetAttribLocation(pSh->GLid, "aTuv"); \/\/attribute TUV (texture coordinates)\n pSh->l_aTuv2 = glGetAttribLocation(pSh->GLid, "aTuv2"); \/\/attribute TUV (texture coordinates)\n \/\/uniforms\n pSh->l_uMVP = glGetUniformLocation(pSh->GLid, "uMVP"); \/\/ transform matrix (Model-View-Projection)\n pSh->l_uMV3x3 = glGetUniformLocation(pSh->GLid, "uMV3x3"); \/\/ Model-View matrix for normals\n pSh->l_uVectorToLight = glGetUniformLocation(pSh->GLid, "uVectorToLight"); \/\/ \n pSh->l_uHalfVector = glGetUniformLocation(pSh->GLid, "uHalfVector"); \/\/ required for specular light\n \/\/material's properties\n pSh->l_uColor = glGetUniformLocation(pSh->GLid, "uColor");\n pSh->l_uTex0 = glGetUniformLocation(pSh->GLid, "uTex0"); \/\/texture id\n pSh->l_uTex1mask = glGetUniformLocation(pSh->GLid, "uTex1mask"); \/\/texture id\n pSh->l_uTex2nm = glGetUniformLocation(pSh->GLid, "uTex2nm"); \/\/texture id\n pSh->l_uTex3 = glGetUniformLocation(pSh->GLid, "uTex3"); \/\/texture id\n pSh->l_uTex1alphaChannelN = glGetUniformLocation(pSh->GLid, "uTex1alphaChannelN");\n pSh->l_uTex1alphaNegative = glGetUniformLocation(pSh->GLid, "uTex1alphaNegative");\n pSh->l_uTex0translateChannelN = glGetUniformLocation(pSh->GLid, "uTex0translateChannelN");\n pSh->l_uAlphaFactor = glGetUniformLocation(pSh->GLid, "uAlphaFactor"); \/\/ for semi-transparency\n pSh->l_uAlphaBlending = glGetUniformLocation(pSh->GLid, "uAlphaBlending"); \/\/ for semi-transparency\n pSh->l_uAmbient = glGetUniformLocation(pSh->GLid, "uAmbient"); \/\/ ambient light\n pSh->l_uSpecularIntencity = glGetUniformLocation(pSh->GLid, "uSpecularIntencity"); \/\/ \n pSh->l_uSpecularMinDot = glGetUniformLocation(pSh->GLid, "uSpecularMinDot"); \/\/ \n pSh->l_uSpecularPowerOf = glGetUniformLocation(pSh->GLid, "uSpecularPowerOf"); \/\/ \n return 1;\n}\nint Shader::cleanUp() {\n int shadersN = shaders.size();\n if (shadersN < 1)\n return -1;\n glUseProgram(0);\n for (int i = 0; i < shadersN; i++) {\n Shader* pSh = shaders.at(i);\n glDeleteProgram(pSh->GLid);\n delete pSh;\n }\n shaders.clear();\n return 1;\n}\n\nGLchar infoLog[1024];\nint logLength;\nint Shader::shaderErrorCheck(int shaderId, std::string ref) {\n \/\/use after glCompileShader()\n if (checkGLerrors(ref) > 0)\n return -1;\n glGetShaderInfoLog(shaderId, 1024, &logLength, infoLog);\n if (logLength == 0)\n return 0;\n mylog("%s shader infoLog:\\n%s\\n", ref.c_str(), infoLog);\n return -1;\n}\nint Shader::programErrorCheck(int programId, std::string ref) {\n \/\/use after glLinkProgram()\n if (checkGLerrors(ref) > 0)\n return -1;\n glGetProgramInfoLog(programId, 1024, &logLength, infoLog);\n if (logLength == 0)\n return 0;\n mylog("%s program infoLog:\\n%s\\n", ref.c_str(), infoLog);\n return -1;\n}\n\nint Shader::compileShaderFromFile(const char* filePath, GLenum shaderType) {\n int shaderId = glCreateShader(shaderType);\n FILE* pFile;\n myFopen_s(&pFile, filePath, "rt");\n if (pFile != NULL)\n {\n \/\/ obtain file size:\n fseek(pFile, 0, SEEK_END);\n int fSize = ftell(pFile);\n rewind(pFile);\n \/\/ size obtained, create buffer\n char* shaderSource = new char[fSize + 1];\n fSize = fread(shaderSource, 1, fSize, pFile);\n shaderSource[fSize] = 0;\n fclose(pFile);\n \/\/ source code loaded, compile\n glShaderSource(shaderId, 1, (const GLchar**)&shaderSource, NULL);\n \/\/myglErrorCheck("glShaderSource");\n glCompileShader(shaderId);\n if (shaderErrorCheck(shaderId, "glCompileShader") < 0)\n return -1;\n delete[] shaderSource;\n }\n else {\n mylog("ERROR loading %s\\n", filePath);\n return -1;\n }\n return shaderId;\n}\nint Shader::linkShaderProgramFromFiles(const char* filePathVertexS, const char* filePathFragmentS) {\n int vertexShaderId = compileShaderFromFile(filePathVertexS, GL_VERTEX_SHADER);\n int fragmentShaderId = compileShaderFromFile(filePathFragmentS, GL_FRAGMENT_SHADER);\n int programId = glCreateProgram();\n glAttachShader(programId, vertexShaderId);\n glAttachShader(programId, fragmentShaderId);\n glLinkProgram(programId);\n if (programErrorCheck(programId, "glLinkProgram") < 0)\n return -1;\n \/\/don't need shaders any longer - detach and delete them\n glDetachShader(programId, vertexShaderId);\n glDetachShader(programId, fragmentShaderId);\n glDeleteShader(vertexShaderId);\n glDeleteShader(fragmentShaderId);\n return programId;\n}\n\nint Shader::buildShaderObjectWithDefines(std::string shaderType, std::string definesString, char* sourceVertex, char* sourceFragment) {\n \/\/create shader object\n Shader* pSh = new Shader();\n shaders.push_back(pSh);\n myStrcpy_s(pSh->shaderType, 20, shaderType.c_str());\n\n pSh->GLid = linkShaderProgramWithDefines(definesString, sourceVertex, sourceFragment);\n \/\/common variables. If not presented, = -1;\n fillLocations(pSh);\n\n return (shaders.size() - 1);\n}\nint Shader::linkShaderProgramWithDefines(std::string definesString00, char* sourceVertex, char* sourceFragment) {\n \/\/build extended definesString\n bool bUSE_NORMALS = false;\n bool bUSE_TEX0 = false;\n bool bUSE_TUV0 = false;\n if (definesString00.find(" PHONG\\n") != std::string::npos)\n bUSE_NORMALS = true;\n if (definesString00.find(" TEXTURE\\n") != std::string::npos) {\n bUSE_TEX0 = true;\n bUSE_TUV0 = true;\n }\n if (definesString00.find(" MIRROR\\n") != std::string::npos) {\n bUSE_NORMALS = true;\n bUSE_TEX0 = true;\n }\n if (definesString00.find(" OVERMASK\\n") != std::string::npos) {\n bUSE_TUV0 = true;\n }\n std::string definesString;\n definesString.assign("#version 320 es\\n");\n definesString.append(definesString00);\n if (bUSE_NORMALS)\n definesString.append("#define USE_NORMALS\\n");\n if (bUSE_TEX0)\n definesString.append("#define USE_TEX0\\n");\n if (bUSE_TUV0)\n definesString.append("#define USE_TUV0\\n");\n\n int vertexShaderId = compileShaderWithDefines(definesString, sourceVertex, GL_VERTEX_SHADER);\n int fragmentShaderId = compileShaderWithDefines(definesString, sourceFragment, GL_FRAGMENT_SHADER);\n\n int programId = glCreateProgram();\n glAttachShader(programId, vertexShaderId);\n glAttachShader(programId, fragmentShaderId);\n glLinkProgram(programId);\n if (programErrorCheck(programId, "glLinkProgram") < 0)\n return -1;\n \/\/don't need shaders any longer - detach and delete them\n glDetachShader(programId, vertexShaderId);\n glDetachShader(programId, fragmentShaderId);\n glDeleteShader(vertexShaderId);\n glDeleteShader(fragmentShaderId);\n \/\/mylog("linking program\\n%s\\n", definesString.c_str());\n return programId;\n}\nint Shader::compileShaderWithDefines(std::string definesString, char* shaderSource, GLenum shaderType) {\n int shaderId = glCreateShader(shaderType);\n if (definesString.empty())\n glShaderSource(shaderId, 1, (const GLchar**)&shaderSource, NULL);\n else { \/\/2 strings\n const char* sourceStrings[2];\n sourceStrings[0] = definesString.c_str();\n sourceStrings[1] = shaderSource;\n \/\/ source code loaded, compile\n glShaderSource(shaderId, 2, (const GLchar**)sourceStrings, NULL);\n }\n \/\/myglErrorCheck("glShaderSource");\n glCompileShader(shaderId);\n if (shaderErrorCheck(shaderId, "glCompileShader") < 0) {\n mylog("ERROR in compileShader,\\n%s\\n%s\\n", definesString.c_str(), shaderSource);\n return -1;\n }\n return shaderId;\n}\n\nint Shader::loadShadersGroup(std::string shaderType, std::string optionsString, char* sourceVertex, char* sourceFragment) {\n struct Terms {\n std::vector<std::string> terms;\n int totalN = 0;\n int currentN = 0;\n };\n std::vector<Terms*> terms;\n std::vector<std::string> termGroups = splitString(optionsString, ";");\n int groupsN = termGroups.size();\n for (int groupN = 0; groupN < groupsN; groupN++) {\n Terms* pTerms = new Terms();\n terms.push_back(pTerms);\n pTerms->terms = splitString(termGroups.at(groupN), "|");\n pTerms->totalN = pTerms->terms.size();\n }\n while (1) {\n std::string definesString = "";\n for (int groupN = 0; groupN < groupsN; groupN++) {\n Terms* pTerms = terms.at(groupN);\n std::string term = pTerms->terms.at(pTerms->currentN);\n if (term.compare("NONE") != 0) {\n definesString.append("#define ");\n definesString.append(term);\n definesString.append("\\n");\n }\n }\n int shaderObjN = buildShaderObjectWithDefines(shaderType, definesString, sourceVertex, sourceFragment);\n \/\/go to next terms combo\n bool noMoreOptions = false;\n for (int groupN = groupsN - 1; groupN >= 0; groupN--) {\n Terms* pTerms = terms.at(groupN);\n if (pTerms->currentN < pTerms->totalN - 1) {\n pTerms->currentN++;\n break;\n }\n else { \/\/ the level exhausted\n pTerms->currentN = 0;\n \/\/proceed to upper level\n if (groupN == 0) {\n noMoreOptions = true;\n break;\n }\n }\n }\n if (noMoreOptions)\n break;\n }\n return 1;\n}\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\n\n\n\n\u0412 VBO \u0434\u043b\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u0441 \u043a\u0430\u0440\u0442\u0430\u043c\u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u0435\u0439 \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0441\u0447\u0438\u0442\u0430\u0442\u044c Tangent Space<\/strong> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u0435\u0440\u0442\u0435\u043a\u0441\u0430.<\/p>\n\n\n\n6. \u0417\u0430\u043c\u0435\u043d\u0438\u043c ModelBuilder1base.h<\/em> \u043a\u043e\u0434 \u043d\u0430: <\/p>\n\n\n\n#pragma once\n#include <string>\n#include <vector>\n#include "Vertex01.h"\n#include "Triangle01.h"\n#include "VirtualShape.h"\n#include "Group01.h"\n#include "Material.h"\n#include "GameSubj.h"\n#include <map>\n\nclass ModelBuilder1base\n{\npublic:\n\tstd::vector<Vertex01*> vertices;\n\tstd::vector<Triangle01*> triangles;\n\tstd::vector<int> subjNumbersList;\n\tint usingSubjN = -1;\n\n\tstd::vector<Group01*> groupsStack;\n\tGroup01* pCurrentGroup = NULL;\n\tGroup01* pLastClosedGroup = NULL;\n\t\n\tstd::vector<VirtualShape*> vShapesStack;\n\tVirtualShape* pCurrentVShape = NULL;\n\n\tstd::vector<Material*> materialsList;\n\tint usingMaterialN = -1;\n\tstd::vector<int> materialsStack;\n\n\tstd::map<std::string, int> texturesHashMap;\npublic:\n\tvirtual ~ModelBuilder1base();\n\tint useSubjN(int subjN) { return useSubjN(this, subjN); };\n\tstatic int useSubjN(ModelBuilder1base* pMB, int subjN);\n\tint useMaterial(Material* pMT) { return useMaterial(this, pMT); };\n\tstatic int useMaterial(ModelBuilder1base* pMB, Material* pMT);\n\tstatic void lockGroup(ModelBuilder1base* pMB);\n\tstatic void releaseGroup(ModelBuilder1base* pMB);\n\tstatic int addVertex(ModelBuilder1base* pMB, float kx, float ky, float kz, float nx, float ny, float nz);\n\tstatic int add2triangles(ModelBuilder1base* pMB, int nNW, int nNE, int nSW, int nSE, int n);\n\tstatic int addTriangle(ModelBuilder1base* pMB, int n0, int n1, int n2);\n\tint buildDrawJobs(std::vector<GameSubj*> gameSubjs) { return buildDrawJobs(this, gameSubjs); };\n\tstatic int buildDrawJobs(ModelBuilder1base* pMB, std::vector<GameSubj*> gameSubjs);\n\tstatic int rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector<Vertex01*> allVertices, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);\n\tstatic int buildSingleDrawJob(Material* pMT, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);\n\tstatic int moveGroupDg(ModelBuilder1base* pMB, float aX, float aY, float aZ, float kX, float kY, float kZ);\n\tstatic int calculateTangentSpace(std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles);\n};\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\n\n\n\n7. \u0417\u0430\u043c\u0435\u043d\u0438\u043c ModelBuilder1base.cpp<\/em> \u043a\u043e\u0434 \u043d\u0430: <\/p>\n\n\n\n#include "ModelBuilder1base.h"\n#include "platform.h"\n#include "utils.h"\n#include "DrawJob.h"\n#include "Shader.h"\n\nextern float degrees2radians;\n\nModelBuilder1base::~ModelBuilder1base() {\n\t\/\/clear all vectors\n\tint itemsN = vertices.size();\n\tfor (int i = 0; i < itemsN; i++)\n\t\tdelete vertices.at(i);\n\tvertices.clear();\n\n\titemsN = triangles.size();\n\tfor (int i = 0; i < itemsN; i++)\n\t\tdelete triangles.at(i);\n\ttriangles.clear();\n\n\titemsN = vShapesStack.size();\n\tfor (int i = 0; i < itemsN; i++)\n\t\tdelete vShapesStack.at(i);\n\tvShapesStack.clear();\n\n\titemsN = groupsStack.size();\n\tfor (int i = 0; i < itemsN; i++)\n\t\tdelete groupsStack.at(i);\n\tgroupsStack.clear();\n\n\titemsN = materialsList.size();\n\tfor (int i = 0; i < 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->usingSubjN = subjN;\n\tint itemsN = pMB->subjNumbersList.size();\n\tbool newN = true;\n\tif (itemsN > 0)\n\t\tfor (int i = 0; i < itemsN; i++)\n\t\t\tif (pMB->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->subjNumbersList.push_back(subjN);\n\treturn subjN;\n}\nint ModelBuilder1base::useMaterial(ModelBuilder1base* pMB, Material* pMT) {\n\tint itemsN = pMB->materialsList.size();\n\tif (itemsN > 0)\n\t\tfor (int i = 0; i < itemsN; i++)\n\t\t\tif (memcmp(pMB->materialsList.at(i), pMT, sizeof(Material)) == 0) {\n\t\t\t\tpMB->usingMaterialN = i;\n\t\t\t\treturn i;\n\t\t\t}\n\t\/\/if here - add new material to the list\n\tpMB->usingMaterialN = itemsN;\n\t\/\/create a copy of new Material and add to the list\n\tMaterial* pMTnew = new Material(*pMT);\n\tpMB->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->triangles.size() - 1;\n}\nint ModelBuilder1base::addTriangle(ModelBuilder1base* pMB, int i0, int i1, int i2) {\n\tTriangle01* pTR = new Triangle01();\n\tpMB->triangles.push_back(pTR);\n\tpTR->idx[0] = i0;\n\tpTR->idx[1] = i1;\n\tpTR->idx[2] = i2;\n\tpTR->subjN = pMB->usingSubjN;\n\tpTR->materialN = pMB->usingMaterialN;\n\treturn pMB->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->vertices.push_back(pVX);\n\tpVX->aPos[0] = kx;\n\tpVX->aPos[1] = ky;\n\tpVX->aPos[2] = kz;\n\t\/\/normal\n\tpVX->aNormal[0] = nx;\n\tpVX->aNormal[1] = ny;\n\tpVX->aNormal[2] = nz;\n\tpVX->subjN = pMB->usingSubjN;\n\tpVX->materialN = pMB->usingMaterialN;\n\treturn pMB->vertices.size() - 1;\n}\nint ModelBuilder1base::buildDrawJobs(ModelBuilder1base* pMB, std::vector<GameSubj*> gameSubjs) {\n\tint totalSubjsN = pMB->subjNumbersList.size();\n\tif (totalSubjsN < 1) {\n\t\tpMB->subjNumbersList.push_back(-1);\n\t\ttotalSubjsN = 1;\n\t}\n\tint totalMaterialsN = pMB->materialsList.size();\n\tif (totalSubjsN < 2 && totalMaterialsN < 2) {\n\t\t\/\/simple single DrawJob\n\t\tMaterial* pMT = pMB->materialsList.at(0);\n\t\tGameSubj* pGS = NULL;\n\t\tint gsN = pMB->subjNumbersList.at(0);\n\t\tif (gsN >= 0)\n\t\t\tpGS = gameSubjs.at(gsN);\n\t\tif (pGS != NULL)\n\t\t\tpGS->djStartN = DrawJob::drawJobs.size();\n\t\tbuildSingleDrawJob(pMT, pMB->vertices, pMB->triangles);\n\t\tif (pGS != NULL)\n\t\t\tpGS->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;\n\t\treturn 1;\n\t}\n\tint totalVertsN = pMB->vertices.size();\n\tint totalTrianglesN = pMB->triangles.size();\n\t\/\/clear flags\n\tfor (int vN = 0; vN < totalVertsN; vN++) {\n\t\tVertex01* pVX = pMB->vertices.at(vN);\n\t\tpVX->flag = 0;\n\t}\n\tfor (int tN = 0; tN < totalTrianglesN; tN++) {\n\t\tTriangle01* pTR = pMB->triangles.at(tN);\n\t\tpTR->flag = 0;\n\t}\n\tint addedDJs = 0;\n\tfor (int sN = 0; sN < totalSubjsN; sN++) {\n\t\tGameSubj* pGS = NULL;\n\t\tint gsN = pMB->subjNumbersList.at(sN);\n\t\tif (gsN >= 0)\n\t\t\tpGS = gameSubjs.at(gsN);\n\t\tif (pGS != NULL)\n\t\t\tpGS->djStartN = DrawJob::drawJobs.size();\n\t\tfor (int mtN = 0; mtN < totalMaterialsN; mtN++) {\n\t\t\tMaterial* pMT = pMB->materialsList.at(mtN);\n\t\t\tstd::vector<Vertex01*> useVertices;\n\t\t\tstd::vector<Triangle01*> useTriangles;\n\t\t\tfor (int vN = 0; vN < totalVertsN; vN++) {\n\t\t\t\tVertex01* pVX = pMB->vertices.at(vN);\n\t\t\t\tif (pVX->flag != 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pVX->subjN != gsN)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pVX->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->altN = vN;\n\t\t\t\tpVX->flag = 1;\n\t\t\t\tif (pVX->endOfSequence > 0) {\n\t\t\t\t\trearrangeArraysForDrawJob(pMB, pMB->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 < 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 < 1)\n\t\t\t\tcontinue; \/\/to next material\n\t\t\t\/\/pick triangles\n\t\t\tfor (int tN = 0; tN < totalTrianglesN; tN++) {\n\t\t\t\tTriangle01* pTR = pMB->triangles.at(tN);\n\t\t\t\tif (pTR->flag != 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pTR->subjN != gsN)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (pTR->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->flag = 1;\n\t\t\t}\n\t\t\trearrangeArraysForDrawJob(pMB, pMB->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 < 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 < 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->djTotalN = DrawJob::drawJobs.size() - pGS->djStartN;\n\t}\n\treturn addedDJs;\n}\n\nint ModelBuilder1base::buildSingleDrawJob(Material* pMT, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {\n\tint totalVertsN = useVertices.size();\n\tif (totalVertsN < 1)\n\t\treturn 0;\n\tif (pMT->uTex2nm >= 0)\n\t\tcalculateTangentSpace(useVertices, useTriangles);\n\tpMT->pickShaderNumber();\n\tDrawJob* pDJ = new DrawJob();\n\t\/\/copy material to DJ\n\tmemcpy(&pDJ->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->setDesirableOffsets(&stride, pDJ->mt.shaderN, VBOid);\n\t\/\/create an array for VBO\n\tint bufferSize = totalVertsN * stride;\n\tfloat* vertsBuffer = new float[bufferSize];\n\t\/\/fill vertsBuffer\n\tShader* pSh = Shader::shaders.at(pDJ->mt.shaderN);\n\tint floatSize = sizeof(float);\n\tfor (int vN = 0; vN < 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(&vertsBuffer[idx + pDJ->aPos.offset \/ floatSize], pVX->aPos, 3 * floatSize);\n\t\tif (pSh->l_aNormal >= 0) \/\/normal\n\t\t\tmemcpy(&vertsBuffer[idx + pDJ->aNormal.offset \/ floatSize], pVX->aNormal, 3 * floatSize);\n\t\tif (pSh->l_aTuv >= 0) \/\/attribute TUV (texture coordinates)\n\t\t\tmemcpy(&vertsBuffer[idx + pDJ->aTuv.offset \/ floatSize], pVX->aTuv, 2 * floatSize);\n\t\tif (pSh->l_aTuv2 >= 0) \/\/attribute TUV2 (normal maps)\n\t\t\tmemcpy(&vertsBuffer[idx + pDJ->aTuv2.offset \/ floatSize], pVX->aTuv2, 2 * floatSize);\n\t\tif (pSh->l_aTangent >= 0)\n\t\t\tmemcpy(&vertsBuffer[idx + pDJ->aTangent.offset \/ floatSize], pVX->aTangent, 3 * floatSize);\n\t\tif (pSh->l_aBinormal >= 0)\n\t\t\tmemcpy(&vertsBuffer[idx + pDJ->aBinormal.offset \/ floatSize], pVX->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[] vertsBuffer;\n\tpDJ->pointsN = totalVertsN;\n\n\tint totalTrianglesN = useTriangles.size();\n\tif (totalTrianglesN > 0) {\n\t\t\/\/create EBO\n\t\tint totalIndexesN = totalTrianglesN * 3;\n\t\t\/\/create buffer\n\t\tGLushort* indexBuffer = new GLushort[totalIndexesN];\n\t\tfor (int tN = 0; tN < totalTrianglesN; tN++) {\n\t\t\tTriangle01* pTR = useTriangles[tN];\n\t\t\tint idx = tN * 3;\n\t\t\tindexBuffer[idx] = (GLushort)pTR->idx[0];\n\t\t\tindexBuffer[idx + 1] = (GLushort)pTR->idx[1];\n\t\t\tindexBuffer[idx + 2] = (GLushort)pTR->idx[2];\n\t\t}\n\t\t\/\/buffer is ready, create IBO\n\t\tpDJ->glEBOid = DrawJob::newBufferId();\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pDJ->glEBOid);\n\t\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndexesN * sizeof(GLushort), indexBuffer, GL_STATIC_DRAW);\n\t\tdelete[] indexBuffer;\n\t\tpDJ->pointsN = totalIndexesN;\n\t}\n\t\/\/create and fill vertex attributes array (VAO)\n\tpDJ->buildVAO();\n\treturn 1;\n}\n\nint ModelBuilder1base::rearrangeArraysForDrawJob(ModelBuilder1base* pMB, std::vector<Vertex01*> allVertices, std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {\n\tint totalTrianglesN = useTriangles.size();\n\tif (totalTrianglesN < 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 < totalVerticesN; i++) {\n\t\tVertex01* pVX1 = useVertices.at(i);\n\t\tVertex01* pVX0 = allVertices.at(pVX1->altN);\n\t\tpVX0->altN = i;\n\t}\n\t\/\/replace triangle original indices by new numbers saved in original vertices altN\n\tfor (int tN = 0; tN < totalTrianglesN; tN++) {\n\t\tTriangle01* pTR = useTriangles.at(tN);\n\t\tfor (int i = 0; i < 3; i++) {\n\t\t\tVertex01* pVX0 = allVertices.at(pTR->idx[i]);\n\t\t\tpTR->idx[i] = pVX0->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->vertices.size();\n\tfor (int i = pMB->pCurrentGroup->fromVertexN; i < vertsN; i++) {\n\t\tVertex01* pVX = pMB->vertices.at(i);\n\t\tmat4x4_mul_vec4plus(pVX->aPos, transformMatrix, pVX->aPos, 1);\n\t\tmat4x4_mul_vec4plus(pVX->aNormal, transformMatrix, pVX->aNormal, 0);\n\t}\n\treturn 1;\n}\n\nvoid ModelBuilder1base::lockGroup(ModelBuilder1base* pMB) {\n\tif (pMB->pCurrentGroup != NULL)\n\t\tpMB->groupsStack.push_back(pMB->pCurrentGroup);\n\tpMB->pCurrentGroup = new Group01();\n\tpMB->pCurrentGroup->fromVertexN = pMB->vertices.size();\n\tpMB->pCurrentGroup->fromTriangleN = pMB->triangles.size();\n}\nvoid ModelBuilder1base::releaseGroup(ModelBuilder1base* pMB) {\n\tif (pMB->pLastClosedGroup != NULL)\n\t\tdelete pMB->pLastClosedGroup;\n\tpMB->pLastClosedGroup = pMB->pCurrentGroup;\n\n\tif (pMB->groupsStack.size() > 0) {\n\t\tpMB->pCurrentGroup = pMB->groupsStack.back();\n\t\tpMB->groupsStack.pop_back();\n\t}\n\telse\n\t\tpMB->pCurrentGroup = NULL;\n}\nint ModelBuilder1base::calculateTangentSpace(std::vector<Vertex01*> useVertices, std::vector<Triangle01*> useTriangles) {\n\tint totalVertsN = useVertices.size();\n\tif (totalVertsN < 1)\n\t\treturn 0;\n\tint totalTrianglesN = useTriangles.size();\n\t\/\/assuming that GL_TRIANGLES\n\t\/\/clear flags\n\tfor (int vN = 0; vN < totalVertsN; vN++) {\n\t\tVertex01* pV = useVertices.at(vN);\n\t\tpV->flag = 0;\n\t}\n\tfor (int vN = 0; vN < totalVertsN; vN++) {\n\t\tVertex01* pVX = useVertices.at(vN);\n\t\tif (pVX->flag != 0)\n\t\t\tcontinue;\n\t\tTriangle01* pT = NULL;\n\t\tfor (int tN = 0; tN < totalTrianglesN; tN++) {\n\t\t\tpT = useTriangles.at(tN);\n\t\t\tbool haveTriangle = false;\n\t\t\tfor (int i = 0; i < 3; i++)\n\t\t\t\tif (pT->idx[i] == vN) {\n\t\t\t\t\thaveTriangle = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (haveTriangle)\n\t\t\t\tbreak;\n\t\t}\n\t\tVertex01* pV[3];\n\t\tfor (int i = 0; i < 3; i++)\n\t\t\tpV[i] = useVertices.at(pT->idx[i]);\n\n\t\tfloat dPos1[3];\n\t\tfloat dPos2[3];\n\t\tfloat dUV1[2];\n\t\tfloat dUV2[2];\n\t\tfor (int i = 0; i < 3; i++) {\n\t\t\tdPos1[i] = pV[1]->aPos[i] - pV[0]->aPos[i];\n\t\t\tdPos2[i] = pV[2]->aPos[i] - pV[0]->aPos[i];\n\t\t}\n\t\tfor (int i = 0; i < 2; i++) {\n\t\t\tdUV1[i] = pV[1]->aTuv2[i] - pV[0]->aTuv2[i];\n\t\t\tdUV2[i] = pV[2]->aTuv2[i] - pV[0]->aTuv2[i];\n\t\t}\n\n\t\tfloat tangent[3];\n\t\tfloat binormal[3];\n\t\tfloat divider = dUV1[0] * dUV2[1] - dUV1[1] * dUV2[0];\n\t\tif (divider == 0) {\n\t\t\tv3set(tangent, 1, 0, 0);\n\t\t\tv3set(binormal, 0, -1, 0);\n\t\t}\n\t\telse {\n\t\t\tfloat r = 1.0f \/ divider;\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\ttangent[i] = (dPos1[i] * dUV2[1] - dPos2[i] * dUV1[1]) * r;\n\t\t\t\tbinormal[i] = -(dPos2[i] * dUV1[0] - dPos1[i] * dUV2[0]) * r;\n\t\t\t}\n\t\t\tvec3_norm(tangent, tangent);\n\t\t\tvec3_norm(binormal, binormal);\n\t\t}\n\t\t\/\/add to all 3 vertices\n\t\tfor (int n = 0; n < 3; n++) {\n\t\t\tif (pV[n]->flag > 0)\n\t\t\t\tcontinue;\n\t\t\tv3copy(pV[n]->aTangent, tangent);\n\t\t\tv3copy(pV[n]->aBinormal, binormal);\n\t\t\tpV[n]->flag = 1;\n\t\t}\n\t}\n\t\/\/normalize tangent and binormal around normal\n\tfor (int vN = 0; vN < totalVertsN; vN++) {\n\t\tVertex01* pV = useVertices.at(vN);\n\t\tfloat v3out[3];\n\t\t\/\/tangent\n\t\tvec3_mul_cross(v3out, pV->aNormal, pV->aBinormal);\n\t\tif (v3dotProduct(pV->aTangent, v3out) < 0)\n\t\t\tv3inverse(v3out);\n\t\tv3copy(pV->aTangent, v3out);\n\t\t\/\/binormal\n\t\tvec3_mul_cross(v3out, pV->aNormal, pV->aTangent);\n\t\tif (v3dotProduct(pV->aBinormal, v3out) < 0)\n\t\t\tv3inverse(v3out);\n\t\tv3copy(pV->aBinormal, v3out);\n\t}\n\treturn 1;\n}\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
- \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 buildSingleDrawJob(..)<\/em>, \u0435\u0441\u043b\u0438 normal map \u0437\u0430\u0434\u0430\u043d\u0430 (pMT->uTex2nm >= 0<\/em>), \u0442\u043e\u0433\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c calculateTangentSpace(..)<\/em><\/li><\/ul>\n\n\n\n
\n\n\n\n <\/p>\n\n\n\n
\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f calculateTangentSpace(..)<\/em> \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 v3inverse(..)<\/em> \u0438 v3dotProduct(..)<\/em><\/p>\n\n\n\n8. \u0417\u0430\u043c\u0435\u043d\u0438\u043c utils.h<\/em> \u043a\u043e\u0434 \u043d\u0430: <\/p>\n\n\n\n#pragma once\n#include <string>\n#include <vector>\n#include "linmath.h"\n\nint checkGLerrors(std::string ref);\nvoid mat4x4_mul_vec4plus(vec4 vOut, mat4x4 M, vec4 vIn, int v3);\n\nvoid v3set(float* vOut, float x, float y, float z);\nvoid v3copy(float* vOut, float* vIn);\nfloat v3pitchRd(float* vIn);\nfloat v3yawRd(float* vIn);\nfloat v3pitchDg(float* vIn);\nfloat v3yawDg(float* vIn);\n\nfloat v3dotProduct(float* a0, float* b0);\nfloat v3dotProductNorm(float* a, float* b);\nvoid v3inverse(float inV[]);\nvoid v3inverse(float outV[], float inV[]);\nfloat v3length(float* v);\nfloat v3lengthXZ(float v[]);\nfloat v3lengthXY(float v[]);\nbool v3equals(float v[], float x);\nbool v3match(float v0[], float v1[]);\nvoid v3fromTo(float* v, float* v0, float* v1);\nfloat v3lengthFromTo(float* v0, float* v1);\nvoid v3dirFromTo(float* v, float* v0, float* v1);\n\nlong long int getSystemMillis();\nlong long int getSystemNanos();\n\nint getRandom(int fromN, int toN);\nfloat getRandom(float fromN, float toN);\nstd::vector<std::string> splitString(std::string inString, std::string delimiter);\nstd::string trimString(std::string inString);\nbool fileExists(const char* filePath);\nstd::string getFullPath(std::string filePath);\nstd::string getInAppPath(std::string filePath);\nint makeDirs(std::string filePath);\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
- \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435<\/li><\/ul>\n\n\n\n
\n\n\n\n9. \u0417\u0430\u043c\u0435\u043d\u0438\u043c utils.cpp<\/em> \u043a\u043e\u0434 \u043d\u0430:<\/p>\n\n\n\n#include "utils.h"\n#include "platform.h"\n#include <chrono>\n#include <stdlib.h> \/* srand, rand *\/\n#include <sys\/stat.h> \/\/if fileExists\n#include <time.h> \/\/for srand()\n\nextern std::string filesRoot;\nextern float radians2degrees;\n\nint checkGLerrors(std::string ref) {\n \/\/can be used after any GL call\n int res = glGetError();\n if (res == 0)\n return 0;\n std::string errCode;\n switch (res) {\n \/\/case GL_NO_ERROR: errCode = "GL_NO_ERROR"; break;\n case GL_INVALID_ENUM: errCode = "GL_INVALID_ENUM"; break;\n case GL_INVALID_VALUE: errCode = "GL_INVALID_VALUE"; break;\n case GL_INVALID_OPERATION: errCode = "GL_INVALID_OPERATION"; break;\n case GL_INVALID_FRAMEBUFFER_OPERATION: errCode = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;\n case GL_OUT_OF_MEMORY: errCode = "GL_OUT_OF_MEMORY"; break;\n default: errCode = "??"; break;\n }\n mylog("GL ERROR %d-%s in %s\\n", res, errCode.c_str(), ref.c_str());\n return -1;\n}\nvoid mat4x4_mul_vec4plus(vec4 vOut, mat4x4 M, vec4 vIn, int v3) {\n vec4 v2;\n if (vOut == vIn) {\n memcpy(&v2, vIn, sizeof(vec4));\n vIn = v2;\n }\n vIn[3] = (float)v3;\n mat4x4_mul_vec4(vOut, M, vIn);\n}\nvoid v3set(float* vOut, float x, float y, float z) {\n vOut[0] = x;\n vOut[1] = y;\n vOut[2] = z;\n}\nvoid v3copy(float* vOut, float* vIn) {\n for (int i = 0; i < 3; i++)\n vOut[i] = vIn[i];\n}\nfloat v3yawRd(float* vIn) {\n return atan2f(vIn[0], vIn[2]);\n}\nfloat v3pitchRd(float* vIn) {\n return -atan2f(vIn[1], sqrtf(vIn[0] * vIn[0] + vIn[2] * vIn[2]));\n}\nfloat v3pitchDg(float* vIn) { \n return v3pitchRd(vIn) * radians2degrees; \n}\nfloat v3yawDg(float* vIn) { \n return v3yawRd(vIn) * radians2degrees; \n}\n\nlong long int getSystemMillis() {\n auto currentTime = std::chrono::system_clock::now().time_since_epoch();\n return std::chrono::duration_cast<std::chrono::milliseconds>(currentTime).count();\n}\nlong long int getSystemNanos() {\n auto currentTime = std::chrono::system_clock::now().time_since_epoch();\n return std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime).count();\n}\nint randomCallN = 0;\nint getRandom() {\n if (randomCallN % 1000 == 0)\n srand((unsigned int)getSystemNanos()); \/\/re-initialize random seed:\n randomCallN++;\n return rand();\n}\nint getRandom(int fromN, int toN) {\n int randomN = getRandom();\n int range = toN - fromN + 1;\n return (fromN + randomN % range);\n}\nfloat getRandom(float fromN, float toN) {\n int randomN = getRandom();\n float range = toN - fromN;\n return (fromN + (float)randomN \/ RAND_MAX * range);\n}\nstd::vector<std::string> splitString(std::string inString, std::string delimiter) {\n std::vector<std::string> outStrings;\n int delimiterSize = delimiter.size();\n outStrings.clear();\n while (inString.size() > 0) {\n int delimiterPosition = inString.find(delimiter);\n if (delimiterPosition == 0) {\n inString = inString.substr(delimiterSize, inString.size() - delimiterSize);\n continue;\n }\n if (delimiterPosition == std::string::npos) {\n \/\/last element\n outStrings.push_back(trimString(inString));\n break;\n }\n std::string outString = inString.substr(0, delimiterPosition);\n outStrings.push_back(trimString(outString));\n int startAt = delimiterPosition + delimiterSize;\n inString = inString.substr(startAt, inString.size() - startAt);\n }\n return outStrings;\n}\nstd::string trimString(std::string inString) {\n \/\/Remove leading and trailing spaces\n int startsAt = inString.find_first_not_of(" ");\n if (startsAt == std::string::npos)\n return "";\n int endsAt = inString.find_last_not_of(" ") + 1;\n return inString.substr(startsAt, endsAt - startsAt);\n}\nbool fileExists(const char* filePath) {\n struct stat info;\n if (stat(filePath, &info) == 0)\n return true;\n else\n return false;\n}\nstd::string getFullPath(std::string filePath) {\n if (filePath.find(filesRoot) == 0)\n return filePath;\n else\n return (filesRoot + filePath);\n}\nstd::string getInAppPath(std::string filePath) {\n std::string inAppPath(filePath);\n if (inAppPath.find(filesRoot) == 0) {\n int startsAt = filesRoot.size();\n inAppPath = inAppPath.substr(startsAt, inAppPath.size() - startsAt);\n }\n if (inAppPath.find(".") != std::string::npos) {\n \/\/cut off file name\n int endsAt = inAppPath.find_last_of("\/");\n inAppPath = inAppPath.substr(0, endsAt + 1);\n }\n return inAppPath;\n}\nint makeDirs(std::string filePath) {\n filePath = getFullPath(filePath);\n std::string inAppPath = getInAppPath(filePath);\n std::vector<std::string> path = splitString(inAppPath, "\/");\n int pathSize = path.size();\n filePath.assign(filesRoot);\n for (int i = 0; i < pathSize; i++) {\n filePath.append("\/" + path.at(i));\n if (fileExists(filePath.c_str())) {\n continue;\n }\n \/\/create dir\n myMkDir(filePath.c_str());\n mylog("Folder %d: %s created.\\n", i, filePath.c_str());\n }\n return 1;\n}\nvoid v3inverse(float inV[]) {\n return v3inverse(inV, inV);\n}\nvoid v3inverse(float outV[], float inV[]) {\n for (int i = 0; i < 3; i++)\n outV[i] = -inV[i];\n return;\n}\n\nfloat v3dotProduct(float* a0, float* b0) {\n float a[3];\n float b[3];\n vec3_norm(a, a0);\n vec3_norm(b, b0);\n return v3dotProductNorm(a, b);\n}\nfloat v3dotProductNorm(float* a, float* b) {\n \/\/assuming that vectors are normalized\n float dp = 0.0f;\n for (int i = 0; i < 3; i++)\n dp += a[i] * b[i];\n return dp;\n}\nfloat v3length(float* v) {\n float r = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];\n if (r == 0)\n return 0;\n return sqrtf(r);\n}\nfloat v3lengthXZ(float v[]) {\n float r = v[0] * v[0] + v[2] * v[2];\n if (r == 0)\n return 0;\n return sqrtf(r);\n}\nfloat v3lengthXY(float v[]) {\n float r = v[0] * v[0] + v[1] * v[1];\n if (r == 0)\n return 0;\n return sqrtf(r);\n}\nbool v3equals(float v[],float x) {\n for (int i = 0; i < 3; i++)\n if (v[i] != x)\n return false;\n return true;\n}\nbool v3match(float v0[], float v1[]) {\n for (int i = 0; i < 3; i++)\n if (v0[i] != v1[i])\n return false;\n return true;\n}\nvoid v3fromTo(float* v, float* v0, float* v1) {\n for (int i = 0; i < 3; i++)\n v[i] = v1[i] - v0[i];\n}\nfloat v3lengthFromTo(float* v0, float* v1) {\n float v[3];\n v3fromTo(v, v0, v1);\n float r = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];\n if (r == 0)\n return 0;\n return sqrtf(r);\n}\nvoid v3dirFromTo(float* v, float* v0, float* v1) {\n v3fromTo(v, v0, v1);\n vec3_norm(v,v);\n}\n\n<\/pre><\/div>\n\n\n<\/p>\n\n\n\n
\n\n\n\n10. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a.<\/p>\n\n\n\n
\u0414\u043e<\/strong>:<\/p>\n\n\n\n
<\/p>\n\n\n\n
<\/p>\n\n\n\n
\u041f\u043e\u0441\u043b\u0435<\/strong>:<\/p>\n\n\n\n
<\/p>\n\n\n\n
<\/p>\n\n\n\n