{"id":354,"date":"2021-11-29T22:15:34","date_gmt":"2021-11-29T22:15:34","guid":{"rendered":"https:\/\/writingagame.com\/?p=354"},"modified":"2021-12-04T18:55:55","modified_gmt":"2021-12-04T18:55:55","slug":"chapter-5-cross-platform-windows","status":"publish","type":"post","link":"https:\/\/writingagame.com\/index.php\/2021\/11\/29\/chapter-5-cross-platform-windows\/","title":{"rendered":"Chapter 5. Cross-platform, Windows"},"content":{"rendered":"\n<p>In this chapter we will dissect our GLFW spinning triangle sample. We will move \u201cgame\u201d implementation into a separate class, which we will reuse later in Android version. It will be triangle rendering related code. In order to make it platform-independent we will separate it from platform-specific calls. All environment related code, such as window creation, GL initialization, and so on, we will leave in <em>main.cpp<\/em> as is.<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Start Visual Studio, open <em>C:\\CPP\\a999hello\\p_windows\\p_windows.sln<\/em> solution.<\/li><\/ol>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>2. Under  <em style=\"font-size: revert;\">p_windows<\/em>  project add new filter.<\/p>\n\n\n\n<p>Right-click on <em style=\"font-size: revert;\">p_windows<\/em>  project -&gt; <em>Add -&gt; New <strong>Filter<\/strong><\/em>. Name &#8211; <strong>xTheGame<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>3. Under <em>xTheGame <\/em>add new class. We won\u2019t use \u201cadd Class\u201d since it will place files at it\u2019s own discretion, not where we want. We\u2019ll better add it file-by-file.<\/p>\n\n\n\n<p>Right-click on <em>xTheGame <\/em>-&gt; <em>Add -&gt; New <strong>Item<\/strong><\/em>, <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Header File (.h)<\/li><li>Name \u2013 <strong>TheGame.h<\/strong><\/li><li>Change location to <em>C:\\CPP\\<em>a999hello<\/em>\\<\/em><\/li><\/ul>\n\n\n\n<p><strong>Add<\/strong>.<\/p>\n\n\n\n<p><em>TheGame <\/em>class will consist of 5 methods\/functions and 3 variables, summarized in <em>TheGame.h<\/em>.<\/p>\n\n\n\n<p>Copy and paste following code to <em>TheGame.h<\/em>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#pragma once\nclass TheGame\n{\npublic:\n\tint screenSize&#91;2];\n\tfloat screenRatio;\n\tbool bExitGame;\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><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>4. Now &#8211; implementation:<\/p>\n\n\n\n<p>Right-click on <em>xTheGame <\/em>-&gt; <em>Add -&gt; New <strong>Item<\/strong><\/em>, <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>C++ File (.cpp)<\/li><li>Name \u2013 <strong>TheGame.cpp<\/strong><\/li><li>Location &#8211; <em>C:\\CPP\\<em>a999hello<\/em>\\<\/em><\/li><\/ul>\n\n\n\n<p>Add.<\/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;TheGame.h&quot;\n#include &quot;platform.h&quot;\n#include &quot;linmath.h&quot;\n\nstatic const struct\n{\n    float x, y;\n    float r, g, b;\n} vertices&#91;3] =\n{\n    { -0.6f, -0.4f, 1.f, 0.f, 0.f },\n    {  0.6f, -0.4f, 0.f, 1.f, 0.f },\n    {   0.f,  0.6f, 0.f, 0.f, 1.f }\n};\n\nstatic const char* vertex_shader_text =\n&quot;#version 320 es\\n&quot;\n&quot;precision lowp float;\\n&quot;\n&quot;uniform mat4 MVP;\\n&quot;\n&quot;in vec3 vCol;\\n&quot;\n&quot;in vec2 vPos;\\n&quot;\n&quot;out vec3 color;\\n&quot;\n&quot;void main()\\n&quot;\n&quot;{\\n&quot;\n&quot;    gl_Position = MVP * vec4(vPos, 0.0, 1.0);\\n&quot;\n&quot;    color = vCol;\\n&quot;\n&quot;}\\n&quot;;\n\nstatic const char* fragment_shader_text =\n&quot;#version 320 es\\n&quot;\n&quot;precision lowp float;\\n&quot;\n&quot;in vec3 color;\\n&quot;\n&quot;out vec4 FragColor;\\n&quot;\n&quot;void main()\\n&quot;\n&quot;{\\n&quot;\n&quot;    FragColor = vec4(color, 1.0);\\n&quot;\n&quot;}\\n&quot;;\n\nunsigned int vao_buffer, vertex_buffer, vertex_shader, fragment_shader, program;\nint mvp_location, vpos_location, vcol_location;\nfloat angle_z = 0;\n\nint TheGame::getReady() {\n    bExitGame = false;\n\n    glGenVertexArrays(1, &amp;vao_buffer);\n    glBindVertexArray(vao_buffer);\n\n    glGenBuffers(1, &amp;vertex_buffer);\n    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);\n\n    vertex_shader = glCreateShader(GL_VERTEX_SHADER);\n    glShaderSource(vertex_shader, 1, &amp;vertex_shader_text, NULL);\n    glCompileShader(vertex_shader);\n\n    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(fragment_shader, 1, &amp;fragment_shader_text, NULL);\n    glCompileShader(fragment_shader);\n\n    program = glCreateProgram();\n    glAttachShader(program, vertex_shader);\n    glAttachShader(program, fragment_shader);\n    glLinkProgram(program);\n\n    mvp_location = glGetUniformLocation(program, &quot;MVP&quot;);\n\n    vpos_location = glGetAttribLocation(program, &quot;vPos&quot;);\n    vcol_location = glGetAttribLocation(program, &quot;vCol&quot;);\n\n    glEnableVertexAttribArray(vpos_location);\n    glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,\n        sizeof(vertices&#91;0]), (void*)0);\n    glEnableVertexAttribArray(vcol_location);\n    glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,\n        sizeof(vertices&#91;0]), (void*)(sizeof(float) * 2));\n\n    return 1;\n}\nint TheGame::drawFrame() {\n    myPollEvents();\n\n    mat4x4 m, p, mvp;\n\n    glClear(GL_COLOR_BUFFER_BIT);\n    angle_z += 0.01f;\n    mat4x4_identity(m);\n    mat4x4_rotate_Z(m, m, angle_z);\n    mat4x4_ortho(p, -screenRatio, screenRatio, -1.f, 1.f, 1.f, -1.f);\n    mat4x4_mul(mvp, p, m);\n\n    glUseProgram(program);\n    glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*)mvp);\n    glDrawArrays(GL_TRIANGLES, 0, 3);\n\n    mySwapBuffers();\n    return 1;\n}\nint TheGame::cleanUp() {\n    return 1;\n}\nint TheGame::onScreenResize(int width, int height) {\n    if (screenSize&#91;0] == width &amp;&amp; screenSize&#91;1] == height)\n        return 0;\n    screenSize&#91;0] = width;\n    screenSize&#91;1] = height;\n    screenRatio = (float)width \/ (float)height;\n    glViewport(0, 0, width, height);\n    mylog(&quot; screen size %d x %d\\n&quot;, 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><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Please note, that this code doesn\u2019t have platform-specific references (such as GLAD and GLFW), which means that it <strong>can <\/strong>be re-used on another platform, particularly on Android, which we\u2019ll definitely try in the next chapter.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>5. Also (as usual) we need to notify <em>p_windows <\/em>project where to look for <em>TheGame.h<\/em>.<\/p>\n\n\n\n<p>Right-click on  <em>p_windows <\/em> project -&gt; Properties, <strong>All Configurations<\/strong>, Win32, <em>Configuration Properties -&gt; C\/C++ -&gt; General<\/em>, open <em>Additional Include Directories -&gt; Edit<\/em>, add new line. <\/p>\n\n\n\n<p><strong>IMPORTANT<\/strong>: This time instead of navigating to <em>C:\\CPP\\a999hello<\/em> (where <em>TheGame <\/em>is actually located), <strong>manually <\/strong>add<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>..<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Yes, it\u2019s just 2 dots, which means 1 folder level up (from <em>p_windows <\/em>appication root folder).<\/p>\n\n\n\n<p>Ok, Apply, Ok.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>6. As planned, platform-specific code we&#8217;ll place <strong>outside <\/strong>of <em>TheGame <\/em>class. Particularly, GLFW and GLAD declarations, events handling and swap screen buffers call.<\/p>\n\n\n\n<p>So, open <em>platform.h<\/em> and replace code by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#pragma once\n#include &lt;glad\/glad.h&gt;\n\nvoid mylog(const char* _Format, ...);\nvoid mySwapBuffers();\nvoid myPollEvents();\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Also, it was a nice occasion to move <em>mylog(..)<\/em> from <em>.h<\/em> to <em>.cpp<\/em><\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>7. Implementation:<\/p>\n\n\n\n<p>Right-click on <em>xPlatform <\/em>-&gt; <em>Add -&gt; New <strong>Item<\/strong><\/em>, <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>C++ File (.cpp)<\/li><li>Name \u2013 <strong>platform.cpp<\/strong><\/li><li>Location &#8211; <em>C:\\CPP\\<em>p_windows<\/em>\\<\/em><\/li><\/ul>\n\n\n\n<p><strong>Add<\/strong>.<\/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 &lt;stdarg.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;GLFW\/glfw3.h&gt;\n#include &quot;platform.h&quot;\n#include &quot;TheGame.h&quot;\n\nextern GLFWwindow* myMainWindow;\nextern TheGame theGame;\n\nvoid mylog(const char* _Format, ...) {\n#ifdef _DEBUG\n    va_list _ArgList;\n    va_start(_ArgList, _Format);\n    vprintf(_Format, _ArgList);\n    va_end(_ArgList);\n#endif\n};\nvoid mySwapBuffers() {\n    glfwSwapBuffers(myMainWindow);\n}\nvoid myPollEvents() {\n    glfwPollEvents();\n    \/\/check if closing the window\n    theGame.bExitGame = glfwWindowShouldClose(myMainWindow);\n    \/\/check screen size\n    int width, height;\n    glfwGetFramebufferSize(myMainWindow, &amp;width, &amp;height);\n    theGame.onScreenResize(width, height);\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>8. <em>main.cpp<\/em>, accordingly, is much shorter now:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [7,21,47]; title: ; notranslate\" title=\"\">\n#include &lt;glad\/glad.h&gt;\n#define GLFW_INCLUDE_NONE\n#include &lt;GLFW\/glfw3.h&gt;\n\n#include &lt;stdlib.h&gt;\n\n#include &quot;TheGame.h&quot;\n#include &quot;platform.h&quot;\n\nstatic void error_callback(int error, const char* description)\n{\n    mylog(&quot;Error: %s\\n&quot;, description);\n}\n\nstatic void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)\n{\n    if (key == GLFW_KEY_ESCAPE &amp;&amp; action == GLFW_PRESS)\n        glfwSetWindowShouldClose(window, GLFW_TRUE);\n}\n\nTheGame theGame;\nGLFWwindow* myMainWindow;\n\nint main(void)\n{\n    glfwSetErrorCallback(error_callback);\n\n    if (!glfwInit())\n        exit(EXIT_FAILURE);\n\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);\n\n    myMainWindow = glfwCreateWindow(640, 480, &quot;OurProject&quot;, NULL, NULL);\n    if (!myMainWindow)\n    {\n        glfwTerminate();\n        exit(EXIT_FAILURE);\n    }\n\n    glfwSetKeyCallback(myMainWindow, key_callback);\n\n    glfwMakeContextCurrent(myMainWindow);\n    gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress); \/\/gladLoadGL(glfwGetProcAddress);\n    glfwSwapInterval(1);\n\n    theGame.run();\n\n    glfwDestroyWindow(myMainWindow);\n    glfwTerminate();\n    exit(EXIT_SUCCESS);\n}\n\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p>Replace all code in <em>main.cpp<\/em> by this one.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Please note, that this code does NOT contain any game-specific code, which means that we can re-use it \u201cas is\u201d in our ANY future Windows project.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>9. Now build and run (green arrow). Works!<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>We also can run it in Release configuration, then it will work without Console window.<\/li><\/ul>\n\n\n\n<p>Our next task \u2013 to make it work on Android.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n","protected":false},"excerpt":{"rendered":"<p class=\"mb-2\">In this chapter we will dissect our GLFW spinning triangle sample. We will move \u201cgame\u201d implementation into a separate class, which we will reuse later in Android version. It will be triangle rendering related code. In order to make it platform-independent we will separate it from platform-specific calls. All environment related code, such as window [&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-354","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\/354","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=354"}],"version-history":[{"count":8,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/354\/revisions"}],"predecessor-version":[{"id":471,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/posts\/354\/revisions\/471"}],"wp:attachment":[{"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/media?parent=354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/categories?post=354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writingagame.com\/index.php\/wp-json\/wp\/v2\/tags?post=354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}