tresonance

OPENGL_ROOT

May 18th, 2020
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.27 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////
  2. // Headers
  3. ////////////////////////////////////////////////////////////
  4.  
  5. /// GLEW is needed to provide OpenGL extensions.
  6. #include <GL/glew.h>
  7.  
  8. #include <SFML/Graphics.hpp>
  9. #include <SFML/OpenGL.hpp>
  10.  
  11. /// GLM is needed to provide 3D math properties, particularly matrices for 3D transformations.
  12. #define GLM_ENABLE_EXPERIMENTAL
  13. #include "glm/glm.hpp"
  14. #include "glm/gtx/transform.hpp"
  15.  
  16. #include <iostream>
  17.  
  18. #ifndef GL_SRGB8_ALPHA8
  19. #define GL_SRGB8_ALPHA8 0x8C43
  20. #endif
  21.  
  22. ///Basic vertex shader that transforms the vertex position based on a projection view matrix and passes the texture coordinate to the fragment shader.
  23. const std::string defaultVertexShader =
  24. "#version 330\n"\
  25. "attribute vec3 position;"\
  26. "attribute vec2 texCoord;" \
  27. "uniform mat4 pvm;" \
  28.  
  29. "varying vec2 uv;" \
  30.  
  31. "void main() {"\
  32. "   gl_Position = pvm * vec4(position, 1.0);"\
  33. "   uv = texCoord;"\
  34. "}";
  35.  
  36. ///Basic fragment shader that returns the colour of a pixel based on the input texture and its coordinate.
  37. const std::string defaultFragShader =
  38. "#version 330\n" \
  39. "uniform sampler2D texture;" \
  40. "varying vec2 uv;" \
  41.  
  42. "void main() {" \
  43. "   gl_FragColor = texture2D(texture, uv);" \
  44. "}";
  45.  
  46. ///Shader Types
  47. enum class ShaderType { Vertex, Fragment, Geometry, Count };
  48. ///Standard Uniforms in the shader.
  49. enum class UniformType { TransformPVM, Count };
  50. ///Vertex attributes for shaders and the input vertex array.
  51. enum class VertexAttribute { Position, TexCoord, COUNT };
  52.  
  53. ///Shader Program
  54. GLuint program = 0;
  55.  
  56. ///List of shaders set up for a 3D scene.
  57. GLuint shader[static_cast<unsigned int>(ShaderType::Count)];
  58. ///List of uniforms that can be defined values for the shader.
  59. GLint uniform[static_cast<unsigned int>(UniformType::Count)];
  60.  
  61. ///Vertex Array Object ID.
  62. GLuint vao = 0;
  63. ///Vertex Buffer Object for Vertices.
  64. GLuint vertexVBO = 0;
  65. ///Vertex Buffer Object for Indices.
  66. GLuint indexVBO = 0;
  67. ///Depending on input, the amount of vertices or indices that are needed to be drawn for this object.
  68. unsigned int drawCount;
  69.  
  70. ///Checks for any errors specific to the shaders. It will output any errors within the shader if it's not valid.
  71. void checkError(GLuint l_shader, GLuint l_flag, bool l_program, const std::string& l_errorMsg)
  72. {
  73.     GLint success = 0;
  74.     GLchar error[1024] = { 0 };
  75.     if (l_program) { glGetProgramiv(l_shader, l_flag, &success); }
  76.     else { glGetShaderiv(l_shader, l_flag, &success); }
  77.  
  78.     if (success) { return; }
  79.     if (l_program) {
  80.         glGetProgramInfoLog(l_shader, sizeof(error), nullptr, error);
  81.     }
  82.     else {
  83.         glGetShaderInfoLog(l_shader, sizeof(error), nullptr, error);
  84.     }
  85.  
  86.     std::cout << l_errorMsg << "\n";
  87. }
  88.  
  89. ///Creates and compiles a shader.
  90. GLuint buildShader(const std::string& l_src, unsigned int l_type)
  91. {
  92.     GLuint shaderID = glCreateShader(l_type);
  93.     if (!shaderID) {
  94.         std::cout << "Bad shader type!";
  95.         return 0;
  96.     }
  97.     const GLchar* sources[1];
  98.     GLint lengths[1];
  99.     sources[0] = l_src.c_str();
  100.     lengths[0] = l_src.length();
  101.     glShaderSource(shaderID, 1, sources, lengths);
  102.     glCompileShader(shaderID);
  103.     checkError(shaderID, GL_COMPILE_STATUS, false, "Shader compile error: ");
  104.     return shaderID;
  105. }
  106.  
  107. ///Function to load the shaders from string data.
  108. void LoadFromMemory(const std::string& shaderData, ShaderType type)
  109. {
  110.     if (shaderData.empty())
  111.         return;
  112.  
  113.     if (shader[static_cast<unsigned int>(type)])
  114.     {
  115.         glDetachShader(program, shader[static_cast<unsigned int>(type)]);
  116.         glDeleteShader(shader[static_cast<unsigned int>(type)]);
  117.     }
  118.  
  119.     switch (type)
  120.     {
  121.     case ShaderType::Vertex:
  122.         shader[static_cast<unsigned int>(type)] = buildShader(shaderData, GL_VERTEX_SHADER);
  123.         break;
  124.     case ShaderType::Geometry:
  125.         shader[static_cast<unsigned int>(type)] = buildShader(shaderData, GL_GEOMETRY_SHADER);
  126.         break;
  127.     case ShaderType::Fragment:
  128.         shader[static_cast<unsigned int>(type)] = buildShader(shaderData, GL_FRAGMENT_SHADER);
  129.         break;
  130.     default:
  131.         break;
  132.     }
  133.  
  134.     if (program == 0)
  135.     {
  136.         program = glCreateProgram();
  137.     }
  138.  
  139.     glAttachShader(program, shader[static_cast<unsigned int>(type)]);
  140.     glBindAttribLocation(program, static_cast<GLuint>(VertexAttribute::Position), "position");
  141.     glBindAttribLocation(program, static_cast<GLuint>(VertexAttribute::TexCoord), "texCoord");
  142.  
  143.     glLinkProgram(program);
  144.     checkError(program, GL_LINK_STATUS, true, "Shader link error:");
  145.     glValidateProgram(program);
  146.     checkError(program, GL_VALIDATE_STATUS, true, "Invalid shader:");
  147.  
  148.     uniform[static_cast<unsigned int>(UniformType::TransformPVM)] = glGetUniformLocation(program, "pvm");
  149. }
  150.  
  151. ////////////////////////////////////////////////////////////
  152. /// Entry point of application
  153. ///
  154. /// \return Application exit code
  155. ///
  156. ////////////////////////////////////////////////////////////
  157. int main()
  158. {
  159.     bool exit = false;
  160.     bool sRgb = false;
  161.  
  162.     while (!exit)
  163.     {
  164.         // Request a 24-bits depth buffer when creating the window
  165.         sf::ContextSettings contextSettings;
  166.         contextSettings.depthBits = 24;
  167.         contextSettings.sRgbCapable = sRgb;
  168.  
  169.         // Create the main window
  170.         sf::RenderWindow window(sf::VideoMode(800, 600), "SFML graphics with OpenGL", sf::Style::Default, contextSettings);
  171.         window.setVerticalSyncEnabled(true);
  172.  
  173.         // Initialise GLEW for the extended functions.
  174.         glewExperimental = GL_TRUE;
  175.         if (glewInit() != GLEW_OK)
  176.             return EXIT_FAILURE;
  177.  
  178.         // Create a sprite for the background
  179.         sf::Texture backgroundTexture;
  180.         backgroundTexture.setSrgb(sRgb);
  181.         if (!backgroundTexture.loadFromFile("resources/background.jpg"))
  182.             return EXIT_FAILURE;
  183.         sf::Sprite background(backgroundTexture);
  184.  
  185.         // Create some text to draw on top of our OpenGL object
  186.         sf::Font font;
  187.         if (!font.loadFromFile("resources/sansation.ttf"))
  188.             return EXIT_FAILURE;
  189.         sf::Text text("SFML / OpenGL demo", font);
  190.         sf::Text sRgbInstructions("Press space to toggle sRGB conversion", font);
  191.         sf::Text mipmapInstructions("Press return to toggle mipmapping", font);
  192.         text.setFillColor(sf::Color(255, 255, 255, 170));
  193.         sRgbInstructions.setFillColor(sf::Color(255, 255, 255, 170));
  194.         mipmapInstructions.setFillColor(sf::Color(255, 255, 255, 170));
  195.         text.setPosition(250.f, 450.f);
  196.         sRgbInstructions.setPosition(150.f, 500.f);
  197.         mipmapInstructions.setPosition(180.f, 550.f);
  198.  
  199.         // Load a texture to apply to our 3D cube
  200.         sf::Texture texture;
  201.         if (!texture.loadFromFile("resources/texture.jpg"))
  202.             return EXIT_FAILURE;
  203.  
  204.         // Attempt to generate a mipmap for our cube texture
  205.         // We don't check the return value here since
  206.         // mipmapping is purely optional in this example
  207.         texture.generateMipmap();
  208.  
  209.         // Make the window the active window for OpenGL calls
  210.         window.setActive(true);
  211.  
  212.         // Load the shaders we need.
  213.         if (program == 0)
  214.         {
  215.             LoadFromMemory(defaultVertexShader, ShaderType::Vertex);
  216.             LoadFromMemory(defaultFragShader, ShaderType::Fragment);
  217.         }
  218.  
  219.         // Enable Z-buffer read and write and culling.
  220.         glEnable(GL_DEPTH_TEST);
  221.         glEnable(GL_CULL_FACE);
  222.         glCullFace(GL_BACK);
  223.  
  224.         // Setup a perspective projection
  225.         GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
  226.         glm::mat4 projection = glm::frustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.0f);
  227.  
  228.         // Define a 3D cube (6 faces made of 2 triangles composed by 3 indices of a list of vertices)
  229.         static const GLfloat cube[] =
  230.         {
  231.              // positions   // texture coordinates
  232.             //front
  233.             -20, -20, -20,  0, 0,
  234.              20, -20, -20,  1, 0,
  235.              20,  20, -20,  1, 1,
  236.             -20,  20, -20,  0, 1,
  237.             //right
  238.              20,  20, -20,  1, 1,
  239.              20,  20,  20,  0, 1,
  240.              20, -20,  20,  0, 0,
  241.              20, -20, -20,  1, 0,
  242.             //back
  243.             -20, -20,  20,  0, 0,
  244.              20, -20,  20,  1, 0,
  245.              20,  20,  20,  1, 1,
  246.             -20,  20,  20,  0, 1,
  247.             //left
  248.             -20, -20,  20,  0, 0,
  249.             -20, -20, -20,  1, 0,
  250.             -20,  20, -20,  1, 1,
  251.             -20,  20,  20,  0, 1,
  252.             //upper
  253.              20, -20,  20,  0, 1,
  254.             -20, -20,  20,  1, 1,
  255.             -20, -20, -20,  1, 0,
  256.              20, -20, -20,  0, 0,
  257.             //bottom
  258.             -20,  20, -20,  0, 1,
  259.              20,  20, -20,  1, 1,
  260.              20,  20,  20,  1, 0,
  261.             -20,  20,  20,  0, 0,
  262.         };
  263.        
  264.         // Define indices for 3D cube.
  265.         static const unsigned int indices[] =
  266.         {
  267.             2, 1, 0, 3, 2, 0, //front
  268.             4, 5, 6, 4, 6, 7, //right
  269.             8, 9, 10, 8, 10, 11, //back
  270.             14, 13, 12, 15, 14, 12, //left
  271.             16, 17, 18, 16, 18, 19, //upper
  272.             22, 21, 20, 23, 22, 20  //bottom
  273.         };
  274.  
  275.         // Stride is the number of bytes per array element.
  276.         auto stride = sizeof(GLfloat) * 5;
  277.         // Data offset for texture coordinate in bytes.
  278.         auto textureCoordOffset = sizeof(GLfloat) * 3;
  279.         // Amount of index elements in total.
  280.         drawCount = sizeof(indices) / sizeof(unsigned int);
  281.  
  282.  
  283.         // Generate Vertex Array and Vertex Buffer and point the area of data to assign to each attribute.
  284.         glGenVertexArrays(1, &vao);
  285.         glBindVertexArray(vao);
  286.         glGenBuffers(1, &vertexVBO);
  287.         glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
  288.         glBufferData(GL_ARRAY_BUFFER, drawCount * stride, cube, GL_STATIC_DRAW);
  289.         glEnableVertexAttribArray(static_cast<GLuint>(VertexAttribute::Position));
  290.         glVertexAttribPointer(static_cast<GLuint>(VertexAttribute::Position), 3, GL_FLOAT, GL_FALSE, stride, 0);
  291.         glEnableVertexAttribArray(static_cast<GLuint>(VertexAttribute::TexCoord));
  292.         glVertexAttribPointer(static_cast<GLuint>(VertexAttribute::TexCoord), 2, GL_FLOAT, GL_FALSE, stride, (void*)textureCoordOffset);
  293.        
  294.         // Generate Index Buffer and define the amount of indices to point to.
  295.         glGenBuffers(1, &indexVBO);
  296.         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
  297.         glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawCount * sizeof(indices[0]), indices, GL_STATIC_DRAW);
  298.        
  299.         //Make sure to bind the vertex array to null if you wish to define more objects.
  300.         glBindVertexArray(0);
  301.  
  302.         // Make the window no longer the active window for OpenGL calls
  303.         window.setActive(false);
  304.  
  305.         // Create a clock for measuring the time elapsed
  306.         sf::Clock clock;
  307.  
  308.         // Flag to track whether mipmapping is currently enabled
  309.         bool mipmapEnabled = true;
  310.  
  311.         // Start game loop
  312.         while (window.isOpen())
  313.         {
  314.             // Process events
  315.             sf::Event event;
  316.             while (window.pollEvent(event))
  317.             {
  318.                 // Close window: exit
  319.                 if (event.type == sf::Event::Closed)
  320.                 {
  321.                     exit = true;
  322.                     window.close();
  323.                 }
  324.  
  325.                 // Escape key: exit
  326.                 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
  327.                 {
  328.                     exit = true;
  329.                     window.close();
  330.                 }
  331.  
  332.                 // Return key: toggle mipmapping
  333.                 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Return))
  334.                 {
  335.                     if (mipmapEnabled)
  336.                     {
  337.                         // We simply reload the texture to disable mipmapping
  338.                         if (!texture.loadFromFile("resources/texture.jpg"))
  339.                             return EXIT_FAILURE;
  340.  
  341.                         mipmapEnabled = false;
  342.                     }
  343.                     else
  344.                     {
  345.                         texture.generateMipmap();
  346.  
  347.                         mipmapEnabled = true;
  348.                     }
  349.                 }
  350.  
  351.                 // Space key: toggle sRGB conversion
  352.                 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
  353.                 {
  354.                     sRgb = !sRgb;
  355.                     window.close();
  356.                 }
  357.  
  358.                 // Adjust the viewport when the window is resized
  359.                 if (event.type == sf::Event::Resized)
  360.                 {
  361.                     // Make the window the active window for OpenGL calls
  362.                     window.setActive(true);
  363.  
  364.                     glViewport(0, 0, event.size.width, event.size.height);
  365.  
  366.                     // Make the window no longer the active window for OpenGL calls
  367.                     window.setActive(false);
  368.                 }
  369.             }
  370.  
  371.             // Clear the depth buffer
  372.             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  373.  
  374.             // Configure the viewport (the same size as the window)
  375.             glViewport(0, 0, window.getSize().x, window.getSize().y);
  376.  
  377.             // Draw the background
  378.             window.pushGLStates();
  379.             window.draw(background);
  380.             window.popGLStates();
  381.  
  382.             // Make the window the active window for OpenGL calls
  383.             window.setActive(true);
  384.  
  385.             // Bind the texture
  386.             sf::Texture::bind(&texture);
  387.             glBindVertexArray(vao);
  388.  
  389.             // We get the position of the mouse cursor, so that we can move the box accordingly
  390.             float x = sf::Mouse::getPosition(window).x * 200.f / window.getSize().x - 100.f;
  391.             float y = -sf::Mouse::getPosition(window).y * 200.f / window.getSize().y + 100.f;
  392.  
  393.             // Apply some transformations
  394.             glm::mat4 matrix_pos = glm::translate(glm::vec3(x, y, -100.f));
  395.             glm::mat4 matrix_rotX = glm::rotate(clock.getElapsedTime().asSeconds() * 50.f * (3.1415926f / 180.0f), glm::vec3(1.f, 0.f, 0.f));
  396.             glm::mat4 matrix_rotY = glm::rotate(clock.getElapsedTime().asSeconds() * 30.f * (3.1415926f / 180.0f), glm::vec3(0.f, 1.f, 0.f));
  397.             glm::mat4 matrix_rotZ = glm::rotate(clock.getElapsedTime().asSeconds() * 90.f * (3.1415926f / 180.0f), glm::vec3(0.f, 0.f, 1.f));
  398.  
  399.             glm::mat4 matrix_rotation = matrix_rotZ * matrix_rotY * matrix_rotX;
  400.             glm::mat4 transform = matrix_pos * matrix_rotation;
  401.  
  402.             glm::mat4 identity;
  403.             glm::mat4 viewProj = projection * transform;
  404.  
  405.             //Bind the shaders.
  406.             glUseProgram(program);
  407.  
  408.             //Set the uniforms for the shader to use.
  409.             if (uniform[(int)UniformType::TransformPVM] >= 0)
  410.                 glUniformMatrix4fv((unsigned int)uniform[(int)UniformType::TransformPVM], 1, GL_FALSE, &viewProj[0][0]);
  411.  
  412.             // Draw the cube
  413.             glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_INT, 0);
  414.  
  415.             // Reset the vertex array bound, shader and texture for other assets to draw.
  416.             glBindVertexArray(0);
  417.             glUseProgram(0);
  418.             glBindTexture(GL_TEXTURE_2D, 0);
  419.  
  420.             // Make the window no longer the active window for OpenGL calls
  421.             window.setActive(false);
  422.  
  423.             // Draw some text on top of our OpenGL object
  424.             window.pushGLStates();
  425.             window.draw(text);
  426.             window.draw(sRgbInstructions);
  427.             window.draw(mipmapInstructions);
  428.             window.popGLStates();
  429.  
  430.             // Finally, display the rendered frame on screen
  431.             window.display();
  432.         }
  433.  
  434.         //Destroy all buffers, shaders and programs.
  435.         glDeleteBuffers(1, &vertexVBO);
  436.         glDeleteBuffers(1, &indexVBO);
  437.         glDeleteVertexArrays(1, &vao);
  438.  
  439.         //Setting these values to zero will allow them to be initialised with new data on reset.
  440.         vertexVBO = 0;
  441.         indexVBO = 0;
  442.         vao = 0;
  443.  
  444.         for (unsigned int i = 0; i < static_cast<unsigned int>(ShaderType::Count); i++)
  445.         {
  446.             glDetachShader(program, shader[i]);
  447.             glDeleteShader(shader[i]);
  448.             shader[i] = 0;
  449.         }
  450.  
  451.         for (unsigned int i = 0; i < static_cast<unsigned int>(UniformType::Count); i++)
  452.         {
  453.             uniform[i] = -1;
  454.         }
  455.  
  456.         glDeleteProgram(program);
  457.         program = 0;
  458.     }
  459.  
  460.     return EXIT_SUCCESS;
  461. }
Add Comment
Please, Sign In to add comment