I am developing an application using GLFW, whereby the user can input some information into the console, the program does some processing on the information, then opens an opengl window (using GLFW) to display the results. The user can then close the window, and be returned to the main menu and enter more information if they want.
Currently the problem I'm having is that once closing the GLFW/OpenGL window the console no longer accepts any input from scanf(). I am fairly certain that I am closing GLFW properly, so I am unsure as to what the problem is.
The code I am using is below:
Main.c:
#include <stdio.h>
#include <stdlib.h>
#include "glfw.h"
#include "pantograph.h"
int main(int argc, char** argv)
{
printf("program start");
int a = 0;
scanf("%i",&a); //this works
printf("%c",a);
p_open_window(1000, 500, 0, "hi there");
int i = 0;
for(i=0;i<1000;i++)
{
p_begin_render();
glBegin(GL_POINTS);
glVertex2i(i,i/2);
glEnd();
scanf("%i",&a);
p_end_render();
}
p_close_window();
scanf("%i",&a); //this does not work
printf("%i",a);
return 0;
}
pantograph.h:
int p_open_window(int width, int height, int fullscreen, const char* title)
{
glfwInit();
glfwDisable(GLFW_AUTO_POLL_EVENTS);
if(fullscreen)
{
glfwOpenWindow(width,height,8,8,8,8,0,0,GLFW_FULLSCREEN);
}else{
glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE);
glfwOpenWindow(width,height,8,8,8,8,0,0,GLFW_WINDOW);
}
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return 1;
}
void p_begin_render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1.0, 1.0, 1.0, 1.0);
glLoadIdentity();
}
void p_end_render()
{
glfwSwapBuffers();
}
void p_close_window()
{
glfwCloseWindow();
glfwTerminate();
}
I'm a little confused by your program flow. You say 'the user can close the window and be returned to the main menu'. But how does the program exit from the (i<1000) loop? If the user just closes the window it seems like it would still be executing the for loop (especially because of the scanf inside the loop).
Have you used a debugger to see which point your program gets caught on?
Thanks to the people at #glfw I've managed to find a somewhat hackish solution...
If you "flush" the input buffer directly after closing the glfw window scanf will start to work again. I'm not entirely sure why, but it seems to work for now, so I'm satsfied.
The code I'm using to do it is as follows (after closing the window):
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
After this, scanf began working again.
Related
I'm creating OpenGL texture using default function glGenTextures. When OpenGL version set to 3.0 everything works fine, but when I override it with 4.2 glGenTextures starts to throw error #1282 (invalid operation). What i'm doing wrong?
Here's code segment I've tested:
#include "GL/freeglut.h"
#include "GL/gl.h"
#define MAJOR_GL_VERSION 3
#define MINOR_GL_VERSION 0
int w = 200;
int h = 200;
const char* title = "title";
int main(int argc, char const *argv[])
{
puts("Overriding default OpenGL version...");
glutInitContextVersion(MAJOR_GL_VERSION, MINOR_GL_VERSION);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA);
glutInitWindowSize(w, h);
glutCreateWindow(title);
printf("Using OpenGL Version: %s\n=========\n", (char*)glGetString(GL_VERSION));
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable( GL_ALPHA_TEST );
glEnable( GL_BLEND );
GLenum error;
GLuint id = 0;
glGenTextures(1, &id);
if((error = glGetError()) != GL_NO_ERROR || id == 0)
{
printf("Gl error: %s (errno %i)\n", gluErrorString(error), error);
return 0;
}
while (1) { }
return 0;
}
The error does probably not happen in the line you expect it to happen. Chances are high that some of the methods before glGenTextures is the problem. Neither of this lines
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_SMOOTH);
are allowed in a OpenGL Core Profile. Profiles were introduces in OpenGL 3.2, thus the Core Profile request does not have any effect when requesting a 3.0 context. But with 3.2+, you'll get a core profile which removed a lot of stuff.
You can either remove the lines mentioned above and replace them with a Core-Profile compatible code. Or you could explicitly request a compatibility profile (glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE) when you want to stick to the fixed function pipeline.
I worked with cairo and X11 before, and had a piece of code working perfectly, and now I am developping a new project (supposed to be a karaoke), and I took a piece of the code that was used to display something on the screen, which worked on the old project, but which doesn't work anymore.
I have been looking for a mistake all day and I must be missing something, because nothing works.
The code is the following.
A first function used to display some text :
void display_line(cairo_surface_t *surface, lyrics_line l)
{
cairo_t *cr;
cr=cairo_create(surface);
cairo_set_source_rgb(cr, 0, 0, 0); // Should paint the window black
cairo_paint(cr);
cairo_set_source_rgb(cr, 1., 1., 1.);
cairo_select_font_face(cr, "Hacker", CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 13);
cairo_move_to(cr, 620, 30);
char text[255];
strcpy(text, l.text);
cairo_show_text(cr, text); // Should print the text in white
cairo_destroy(cr);
printf("%s\n", text);
}
And the main function, that calls the previous one,
void display(song s)
{
// X11 display
Display *dpy;
Window rootwin;
Window win;
int scr;
// init the display
if(!(dpy=XOpenDisplay(NULL))) {
fprintf(stderr, "ERROR: Could not open display\n");
exit(1);
}
scr=DefaultScreen(dpy);
rootwin=RootWindow(dpy, scr);
win=XCreateSimpleWindow(dpy, rootwin, 1, 1, WINSIZEX, WINSIZEY, 0, BlackPixel(dpy, scr), BlackPixel(dpy, scr));
XStoreName(dpy, win, "Karaoke");
KeyPressMask|ButtonPressMask|ExposureMask);
XMapWindow(dpy, win);
// create cairo surface
cairo_surface_t *cs;
cs=cairo_xlib_surface_create(dpy, win, DefaultVisual(dpy, 0), WINSIZEX, WINSIZEY);
cairo_t *cr;
cr=cairo_create(cs);
cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
cairo_paint(cr); // Should fill the window in blue
cairo_destroy(cr);
int i;
printf("\n");
lyrics_line l = {"That's a test", 200};
display_line(cs, l);
usleep(s.text[0].length*10000);
for(i=0; i<s.length; i++)
{
display_line(cs, s.text[i]);
usleep((s.text[i+1].length - s.text[i].length)*10000);
}
cairo_surface_destroy(cs); // destroy cairo surface
XCloseDisplay(dpy); // close the display
}
I don't know if display_line causes a problem, because when I simply try to color the window in blue with displayit doesn't even work.
However, the lyrics do display in the console, so the algorithm is not the problem.
What could I be missing ?
Thanks in advance.
Here, I have two loops. The first loop processes the graphics for a few seconds and then the code goes to the second loop. I process the graphical events via glutMainLoopEvent in the first loop. Before the second loop starts, I would like to close the graphic window. It seems the command glutLeaveMainLoop cannot close the window. What other function should I use to force the window closed right after the first loop?
#include <stdio.h>
#include <GL/freeglut.h>
#include <boost/thread/thread.hpp> // for sleep
void cback_render()
{
if(!glutGetWindow())
return ;
static float rotations = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(rotations, 0, 0, 1);
glBegin(GL_TRIANGLES);
glVertex3f(0,0,0);
glVertex3f(1,0,0);
glVertex3f(0,1,0);
glEnd();
glutSwapBuffers();
if (++rotations > 360) rotations -= 360;
}
void timer(int )
{
if(!glutGetWindow())
return ;
glutPostRedisplay();
glutMainLoopEvent();
glutTimerFunc(30, timer, 1);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(512, 512);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutCreateWindow("freegluttest");
glutDisplayFunc (cback_render);
glutTimerFunc(30, timer, 1);
long i=0;
while(glutGetWindow() && i< 30)
{
printf("[%ld]\n",i);
i++;
glutMainLoopEvent();
boost::this_thread::sleep( boost::posix_time::milliseconds(100) );
}
glutMainLoopEvent();
glutLeaveMainLoop(); // does not work
glutMainLoopEvent();
// do something else ....
while(1)
{
// other calculations
boost::this_thread::sleep( boost::posix_time::milliseconds(100) );
}
return 0;
}
Ok from the freeglut docs at http://freeglut.sourceforge.net/docs/api.php#EventProcessing
The function you are using glutLeaveMainLoop() is to simply stop the glut's main loop, if it is started by glutMainLoop() not glutMainLoopEvent().
Since you are controlling the loop yourself in your example, glutLeaveMainLoop() won't do anything.
It is intended to leave glut's main loop IF glut is controlling it not you.
Since you have a while(1) at the end with a 100ms sleep, the app will do nothing else when it gets there after all the frames have been rendered. If you want to destroy the window use some window function like glutDestroyWindow().
I keep calling glutMainLoopEvent to process the graphics. However, after someone closed the window, I would like to exit the loop and show Code reached here. . it seems when a window is closed, an exit function is called and the entire application stops. While I need the application to continue. How should I fix the code?
#include <stdio.h>
#include <GL/freeglut.h>
//display function - draws a triangle rotating about the origin
void cback_render()
{
//keeps track of rotations
static float rotations = 0;
//OpenGL stuff for triangle
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(rotations, 0, 0, 1);
glBegin(GL_TRIANGLES);
glVertex3f(0,0,0);
glVertex3f(1,0,0);
glVertex3f(0,1,0);
glEnd();
//display on screen
glutSwapBuffers();
//rotate triangle a little bit, wrapping around at 360°
if (++rotations > 360) rotations -= 360;
}
void timer(int value )
{
glutPostRedisplay();
glutMainLoopEvent();
glutTimerFunc(30, timer, 1);
}
int main(int argc, char **argv)
{
//initialisations
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(512, 512);
//create window and register display callback
glutCreateWindow("freegluttest");
glutDisplayFunc (cback_render);
glutTimerFunc(30, timer, 1);
//loop forever
long i=0;
while(1)
{
printf("[%ld]\n",i);
i++;
glutMainLoopEvent();
}
printf("Code reached here.");
return 0;
}
Use GLUT_ACTION_ON_WINDOW_CLOSE to allow your program to continue when a window is closed.
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,
GLUT_ACTION_GLUTMAINLOOP_RETURNS);
Sources:
http://www.lighthouse3d.com/cg-topics/glut-and-freeglut/
http://freeglut.sourceforge.net/docs/api.php
I'm trying to use the Cairo graphics library on Linux in C to make a pretty lightweight x11 GUI.
After trying very hard to follow the woefully incomplete guide that cairo gives for x11, this is the best I've got:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/renderproto.h>
//This function should give us a new x11 surface to draw on.
cairo_surface_t* create_x11_surface(int x, int y)
{
Display* d;
Drawable da;
int screen;
cairo_surface_t* sfc;
if((d = XOpenDisplay(NULL)) == NULL)
{
printf("failed to open display\n");
exit(1);
}
screen = DefaultScreen(d);
da = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, x, y, 0, 0, 0);
XSelectInput(d, da, ButtonPressMask | KeyPressMask);
XMapWindow(d, da);
sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), x, y);
cairo_xlib_surface_set_size(sfc, x, y);
return sfc;
}
int main(int argc, char** argv)
{
//create a new cairo surface in an x11 window as well as a cairo_t* to draw
//on the x11 window with.
cairo_surface_t* surface = create_x11_surface(300, 200);
cairo_t* cr = cairo_create(surface);
while(1)
{
//save the empty drawing for the next time through the loop.
cairo_push_group(cr);
//draw some text
cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 32.0);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, 10.0, 25.0);
if((argc == 2) && (strnlen(argv[1], 100) < 50))
cairo_show_text(cr, argv[1]);
else
cairo_show_text(cr, "usage: ./p1 <string>");
//put the drawn text onto the screen(?)
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_flush(surface);
//pause for a little bit.
int c = getchar();
//change the text around so we can see the screen update.
for(int i = 0; i < strnlen(argv[1], 100); i++)
{
argv[1][i] = argv[1][i + 1];
}
if(c == 'q')
{
break;
}
}
cairo_surface_destroy(surface);
return 0;
}
On Linux systems that have Cairo installed, it can be compiled with
gcc -o myprog $(pkg-config --cflags --libs cairo x11) -std=gnu99 main.c
And it should be run with a single argument.
For reasons I don't understand at all, inserting the line
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_write_to_png (surface, "hello.png"); //<--------- inserted
cairo_surface_flush(surface);
Puts something on the screen, but there are 2 problems:
Text that I draw with this method is persistent, creating a smearing effect.
I don't want some .png file mediating between my program and an x11 window. Data should be sent directly!
Several issues:
In X11, the X11 server doesn't save what you drew to a window, but instead sends an ExposeEvent to your window that tells it to redraw. This means you get a black window, because you do not handle this event.
getchar only gives you something after a line break, so just typing something won't help.
libX11 buffers stuff and only sends it to the X11 server when you wait for an event (or the buffer fills up). Since you never wait for an event, it never flushes. Calling XFlush explicitly helps.
The group that you push is useless. Just get rid of it.
Your code to move the string one direction to the left easily goes beyond the end of the string. You apparently know this already, because you 'fixed' this with a strnlen.
Here is a little better solution, but it still gives you an initially black window, because you draw to it before it is mapped:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
//This function should give us a new x11 surface to draw on.
cairo_surface_t* create_x11_surface(Display *d, int x, int y)
{
Drawable da;
int screen;
cairo_surface_t* sfc;
screen = DefaultScreen(d);
da = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, x, y, 0, 0, 0);
XSelectInput(d, da, ButtonPressMask | KeyPressMask);
XMapWindow(d, da);
sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), x, y);
return sfc;
}
int main(int argc, char** argv)
{
Display *d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Failed to open display\n");
return 1;
}
//create a new cairo surface in an x11 window as well as a cairo_t* to draw
//on the x11 window with.
cairo_surface_t* surface = create_x11_surface(d, 300, 200);
cairo_t* cr = cairo_create(surface);
char *text = argv[1];
size_t text_len = 0;
if (argc != 2)
text = NULL;
else
text_len = strlen(text);
while(1)
{
// Clear the background
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
//draw some text
cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 32.0);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, 10.0, 25.0);
if (text)
cairo_show_text(cr, text);
else
cairo_show_text(cr, "usage: ./p1 <string>");
cairo_surface_flush(surface);
XFlush(d);
//pause for a little bit.
int c = getchar();
//change the text around so we can see the screen update.
memmove(text, &text[1], text_len);
if (text_len > 0)
text_len--;
printf("got char %c\n", c);
if(c == 'q')
{
break;
}
}
// XXX: Lots of other stuff isn't properly destroyed here
cairo_surface_destroy(surface);
return 0;
}
Edit: Also, why exactly do you feel like cairo only gives you a woefully incomplete guide? It tells you how to get the cairo parts working and it also explains you some parts about X11, even though you should already know those if you want to use cairo-x11. That's none of its business. The guide you linked to even provides a complete, working and self-contained example: https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c
I've you would have read the complete text of this "imcomplete guide" you would have seen that there is a link to the full sample: https://www.cypherpunk.at/files/2014/11/cairo_xlib_simple.c .