Experimenting with GLFW library: window boundary problem and normalized coordinates

35 Views Asked by At

I'm experimenting with GLFW (compiling with g++ -o nxtBluePixel nxtBluePixel.cpp -lglfw -lGLEW -lGL ) to simply draw a blue box and move it up/down/left/right. I want to output a message "out of bounds" when the box touches the edges of the visible area, which should logically be -1 or 1 (in those so-called normalized OpenGL coordinates, so I read). But the box keeps continuing to move in an "invisible" region outside (and is invisible) but no message is displayed until a while (at least 10 hits or so on a key outside the edge boundary ... ChatGPT 4 can't help me, it says:

"Correct Boundary Check: If you want the "out of bounds" message to appear as soon as the point is about to leave the visible area, your original check without the large epsilon is logically correct. However, if the message appears too late or too early, it might be due to how the point's position is updated or rendered, not the boundary check itself."

any ideas? I never use OpenGL, so I wanted to try... but this is typically the kind of very annoying problem I hate!

and here my code:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
#include <cctype>

GLint worldWidth = 400;
GLint worldHeight = 300;

// Starting position of the pixel
float currX = 0.0f;
float currY = 0.0f;

float stepSize = 1.0f / worldWidth;
float speed = 2.0f;

void updateWorld(char keyPressed, float speed){
  switch (keyPressed) {
  case 'W':
    //up
    currY += stepSize*speed;
    break;
  case 'A':
    //left
    currX -= stepSize*speed;
    break;
  case 'S':
    //down
    currY -= stepSize*speed;
    break;
  case 'D':
    //right
    currX += stepSize*speed;
    break;
  }

  //using openGL 'normalized' coords i.e. between -1 and 1
  if (currX >= 1.0 || currX <= -1.0 || currY >= 1.0 || currY <= -1.0){
    printf("OUT OF BOUNDS !!!!");
  }



}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
  char key_str = '0';
  if (action == GLFW_PRESS || action == GLFW_REPEAT) {
    switch (key) {
    case GLFW_KEY_W:
      key_str = 'W';
      break;
    case GLFW_KEY_A:
      key_str = 'A';
      break;
    case GLFW_KEY_S:
      key_str = 'S';
      break;
    case GLFW_KEY_D:
      key_str = 'D';
      break;
    case GLFW_KEY_Q:
      printf("Bye ...");
      glfwSetWindowShouldClose(window, GL_TRUE);
      break;
    default:
      printf("unknown key pressed \n");
      break;
    }
    updateWorld(key_str, speed);
  }
}

int main(void) {
  GLFWwindow* window;

  // Initialize the library
  if (!glfwInit())
    return -1;

  //remove win frame
  //glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);


  // Create a windowed mode window and its OpenGL context
  window = glfwCreateWindow(worldWidth, worldHeight, "Move Pixel with Keyboard", NULL, NULL);
  if (!window) {
    glfwTerminate();
    return -1;
  }

  // Make the window's context current
  glfwMakeContextCurrent(window);

  // Set the keyboard input callback
  glfwSetKeyCallback(window, key_callback);

  // Initialize GLEW
  glewExperimental = GL_TRUE;
  if (glewInit() != GLEW_OK) {
    std::cerr << "Failed to initialize GLEW" << std::endl;
    return -1;
  }

  //glfwGetFramebufferSize(window, &worldWidth, &worldHeight);
  // Define the viewport dimensions
  glViewport(0, 0, worldWidth, worldHeight);

  // Set point size
  glPointSize(10.0f); // Increase if you want the "pixel" to be bigger

  // Loop until the user closes the window
  while (!glfwWindowShouldClose(window)) {
    // Render here
    glClear(GL_COLOR_BUFFER_BIT);

    // Set the drawing color to blue
    glColor3f(0.0f, 0.0f, 1.0f); // RGB: Blue

    // Draw a point at the current position
    glBegin(GL_POINTS);
    glVertex2f(currX, currY); // Use the updated position
    glEnd();

    // Swap front and back buffers
    glfwSwapBuffers(window);

    // Poll for and process events
    glfwPollEvents();
  }

  glfwTerminate();
  return 0;
}

In the worst case i can debug step by step with printf ... but well it will take a long time and it won't necessarily allow me to understand from where this behavior stems because I see there is an "epsilon" but it changes with resolution so i don't have the formula, it would always be "trial and error" to determined the "epsilon" to use to add or subtract from the theoretical -1 or 1 boundaries.

1

There are 1 best solutions below

1
AlanTuring On

i found a way, using:

  • integer pixel coordinates which is much more intuitive and convenient at least for what i'm doing here
  • and considering the "pixel size"

i wanted to paste my code but the crazy blocking rules pretending my code is not "formatted" correctly prohibits it! ctrl-k does not work ... so i wonder how people can post anything here anymore?

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
#include <cctype>

float pixelSize = 10.0;
GLint worldWidth = 800;
GLint worldHeight = 600;

//float epsilonX = 1.16*pixelSize/worldWidth;
//float epsilonY = 1.16*pixelSize/worldHeight;

// Starting position of the pixel
//float currX = 0.2f;
//float currY = 0.5f;
int currX = 25;
int currY = 50;

//float stepSize = 1.0f / worldWidth;
int stepSize = 1;
//float speed = 2.0f;


bool isCollision = false;

// OpenGL functions

void setupOrthographicProjection(int screenWidth, int screenHeight) {
    // Set up an orthographic projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, screenWidth, 0.0, screenHeight, -1.0, 1.0);

    // Switch back to the model view matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}



/////////////////////////////////////////////////


void updateWorld(char keyPressed){
  int p = ((int) pixelSize)/2;
  switch (keyPressed) {
  case 'W':
    //up
    currY += stepSize;
    break;
  case 'A':
    //left
    currX -= stepSize;
    break;
  case 'S':
    //down
    currY -= stepSize;
    break;
  case 'D':
    //right
    currX += stepSize;
    break;
  }
  printf("currX=%d, currY=%d \n", currX, currY);

  /*
  //using openGL 'normalized' coords i.e. between -1 and 1
  if (currX >= (1.0-epsilonX) || currX <= (-1.0+epsilonX) || currY >= (1.0-epsilonY) || currY <= (-1.0+epsilonY)){
    printf("You hit the walls !!!!");
    isCollision = true;
  }
  */
  if (currX <= p || currX >= (worldWidth-p) || currY <= p || currY >= (worldHeight-p)){
    printf("You hit the walls !!!!");
    isCollision = true;
  }
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
  char key_str = '0';
  if (action == GLFW_PRESS || action == GLFW_REPEAT) {
    switch (key) {
    case GLFW_KEY_W:
      key_str = 'W';
      break;
    case GLFW_KEY_A:
      key_str = 'A';
      break;
    case GLFW_KEY_S:
      key_str = 'S';
      break;
    case GLFW_KEY_D:
      key_str = 'D';
      break;
    case GLFW_KEY_Q:
      printf("Bye ...");
      glfwSetWindowShouldClose(window, GL_TRUE);
      break;
    default:
      printf("unknown key pressed \n");
      break;
    }
    updateWorld(key_str);
  }
}

int main(void) {
  GLFWwindow* window;

  // Initialize the library
  if (!glfwInit())
    return -1;

  //remove win frame
  //glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);


  // Create a windowed mode window and its OpenGL context
  window = glfwCreateWindow(worldWidth, worldHeight, "Move Pixel with Keyboard", NULL, NULL);
  if (!window) {
    glfwTerminate();
    return -1;
  }

  // Make the window's context current
  glfwMakeContextCurrent(window);

  // Set the keyboard input callback
  glfwSetKeyCallback(window, key_callback);

  // Initialize GLEW
  glewExperimental = GL_TRUE;
  if (glewInit() != GLEW_OK) {
    std::cerr << "Failed to initialize GLEW" << std::endl;
    return -1;
  }

  //glfwGetFramebufferSize(window, &worldWidth, &worldHeight);


  setupOrthographicProjection(worldWidth, worldHeight);

  // Define the viewport dimensions
  glViewport(0, 0, worldWidth, worldHeight);

  // Set point size
  glPointSize(pixelSize); // Increase if you want the "pixel" to be bigger

  // Loop until the user closes the window
  while (!glfwWindowShouldClose(window) && !isCollision) {
    // Render here
    glClear(GL_COLOR_BUFFER_BIT);

    // Set the drawing color to blue
    glColor3f(1.0f, 0.0f, 1.0f); // RGB: Blue

    // Draw a point at the current position
    glBegin(GL_POINTS);
    glVertex2f(currX, currY); // Use the updated position
    glEnd();

    // Swap front and back buffers
    glfwSwapBuffers(window);

    // Poll for and process events
    glfwPollEvents();
  }

  glfwTerminate();
  return 0;
}