Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: understanding sfml and opengl2d  (Read 2969 times)

0 Members and 1 Guest are viewing this topic.

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
understanding sfml and opengl2d
« on: December 22, 2015, 02:19:47 am »
for sake understanding sfml and how it handles opengl internally, i have created mini-opengl program that draw simple chess board on screen. of course this can be done in sfml like this:

sf::Sprite sprite(texture);
window.draw(sprite);

as i said, the purpose of this exercise is to understand sfml and opengl as well. the same above code can be writtern in opengl like this:
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <vector>

int main()
{
        sf::Window window(sf::VideoMode(800, 600), "OpenGL");

        // Set the viewport
        glViewport(0, 0, window.getSize().x, window.getSize().y);

        // Initialize Projection Matrix
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        // Set drawing surface properties - either Perspective or Orthographic: make origin (0,0) at top-left corner of screen
        glOrtho(0.0, window.getSize().x, window.getSize().y, 0.0, -1.0, 1.0);

        // Initialize Modelview Matrix
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // Initialize Texture Matrix
        glMatrixMode(GL_TEXTURE);
        glPushMatrix();

        // Initialize vertices: use window coordinate for width and height
        auto width = static_cast<float>(window.getSize().x);
        auto height = static_cast<float>(window.getSize().y);

        std::vector<float> vertices =
        {
                0,     0,
                0,     height,
                width, height,
                width, 0
        };

        // Initialize colors
        std::vector<float> colors =
        {
                1, 0, 0,
                0, 1, 0,
                0, 0, 1,
                0, 1, 1
        };

        // Initialize texture virtice
        std::vector<float> texCoord =
        {
                0, 0,
                0, 1,
                1, 1,
                1, 0
        };
       
        // Create texture: simple chess board
        std::vector<unsigned char> textureData(64);
        for (auto i = 0u; i < textureData.size(); ++i)
                textureData[i] = ((i + (i / 8)) % 2) * 128 + 127;

        // Upload to GPU texture
        GLuint texture;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 8, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, textureData.data());
        glBindTexture(GL_TEXTURE_2D, 0);

        // Initialize clear colors
        glClearColor(0.f, 0.f, 0.f, 1.f);

        while (window.isOpen())
        {
                sf::Event windowEvent;
                while (window.pollEvent(windowEvent))
                {
                        if (windowEvent.type == sf::Event::Closed)
                                window.close();
                }

                // render
                glClear(GL_COLOR_BUFFER_BIT);

                glMatrixMode(GL_MODELVIEW);

                glBindTexture(GL_TEXTURE_2D, texture);
                glEnable(GL_TEXTURE_2D);
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_COLOR_ARRAY);
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
       
                glVertexPointer(2, GL_FLOAT, 0, vertices.data());
                glColorPointer(3, GL_FLOAT, 0, colors.data());
                glTexCoordPointer(2, GL_FLOAT, 0, texCoord.data());

                glDrawArrays(GL_QUADS, 0, 4);

                glDisable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, 0);
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                glDisableClientState(GL_VERTEX_ARRAY);
                glDisableClientState(GL_COLOR_ARRAY);

                window.display();
        }
}

i have two questions regarding this matter:

  • how sfml manged the coordinate system since it doesn't use either Perspective or Orthographic
  • i would like to get code review for my implementation
« Last Edit: December 22, 2015, 02:53:39 am by MORTAL »

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 878
    • View Profile
Re: understanding sfml and opengl2d
« Reply #1 on: December 22, 2015, 09:16:09 am »
SFML effectively uses orthographic projection (since there's no Z coordinate).

When writing raw OpenGL, you don't really have to call glOrtho() or any of the other helper functions. These are really just there to make setting up the correct transformation matrixes easier. SFML simply skips this step, setting up the matrixes as needed.

Regarding a code review, well, let's say "state changes are expensive". As such, don't enable/disable states, unless you have to. In your example, you could just set the proper states (like enabling 2D texturing) first, then start your main loop.

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re: understanding sfml and opengl2d
« Reply #2 on: December 22, 2015, 12:10:52 pm »
SFML effectively uses orthographic projection (since there's no Z coordinate).

When writing raw OpenGL, you don't really have to call glOrtho() or any of the other helper functions. These are really just there to make setting up the correct transformation matrixes easier. SFML simply skips this step, setting up the matrixes as needed.
thanks a lot Mario for replying, that's really helpful to understand SFML. it seems that SFML is heavily rely on transformation matrixes. and cleverly implemented it in such ease and simplified way. many books and tutorial used glm header library to apply a necessary transformation, although, glm has so called glm::ortho to do ographic projection.


Regarding a code review, well, let's say "state changes are expensive". As such, don't enable/disable states, unless you have to. In your example, you could just set the proper states (like enabling 2D texturing) first, then start your main loop.
i was reading a statement from someone says "OpenGL is a giant state machine". i guess i have messed interpret it.
i have implemented your suggestions, here link to it:
https://gist.github.com/MORTAL2000/e8ff971054785cdb2d7b


Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re: understanding sfml and opengl2d
« Reply #3 on: December 23, 2015, 12:22:19 am »
i figure it out how SFML manged the coordinate system without using glOrtho or gluOrtho2D. it simply calculates the Orthographic projection based on sf::tranform manually in sf::view and then the sf::RenderTaget uploaded return projection matrix from sf::view to OpenGL projection stack regularly as  glOrtho do.

according to what SFML do, i have edit my OpenGL-exercise:

#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <vector>

int main()
{
        sf::Window window(sf::VideoMode(800, 600), "OpenGL");

        // Set Orthographic
        auto width = static_cast<float>(window.getSize().x);
        auto height = static_cast<float>(window.getSize().y);
        auto a = 2.f / width;
        auto b = 2.f / height;
        std::vector<float> matrix =
        {
                 a , 0, 0, 0,
                 0, -b, 0, 0,
                 0,  0, 1, 0,
                -1,  1, 0, 1
        };

        // Set the projection matrix
        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(matrix.data());

        // Initialize vertices:
        std::vector<float> vertices =
        {
                0,     0,
                0,     height,
                width, height,
                width, 0
        };

        // Initialize colors
        std::vector<float> colors =
        {
                1, 0, 0,
                0, 1, 0,
                0, 0, 1,
                0, 1, 1
        };

        // Initialize texture virtice
        std::vector<float> texCoord =
        {
                0, 0,
                0, 1,
                1, 1,
                1, 0
        };

        // Create texture: simple chess board 8x8
        auto numRows = 8u;
        auto numCols = 8u;
        auto character = 172u;
        auto remain = 255u - character;
        std::vector<unsigned char> texture(numCols * numRows);
        for (auto i = 0u; i < texture.size(); ++i)
                texture[i] = ((i + (i / numCols)) % 2) * remain + character;

        // Upload to GPU texture
        unsigned textureID;
        glGenTextures(1, &textureID);
        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, numCols, numRows, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texture.data());

        // Initialize clear colors
        glClearColor(0.f, 0.f, 0.f, 1.f);

        // Activate necessary states
        glEnable(GL_TEXTURE_2D);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(2, GL_FLOAT, 0, vertices.data());
        glColorPointer(3, GL_FLOAT, 0, colors.data());
        glTexCoordPointer(2, GL_FLOAT, 0, texCoord.data());

        while (window.isOpen())
        {
                sf::Event windowEvent;
                while (window.pollEvent(windowEvent))
                {
                        if (windowEvent.type == sf::Event::Closed)
                                window.close();
                }

                // render
                glClear(GL_COLOR_BUFFER_BIT);

                glDrawArrays(GL_QUADS, 0, 4);

                window.display();
        }
}

« Last Edit: December 23, 2015, 02:13:35 am by MORTAL »