#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_Light_Button.H>
#include <FL/Fl_Text_Display.H>
#include <FL/Fl_Text_Buffer.H>
#include <FL/Fl_Button.H>
#if defined(__APPLE__)
# include <OpenGL/gl3.h>
#else
# include <GL/glew.h>
#endif
#include <FL/gl.h>
void add_output(const char *format, ...);
class SimpleGL3Window : public Fl_Gl_Window {
GLuint shaderProgram;
GLuint vertexArrayObject;
GLuint vertexBuffer;
GLint positionUniform;
GLint colourAttribute;
GLint positionAttribute;
int gl_version_major;
public:
SimpleGL3Window(int x, int y, int w, int h) : Fl_Gl_Window(x, y, w, h) {
mode(FL_RGB8 | FL_DOUBLE | FL_OPENGL3);
shaderProgram = 0;
gl_version_major = 0;
}
void draw(void) FL_OVERRIDE {
if (gl_version_major >= 3 && !shaderProgram) {
// Initialize shaders
GLuint vs, fs;
int Mslv, mslv;
sscanf((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), "%d.%d", &Mslv, &mslv);
add_output("Shading Language Version=%d.%d\n", Mslv, mslv);
// Vertex shader
const char *vss_format = "#version %d%d\n"
"uniform vec2 p;"
"in vec4 position;"
"in vec4 colour;"
"out vec4 colourV;"
"void main (void) {"
" colourV = colour;"
" gl_Position = vec4(p, 0.0, 0.0) + position;"
"}";
char vss_string[300];
snprintf(vss_string, 300, vss_format, Mslv, mslv);
const char *vss = vss_string;
// Fragment shader
const char *fss_format = "#version %d%d\n"
"in vec4 colourV;"
"out vec4 fragColour;"
"void main(void) {"
" fragColour = colourV;"
"}";
char fss_string[200];
snprintf(fss_string, 200, fss_format, Mslv, mslv);
const char *fss = fss_string;
// Compile vertex shader
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vss, NULL);
glCompileShader(vs);
// Compile fragment shader
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fss, NULL);
glCompileShader(fs);
// Link program
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glBindFragDataLocation(shaderProgram, 0, "fragColour");
glLinkProgram(shaderProgram);
// Get attribute/uniform locations
positionUniform = glGetUniformLocation(shaderProgram, "p");
colourAttribute = glGetAttribLocation(shaderProgram, "colour");
positionAttribute = glGetAttribLocation(shaderProgram, "position");
glDeleteShader(vs);
glDeleteShader(fs);
// Upload vertex data (position + color)
GLfloat vertexData[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Red
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, // Green
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Blue
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f // White
};
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 4*8*sizeof(GLfloat), vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray((GLuint)positionAttribute);
glEnableVertexAttribArray((GLuint)colourAttribute);
glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE,
8*sizeof(GLfloat), 0);
glVertexAttribPointer((GLuint)colourAttribute, 4, GL_FLOAT, GL_FALSE,
8*sizeof(GLfloat), (char*)0 + 4*sizeof(GLfloat));
glUseProgram(shaderProgram);
}
else if (!valid()) {
glViewport(0, 0, pixel_w(), pixel_h());
}
// Clear and draw
glClearColor(0.08f, 0.8f, 0.8f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (shaderProgram) {
GLfloat p[] = {0, 0};
glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
// Draw FLTK child widgets on top
Fl_Gl_Window::draw();
}
int handle(int event) FL_OVERRIDE {
static int first = 1;
if (first && event == FL_SHOW && shown()) {
first = 0;
make_current();
#ifndef __APPLE__
GLenum err = glewInit();
if (err) Fl::warning("glewInit() failed returning %u", err);
else add_output("Using GLEW %s\n", glewGetString(GLEW_VERSION));
#endif
const uchar *glv = glGetString(GL_VERSION);
add_output("GL_VERSION=%s\n", glv);
sscanf((const char *)glv, "%d", &gl_version_major);
if (gl_version_major < 3) {
add_output("\nThis platform does not support OpenGL V3\n");
mode(mode() & ~FL_OPENGL3);
}
redraw();
}
int retval = Fl_Gl_Window::handle(event);
if (retval) return retval;
// Handle mouse clicks to interact with scene
if (event == FL_PUSH && gl_version_major >= 3) {
add_output("Mouse clicked in GL window\n");
redraw();
return 1;
}
return retval;
}
void reset(void) {
shaderProgram = 0;
gl_texture_reset();
}
};
Fl_Text_Display *output;
void add_output(const char *format, ...) {
va_list args;
char line_buffer[10000];
va_start(args, format);
vsnprintf(line_buffer, sizeof(line_buffer)-1, format, args);
va_end(args);
output->buffer()->append(line_buffer);
output->scroll(10000, 0);
output->redraw();
}
void button_cb(Fl_Widget *widget, void *) {
add_output("Button '%s' clicked\n", widget->label());
}
void add_widgets(Fl_Gl_Window *g) {
Fl::set_color(FL_FREE_COLOR, 255, 255, 255, 140);
g->begin();
Fl_Button* b = new Fl_Button(0, 0, 60, 30, "button");
b->color(FL_FREE_COLOR);
b->box(FL_DOWN_BOX);
b->callback(button_cb, NULL);
Fl_Button* b2 = new Fl_Button(0, 170, 60, 30, "button2");
b2->color(FL_FREE_COLOR);
b2->box(FL_BORDER_BOX);
b2->callback(button_cb, NULL);
g->end();
}
int main(int argc, char **argv) {
Fl::use_high_res_GL(1);
Fl_Window *topwin = new Fl_Window(800, 300);
SimpleGL3Window *win = new SimpleGL3Window(0, 0, 300, 300);
win->end();
output = new Fl_Text_Display(300, 0, 500, 280);
output->buffer(new Fl_Text_Buffer());
add_widgets(win);
topwin->end();
topwin->resizable(win);
topwin->label("OpenGL 3 Demo - Click GL panel");
topwin->show(argc, argv);
return Fl::run();
}