My GLFW window is displaying whatever is behind it - c

This is the code I am using
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
int main(){
if(!glfwInit()){
fprintf(stderr,"failed glfw initialization");
return -1;
}
GLFWwindow* window = glfwCreateWindow(800,800,"i hope this works",NULL,NULL);
if (!window){
fprintf(stderr,"window creation failed");
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = 1;
if(glewInit() != GLEW_OK){
fprintf(stderr,"glew failed to initialize");
return -1;
}
while(!glfwWindowShouldClose(window)){
}
}
Whenever I run the program, the window shows up, but it has the image of whatever was behind it when the window was opened.
Sometimes it changes when I resize or move the window.

You need to clear your buffers. If you're using two buffers then write:
// Render
// Clear the colorbuffer
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
at the beginning of you Game Loop.
Also write:
// Swap the screen buffers
glfwSwapBuffers(window);
at the end of your Game Loop.
So all together:
while(!glfwWindowShouldClose(window)){
// Render
// Clear the colorbuffer
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* ... Code ... */
// Swap the screen buffers
glfwSwapBuffers(window);
}

Related

OpenGL Black Screen on M2 Macbook

I have been trying to create a basic OpenGL program in C to display a triangle. Except all I am getting is a black screen.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include <GL/glew.h>
#define GL_SILENCE_DEPRECATION
#include "win.h"
#include "shaders/cshader.h"
#include "glew.h"
#define GLFW_INCLUDE_GLCOREARB
#include "glfw3.h"
#include <OpenGL/gl3.h>
int main(void) {
if( !glfwInit()) {
fprintf( stderr, "Failed to initialize GLFW\n" );
return -1;
}
// create window
GLFWwindow* window = createWindow(1280,720);
glewExperimental=GL_TRUE; // Needed in core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
// This will identify our vertex buffer
GLuint vertexbuffer;
// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &vertexbuffer);
// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
// Give our vertices to OpenGL.
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
Shader shader = ShaderInit();
shader.Load(&shader,"/Users/***/Desktop/coding/gl_test/shaders/tri.vert","/Users/***/Desktop/coding/gl_test/shaders/tri.frag");
glUseProgram(shader.program);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glfwMakeContextCurrent(window);
do{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
// Starting from vertex 0; 3 vertices total -> 1 triangle
glUseProgram(shader.program);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
// Swap buffers
if (glGetError() != GL_NO_ERROR){
printf("Err");
}
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
return 0;
}
win.c
#include <stdio.h>
#include <stdlib.h>
#include "/Users/***/Downloads/glew-2.1.0/include/GL/glew.h"
#include "/opt/homebrew/Cellar/glfw/3.3.8/include/GLFW/glfw3.h"
GLFWwindow* createWindow(int WIDTH, int HEIGHT){
glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // We want OpenGL 4.1
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
// Open a window and create its OpenGL context
GLFWwindow* window; // (In the accompanying source code, this variable is global for simplicity)
window = glfwCreateWindow( WIDTH, HEIGHT, "graphic", NULL, NULL);
if( window == NULL ){
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible.\n" );
glfwTerminate();
return NULL;
}
glfwMakeContextCurrent(window);// Initialize GLEW
glfwPollEvents();
return window;
}
The shader program is basic and it compiles and links correctly. I have a vertex and fragment shader that should make the triangle red.
Even if it is broken, I should still be getting a colored screen because of glClear and glClearColor.
I have tried changing opengl versions as well as linking different files, but nothing shows up.
Here is my makefile:
LIBS=-L/opt/homebrew/lib -L/Users/***/Downloads/glew-2.1.0/lib -lGL -lglew
INC=-I/Users/***/Downloads/glew-2.1.0/include
main:
gcc main.c win.c shaders/cshader.c `pkg-config --cflags glfw3` $(LIBS) $(INC) -g -Wall -framework Cocoa -framework OpenGL `pkg-config --libs glfw3` -o test
Everything appears to link and compile without errors. What should I do.
(I know OpenGL is deprecated on new MacOS versions, but lots of people say that at least basic functionality still works)

Continue program even after openGL window closed

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

OpenGL4 gl_texture_2d_array won't display

I want to get started with modern OpenGL while reading the superbible book by coding a cellular automata using a 2d-array texture of size 1280x1280x2 and computing the next state to another layer in a compute shader. The idea is impiously stolen from glumpy examples.
However, while having such ambition in mind, I got confused at even trying to display it, not even passing the samplers into shaders.
Below I included both, the generator, which works OK, and the piece of code that does contain a problem.
gen
#!/usr/bin/env perl
use strict;
use warnings;
sub get_arg {
return (scalar #ARGV == 0) ? shift : shift #ARGV;
}
my $size = get_arg 1280;
my $rate = get_arg ($size >> 1);
my $symbol = (sub { ((shift) < $rate) ? '*' : '_' } );
print "$size\n";
for (0..$size) {
print $symbol->(int(rand() * $size)) for (0..$size);
print "\n";
}
code
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
// including opengl libraries on linux/osx
//include glew
#include <GL/glew.h>
//include opengl
#if defined (__APPLE_CC__)
#include <OpenGL/gl3.h>
#else
#include <GL/gl3.h> /* assert OpenGL 3.2 core profile available. */
#endif
//include glfw3
#define GLFW_INCLUDE_GL3 /* don't drag in legacy GL headers. */
#define GLFW_NO_GLU /* don't drag in the old GLU lib - unless you must. */
#include <GLFW/glfw3.h>
// ----------- the program itself
GLFWwindow *g_window;
#define SIZE 1280
#define WIDTH SIZE
#define HEIGHT SIZE
#define DEPTH 2
init_glfw(const char *name) {
// start GL context and O/S window using the GLFW helper library
assert(glfwInit());
#if defined(__APPLE_CC__)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
g_window = glfwCreateWindow(WIDTH, HEIGHT, name, NULL, NULL);
assert(g_window != NULL);
glfwMakeContextCurrent(g_window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
typedef enum { FILLED = '*', EMPTY = '_' } SYMBOL;
load_array(GLubyte array[SIZE * SIZE * DEPTH], FILE *stream) {
static char c;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
bool approved = false;
GLubyte *it = &array[SIZE * i + j];
while(!approved) {
approved = true;
c = getc(stream);
assert(c != EOF);
switch(c) {
case FILLED:
*it = 0x00;
break;
case EMPTY:
*it = 0xff;
break;
default:
approved = false;
break;
}
}
assert(*it == 0x00 || *it == 0xff);
it[SIZE * SIZE] = it[0];
}
}
}
GLuint create_2d_texture() {
static GLuint texture = 0;
assert(texture == 0);
static GLubyte field[SIZE * SIZE << 1];
load_array(field, stdin);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_ALPHA8, SIZE, SIZE, DEPTH);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, SIZE, SIZE, DEPTH, GL_ALPHA, GL_UNSIGNED_BYTE, field);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
return texture;
}
display() {
GLuint texture = create_2d_texture();
assert(texture != 0);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
while(!glfwWindowShouldClose(g_window)) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glPushMatrix();
glEnable(GL_TEXTURE_2D_ARRAY);
glBegin(GL_QUADS);
glTexCoord3s(0, SIZE, 0); glVertex3f( 0.0f, 0.0f, 0.0 );
glTexCoord3s(SIZE, SIZE, 0); glVertex3f( SIZE, 0.0f, 0.0 );
glTexCoord3s(0, SIZE, 0); glVertex3f( SIZE, SIZE, 0.0 );
glTexCoord3s(0, 0, 0); glVertex3f( 0.0f, SIZE, 0.0 );
glEnd();
glPopMatrix();
glfwSwapBuffers(g_window);
glfwPollEvents();
if(glfwGetKey(g_window, GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(g_window, 1);
}
}
}
main() {
init_glfw("I want to display a texture");
display();
glfwDestroyWindow(g_window);
glfwTerminate();
}
Could you help me to analyse the issues with displaying the 2d array on the screen, please? What I am trying to achieve is to make the whole window randomly black-and-white, but so far I ended up completely confused just adding more layers from googled solutions and man pages.
I am not asking for a working code, just a comprehensible explanation which would help me to get through this problem.
glEnable(GL_TEXTURE_2D_ARRAY);
That gave you an OpenGL error. Even in compatibility profiles, you cannot enable an array texture of any kind. Why?
Because you cannot used fixed-function processing with array textures at all. You cannot use glTexEnv to fetch from an array texture. They're wholly and completely shader-based constructs.
So if you want to use an array texture, you must use a shader.

How to draw on a texture using SDL2_gfx in SDL2 and then render?

I want to implement a MS-Paint-like program (although my actual program will do more than this) where one can draw using mouse.
I am using SDL2 and also SDL2_gfx.
I want to maintain an SDL_Texture where the user will do the drawing in a continuously way without clearing (unless requested by the user) at any time.
And then continuously update the SDL_Texture on to the screen.
My question specifically is how to draw SDL2_gfx primitives on the SDL_Texture and copy that to the renderer. Any completely different way than to use texture will also do for me but must be using SDL2.
Below is a minimal runnable extraction from my code:
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <SDL2/SDL.h>
#include <SDL2_gfxPrimitives.h>
#define WIDTH (320)
#define HEIGHT (240)
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_RendererInfo rendererInfo;
SDL_Texture* texture = NULL;
SDL_Event event;
Sint16 cx = WIDTH/2, cy = HEIGHT/2;
uint8_t quit = 0;
void init()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, SDL_WINDOW_OPENGL, &window, &renderer);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT); // create texture to draw on to
// SDL_SetRenderTarget(renderer, texture); // this one I have removed
}
void draw()
{
pixelRGBA(renderer, cx, cy, 0xff, 0xff, 0x00, 0xff); // draw a pixel here, or whatever cx and cy are mouse position
// what I want is to draw on to the texture, and not directly on the screen buffer
}
void render()
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // set clear color
SDL_RenderClear(renderer); // clear the buffer
SDL_RenderCopy(renderer, texture, NULL, NULL); // now copy the drawn texture to the buffer
SDL_RenderPresent(renderer); // now update window
}
int main(int argc, char* argv[])
{
int p;
init();
while(!quit)
{
SDL_PumpEvents();
p = SDL_PollEvent(&event);
if(p>0)
{
if(event.type==SDL_QUIT) quit = 1;
else
{
// here other things are there to handle the mouse positions etc for drawing exactly what the user wants
// ...
draw();
render();
}
}
}
SDL_Quit();
return 0;
}
Thanks in advance.

Why glClear doesn't clear my screen?

Here is a simple opengl program by me. I'm trying to clear the screen before I draw a triangle. I've called glClear() in my init() function, however, it seemed that it failed to clear the screen.
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
void myIdleFunc()
{
glBegin(GL_TRIANGLES);
{
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
}
glEnd();
glFlush();
usleep(1000000);
}
void init()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE);
glutCreateWindow("Hello, World!");
init();
glutIdleFunc(myIdleFunc);
glutMainLoop();
return 1;
}
Here is a screen-shot, the text is from the gnome terminal in the back ground.
Where's your display callback? You shouldn't use the idle function for drawing.
All drawing needs to take place in the appropriate callbacks, the GL context might not be active until glutMainLoop starts running, and with no active context, your commands simply get ignored (without a context, there might not even be a place to store errors for retrieval with glGetError).
NOTE: Usually you want to clear the buffer at the beginning of every frame. You might get away with clearing just once with single-buffering, but double-buffering is better and requires you to somehow render the entire area between each swap.
Your problem is, that you do clear the screen in your initialization code. But you need to clear it every frame, so right at the start of your display (or in your case idle) function.
I don't use GLUT but a really simple way to display something like this is:
while( !done ) { /* Loop until done. Do drawing. */
glClear( GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glBegin(GL_TRIANGLES);
{
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
}
glEnd();
glFlush();
SwapBuffers( );
etc... event handling....
}
Run this code and probably you will get the solution.
#include<GL/gl.h>
#include<GL/glut.h>
#include<stdio.h>
double x_0 = -100;
double y_0 = -25;
double x_1 = 100;
double y_1 = -25;
double x_2 = 100;
double y_2 = 25;
double x_3 = -100;
double y_3 = 25;
void
init(void)
{
/*initialize the x-y co-ordinate*/
glClearColor(0,0,0,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-320, 319,-240, 239);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
void
drawRectangle()
{
glBegin(GL_LINES);
glVertex2d(x_0, y_0);
glVertex2d(x_1, y_1);
glVertex2d(x_1, y_1);
glVertex2d(x_2, y_2);
glVertex2d(x_2, y_2);
glVertex2d(x_3, y_3);
glVertex2d(x_3, y_3);
glVertex2d(x_0, y_0);
glEnd();
glFlush();
}
int
main(int argc, char *argv[])
{
double x_0, y_0, x_1, y_1;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(400, 400);
glutCreateWindow("Clear Screen");
init();
drawRectangle();
/* clear the screen. You can uncomment following three lines to view the effect of clearing */
// glClearColor(0, 0, 0, 0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// /* don't forget to flush */
// glFlush();
/***/
glutMainLoop();
}
Compile and run -
gcc file.c -lglut -lGLU -lGL
./a.out

Resources