Added support for OpenGL V3 and higher.

On the X11/MSWindows platforms, this requires external installation of the GLEW library.
This fixes STR#3198 and STR#3257.
Added two new examples programs.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10876 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2015-10-27 08:40:56 +00:00
parent 43e4f8a661
commit 7e025aac22
6 changed files with 493 additions and 4 deletions

View File

@ -1094,7 +1094,8 @@ enum Fl_Mode {
FL_RGB8 = 64, FL_RGB8 = 64,
FL_MULTISAMPLE= 128, FL_MULTISAMPLE= 128,
FL_STEREO = 256, FL_STEREO = 256,
FL_FAKE_SINGLE = 512 // Fake single buffered windows using double-buffer FL_FAKE_SINGLE = 512, // Fake single buffered windows using double-buffer
FL_OPENGL3 = 1024
}; };
// image alpha blending // image alpha blending

View File

@ -149,6 +149,7 @@ public:
- \c FL_DEPTH - depth buffer - \c FL_DEPTH - depth buffer
- \c FL_STENCIL - stencil buffer - \c FL_STENCIL - stencil buffer
- \c FL_MULTISAMPLE - multisample antialiasing - \c FL_MULTISAMPLE - multisample antialiasing
- \c FL_OPENGL3 - use OpenGL version 3.0 or more when running Mac OS.
FL_RGB and FL_SINGLE have a value of zero, so they FL_RGB and FL_SINGLE have a value of zero, so they
are "on" unless you give FL_INDEX or FL_DOUBLE. are "on" unless you give FL_INDEX or FL_DOUBLE.
@ -167,6 +168,19 @@ public:
mode() must not be called within draw() since it mode() must not be called within draw() since it
changes the current context. changes the current context.
\note On the <b>MSWindows and Unix/Linux platforms</b>, FLTK produces
contexts for the highest OpenGL version supported by the hardware. Such contexts
are also compatible with lower OpenGL versions. On the <b>Apple OS X
platform</b>, it is necessary to decide whether the source code targets
OpenGL versions higher or lower than 3.0. By default, FLTK
creates contexts adequate for OpenGL versions 1 and 2. To get contexts
for OpenGL 3.0 or higher, the <tt>FL_OPENGL3</tt> flag and Mac OS
version 10.7 or higher are required (in that case the context is NOT
compatible with OpenGL versions 1 or 2). The <tt>FL_OPENGL3</tt> flag has no
effect on non-Apple platforms.
\version the <tt>FL_OPENGL3</tt> flag appeared in version 1.3.4
*/ */
int mode(int a) {return mode(a,0);} int mode(int a) {return mode(a,0);}
/** Set the OpenGL capabilites of the window using platform-specific data. /** Set the OpenGL capabilites of the window using platform-specific data.
@ -179,8 +193,6 @@ public:
<p><b>Mac OS X platform</b>: attributes belong to the <tt>CGLPixelFormatAttribute</tt> enumeration <p><b>Mac OS X platform</b>: attributes belong to the <tt>CGLPixelFormatAttribute</tt> enumeration
(defined by including <tt><OpenGL/OpenGL.h></tt>, e.g., <tt>kCGLPFADoubleBuffer</tt>) (defined by including <tt><OpenGL/OpenGL.h></tt>, e.g., <tt>kCGLPFADoubleBuffer</tt>)
and may be followed by adequate attribute values. and may be followed by adequate attribute values.
The pair <tt>kCGLPFAOpenGLProfile, kCGLOGLPVersion_3_2_Core</tt> allows to create an OpenGL V3.2 profile
under Mac OS X 10.7 and above (and include <OpenGL/gl3.h> to define OpenGL 3 symbols).
*/ */
int mode(const int *a) {return mode(0, a);} int mode(const int *a) {return mode(0, a);}
/** Returns a pointer to the GLContext that this window is using. /** Returns a pointer to the GLContext that this window is using.

View File

@ -449,6 +449,73 @@ The \p scene() method sets the scene to be drawn. The scene is
a collection of 3D objects in a \p csGroup. The scene is redrawn a collection of 3D objects in a \p csGroup. The scene is redrawn
after this call. after this call.
\section opengl3 Using OpenGL 3.0 (or higher versions)
The examples subdirectory contains OpenGL3test.cxx, a toy program
showing how to use OpenGL 3.0 (or higher versions) with FLTK in a cross-platform fashion.
It contains also OpenGL3-glut-test.cxx which shows how to use FLTK's GLUT compatibility
and OpenGL 3.
<b>On the MSWindows and Unix/Linux platforms</b>, FLTK creates contexts implementing
the highest OpenGL version supported by the hardware,
which are also compatible with lower OpenGL versions. Thus, FLTK allows
source code targeting any version of OpenGL. Access to functions from OpenGL versions above 1.1 requires to load function pointers at runtime on these platforms. FLTK recommends to use the GLEW library to perform this. It is therefore
necessary to install the GLEW library (see below). <b>On the Mac OS X platform</b>,
FLTK creates by default contexts implementing OpenGL versions 1 or 2.
To access OpenGL 3.0 (or higher versions), use the <tt>FL_OPENGL3</tt> flag (see below).
Mac OS 10.7 or above is required; GLEW is possible but not necessary.
\par GLEW installation (Unix/Linux and MSWindows platforms)
GLEW is available as a package for most Linux distributions and in source form at http://glew.sourceforge.net/.
For the MSWindows platform, a Visual Studio static library (glew32.lib) can be downloaded from the same web site; a MinGW-style static library (libglew32.a) can be built from source with the make command.
\par Source-level changes for OpenGL 3:
\li Put this in all OpenGL-using source files (instead of \#include <FL/gl.h>,
and before \#include <FL/glut.h> if you use GLUT):
\code
#if defined(__APPLE__)
# include <OpenGL/gl3.h> // defines OpenGL 3.0+ functions
#else
# if defined(WIN32)
# define GLEW_STATIC 1
# endif
# include <GL/glew.h>
#endif
\endcode
\li Add the <tt>FL_OPENGL3</tt> flag when calling Fl_Gl_Window::mode(int a)
or glutInitDisplayMode().
\li Put this in the <tt>handle(int event)</tt> member function of the first to be created
among your Fl_Gl_Window-derived classes:
\code
#ifndef __APPLE__
static int first = 1;
if (first && event == FL_SHOW && shown()) {
first = 0;
make_current();
glewInit(); // defines pters to functions of OpenGL V 1.2 and above
}
#endif
\endcode
\li Alternatively, if you use GLUT, put
\code
#ifndef __APPLE__
glewInit(); // defines pters to functions of OpenGL V 1.2 and above
#endif
\endcode
after the first glutCreateWindow() call.
If GLEW is installed on the Mac OS development platform, it is possible
to use the same code for all platforms, with one exception: put
\code
#ifdef __APPLE__
glewExperimental = TRUE;
#endif
\endcode
before the glewInit() call.
\par Changes in the build process
Link with libGLEW.so (on Unix/Linux), libglew32.a (with MinGW) or glew32.lib
(with MS Visual Studio); no change is needed on the Mac OS platform.
\htmlonly \htmlonly
<hr> <hr>

View File

@ -0,0 +1,199 @@
#include <stdio.h>
#if defined(__APPLE__)
# include <OpenGL/gl3.h> // defines OpenGL 3.0+ functions
#else
# if defined(WIN32)
# define GLEW_STATIC 1
# endif
# include <GL/glew.h>
#endif
#include <FL/glut.H>
// Globals
// Real programs don't use globals :-D
// Data would normally be read from files
GLfloat vertices[] = { -1.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f };
GLfloat colours[] = { 1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f };
GLfloat vertices2[] = { 0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f,
1.0f,0.0f,0.0f };
// two vertex array objects, one for each object drawn
unsigned int vertexArrayObjID[2];
// three vertex buffer objects in this example
unsigned int vertexBufferObjID[3];
void printShaderInfoLog(GLint shader)
{
int infoLogLen = 0;
GLchar *infoLog;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
if (infoLogLen > 0)
{
infoLog = new GLchar[infoLogLen];
// error check for fail to allocate memory omitted
glGetShaderInfoLog(shader,infoLogLen, NULL, infoLog);
fprintf(stderr, "InfoLog:\n%s\n", infoLog);
delete [] infoLog;
}
}
void init(void)
{
// Would load objects from file here - but using globals in this example
// Allocate Vertex Array Objects
glGenVertexArrays(2, &vertexArrayObjID[0]);
// Setup first Vertex Array Object
glBindVertexArray(vertexArrayObjID[0]);
glGenBuffers(2, vertexBufferObjID);
// VBO for vertex data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// VBO for colour data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), colours, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// Setup second Vertex Array Object
glBindVertexArray(vertexArrayObjID[1]);
glGenBuffers(1, &vertexBufferObjID[2]);
// VBO for vertex data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[2]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), vertices2, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
void initShaders(void)
{
GLuint p, f, v;
glClearColor (1.0, 1.0, 1.0, 0.0);
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
#ifdef __APPLE__
#define SHADING_LANG_VERS "140"
#else
#define SHADING_LANG_VERS "130"
#endif
// load shaders
const char *vv = "#version "SHADING_LANG_VERS"\n\
in vec3 in_Position;\
in vec3 in_Color;\
out vec3 ex_Color;\
void main(void)\
{\
ex_Color = in_Color;\
gl_Position = vec4(in_Position, 1.0);\
}";
const char *ff = "#version "SHADING_LANG_VERS"\n\
precision highp float;\
in vec3 ex_Color;\
out vec4 out_Color;\
void main(void)\
{\
out_Color = vec4(ex_Color,1.0);\
}";
glShaderSource(v, 1, &vv,NULL);
glShaderSource(f, 1, &ff,NULL);
GLint compiled;
glCompileShader(v);
glGetShaderiv(v, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
fprintf(stderr, "Vertex shader not compiled.\n");
printShaderInfoLog(v);
}
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
fprintf(stderr, "Fragment shader not compiled.\n");
printShaderInfoLog(f);
}
p = glCreateProgram();
glAttachShader(p,v);
glAttachShader(p,f);
glBindAttribLocation(p,0, "in_Position");
glBindAttribLocation(p,1, "in_Color");
glLinkProgram(p);
glGetProgramiv(p, GL_LINK_STATUS, &compiled);
if (compiled != GL_TRUE) {
GLchar *infoLog; GLint length;
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &length);
infoLog = new GLchar[length];
glGetProgramInfoLog(p, length, NULL, infoLog);
fprintf(stderr, "Link log=%s\n", infoLog);
delete[] infoLog;
}
glUseProgram(p);
}
void display(void)
{
// clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vertexArrayObjID[0]); // First VAO
glDrawArrays(GL_TRIANGLES, 0, 3); // draw first object
glBindVertexArray(vertexArrayObjID[1]); // select second VAO
glVertexAttrib3f((GLuint)1, 1.0, 0.0, 0.0); // set constant color attribute
glDrawArrays(GL_TRIANGLES, 0, 3); // draw second object
}
int main (int argc, char* argv[])
{
Fl::use_high_res_GL(true);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | FL_OPENGL3);
glutInitWindowSize(400,400);
glutCreateWindow("Triangle Test");
#ifndef __APPLE__
GLenum err = glewInit(); // defines pters to functions of OpenGL V 1.2 and above
if (err) Fl::error("glewInit() failed returning %u", err);
fprintf(stderr, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
#endif
int gl_version_major;
const char *glv = (const char*)glGetString(GL_VERSION);
fprintf(stderr, "OpenGL version %s supported\n", glv);
sscanf(glv, "%d", &gl_version_major);
if (gl_version_major < 3) {
fprintf(stderr, "\nThis platform does not support OpenGL V3\n\n");
exit(1);
}
initShaders();
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

209
examples/OpenGL3test.cxx Normal file
View File

@ -0,0 +1,209 @@
#include <stdarg.h>
#include <FL/Fl.H>
#include <FL/x.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>
#if defined(__APPLE__)
# include <OpenGL/gl3.h> // defines OpenGL 3.0+ functions
#else
# if defined(WIN32)
# define GLEW_STATIC 1
# endif
# include <GL/glew.h>
#endif
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;
}
void draw(void) {
if (gl_version_major < 3) return;
if (!shaderProgram) {
GLuint vs;
GLuint fs;
int Mslv, mslv; // major and minor version numbers of the shading language
sscanf((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), "%d.%d", &Mslv, &mslv);
add_output("Shading Language Version=%d.%d\n",Mslv, mslv);
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]; const char *vss = vss_string;
sprintf(vss_string, vss_format, Mslv, mslv);
const char *fss_format="#version %d%d\n\
in vec4 colourV;\
out vec4 fragColour;\
void main(void)\
{\
fragColour = colourV;\
}";
char fss_string[200]; const char *fss = fss_string;
sprintf(fss_string, fss_format, Mslv, mslv);
GLint err; GLchar CLOG[1000]; GLsizei length;
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vss, NULL);
glCompileShader(vs);
glGetShaderiv(vs, GL_COMPILE_STATUS, &err);
if (err != GL_TRUE) {
glGetShaderInfoLog(vs, sizeof(CLOG), &length, CLOG);
add_output("vs ShaderInfoLog=%s\n",CLOG);
}
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fss, NULL);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &err);
if (err != GL_TRUE) {
glGetShaderInfoLog(fs, sizeof(CLOG), &length, CLOG);
add_output("fs ShaderInfoLog=%s\n",CLOG);
}
// Attach the shaders
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glBindFragDataLocation(shaderProgram, 0, "fragColour");
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &err);
if (err != GL_TRUE) {
glGetProgramInfoLog(shaderProgram, sizeof(CLOG), &length, CLOG);
add_output("link log=%s\n", CLOG);
}
// Get pointers to uniforms and attributes
positionUniform = glGetUniformLocation(shaderProgram, "p");
colourAttribute = glGetAttribLocation(shaderProgram, "colour");
positionAttribute = glGetAttribLocation(shaderProgram, "position");
glDeleteShader(vs);
glDeleteShader(fs);
// Upload vertices (1st four values in a row) and colours (following four values)
GLfloat vertexData[]= { -0.5,-0.5,0.0,1.0, 1.0,0.0,0.0,1.0,
-0.5, 0.5,0.0,1.0, 0.0,1.0,0.0,1.0,
0.5, 0.5,0.0,1.0, 0.0,0.0,1.0,1.0,
0.5,-0.5,0.0,1.0, 1.0,1.0,1.0,1.0};
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));
}
else if ((!valid())) {
glViewport(0, 0, pixel_w(), pixel_h());
}
glClearColor(0.08, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
GLfloat p[]={0,0};
glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
virtual int handle(int event) {
static int first = 1;
if (first && event == FL_SHOW && shown()) {
first = 0;
make_current();
#ifndef __APPLE__
GLenum err = glewInit(); // defines pters to functions of OpenGL V 1.2 and above
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\n");
}
if (event == FL_PUSH && gl_version_major >= 3) {
static float factor = 1.1;
GLfloat data[4];
glGetBufferSubData(GL_ARRAY_BUFFER, 0, 4*sizeof(GLfloat), data);
if (data[0] < -0.88 || data[0] > -0.5) factor = 1/factor;
data[0] *= factor;
glBufferSubData(GL_ARRAY_BUFFER, 0, 4*sizeof(GLfloat), data);
glGetBufferSubData(GL_ARRAY_BUFFER, 24*sizeof(GLfloat), 4*sizeof(GLfloat), data);
data[0] *= factor;
glBufferSubData(GL_ARRAY_BUFFER, 24*sizeof(GLfloat), 4*sizeof(GLfloat), data);
redraw();
add_output("push\n");
return 1;
}
return Fl_Gl_Window::handle(event);
}
void reset(void) { shaderProgram = 0; }
};
void toggle_double(Fl_Widget *wid, void *data) {
static bool doublebuff = true;
doublebuff = !doublebuff;
SimpleGL3Window *glwin = (SimpleGL3Window*)data;
int flags = glwin->mode();
if (doublebuff) flags |= FL_DOUBLE; else flags &= ~FL_DOUBLE;
glwin->mode(flags);
glwin->reset();
}
Fl_Text_Display *output; // shared between output_win() and add_output()
void output_win(SimpleGL3Window *gl)
{
output = new Fl_Text_Display(300,0,500, 280);
Fl_Light_Button *lb = new Fl_Light_Button(300, 280, 500, 20, "Double-Buffered");
lb->callback(toggle_double);
lb->user_data(gl);
lb->value(1);
output->buffer(new Fl_Text_Buffer());
}
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->insert(line_buffer);
output->redraw();
}
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_win(win);
topwin->end();
topwin->resizable(win);
topwin->label("Click GL panel to reshape");
topwin->show(argc, argv);
Fl::run();
}

View File

@ -2718,11 +2718,12 @@ NSOpenGLPixelFormat* Fl_X::mode_to_NSOpenGLPixelFormat(int m, const int *alistp)
#define NSOpenGLPFAOpenGLProfile (NSOpenGLPixelFormatAttribute)99 #define NSOpenGLPFAOpenGLProfile (NSOpenGLPixelFormatAttribute)99
#define kCGLPFAOpenGLProfile NSOpenGLPFAOpenGLProfile #define kCGLPFAOpenGLProfile NSOpenGLPFAOpenGLProfile
#define NSOpenGLProfileVersionLegacy (NSOpenGLPixelFormatAttribute)0x1000 #define NSOpenGLProfileVersionLegacy (NSOpenGLPixelFormatAttribute)0x1000
#define NSOpenGLProfileVersion3_2Core (NSOpenGLPixelFormatAttribute)0x3200
#define kCGLOGLPVersion_Legacy NSOpenGLProfileVersionLegacy #define kCGLOGLPVersion_Legacy NSOpenGLProfileVersionLegacy
#endif #endif
if (fl_mac_os_version >= 100700) { if (fl_mac_os_version >= 100700) {
attribs[n++] = NSOpenGLPFAOpenGLProfile; attribs[n++] = NSOpenGLPFAOpenGLProfile;
attribs[n++] = NSOpenGLProfileVersionLegacy; // for now, no public FLTK API for OpenGL v3 profiles attribs[n++] = (m & FL_OPENGL3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
} }
} else { } else {
while (alistp[n] && n < 30) { while (alistp[n] && n < 30) {