Recently I have tried using MSAA (multisample anti-aliasing) under Linux. The result was surprising: everything worked like a charm with Nvidia proprietary drivers, however with nouveau drivers it does not work. The strange thing about this is that glxingo says that GLX_ARB_multisample is supported and I am able to get the appropriate FBConfig with GLX_SAMPLE_BUFFERS set to 1 and GLX_SAMPLES set to 4 (or 8). But when it comes to rendering, the picture is as no anti-aliasing is applied. The problem exists in both my project and freeglut, so I will provide a small glut-based program that demonstarates the problem:
/*
* Test multisampling and polygon smoothing.
*
* Brian Paul
* 4 November 2002
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
static GLfloat Zrot = 0;
static GLboolean Anim = GL_TRUE;
static GLboolean HaveMultisample = GL_TRUE;
static GLboolean DoMultisample = GL_TRUE;
static void
PrintString(const char *s)
{
while (*s) {
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
s++;
}
}
static void
Polygon( GLint verts, GLfloat radius, GLfloat z )
{
int i;
for (i = 0; i < verts; i++) {
float a = (i * 2.0 * 3.14159) / verts;
float x = radius * cos(a);
float y = radius * sin(a);
glVertex3f(x, y, z);
}
}
static void
DrawObject( void )
{
glLineWidth(3.0);
glColor3f(1, 1, 1);
glBegin(GL_LINE_LOOP);
Polygon(12, 1.2, 0);
glEnd();
glLineWidth(1.0);
glColor3f(1, 1, 1);
glBegin(GL_LINE_LOOP);
Polygon(12, 1.1, 0);
glEnd();
glColor3f(1, 0, 0);
glBegin(GL_POLYGON);
Polygon(12, 0.4, 0.3);
glEnd();
glColor3f(0, 1, 0);
glBegin(GL_POLYGON);
Polygon(12, 0.6, 0.2);
glEnd();
glColor3f(0, 0, 1);
glBegin(GL_POLYGON);
Polygon(12, 0.8, 0.1);
glEnd();
glColor3f(1, 1, 1);
glBegin(GL_POLYGON);
Polygon(12, 1.0, 0);
glEnd();
}
static void
Display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glColor3f(1, 1, 1);
if (HaveMultisample) {
glRasterPos2f(-3.1, -1.6);
if (DoMultisample)
PrintString("MULTISAMPLE");
else
PrintString("MULTISAMPLE (off)");
}
glRasterPos2f(-0.8, -1.6);
PrintString("No antialiasing");
glRasterPos2f(1.6, -1.6);
PrintString("GL_POLYGON_SMOOTH");
/* multisample */
if (HaveMultisample) {
glEnable(GL_DEPTH_TEST);
if (DoMultisample)
glEnable(GL_MULTISAMPLE_ARB);
glPushMatrix();
glTranslatef(-2.5, 0, 0);
glPushMatrix();
glRotatef(Zrot, 0, 0, 1);
DrawObject();
glPopMatrix();
glPopMatrix();
glDisable(GL_MULTISAMPLE_ARB);
glDisable(GL_DEPTH_TEST);
}
/* non-aa */
glEnable(GL_DEPTH_TEST);
glPushMatrix();
glTranslatef(0, 0, 0);
glPushMatrix();
glRotatef(Zrot, 0, 0, 1);
DrawObject();
glPopMatrix();
glPopMatrix();
glDisable(GL_DEPTH_TEST);
/* polygon smooth */
glEnable(GL_POLYGON_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glPushMatrix();
glTranslatef(2.5, 0, 0);
glPushMatrix();
glRotatef(Zrot, 0, 0, 1);
DrawObject();
glPopMatrix();
glPopMatrix();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);
glDisable(GL_BLEND);
glutSwapBuffers();
}
static void
Reshape( int width, int height )
{
GLfloat ar = (float) width / (float) height;
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-2.0*ar, 2.0*ar, -2.0, 2.0, -1.0, 1.0);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
static void
Idle( void )
{
Zrot = 0.01 * glutGet(GLUT_ELAPSED_TIME);
glutPostRedisplay();
}
static void
Key( unsigned char key, int x, int y )
{
const GLfloat step = 1.0;
(void) x;
(void) y;
switch (key) {
case 'a':
Anim = !Anim;
if (Anim)
glutIdleFunc(Idle);
else
glutIdleFunc(NULL);
break;
case 'm':
DoMultisample = !DoMultisample;
break;
case 'z':
Zrot = (int) (Zrot - step);
break;
case 'Z':
Zrot = (int) (Zrot + step);
break;
case 27:
exit(0);
break;
}
glutPostRedisplay();
}
static void
Init( void )
{
/* GLUT imposes the four samples/pixel requirement */
int s;
glGetIntegerv(GL_SAMPLES_ARB, &s);
if (!glutExtensionSupported("GL_ARB_multisample") || s < 1) {
printf("Warning: multisample antialiasing not supported.\n");
HaveMultisample = GL_FALSE;
}
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
printf("GL_SAMPLES_ARB = %d\n", s);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
glGetIntegerv(GL_MULTISAMPLE_ARB, &s);
printf("GL_MULTISAMPLE_ARB = %d\n", s);
}
int
main( int argc, char *argv[] )
{
glutInit( &argc, argv );
glutInitWindowPosition( 0, 0 );
glutInitWindowSize( 600, 300 );
glutInitDisplayMode( GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE |
GLUT_DEPTH | GLUT_MULTISAMPLE );
glutCreateWindow(argv[0]);
glutReshapeFunc( Reshape );
glutKeyboardFunc( Key );
glutDisplayFunc( Display );
if (Anim)
glutIdleFunc( Idle );
Init();
glutMainLoop();
return 0;
}
Here is glxinfo output (excluding the visuals info):
name of display: :0.0
display: :0 screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4
server glx extensions:
GLX_ARB_multisample, GLX_EXT_import_context, GLX_EXT_texture_from_pixmap,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_copy_sub_buffer,
GLX_OML_swap_method, GLX_SGI_swap_control, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_visual_select_group,
GLX_INTEL_swap_event
client glx vendor string: Mesa Project and SGI
client glx version string: 1.4
client glx extensions:
GLX_ARB_create_context, GLX_ARB_create_context_profile,
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_EXT_framebuffer_sRGB,
GLX_EXT_create_context_es2_profile, GLX_MESA_copy_sub_buffer,
GLX_MESA_multithread_makecurrent, GLX_MESA_swap_control,
GLX_OML_swap_method, GLX_OML_sync_control, GLX_SGI_make_current_read,
GLX_SGI_swap_control, GLX_SGI_video_sync, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_visual_select_group,
GLX_EXT_texture_from_pixmap, GLX_INTEL_swap_event
GLX version: 1.4
GLX extensions:
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_copy_sub_buffer,
GLX_MESA_multithread_makecurrent, GLX_MESA_swap_control,
GLX_OML_swap_method, GLX_OML_sync_control, GLX_SGI_make_current_read,
GLX_SGI_swap_control, GLX_SGI_video_sync, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_visual_select_group,
GLX_EXT_texture_from_pixmap
OpenGL vendor string: nouveau
OpenGL renderer string: Gallium 0.4 on NVC1
OpenGL version string: 2.1 Mesa 8.0.4
OpenGL shading language version string: 1.30
OpenGL extensions:
GL_ARB_multisample, GL_EXT_abgr, GL_EXT_bgra, GL_EXT_blend_color,
GL_EXT_blend_minmax, GL_EXT_blend_subtract, GL_EXT_copy_texture,
GL_EXT_polygon_offset, GL_EXT_subtexture, GL_EXT_texture_object,
GL_EXT_vertex_array, GL_EXT_compiled_vertex_array, GL_EXT_texture,
GL_EXT_texture3D, GL_IBM_rasterpos_clip, GL_ARB_point_parameters,
GL_EXT_draw_range_elements, GL_EXT_packed_pixels, GL_EXT_point_parameters,
GL_EXT_rescale_normal, GL_EXT_separate_specular_color,
GL_EXT_texture_edge_clamp, GL_SGIS_generate_mipmap,
GL_SGIS_texture_border_clamp, GL_SGIS_texture_edge_clamp,
GL_SGIS_texture_lod, GL_ARB_framebuffer_sRGB, GL_ARB_multitexture,
GL_EXT_framebuffer_sRGB, GL_IBM_multimode_draw_arrays,
GL_IBM_texture_mirrored_repeat, GL_ARB_texture_cube_map,
GL_ARB_texture_env_add, GL_ARB_transpose_matrix,
GL_EXT_blend_func_separate, GL_EXT_fog_coord, GL_EXT_multi_draw_arrays,
GL_EXT_secondary_color, GL_EXT_texture_env_add,
GL_EXT_texture_filter_anisotropic, GL_EXT_texture_lod_bias,
GL_INGR_blend_func_separate, GL_NV_blend_square, GL_NV_light_max_exponent,
GL_NV_texgen_reflection, GL_NV_texture_env_combine4,
GL_SUN_multi_draw_arrays, GL_ARB_texture_border_clamp,
GL_ARB_texture_compression, GL_EXT_framebuffer_object,
GL_EXT_texture_env_combine, GL_EXT_texture_env_dot3, GL_MESA_window_pos,
GL_NV_packed_depth_stencil, GL_NV_texture_rectangle, GL_ARB_depth_texture,
GL_ARB_occlusion_query, GL_ARB_shadow, GL_ARB_texture_env_combine,
GL_ARB_texture_env_crossbar, GL_ARB_texture_env_dot3,
GL_ARB_texture_mirrored_repeat, GL_ARB_window_pos,
GL_EXT_stencil_two_side, GL_EXT_texture_cube_map, GL_NV_depth_clamp,
GL_NV_fog_distance, GL_APPLE_packed_pixels, GL_APPLE_vertex_array_object,
GL_ARB_draw_buffers, GL_ARB_fragment_program, GL_ARB_fragment_shader,
GL_ARB_shader_objects, GL_ARB_vertex_program, GL_ARB_vertex_shader,
GL_ATI_draw_buffers, GL_ATI_texture_env_combine3, GL_EXT_shadow_funcs,
GL_EXT_stencil_wrap, GL_MESA_pack_invert, GL_NV_primitive_restart,
GL_ARB_depth_clamp, GL_ARB_fragment_program_shadow,
GL_ARB_half_float_pixel, GL_ARB_occlusion_query2, GL_ARB_point_sprite,
GL_ARB_shading_language_100, GL_ARB_sync, GL_ARB_texture_non_power_of_two,
GL_ARB_vertex_buffer_object, GL_ATI_blend_equation_separate,
GL_EXT_blend_equation_separate, GL_OES_read_format,
GL_ARB_color_buffer_float, GL_ARB_pixel_buffer_object,
GL_ARB_texture_compression_rgtc, GL_ARB_texture_rectangle,
GL_ATI_texture_compression_3dc, GL_EXT_packed_float,
GL_EXT_pixel_buffer_object, GL_EXT_texture_compression_rgtc,
GL_EXT_texture_mirror_clamp, GL_EXT_texture_rectangle,
GL_EXT_texture_sRGB, GL_EXT_texture_shared_exponent,
GL_ARB_framebuffer_object, GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample, GL_EXT_packed_depth_stencil,
GL_ARB_vertex_array_object, GL_ATI_separate_stencil,
GL_ATI_texture_mirror_once, GL_EXT_draw_buffers2, GL_EXT_draw_instanced,
GL_EXT_gpu_program_parameters, GL_EXT_texture_array,
GL_EXT_texture_compression_latc, GL_EXT_texture_integer,
GL_EXT_texture_sRGB_decode, GL_EXT_timer_query, GL_OES_EGL_image,
GL_MESA_texture_array, GL_ARB_copy_buffer, GL_ARB_depth_buffer_float,
GL_ARB_draw_instanced, GL_ARB_half_float_vertex, GL_ARB_instanced_arrays,
GL_ARB_map_buffer_range, GL_ARB_texture_rg, GL_ARB_texture_swizzle,
GL_ARB_vertex_array_bgra, GL_EXT_separate_shader_objects,
GL_EXT_texture_swizzle, GL_EXT_vertex_array_bgra,
GL_NV_conditional_render, GL_AMD_conservative_depth,
GL_AMD_draw_buffers_blend, GL_ARB_ES2_compatibility,
GL_ARB_draw_buffers_blend, GL_ARB_draw_elements_base_vertex,
GL_ARB_explicit_attrib_location, GL_ARB_fragment_coord_conventions,
GL_ARB_provoking_vertex, GL_ARB_sampler_objects, GL_ARB_seamless_cube_map,
GL_ARB_shader_texture_lod, GL_EXT_provoking_vertex, GL_EXT_texture_snorm,
GL_MESA_texture_signed_rgba, GL_NV_texture_barrier, GL_ARB_robustness,
GL_ARB_transform_feedback2, GL_ARB_conservative_depth,
GL_ARB_texture_storage, GL_EXT_transform_feedback
glewIsSupported says the extension is available, glGetIntegerv says the number of samples is 4, as specified when getting the FBConfig.
I have no idea of what is going on.
Edit: Here is the output of glXQueryExtensionsString:
GLX_ARB_get_proc_address GLX_ARB_multisample GLX_EXT_import_context GLX_EXT_visual_info GLX_EXT_visual_rating GLX_MESA_copy_sub_buffer GLX_MESA_multithread_makecurrent GLX_MESA_swap_control GLX_OML_swap_method GLX_OML_sync_control GLX_SGI_make_current_read GLX_SGI_swap_control GLX_SGI_video_sync GLX_SGIS_multisample GLX_SGIX_fbconfig GLX_SGIX_pbuffer GLX_SGIX_visual_select_group GLX_EXT_texture_from_pixmap
FORGET ABOUT MSAA. On nouveau UNLESS you have very fresh MESA + kernel + X.org.
MSAA is requirement for OpenGL 3.0 and up. So it was not high on priority list, up until recently. You need Mesa 9.0 for that.
(If you want tips on what to do to get those needed software, pls post your hardware, and software - distro, kernel, mesa, xorg - versions).
Related
I have written the attached example program that uses GTK2 in conjunction with EGL and OpenGL. On my system this works fine. On the PC of friend it only will produce a black window and I cannot put my finger on why this happens. We event straces which libraries get loaded (Which are the same). My PC has a NVIDIA MX150, he has a GTX 1030, he uses Debian Strech and I use Debian buster.
I cannot put my finger on the problem. Anyways, heres the code:
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <EGL/egl.h>
#include <GL/gl.h>
static EGLDisplay egl_display;
static EGLSurface egl_surface;
static EGLContext egl_context;
static void realize_cb (GtkWidget *widget)
{
printf("REALIZE\n");
EGLConfig egl_config;
EGLint n_config;
EGLint attributes[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE };
EGLint surf_attrs[] = {
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE
};
egl_display = eglGetDisplay ((EGLNativeDisplayType) gdk_x11_display_get_xdisplay (gtk_widget_get_display (widget)));
eglInitialize (egl_display, NULL, NULL);
eglChooseConfig (egl_display, attributes, &egl_config, 1, &n_config);
eglBindAPI (EGL_OPENGL_API);
egl_surface = eglCreateWindowSurface (egl_display, egl_config, GDK_WINDOW_XID (gtk_widget_get_window (widget)), surf_attrs);
egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, NULL);
}
static gboolean on_configure (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
gtk_widget_queue_draw(widget);
return FALSE;
}
static gboolean draw_cb (GtkWidget *widget, GdkEventExpose *expose, gpointer userdata)
{
printf("DRAW\n");
eglMakeCurrent (egl_display, egl_surface, egl_surface, egl_context);
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);
glViewport (0, 0, alloc.width, alloc.height);
glClearColor (0, 0, 0, 1);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, 100, 0, 100, 0, 1);
glBegin (GL_TRIANGLES);
glColor3f (1, 0, 0);
glVertex2f (50, 10);
glColor3f (0, 1, 0);
glVertex2f (90, 90);
glColor3f (0, 0, 1);
glVertex2f (10, 90);
glEnd ();
eglSwapBuffers (egl_display, egl_surface);
return TRUE;
}
int main (int argc, char **argv)
{
GtkWidget *w;
gtk_init (&argc, &argv);
w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_double_buffered (GTK_WIDGET (w), FALSE);
g_signal_connect (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL);
g_signal_connect (G_OBJECT (w), "expose-event", G_CALLBACK (draw_cb), NULL);
g_signal_connect (G_OBJECT (w), "configure-event", G_CALLBACK (on_configure), NULL);
gtk_widget_show (w);
gtk_main ();
return 0;
}
I'm writing an application in Linux using Xlib to manage a window and cairo to draw some text in it. The text content of the window changes during the execution, so I want to adapt the window size to match that of the text extent. If the size of the text extent does not change, the window is always correctly updated with the new text.
But when the text extent changes, and so the window is resized accordingly, the window is cleared but the new text is never shown. Only if there is no call to XResizeWindow the text is actually displayed. The code I'm using is
if (/* Text extent is changed */)
{
XResizeWindow (display, window, new_width, new_height);
cairo_xlib_surface_set_size (surface, new_width, new_height);
}
XClearWindow (display, window);
/* ... Cairo code to draw the text ... */
// cairo_surface_flush (surface);
// XFlush (display);
I have also tried to add after the Cairo code that draws the text the methods cairo_surface_flush and XFlush (commented in the example) but nothing changes.
EDIT: I solved the problem using two threads: the first thread with the usual loop for listening to the Expose events plus the code to redraw the content and the second thread that issues the resize of the window and sends an Expose event to wake up the first thread.
In this example the window is resized every 500 ms to random width and height and a progressive counter is displayed in it at every resize. I use C++11, compile with:
g++ -std=c++11 -o test test.cpp -lX11 -lcairo -lpthread
The code is:
#include <random>
#include <chrono>
#include <thread>
#include <string>
#include <X11/Xlib.h>
#include <cairo/cairo-xlib.h>
Display * d;
Window w;
cairo_surface_t * surface;
int width = 300, height = 300;
unsigned char counter = 0;
std::random_device rd;
std::knuth_b gen (rd ());
std::uniform_int_distribution < > dist (150, 300);
void logic ()
{
XEvent send_event;
send_event.type = Expose;
send_event.xexpose.window = w;
while (true)
{
std::this_thread::sleep_for (std::chrono::milliseconds (500));
++ counter;
width = dist (gen);
height = dist (gen);
cairo_xlib_surface_set_size (surface, width, height);
XResizeWindow (d, w, width, height);
XSendEvent (d, w, False, ExposureMask, & send_event);
XFlush (d);
}
}
int main ( )
{
XInitThreads ();
d = XOpenDisplay (NULL);
w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000);
XMapWindow (d, w);
XSelectInput (d, w, ExposureMask | KeyPressMask);
surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height);
cairo_t * cairo = cairo_create (surface);
cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cairo, 40 );
cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str ());
XFlush (d);
std::thread T (logic);
XEvent event;
while (true)
{
XNextEvent (d, & event);
if (event.type == Expose)
{
XClearWindow (d, w);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str ());
}
else if (event.type == KeyPress)
{
XCloseDisplay (d);
return 0;
}
}
}
But a question remains: is it possible to obtain the same result using only one thread?
Here is a single-threaded version of your code. It is not nice, but it seems to work. The hard part is waiting for events from the X11 server and the timeout simultaneously. I do this with select() in the following code.
Note that I also handle ConfigureNotify events instead of assuming that XResizeWindow always does just what we want.
#include <random>
#include <chrono>
#include <thread>
#include <string>
#include <X11/Xlib.h>
#include <cairo/cairo-xlib.h>
#include <sys/time.h>
Display * d;
Window w;
cairo_surface_t * surface;
int width = 300, height = 300;
unsigned char counter = 0;
std::random_device rd;
std::knuth_b gen (rd ());
std::uniform_int_distribution < > dist (150, 300);
void do_update ()
{
++ counter;
width = dist (gen);
height = dist (gen);
XResizeWindow (d, w, width, height);
// Force a redraw
XClearArea(d, w, 0, 0, 0, 0, True);
}
int main ( )
{
XInitThreads ();
d = XOpenDisplay (NULL);
w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000);
XMapWindow (d, w);
XSelectInput (d, w, ExposureMask | KeyPressMask);
surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height);
cairo_t * cairo = cairo_create (surface);
cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cairo, 40 );
cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str ());
XFlush (d);
struct timeval next_update;
struct timeval now;
struct timeval interval = { 0, 500000 };
gettimeofday(&now, NULL);
timeradd(&now, &interval, &next_update);
while (true)
{
XEvent event;
gettimeofday(&now, NULL);
if (timercmp(&now, &next_update, >)) {
// Store time of next update
timeradd(&now, &interval, &next_update);
puts("update");
do_update();
}
if (!XPending(d)) {
struct timeval remaining;
fd_set fds;
int fd = ConnectionNumber(d);
FD_ZERO(&fds);
FD_SET(fd, &fds);
timersub(&next_update, &now, &remaining);
select(fd + 1, &fds, NULL, NULL, &remaining);
} else {
XNextEvent (d, & event);
if (event.type == Expose)
{
XClearWindow (d, w);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str ());
}
if (event.type == ConfigureNotify)
{
cairo_xlib_surface_set_size (surface, event.xconfigure.width, event.xconfigure.height);
}
else if (event.type == KeyPress)
{
XCloseDisplay (d);
return 0;
}
}
}
}
I'm testing out several of Sumantha Guha's code and there's something that isn't working quite right... All of the sample code where he uses GLUT_DOUBLE and glutSwapBuffers() does not work on my ubuntu machine, but works on my Windows machine. More accurately the window that pops out simply traces the background.
I've had this issue before on Windows where Flush and single buffers don't work, but now this is happening on Linux where Double buffers and glutSwapBuffers do not work. Any idea as to what may be causing this?
Sample of code that I tried loading. Compiles fine, just get a window that traces the background.
///////////////////////////////////////////////////////////////////////////////////////////////////////
// loadTextures.cpp
//
// This stripped-down program shows how to load both external and program-generated images as textures.
//
// NOTE: The Textures folder must be in the same one as this program.
//
// Interaction:
// Press the left and right arrow keys to rotate the square.
// Press space to toggle between textures.
// Press delete to reset.
//
// Sumanta Guha
///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
// TEXTURE GREDITS:
// canLabel.bmp, thanks anonymous.
// canTop.bmp, thanks www.acoustica.com.
// cray2.bmp, thanks NASA website www.nasa.gov.
// grass.bmp, thanks www.amazingtextures.com.
// launch.bmp, thanks NASA website www.nasa.gov.
// nightsky.bmp, thanks anonymous.
// sky.bmp, thanks www.mega-tex.nl.
// trees.bmp, thanks anonymous.
////////////////////////////////////////////////
#include <cstdlib>
#include <iostream>
#include <fstream>
#ifdef __APPLE__
# include <GLUT/glut.h>
# include <OpenGL/glext.h>
#else
# include <GL/glut.h>
# include <GL/glext.h>
#endif
using namespace std;
// Globals.
static unsigned int texture[2]; // Array of texture indices.
static unsigned char chessboard[64][64][3]; // Storage for chessboard image.
static float angle = 0.0; // Angle to rotate textured square.
static int id = 0; // Currently displayed texture id.
// Struct of bitmap file.
struct BitMapFile
{
int sizeX;
int sizeY;
unsigned char *data;
};
// Routine to read a bitmap file.
// Works only for uncompressed bmp files of 24-bit color.
BitMapFile *getBMPData(string filename)
{
BitMapFile *bmp = new BitMapFile;
unsigned int size, offset, headerSize;
// Read input file name.
ifstream infile(filename.c_str(), ios::binary);
// Get the starting point of the image data.
infile.seekg(10);
infile.read((char *) &offset, 4);
// Get the header size of the bitmap.
infile.read((char *) &headerSize,4);
// Get width and height values in the bitmap header.
infile.seekg(18);
infile.read( (char *) &bmp->sizeX, 4);
infile.read( (char *) &bmp->sizeY, 4);
// Allocate buffer for the image.
size = bmp->sizeX * bmp->sizeY * 24;
bmp->data = new unsigned char[size];
// Read bitmap data.
infile.seekg(offset);
infile.read((char *) bmp->data , size);
// Reverse color from bgr to rgb.
int temp;
for (int i = 0; i < size; i += 3)
{
temp = bmp->data[i];
bmp->data[i] = bmp->data[i+2];
bmp->data[i+2] = temp;
}
return bmp;
}
// Load external textures.
void loadExternalTextures()
{
// Local storage for bmp image data.
BitMapFile *image[1];
// Load the texture.
image[0] = getBMPData("Textures/launch.bmp");
// Activate texture index texture[0].
glBindTexture(GL_TEXTURE_2D, texture[0]);
// Set texture parameters for wrapping.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture parameters for filtering.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Specify an image as the texture to be bound with the currently active texture index.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image[0]->sizeX, image[0]->sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, image[0]->data);
}
// Routine to load a program-generated image as a texture.
void loadProceduralTextures()
{
// Activate texture index texture[1].
glBindTexture(GL_TEXTURE_2D, texture[1]);
// Set texture parameters for wrapping.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture parameters for filtering.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Specify an image as the texture to be bound with the currently active texture index.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, chessboard);
}
// Create 64 x 64 RGB image of a chessboard.
void createChessboard(void)
{
int i, j;
for (i = 0; i < 64; i++)
for (j = 0; j < 64; j++)
if ( ( ((i/8)%2) && ((j/8)%2) ) || ( !((i/8)%2) && !((j/8)%2) ) )
{
chessboard[i][j][0] = 0x00;
chessboard[i][j][1] = 0x00;
chessboard[i][j][2] = 0x00;
}
else
{
chessboard[i][j][0] = 0xFF;
chessboard[i][j][1] = 0xFF;
chessboard[i][j][2] = 0xFF;
}
}
// Initialization routine.
void setup(void)
{
glClearColor(0.8, 0.8, 0.8, 0.0);
// Create texture index array.
glGenTextures(2, texture);
// Load external texture and generate and load procedural texture.
loadExternalTextures();
createChessboard();
loadProceduralTextures();
// Turn on OpenGL texturing.
glEnable(GL_TEXTURE_2D);
// Specify how texture values combine with current surface color values.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
// Drawing routine.
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glRotatef(angle, 0.0, 1.0, 0.0);
// Activate a texture.
glBindTexture(GL_TEXTURE_2D, texture[id]);
// Map the texture onto a square polygon.
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0); glVertex3f(-10.0, -10.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(10.0, -10.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(10.0, 10.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-10.0, 10.0, 0.0);
glEnd();
glutSwapBuffers();
}
// OpenGL window reshape routine.
void resize(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-5.0, 5.0, -5.0, 5.0, 5.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
exit(0);
break;
case ' ':
id++;
if (id == 2) id = 0;
glutPostRedisplay();
break;
case 127:
angle = 0.0;
glutPostRedisplay();
break;
default:
break;
}
}
// Callback routine for non-ASCII key entry.
void specialKeyInput(int key, int x, int y)
{
if (key == GLUT_KEY_LEFT)
{
angle -= 5.0;
if (angle < 0.0) angle += 360.0;
}
if (key == GLUT_KEY_RIGHT)
{
angle += 5.0;
if (angle > 360.0) angle -= 360.0;
}
glutPostRedisplay();
}
// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
cout << "Interaction:" << endl;
cout << "Press the left and right arrow keys to rotate the square." << endl
<< "Press space to toggle between textures." << endl
<< "Press delete to reset." << endl;
}
// Main routine.
int main(int argc, char **argv)
{
printInteraction();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("loadTextures.cpp");
setup();
glutDisplayFunc(drawScene);
glutReshapeFunc(resize);
glutKeyboardFunc(keyInput);
glutSpecialFunc(specialKeyInput);
glutMainLoop();
return 0;
}
I'm looking for a good source of GLES2 samples for C++ (or C) on x86 Linux with Xorg.
The samples I can find are all in Objective C for iOS, or Java for Android, or JavaScript for WebGL.
The Kronos web site has a "tutorials" section that contains two lines saying "our tutorials index will go here." Given that GLES2 is 5 years old, I don't have much hope on a sudden surge of content there.
I already know OpenGL pretty well. I'd just like some convenient source for copy-and-paste context set-up code, really. Where can I find something like that?
Mesa demos!
http://cgit.freedesktop.org/mesa/demos
http://cgit.freedesktop.org/mesa/demos/tree/src/egl/opengles2
http://cgit.freedesktop.org/mesa/demos/tree/src/egl/opengles2/es2tri.c
GLFW, Mesa, Ubuntu 16.04 AMD64
I'm not sure if GLUT supports GLES, but GLFW does, greatly simplifying window management.
sudo apt-get install libglfw3-dev libgles2-mesa-dev
gcc glfw_triangle.c -lGLESv2 -lglfw
Output:
Source:
#include <stdio.h>
#include <stdlib.h>
#define GLFW_INCLUDE_ES2
#include <GLFW/glfw3.h>
static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
static const GLchar* vertex_shader_source =
"#version 100\n"
"attribute vec3 position;\n"
"void main() {\n"
" gl_Position = vec4(position, 1.0);\n"
"}\n";
static const GLchar* fragment_shader_source =
"#version 100\n"
"void main() {\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
static const GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
};
GLint common_get_shader_program(const char *vertex_shader_source, const char *fragment_shader_source) {
enum Consts {INFOLOG_LEN = 512};
GLchar infoLog[INFOLOG_LEN];
GLint fragment_shader;
GLint shader_program;
GLint success;
GLint vertex_shader;
/* Vertex shader */
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex_shader, INFOLOG_LEN, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
}
/* Fragment shader */
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment_shader, INFOLOG_LEN, NULL, infoLog);
printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
}
/* Link shaders */
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}
int main(void) {
GLuint shader_program, vbo;
GLint pos;
GLFWwindow* window;
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);
printf("GL_VERSION : %s\n", glGetString(GL_VERSION) );
printf("GL_RENDERER : %s\n", glGetString(GL_RENDERER) );
shader_program = common_get_shader_program(vertex_shader_source, fragment_shader_source);
pos = glGetAttribLocation(shader_program, "position");
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, WIDTH, HEIGHT);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glEnableVertexAttribArray(pos);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
}
glDeleteBuffers(1, &vbo);
glfwTerminate();
return EXIT_SUCCESS;
}
The key line lines of code are:
#define GLFW_INCLUDE_ES2
#include <GLFW/glfw3.h>
GLFW_INCLUDE_ES2 is documented at: http://www.glfw.org/docs/latest/build_guide.html#build_macros and a quick look at the source shows that it forwards to GLES:
#elif defined(GLFW_INCLUDE_ES2)
#include <GLES2/gl2.h>
#if defined(GLFW_INCLUDE_GLEXT)
#include <GLES2/gl2ext.h>
#endif
This source seems to be is in the common subset of GLES and OpenGL (like much of GLES), and also compiles with -lGL if we remove the #define GLFW_INCLUDE_ES2.
If we add things which are not in GLES like immediate rendering glBegin, link fails as expected.
See also: How to develop OpenGL ES (GLES) 2.0 applications on Linux?
Credits: genpfult made the code much more correct.
ARM Mali OpenGL ES SDK
download from: http://malideveloper.arm.com/resources/sdks/opengl-es-sdk-for-linux/
open the documentation HTML on a browser
follow the "Quick Start Guide", it's simple
Contains several interesting open source examples + windowing system boilerplate (X11 + EGL).
The build system supports easy cross compilation for ARM / Mali SoCs, but I haven't tested that yet.
The key component included seems to be the "OpenGL ES Emulator" http://malideveloper.arm.com/resources/tools/opengl-es-emulator/ which "maps OpenGL ES 3.2 API calls to the OpenGL API". But that does not ship with source, only precompiled.
Uses a custom enterprisey EULA that appears to be permissive, but yeah, ask your lawyer.
Tested on SDK v2.4.4.
I have created a simple particle simulation for a fountain from this source. I also wanted to implement this using C++ classes. So, tried to put the above part of the logic into classes at this source (This is a very nice framework). I just have to inherit the class and redefine the functionalities that I would like.
I defined the functions for display() in which I call my DrawObjects().
I am running into the following issues:
I am initializing the number of particles to as low as 50 or 100 or 500. Nothing visible.
I am trying to load a texture(BMP) for my particles. It is failing for some reason. I tried both relative and absolute paths. Then tried to load a RAW texture(using IrfanViewer) with no luck. Also tried to remove the texture code to make them simple OpenGL primitives. Again no luck.
I wrote a simple DrawAxis() function which actually needs to draw cyan colored axis with red colored strings. However, gray colored primitives are showing up. I checked the code for usage of grayscale configuration, but no such thing.
Note: Working on Windows VC++ 2010. Code can be found at NippyZip.
Minimal Code
Main.cpp
#include "ParticleSimulation.h"
int main(int argc, char *argv[]) {
ParticleSimulation particleSimulation(50);
particleSimulation.InitParticles();
particleSimulation.setLookAt(80.0, 80.0, 80.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
particleSimulation.startFramework(argc, argv);
// **Note** No code below startFramework() will get executed
return 0;
}
GlutFramework.cpp
#include "GlutFramework.h"
namespace glutFramework {
// Set constants
const double GlutFramework::FRAME_TIME = 1.0 / GlutFramework::FPS * 1000.0; // Milliseconds
GlutFramework *GlutFramework::instance = NULL;
GlutFramework::GlutFramework() {
elapsedTimeInSeconds = 0;
frameTimeElapsed = 0;
title = "GLUT Framework: Paul Solt 2010";
eyeVector = Vector<float>(0.0, 0.0, -10.0); // move the eye position back
position = 0.0f;
direction = 1.0 / FRAME_TIME;
}
GlutFramework::~GlutFramework() {
}
void GlutFramework::startFramework(int argc, char *argv[]) {
setInstance(); // Sets the instance to self, used in the callback wrapper functions
// Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(WINDOW_X_POSITION, WINDOW_Y_POSITION);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow(title.c_str());
// Function callbacks with wrapper functions
glutReshapeFunc(reshapeWrapper);
glutMouseFunc(mouseButtonPressWrapper);
glutMotionFunc(mouseMoveWrapper);
glutDisplayFunc(displayWrapper);
glutKeyboardFunc(keyboardDownWrapper);
glutKeyboardUpFunc(keyboardUpWrapper);
glutSpecialFunc(specialKeyboardDownWrapper);
glutSpecialUpFunc(specialKeyboardUpWrapper);
init(); // Initialize
glutIdleFunc(runWrapper); // The program run loop
glutMainLoop(); // Start the main GLUT thread
}
void GlutFramework::load() {
// Subclass and override this method
}
void GlutFramework::display(float dTime) {
// Subclass and override this method
static int frame = 0;
std::cout << "GlutFramework Display: Frame: " << frame << ", dt(sec): " << dTime << ", Position: " << position << std::endl;
++frame;
// DEMO: Create a teapot and move it back and forth on the x-axis
glTranslatef(position, 0.0f, 0.0f);
glutSolidTeapot(2.5);
if(position > 4 && direction > 0) {
direction = -1.0 / FRAME_TIME;
} else if(position < -4 && direction < 0) {
direction = 1.0 / FRAME_TIME;
}
position += direction;
}
void GlutFramework::reshape(int width, int height) {
glViewport(0,0,(GLsizei)width,(GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) width, 0.0, (GLdouble) height);
}
void GlutFramework::mouseButtonPress(int button, int state, int x, int y) {
printf("MouseButtonPress: x: %d y: %d\n", x, y);
}
void GlutFramework::mouseMove(int x, int y) {
printf("MouseMove: x: %d y: %d\n", x, y);
}
void GlutFramework::keyboardDown( unsigned char key, int x, int y )
{
// Subclass and override this method
printf( "KeyboardDown: %c = %d\n", key, (int)key );
if (key==27) { //27 =- ESC key
exit (0);
}
keyStates.keyDown( (int)key );
}
void GlutFramework::keyboardUp( unsigned char key, int x, int y )
{
// Subclass and override this method
printf( "KeyboardUp: %c \n", key );
keyStates.keyUp( (int)key );
}
void GlutFramework::specialKeyboardDown( int key, int x, int y )
{
// Subclass and override this method
printf( "SpecialKeyboardDown: %d\n", key );
}
void GlutFramework::specialKeyboardUp( int key, int x, int y )
{
// Subclass and override this method
printf( "SpecialKeyboardUp: %d \n", key );
}
// ******************************
// ** Graphics helper routines **
// ******************************
// Initialize the projection/view matricies.
void GlutFramework::setDisplayMatricies() {
/* Setup the projection and model view matricies */
int width = glutGet( GLUT_WINDOW_WIDTH );
int height = glutGet( GLUT_WINDOW_HEIGHT );
float aspectRatio = width/height;
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60, aspectRatio, 1, 500.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt(eyeVector.x, eyeVector.y, eyeVector.z,
centerVector.x, centerVector.y, centerVector.z,
upVector.x, upVector.y, upVector.z);
}
void GlutFramework::setupLights() {
GLfloat light1_position[] = { 0.0, 1.0, 1.0, 0.0 };
GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
GLfloat ambient_light[] = { 0.8, 0.8, 0.8, 1.0 };
glLightfv( GL_LIGHT0, GL_POSITION, light1_position );
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient_light );
glLightfv( GL_LIGHT0, GL_DIFFUSE, white_light );
glLightfv( GL_LIGHT0, GL_SPECULAR, white_light );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
}
void GlutFramework::setLookAt(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ, float upX, float upY, float upZ) {
eyeVector = Vector<float>(eyeX, eyeY, eyeZ);
centerVector = Vector<float>(centerX, centerY, centerZ);
upVector = Vector<float>(upX, upY, upZ);
}
Vector<float> GlutFramework::getEyeVector() const {
return eyeVector;
}
Vector<float> GlutFramework::getCenterVector() const {
return centerVector;
}
Vector<float> GlutFramework::getUpVector() const {
return upVector;
}
void GlutFramework::setTitle(std::string theTitle) {
title = theTitle;
}
// **************************
// ** GLUT Setup functions **
// **************************
void GlutFramework::init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
load();
}
void GlutFramework::setInstance() {
//std::cout << "GlutFramework::setInstance()" << std::endl;
instance = this;
}
void GlutFramework::run() {
if(frameRateTimer.isStopped()) { // The initial frame has the timer stopped, start it once
frameRateTimer.start();
}
frameRateTimer.stop(); // stop the timer and calculate time since last frame
double milliseconds = frameRateTimer.getElapsedMilliseconds();
frameTimeElapsed += milliseconds;
if( frameTimeElapsed >= FRAME_TIME ) { // If the time exceeds a certain "frame rate" then show the next frame
glutPostRedisplay();
frameTimeElapsed -= FRAME_TIME; // remove a "frame" and start counting up again
}
frameRateTimer.start(); // start the timer
}
void GlutFramework::displayFramework() {
if(displayTimer.isStopped()) { // Start the timer on the initial frame
displayTimer.start();
}
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Clear once
displayTimer.stop(); // Stop the timer and get the elapsed time in seconds
elapsedTimeInSeconds = displayTimer.getElapsedSeconds(); // seconds
setupLights();
setDisplayMatricies();
display(elapsedTimeInSeconds);
glutSwapBuffers();
displayTimer.start(); // reset the timer to calculate the time for the next frame
}
// ******************************************************************
// ** Static functions which are passed to Glut function callbacks **
// ******************************************************************
void GlutFramework::displayWrapper() {
instance->displayFramework();
}
void GlutFramework::reshapeWrapper(int width, int height) {
instance->reshape(width, height);
}
void GlutFramework::runWrapper() {
instance->run();
}
void GlutFramework::mouseButtonPressWrapper(int button, int state, int x, int y) {
instance->mouseButtonPress(button, state, x, y);
}
void GlutFramework::mouseMoveWrapper(int x, int y) {
instance->mouseMove(x, y);
}
void GlutFramework::keyboardDownWrapper(unsigned char key, int x, int y) {
instance->keyboardDown(key,x,y);
}
void GlutFramework::keyboardUpWrapper(unsigned char key, int x, int y) {
instance->keyboardUp(key,x,y);
}
void GlutFramework::specialKeyboardDownWrapper(int key, int x, int y) {
instance->specialKeyboardDown(key,x,y);
}
void GlutFramework::specialKeyboardUpWrapper(int key, int x, int y) {
instance->specialKeyboardUp(key,x,y);
}
} // namespace
ParticleSimulation.h
#include "preheader.h"
#include "Particle.h"
#include "GlutFramework.h"
#ifndef ___PARTICLESIMULATION_H___
#define ___PARTICLESIMULATION_H___
using namespace glutFramework;
#ifndef ABS_IMAGE_LOCATION
#define ABS_IMAGE_LOCATION "E:/IIIT B/College/Sem 3/CG/GraphicAssignment3/images/particle.bmp"
#endif
class ParticleSimulation : virtual public GlutFramework{
private:
GLuint numParticles; // total number of particles in the system
Particle *particles;
GLuint textureParticle;
//static GLint textureCount;
//functions
void AllocateObjects(void );
void DeAllocateObjects(void );
public:
ParticleSimulation(void );
ParticleSimulation(GLuint numParticles);
~ParticleSimulation(void );
void InitParticles(void );
void EvolveParticle(void );
void DisplayObjects(void );
void LoadTextureRAW(const char * filename, int wrap);
void LoadTextureBMP(const char * filename, int wrap);
void FreeTexture(void );
void DrawAxis();
void RenderBitmapString(GLfloat x, GLfloat y, GLfloat z, void *font, char *string);
//virtual functions
void display(float dTime);
};
#endif //___PARTICLESIMULATION_H___
ParticleSimulation.cpp
#include "ParticleSimulation.h"
using namespace std;
. . .
void ParticleSimulation::DisplayObjects(){
// rendering functions
glLoadIdentity();
//glRotatef(20.0, 1.0, 0.0, 0.0); // show scene from top front
//glBindTexture(GL_TEXTURE_2D, this->textureParticle); // choose particle texture
for (int i = 0; i <= this->numParticles; i++){
GLfloat xpos = 0.0f, ypos = 0.0f, zpos = 0.0f;
particles[i].getPosition(xpos, ypos, zpos);
if(ypos < 0.0)
particles[i].setLifeTime(0.0);
if(particles[i].getActiveStatus() && particles[i].getLifeTime() > 0.0) {
GLfloat red = 0.0f, green = 0.0f, blue = 0.0f;
particles[i].getColor(red, green, blue);
glColor3f(red, green, blue);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(0.0,1.0); glVertex3f(xpos + 0.002, ypos + 0.002, zpos + 0.0); // top right
glVertex2f(0.0,0.0); glVertex3f(xpos - 0.002, ypos + 0.002, zpos + 0.0); // top left
glVertex2f(1.0,1.0); glVertex3f(xpos + 0.002, ypos - 0.002, zpos + 0.0); // bottom right
glVertex2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
//glTexCoord2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
glEnd();
} else {
particles[i].CreateParticle();
}
}
EvolveParticle();
}
void ParticleSimulation::EvolveParticle()
{
for(int i = 0; i <= this->numParticles; i++){ // evolve the particle parameters
GLfloat xpos = 0.0f, ypos = 0.0f, zpos = 0.0f;
GLfloat green = 0.0f, red = 0.0f, blue = 0.0f;
GLfloat xVel = 0.0f, yVel = 0.0f, zVel = 0.0f;
particles[i].setLifeTime( particles[i].getLifeTime() - particles[i].getDecay() );
particles[i].getPosition(xpos, ypos, zpos);
particles[i].getSpeed(xVel, yVel, zVel);
particles[i].getPosition(xpos += xVel, ypos += yVel, zpos += zVel);
particles[i].getSpeed(xVel, yVel -= 0.00007, zVel);
}
}
// Texture ///////////////////////////////////////////////////////////
// load a 256x256 RGB .RAW file as a texture
void ParticleSimulation::LoadTextureBMP(const char * filename, int wrap)
{
int width = 0, height = 0;
BYTE *data = NULL;
FILE *file = NULL;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) {
cout << "\nFile could not be opened." << endl;
return;
}
// allocate buffer
width = 256;
height = 256;
data = (BYTE *) malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose(file);
// allocate a texture name
this->textureParticle = 0;
glGenTextures( 1, &this->textureParticle );
// select our current texture
glBindTexture( GL_TEXTURE_2D, this->textureParticle );
// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// when texture area is small, bilinear filter the closest MIP map
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST );
// when texture area is large, bilinear filter the first MIP map
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// if wrap is true, the texture wraps over at the edges (repeat)
// ... false, the texture ends at the edges (clamp)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
wrap ? GL_REPEAT : GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
wrap ? GL_REPEAT : GL_CLAMP );
// build our texture MIP maps
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width,
height, GL_RGB, GL_UNSIGNED_BYTE, data );
// free buffer
free( data );
return;
}
void ParticleSimulation::FreeTexture(void )
{
glDeleteTextures(1, &this->textureParticle);
}
void ParticleSimulation::DrawAxis() {
char s1[10];
glPushMatrix();
glColor3f(1.0f, 0.0f, 0.0f);
sprintf(s1, "X-axis");
RenderBitmapString(50.0f, 0.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Y-axis");
RenderBitmapString(0.0f, 50.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Z-axis");
RenderBitmapString(0.0f, 0.0f, 50.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Origin");
RenderBitmapString(0.0f, 0.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
glPointSize(4.0f);
glColor3f(0.0f, 1.0f, 1.0f);
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 50.0f, 0.0f);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(50.0f, 0.0f, 0.0f);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 50.0f);
glEnd();
glPopMatrix();
}
void ParticleSimulation::display(float dTime)
{
static int frame = 0;
//cout << "GlutFramework Display: Frame: " << frame << ", dt(sec): " << dTime << ", Position: " << position << endl;
++frame;
//cout << "Calling the DisplayObject Function" << endl;
//glTranslatef(0.0f, 0.0f, 0.0f);
//glutSolidTeapot(2.5);
DrawAxis(); //Aditya: Working with grayscale though
DisplayObjects(); //Aditya: Nothing is drawn
}
LoadTextureBMP() is being invoked (with its bevy of OpenGL calls) before you have an OpenGL context (via startFramework()).
You need a current context before issuing GL commands.
EDIT:
for(int i = 0; i <= this->numParticles; i++)
Stop that. You're accessing off the end of your allocated memory.
Do this:
for(int i = 0; i < this->numParticles; i++)
Notice the less-than instead of the less-than-or-equal. For C/C++ arrays of size N the only valid indexes are in the range [0, N-1]. Your <= will cause the for-loop to try to access element N.
That's bad.
EDIT2:
GlutFramework::init() enables lighting. This is altering the colors in your axis rendering in ParticleSimulation::DrawAxis(). Disable it in ParticleSimulation::display() via glDisable(GL_LIGHTING):
EDIT3:
This will do something but probably not what you expect:
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(0.0,1.0); glVertex3f(xpos + 0.002, ypos + 0.002, zpos + 0.0); // top right
glVertex2f(0.0,0.0); glVertex3f(xpos - 0.002, ypos + 0.002, zpos + 0.0); // top left
glVertex2f(1.0,1.0); glVertex3f(xpos + 0.002, ypos - 0.002, zpos + 0.0); // bottom right
glVertex2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
glEnd();
You seem to think that glVertex2f() will somehow generate texture coordinates. It will not. You're looking for glTexCoord2f().
For drawing view-aligned triangles you'll want to look into billboarding.