I am using the glc library to render font in the context of glfw window. However, I am not able to set co-ordinate to the font. It is always rendering the font at (0,0) position (i.e. at the below-left corner).
Below is the code to render sample string using GLC library,
int main(){
GLint ctx, myFont;
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
GLFWwindow* window = glfwCreateWindow(500, 500, "font rendering", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glfwSwapInterval(1);
if ( GLEW_OK != glewInit( ) )
{
std::cout << "Failed to initialize GLEW" << std::endl;
}
ctx = glcGenContext();
glcContext(ctx);
myFont = glcGenFontID();
glcNewFontFromFamily(myFont, "Palatino");
glcFontFace(myFont, "Normal");
glcFont(myFont);
glViewport(0, 0, 500, 500);
glMatrixMode(GL_PROJECTION); // make the projection matrix the current matrix
glLoadIdentity(); // init the projection matrix by the identity matrix
glOrtho(0.0, 500.0, 500.0, 0.0, -1.0, 1.0); // top-left (0, 0); bottom-right (500, 500)
glcScale(100,100);
glcRenderString("Sample Text");
glMatrixMode(GL_MODELVIEW); // make the modelview matrix the current matrix
glLoadIdentity(); // init the modelview matrix by the identity matrix
glfwSwapBuffers(window);
while(!glfwWindowShouldClose(window)){
}
Here, glTranslatef(100,100, 0); does not work and if I use glRasterPos3f(x,y,z); then nothing will get render onto the screen.
Did I miss something here?
The projection matrix describes how the objects are projected onto the viewport. If there is no projection matrix, the objects have to be setup in normalized device space where all coordinates are int the range [-1.0, 1.0].
Since you want to draw in 2D, I recommend to setup an orthographic projection, which maps the viewspace 1:1 to window coordinates.
Use glOrtho for this and use glMatrixMode to switch between the projection matrix stack and the modelview matrix stack:
glViewport(0, 0, 500, 500);
glMatrixMode(GL_PROJECTION); // make the projection matrix the current matrix
glLoadIdentity(); // init the projection matrix by the identity matrix
glOrtho(0.0, 500.0, 500.0, 0.0, -1.0, 1.0); // top-left (0, 0); bottom-right (500, 500)
glMatrixMode(GL_MODELVIEW); // make the modelview matrix the current matrix
glLoadIdentity(); // init the modelview matrix by the identity matrix
glcScale(100,100);
.....
glcRenderString renders a string by using glBitmap respectively glDrawPixels. Becaus of that the positon has to be set by glRasterPos.
If you want to render the string in red, then you have to skip the red an green color component. This can be done by glPixelTransfer.
e.g.
glPixelTransferf(GL_RED_SCALE, 1.0f);
glPixelTransferf(GL_GREE_SCALE, 0.0f);
glPixelTransferf(GL_BLUE_SCALE, 0.0f);
Related
The question asks to draw the rectangle when I press "r" in the keyboard. I try to write a function to draw this rectangle. The character call back function is correct and it gives me feedback that I already press "r". I don't know how to make the triangle appear. I added this line glfwSwapBuffers(window) in the function, but it's still not working. Thanks for help in advance.
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <cmath>
#include <iostream>
#define WINDOW_WIDTH 900
#define WINDOW_HEIGHT 600
float frameBuffer[WINDOW_HEIGHT][WINDOW_WIDTH][3];
bool mask[WINDOW_HEIGHT][WINDOW_WIDTH];
GLFWwindow *window;
void display()
{
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2i(50, 90);
glVertex2i(100, 90);
glVertex2i(100, 150);
glVertex2i(50, 150);
glEnd();
glFlush();
}
void CharacterCallback(GLFWwindow* lWindow, unsigned int key)
{
if(char(key) == 'r')
display();
}
void Init()
{
glfwInit();
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "- <xx>", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSetCharCallback(window, CharacterCallback);
glewExperimental = GL_TRUE;
glewInit();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
ClearFrameBuffer();
}
int main()
{
Init();
while (glfwWindowShouldClose(window) == 0)
{
glClear(GL_COLOR_BUFFER_BIT);
Display();
glFlush();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
When you draw by glBegin/glEnd sequences, then each vertex coordinate is transformed by the current view matrix and current projection matrix.
When you draw a scene, then after the transformations, the coordinates of the geometry have to be in clip space respectively normalized device space. The normalized device space is a cubic volume, with the left bottom front (-1, -1, -1) and right top far (1, 1, 1). All the geometry which is in this cube is "visible" on the viewport. All the geometry which is out of this cube is clipped.
If you want to draw a scene by using window ("pixel") coordinates, then you've to setup an orthographic projection by glOrtho. At Orthographic Projection, the view space coordinates are linearly transformed to the clip space coordinates. This means orthographic projection matrix can be used to scale the view space coordinates. e.g.:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble)WINDOW_WIDTH, (GLdouble)WINDOW_HEIGHT, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
You can do this at the end of Init().
I made a simple OpenGL program that draws a 2D texture to the screen. When you resize the window, it doesn't adjust properly, so to fix that, I would just run the projection matrix code again:
if (windowSizeChange)
{
std::cout << "Window resized." << std::endl;
std::cout << windowWidth << " " << windowHeight << std::endl;
windowSizeChange = false;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
However, running this code warps the image. To my understanding, to make it so I can draw 2D-like on the screen, my texture is drawn using an orthographic projection matrix which means there is a plane that is "parallel" with the window port or something like that which I draw on. When I try to re-make it to accommodate for the new window size, it doesn't adjust properly. What's going wrong with this code?
In your code you're changing the ortho matrix, but you also need to change the glViewport:
if (windowSizeChange)
{
glViewport(0, 0, windowWidth, windowHeight); // <-- Add this
std::cout << "Window resized." << std::endl;
std::cout << windowWidth << " " << windowHeight << std::endl;
windowSizeChange = false;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
Orthographic matrices are, like you said, just a matrix that in this case is parallel to the screen. When we call glOrtho, it changes the size of the matrix we're working with, and glViewport tells openGL the size of the viewport (in this case, our window) we're working with. You'll generally want glOrtho and glViewport to be the same dimensions
When the size of the window and the framebuffer has been changed, then you have to adjust the viewport rectangle.
The viewport rectangle can be set by glViewport and specifies how the normalized device coordinates are mapped to window coordinates. It defines the area of the framebuffer, where the normalized device coordinates from (-1, -1) to (1, 1) are mapped to.
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, windowWidth, windowHeight, 0.0, -1.0, 1.0);
My 3D world draws perfectly every time but the 2D text never draws. The code below features my latest effort using a tutorial from lighthouse3D. I get the feeling its something stupidly simple and im just not seeing it.
Rendering code :
void ScreenGame::draw(SDL_Window * window)
{
glClearColor(0.5f,0.5f,0.5f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set up projection matrix
glm::mat4 projection(1.0);
projection = glm::perspective(60.0f,800.0f/600.0f,1.0f,150.0f);
rt3d::setUniformMatrix4fv(shaderProgram, "projection", glm::value_ptr(projection));
GLfloat scale(1.0f); // just to allow easy scaling of complete scene
glm::mat4 modelview(1.0); // set base position for scene
mvStack.push(modelview);
mvStack.top() = glm::lookAt(camera->getEye(),camera->getAt(),camera->getUp());
glm::vec4 tmp = mvStack.top()*lightPos;
light0.position[0] = tmp.x;
light0.position[1] = tmp.y;
light0.position[2] = tmp.z;
rt3d::setLightPos(shaderProgram, glm::value_ptr(tmp));
glUseProgram(skyBoxShader); // Switch shaders, reset uniforms for skybox
rt3d::setUniformMatrix4fv(skyBoxShader, "projection", glm::value_ptr(projection));
glDepthMask(GL_FALSE); // make sure depth test is off
glm::mat3 mvRotOnlyMat3 = glm::mat3(mvStack.top());
mvStack.push( glm::mat4(mvRotOnlyMat3) );
skyBox->draw(mvStack); // drawing skybox
mvStack.pop();
glDepthMask(GL_TRUE); // make sure depth test is on
mvStack.top() = glm::lookAt(camera->getEye(),camera->getAt(),camera->getUp());
glUseProgram(shaderProgram); // Switch back to normal shader program
rt3d::setUniformMatrix4fv(shaderProgram, "projection", glm::value_ptr(projection));
rt3d::setLightPos(shaderProgram, glm::value_ptr(tmp));
rt3d::setLight(shaderProgram, light0);
// Draw all visible objects...
Ball->draw(mvStack);
ground->draw(mvStack);
building1->draw(mvStack);
building2->draw(mvStack);
setOrthographicProjection();
glPushMatrix();
glLoadIdentity();
renderBitmapString(5,30,1,GLUT_BITMAP_HELVETICA_18,"Text Test");
glPopMatrix();
restorePerspectiveProjection();
SDL_GL_SwapWindow(window); // swap buffers
}
using the following methods :
void setOrthographicProjection() {
// switch to projection mode
glMatrixMode(GL_PROJECTION);
// save previous matrix which contains the
//settings for the perspective projection
glPushMatrix();
// reset matrix
glLoadIdentity();
// set a 2D orthographic projection
glOrtho(0.0F, 800, 600, 0.0F, -1.0F, 1.0F);
// switch back to modelview mode
glMatrixMode(GL_MODELVIEW);
}
void restorePerspectiveProjection() {
glMatrixMode(GL_PROJECTION);
// restore previous projection matrix
glPopMatrix();
// get back to modelview mode
glMatrixMode(GL_MODELVIEW);
}
void renderBitmapString(
float x,
float y,
int spacing,
void *font,
char *string) {
char *c;
int x1=x;
for (c=string; *c != '\0'; c++) {
glRasterPos2f(x1,y);
glutBitmapCharacter(font, *c);
x1 = x1 + glutBitmapWidth(font,*c) + spacing;
}
}
I need to draw a cube and project it with the default projection matrix. Also, I want to draw a hud controlling the orientation of the sphere. The hud is projected with another projection matrix.
render()
{
DrawGUI(); // project GUI with another projection matrix
glPushMatrix();
glutSolidCube(); // project the cube with the default projection matrix
glPopMatrix();
glutSwapBuffers();
}
reshape()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
...
}
DrawGUI()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(...); // project the GUI with this matrix
glMatrixMode(GL_MODELVEIW);
glPushMatrix();
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
#define BUFFER_LENGTH 64
void processSelection(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and save the matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glRenderMode(GL_SELECT);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glOrtho (-100, 100, -100, 100, -100, 100); // this line of code is the most
glMatrixMode(GL_MODELVIEW);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
// Restore the projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
The render part works well. Both the GUI and the cube are drawn without problem. However, the selection does not work as intended.
My question is: Since I project 3D models with different projection matrix, how should I deal with selection? I try to implement the typical selection buffer approach, but every time I click in the window, the selection buffer always contains the GUI even if I do not click on the GUI. Also, if I click on the cube, the selection buffer ends up with both the cube and the GUI.
If you use the selection buffer approach, you render with mixed projections as you do when doing the usual render. The only difference, is, that you apply that pick matrix as well. Also don't try to be too clever with the matrix pushing / poping. It rarely makes sense to use that in the projection matrix stack (hence it requires to have only 2 push levels, instead of the 32 for the modelview). Also don't use the reshape function to define the projection matrix.
DrawCube()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glutSolidCube();
}
DrawGUI()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
}
void render()
{
// base the projection on whats already in the projection
// matrix stack. For normal render this is identity, for
// selection it is a pick matrix.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluOrtho2D(...); // project the GUI with this matrix
DrawGUI();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(...);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
render();
glutSwapBuffers();
}
#define BUFFER_LENGTH 64
void select(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and augment it with a picking matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glRenderMode(GL_SELECT);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
}
Note that OpenGL selection mode is usually not GPU accelerated and hence very slow. Also it's been deprecated and removed from modern OpenGL versions. It's highly recommended to use either index buffer selection (i.e. render each object with a dedicated index "color") or perform manual ray-intersection picking into the scene data.
How to move a 2D object in the direction of a point (not a GL_POINTS, but coordinates) using OpenGL?
For a better understanding of my code:
I've splited most of my code into different source codes, but this is the one that is actually creating the shapes and setting the scene:
void setupScene(int clearColor[]) {
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
//glClearColor(250, 250, 250, 1.0); // Set the cleared screen colour to black.
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); // This sets up the viewport so that the coordinates (0, 0) are at the top left of the window.
// Set up the orthographic projection so that coordinates (0, 0) are in the top left.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, -10, 10);
// Back to the modelview so we can draw stuff.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the screen and depth buffer.
}
void drawScene() {
setupScene((int[]){250, 250, 250, 1});
triangle(210, WINDOW_WIDTH, WINDOW_HEIGHT);
glBegin(GL_QUADS);
glColor3f(RGB(80), RGB(80), RGB(80));
glPushMatrix();
glTranslatef(400, 400, 0);
glVertex2d(200, 100);
glVertex2d(100, 100);
glVertex2d(100, 200);
glVertex2d(200, 200);
glPopMatrix();
glEnd();
glutSwapBuffers(); // Send the scene to the screen.
}
void update(int value) {
glutPostRedisplay(); // Tell GLUT that the display has changed.
glutTimerFunc(25, update, 0); // Tell GLUT to call update again in 25 milliseconds.
}
You need to translate the modelview matrix. Assuming you're in modelview mode already:
glPushMatrix();
glTranslatef(x, y, z);
// Draw your shape
glPopMatrix();
[Edit]
#paddy: Something like this? I tried this but the square isn't moving.
pastebin.com/2PCsy5kC
Try explicitly selecting the modelview matrix. Your example does not tell us which mode it's currently in:
glSetMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x, y, z);
// Draw your shape
glPopMatrix();
Normally at the beginning of your render you reset everything... So you enter the GL_PROJECTION mode, call glLoadIdentity() to reset it and set up your camera, then do this for the GL_MODELVIEW matrix as well.
Answer on the behalf of the OP:
Thanks #paddy, I was trying to understand the use of glTranslatef and came with the solution. Here is the working code, it will create a square at 100x100 and will move it until 400x200:
void setupScene(int clearColor[]) {
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
//glClearColor(250, 250, 250, 1.0); // Set the cleared screen colour to black.
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); // This sets up the viewport so that the coordinates (0, 0) are at the top left of the window.
// Set up the orthographic projection so that coordinates (0, 0) are in the top left.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, -10, 10);
// Back to the modelview so we can draw stuff.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the screen and depth buffer.
}
int a = 100;
int b = 200;
int x = 100;
int y = 100;
void drawScene() {
setupScene((int[]){250, 250, 250, 1});
triangle(210, WINDOW_WIDTH, WINDOW_HEIGHT);
glPushMatrix();
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
glColor3f(RGB(80), RGB(80), RGB(80));
glVertex2d(b, a);
glVertex2d(a, a);
glVertex2d(a, b);
glVertex2d(b, b);
glEnd();
glPopMatrix();
glutSwapBuffers(); // Send the scene to the screen.
}
void update(int value) {
if (x != 400 && y != 200) {
x += 4;
y += 2;
}
glutPostRedisplay(); // Tell GLUT that the display has changed.
glutTimerFunc(25, update, 0); // Tell GLUT to call update again in 25 milliseconds.
}