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

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

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

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

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

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

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

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

Warning: Cannot modify header information - headers already sent by (output started at /home/ruwritingagame/public_html/wp-includes/functions.php:6131) in /home/ruwritingagame/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1902
{"id":744,"date":"2021-12-08T22:45:37","date_gmt":"2021-12-08T22:45:37","guid":{"rendered":"https:\/\/writingagame.com\/?p=744"},"modified":"2022-02-03T18:50:30","modified_gmt":"2022-02-03T18:50:30","slug":"chapter-24-synchronization","status":"publish","type":"post","link":"https:\/\/writingagame.ru\/index.php\/2021\/12\/08\/chapter-24-synchronization\/","title":{"rendered":"\u0413\u043b\u0430\u0432\u0430 24. \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f"},"content":{"rendered":"\n

\u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430 \u043e\u0431\u043e\u0438\u0445 \u043c\u043e\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445 (Android \u0438 PC) \u043a\u0443\u0431\u0438\u043a \u0434\u0435\u043b\u0430\u0435\u0442 1 \u043e\u0431\u043e\u0440\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 4 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u042d\u0442\u043e 360 \u043a\u0430\u0434\u0440\u043e\u0432 (\u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441 \u0437\u0430 \u043a\u0430\u0434\u0440). \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 360\/4=90 \u043a\u0430\u0434\u0440\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 (frames per second, FPS). \u041f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u044d\u0442\u0430 \u0446\u0438\u0444\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0430 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043c\u043e\u0433\u0443\u0442 \u0432\u043b\u0438\u044f\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0444\u0430\u043a\u0442\u043e\u0440\u044b. \u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438 \u0447\u0435\u0433\u043e \u043c\u044b \u0440\u0435\u043d\u0434\u0440\u0438\u043c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u043e\u0442\u043d\u043e \u0437\u0430\u043d\u044f\u0442 \u043d\u0430\u0448 \u044d\u043a\u0440\u0430\u043d.<\/p>\n\n\n\n

\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0443\u0436\u043d\u0430 \u0447\u0442\u043e\u0431\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u044c FPS \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0439 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0439. \u0412\u044b\u0448\u0435 FPS – \u043c\u044f\u0433\u0447\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f. \u041d\u0438\u0436\u0435 FPS – \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0440\u0438\u043d\u0433.<\/p>\n\n\n\n

“\u0417\u043e\u043b\u043e\u0442\u0430\u044f \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0430” – 30 FPS. \u041d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439, 24 (\u043a\u0430\u043a \u0432\u043f\u043e\u043b\u043d\u0435 \u043a\u043e\u043c\u0444\u043e\u0440\u0442\u043d\u043e\u0435) \u0431\u044b\u043b\u043e \u043a\u0438\u043d\u043e-\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c \u0446\u0435\u043b\u044b\u0439 \u0432\u0435\u043a.<\/p>\n\n\n\n

1000\/30 \u0434\u0430\u0435\u0442 \u043d\u0430\u043c 33 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043d\u0430 \u0440\u0435\u043d\u0434\u0440\u0438\u043d\u0433 \u043a\u0430\u0434\u0440\u0430. \u041d\u0435 \u0442\u0430\u043a \u0447\u0442\u043e\u0431 \u043c\u043d\u043e\u0433\u043e (\u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e \u043a\u0430\u0434\u0440\u0430), \u043d\u043e \u043c\u044b \u043f\u043e\u0441\u0442\u0432\u0440\u0430\u0435\u043c\u0441\u044f \u0432\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f.<\/p>\n\n\n\n

\u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/strong>:<\/p>\n\n\n\n

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


\n\n\n\n

\u0412 TheGame.cpp<\/em>, \u043a\u043e\u0433\u0434\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u043a\u0430\u0434\u0440 \u0433\u043e\u0442\u043e\u0432, \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u0432\u044b\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u044d\u043a\u0440\u0430\u043d, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0438 \u0436\u0434\u0430\u0442\u044c \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 33 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043a\u0430\u0434\u0440\u0430.<\/p>\n\n\n\n

\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f<\/p>\n\n\n\n

\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0432 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445.<\/h2>\n\n\n\n

MS \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u0432\u043e\u044e \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0432\u0435\u0449\u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 chrono<\/em> – \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0435 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n\n\n

\n    auto currentTime = std::chrono::system_clock::now().time_since_epoch();\n    return std::chrono::duration_cast<std::chrono::milliseconds>(currentTime).count();\n<\/pre><\/div>\n\n\n


\u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 TheGame<\/em> \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445.<\/p>\n\n\n\n

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

\n#pragma once\n#include <vector>\n#include "GameSubj.h"\n#include "Camera.h"\n\nclass TheGame\n{\npublic:\n\tint screenSize[2];\n\tfloat screenAspectRatio = 1;\n\t\/\/synchronization\n\tlong long int lastFrameMillis = 0;\n\tint targetFPS = 30;\n\tint millisPerFrame = 1000 \/ targetFPS;\n\n\tbool bExitGame;\n\tCamera mainCamera;\n\tfloat dirToMainLight[4] = { 1,1,1,0 };\n\n\t\/\/static arrays (vectors) of active GameSubjs\n\tstatic std::vector<GameSubj*> gameSubjs;\npublic:\n\tint run();\n\tint getReady();\n\tint drawFrame();\n\tint cleanUp();\n\tint onScreenResize(int width, int height);\n};\n\n<\/pre><\/div>\n\n\n

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


\n\n\n\n

3. \u0417\u0430\u043c\u0435\u043d\u0438\u043c TheGame.cpp<\/em> \u043a\u043e\u0434 \u043d\u0430:<\/p>\n\n\n

\n#include "TheGame.h"\n#include "platform.h"\n#include "utils.h"\n#include "linmath.h"\n#include "Texture.h"\n#include "Shader.h"\n#include "DrawJob.h"\n#include "ModelBuilder.h"\n#include "TexCoords.h"\n\nextern std::string filesRoot;\nextern float degrees2radians;\n\nstd::vector<GameSubj*> TheGame::gameSubjs;\n\nint TheGame::getReady() {\n    bExitGame = false;\n    Shader::loadShaders();\n    glEnable(GL_CULL_FACE);\n\n    \/\/=== create box ========================\n    GameSubj* pGS = new GameSubj();\n    gameSubjs.push_back(pGS);\n\n    pGS->name.assign("box1");\n    pGS->ownCoords.setPosition(0, 0, 0);\n    pGS->ownCoords.setDegrees(0, 0, 0);\n    pGS->ownSpeed.setDegrees(0,3,0);\n\n    ModelBuilder* pMB = new ModelBuilder();\n    pMB->useSubjN(gameSubjs.size() - 1);\n\n    \/\/define VirtualShape\n    VirtualShape vs;\n    vs.setShapeType("box-tank");\n    vs.whl[0] = 60;\n    vs.whl[1] = 160;\n    vs.whl[2] = 390;\n    vs.setExt(20);\n    vs.extD = 0;\n    vs.extF = 0; \/\/to make front face "flat"\n    vs.sectionsR = 2;\n\n    Material mt;\n    \/\/define material - flat red\n    mt.shaderN = Shader::spN_phong_ucolor;\n    mt.primitiveType = GL_TRIANGLES;\n    mt.uColor.setRGBA(255, 0, 0,255); \/\/red\n    pMB->useMaterial(&mt);\n\n    pMB->buildBoxFace(pMB,"front v", &vs);\n    pMB->buildBoxFace(pMB, "back v", &vs);\n    pMB->buildBoxFace(pMB, "top", &vs);\n    pMB->buildBoxFace(pMB, "bottom", &vs);\n    pMB->buildBoxFace(pMB, "left all", &vs);\n\n    mt.uColor.clear(); \/\/ set to zero;\n    mt.uTex0 = Texture::loadTexture(filesRoot + "\/dt\/sample_img.png");\n    mt.shaderN = Shader::spN_phong_tex;\n    pMB->useMaterial(&mt);\n    TexCoords tc;\n    tc.set(mt.uTex0, 11, 12, 256, 128, "h"); \/\/flip horizontally\n    pMB->buildBoxFace(pMB, "right all", &vs, &tc);\n\n    pMB->buildDrawJobs(gameSubjs);\n\n    delete pMB;\n\n    \/\/===== set up camera\n    mainCamera.ownCoords.setDegrees(15, 180, 0); \/\/set camera angles\/orientation\n    mainCamera.viewRangeDg = 30;\n    mainCamera.stageSize[0] = 500;\n    mainCamera.stageSize[1] = 375;\n    memcpy(mainCamera.lookAtPoint, pGS->ownCoords.pos, sizeof(float) * 3);\n    mainCamera.onScreenResize();\n\n    \/\/===== set up light\n    v3set(dirToMainLight, -1, 1, 1);\n    vec3_norm(dirToMainLight, dirToMainLight);\n\n    return 1;\n}\nint TheGame::drawFrame() {\n    myPollEvents();\n\n    \/\/glClearColor(0.0, 0.0, 0.5, 1.0);\n    glClear(GL_COLOR_BUFFER_BIT);\n\n    \/\/calculate halfVector\n    float dirToCamera[4] = { 0,0,-1,0 }; \/\/-z\n    mat4x4_mul_vec4plus(dirToCamera, *mainCamera.ownCoords.getRotationMatrix(), dirToCamera, 0);\n\n    float uHalfVector[4] = { 0,0,0,0 };\n    for (int i = 0; i < 3; i++)\n        uHalfVector[i] = (dirToCamera[i] + dirToMainLight[i]) \/ 2;\n    vec3_norm(uHalfVector, uHalfVector);\n\n    mat4x4 mProjection, mViewProjection, mMVP, mMV4x4;\n    \/\/mat4x4_ortho(mProjection, -(float)screenSize[0] \/ 2, (float)screenSize[0] \/ 2, -(float)screenSize[1] \/ 2, (float)screenSize[1] \/ 2, 100.f, 500.f);\n    float nearClip = mainCamera.focusDistance - 250;\n    float farClip = mainCamera.focusDistance + 250;\n    mat4x4_perspective(mProjection, mainCamera.viewRangeDg * degrees2radians, screenAspectRatio, nearClip, farClip);\n    mat4x4_mul(mViewProjection, mProjection, mainCamera.lookAtMatrix);\n    \/\/mViewProjection[1][3] = 0; \/\/keystone effect\n\n    \/\/scan subjects\n    int subjsN = gameSubjs.size();\n    for (int subjN = 0; subjN < subjsN; subjN++) {\n        GameSubj* pGS = gameSubjs.at(subjN);\n        \/\/behavior - apply rotation speed\n        pGS->moveSubj();\n        \/\/prepare subject for rendering\n        pGS->buildModelMatrix(pGS);\n        \/\/build MVP matrix for given subject\n        mat4x4_mul(mMVP, mViewProjection, pGS->ownModelMatrix);\n        \/\/build Model-View (rotation) matrix for normals\n        mat4x4_mul(mMV4x4, mainCamera.lookAtMatrix, (vec4*)pGS->ownCoords.getRotationMatrix());\n        \/\/convert to 3x3 matrix\n        float mMV3x3[3][3];\n        for (int y = 0; y < 3; y++)\n            for (int x = 0; x < 3; x++)\n                mMV3x3[y][x] = mMV4x4[y][x];\n        \/\/render subject\n        for (int i = 0; i < pGS->djTotalN; i++) {\n            DrawJob* pDJ = DrawJob::drawJobs.at(pGS->djStartN + i);\n            pDJ->execute((float*)mMVP, *mMV3x3, dirToMainLight, uHalfVector, NULL);\n        }\n    }\n    \/\/synchronization\n    while (1) {\n        long long int currentMillis = getSystemMillis();\n        long long int millisSinceLastFrame = currentMillis - lastFrameMillis;\n        if (millisSinceLastFrame >= millisPerFrame) {\n            lastFrameMillis = currentMillis;\n            break;\n        }\n    }\n    mySwapBuffers();\n    return 1;\n}\n\nint TheGame::cleanUp() {\n    int itemsN = gameSubjs.size();\n    \/\/delete all UISubjs\n    for (int i = 0; i < itemsN; i++) {\n        GameSubj* pGS = gameSubjs.at(i);\n        delete pGS;\n    }\n    gameSubjs.clear();\n    \/\/clear all other classes\n    Texture::cleanUp();\n    Shader::cleanUp();\n    DrawJob::cleanUp();\n    return 1;\n}\nint TheGame::onScreenResize(int width, int height) {\n    if (screenSize[0] == width && screenSize[1] == height)\n        return 0;\n    screenSize[0] = width;\n    screenSize[1] = height;\n    screenAspectRatio = (float)width \/ height;\n    glViewport(0, 0, width, height);\n    mainCamera.onScreenResize();\n    mylog(" screen size %d x %d\\n", width, height);\n    return 1;\n}\nint TheGame::run() {\n    getReady();\n    while (!bExitGame) {\n        drawFrame();\n    }\n    cleanUp();\n    return 1;\n}\n\n<\/pre><\/div>\n\n\n

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

  • \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 FPS \u0442\u0435\u043f\u0435\u0440\u044c \u0432 3 \u0440\u0430\u0437\u0430 \u043d\u0438\u0436\u0435 (30 \u0432\u043c\u0435\u0441\u0442\u043e 90 \u0440\u0430\u043d\u0435\u0435), \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a\u0443\u0431\u0438\u043a\u0430 (\u0441\u0442\u0440\u043e\u043a\u0430 28).<\/li><\/ul>\n\n\n\n
    \n\n\n\n

    \u0424\u0443\u043d\u043a\u0446\u0438\u044e getSystemMillis()<\/em> \u043c\u044b \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0432 \u043d\u0430\u0431\u043e\u0440\u0435 utils<\/strong>.<\/p>\n\n\n\n

    4. \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\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

    • \u041f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u043f\u043e\u0432\u043e\u0434\u043e\u043c, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043f \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0442\u0430\u043a \u0447\u0442\u043e getSystemMillis()<\/em> – \u043d\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435.<\/li><\/ul>\n\n\n\n
      \n\n\n\n

      5. \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}\n\n<\/pre><\/div>\n\n\n

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

      \u0415\u0449\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b:<\/p>\n\n\n\n

      • getRandom()<\/em> – \u0441\u043a\u043e\u0440\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u044f\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 \u0447\u0438\u0441\u043b\u0430. \u0412 C++ \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f rand()<\/em>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0441\u0435\u0432\u0434\u043e-\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 integer \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 \u043e\u0442 0 \u0434\u043e RAND_MAX. \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u044b \u0437\u0430\u0432\u0435\u0440\u043d\u0435\u043c \u0435\u0435 \u0432 \u043f\u0430\u0440\u0443 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 int <\/em>\u0438\u043b\u0438 float <\/em>\u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435.<\/li>
      • \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b getFullPath()<\/em> \u0438 getInAppPath()<\/em> \u0438\u0437 FileLoader<\/em>.<\/li>
      • \u0415\u0449\u0435 \u043f\u0430\u0440\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438: splitString(\u2026)<\/em> – \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 trimString(\u2026)<\/em>– \u0443\u0431\u0440\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u0435\u043b\u044b.<\/li>
      • \u0418 \u043f\u0430\u0440\u0430 – \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438: \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 fileExists(\u2026)<\/em> \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432 makeDirs(\u2026)<\/em>.<\/li><\/ul>\n\n\n\n
        \n\n\n\n

        6. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a.<\/p>\n\n\n\n

        \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a \u0436\u0435. \u0417\u043d\u0430\u0447\u0438\u0442, \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430.<\/p>\n\n\n\n

        \u041d\u0430 \u0410\u043d\u0434\u0440\u043e\u0438\u0434\u0435 \u0442\u043e\u0436\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043e, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0442\u0430\u043a\u0430\u044f \u0436\u0435 \u0433\u043b\u0430\u0434\u043a\u0430\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 30 FPS – \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440.<\/p>\n\n\n\n


        \n","protected":false},"excerpt":{"rendered":"

        \u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430 \u043e\u0431\u043e\u0438\u0445 \u043c\u043e\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445 (Android \u0438 PC) \u043a\u0443\u0431\u0438\u043a \u0434\u0435\u043b\u0430\u0435\u0442 1 \u043e\u0431\u043e\u0440\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 4 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u042d\u0442\u043e 360 \u043a\u0430\u0434\u0440\u043e\u0432 (\u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 1 \u0433\u0440\u0430\u0434\u0443\u0441 \u0437\u0430 \u043a\u0430\u0434\u0440). \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 360\/4=90 \u043a\u0430\u0434\u0440\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 (frames per second, FPS). \u041f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u044d\u0442\u0430 \u0446\u0438\u0444\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0430 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043c\u043e\u0433\u0443\u0442 \u0432\u043b\u0438\u044f\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-744","post","type-post","status-publish","format-standard","hentry","category-cross-platform-3d"],"_links":{"self":[{"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/posts\/744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/comments?post=744"}],"version-history":[{"count":11,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/posts\/744\/revisions"}],"predecessor-version":[{"id":1400,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/posts\/744\/revisions\/1400"}],"wp:attachment":[{"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/media?parent=744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/categories?post=744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writingagame.ru\/index.php\/wp-json\/wp\/v2\/tags?post=744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}