cursor area doesn't refresh in draw window when using mouse to zoom



Hello,

I am new to the world of GTK+, and OpenGL.  I am using GTK+ 2.0,
gtkglext, and Mesa 3D to develop a simple application to display an
image, zoom, pan etc.  I have been able to successfully load, display
and zoom the image.  However, whenever the image is zoomed using the
mouse, the area around the cursor does not update (it seems to be a
small box encompassing the cursor).  I am using
gtk_widget_queue_draw_area in my mouse button event handler to force a
redraw of the screen with a new field of view value in gluPerspective. 
I am not sure if the redraw problem is something I am doing wrong in
GTK+, or if has something to do with OpenGL or the gtkglext library I am
using to make an OpenGL-drawable window.

any advice would be greatly appreciated!
thanks,
Melissa


#include <stdlib.h>
#include <gtk/gtk.h>
#include <gtk/gtkgl.h>
#include <gdk/gdkkeysyms.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>      // Header file for standard file i/o.

// storage for one texture 
GLuint texture[1];
GLfloat zoom, zoomStep;
gboolean doZoom;
int prevX, prevY;

// Image type - contains height, width, and data
struct Image {
    unsigned long sizeX;
    unsigned long sizeY;
    char *data;
};
typedef struct Image Image;

int ImageLoad(char *filename, Image *image) ;
void LoadGLTextures();

static void realize (GtkWidget *widget, gpointer data)
{
   g_print("in realize function\n");
   GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
   GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);

   if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
      return;

   GLfloat Width = widget->allocation.width;
   GLfloat Height = widget->allocation.height;

   LoadGLTextures();  // Load the texture(s)

   glEnable(GL_TEXTURE_2D);  // Enable texture mapping
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);  // Clear the background color
to blue
   glClearDepth(1.0);  // Enables clearing of the depth buffer
   glDepthFunc(GL_LESS);  // The type of depth test to do
   glEnable(GL_DEPTH_TEST);  // Enables depth testing
   glShadeModel(GL_SMOOTH);  // Enables smooth color shading

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();  // Reset the projection matrix

   gluPerspective(45.0f, Width/Height, 0.1f, 100.0f);  
   glMatrixMode(GL_MODELVIEW);

   gdk_gl_drawable_gl_end(gldrawable);




}

static gboolean configure_event (GtkWidget *widget, GdkEventConfigure
*event, gpointer data)
{
   g_print("in configure_event function\n");
   return 1;
}

static gboolean expose_event (GtkWidget *widget, GdkEventExpose *event,
gpointer data)
{
   //g_print("in expose_event function\n");
   GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
   GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);

   if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
      return FALSE;

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// do zooming if necessary
   if (doZoom)
      {
         //g_print("zooming\n");
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         gluPerspective(zoom+zoomStep,
(widget->allocation.width)/(widget->allocation.height), 1, 100);
         glMatrixMode(GL_MODELVIEW);
      }

   glLoadIdentity();
   glTranslatef(0.0f, 0.0f, -4.0f);  // move 5 units into the screen

   glBindTexture(GL_TEXTURE_2D, texture[0]);  // choose the texture to
use

   glBegin(GL_QUADS);  // begin drawing a cube

   // Front Face (note that the texture's corners have to match the
quad's corners)
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);   // Bottom
Left Of The Texture and Quad
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);   // Bottom
Right Of The Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);   // Top
Right Of The Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);   // Top
                                                                // Left Of The Texture and Quad

   glEnd();                                    // done with the polygon.

   // since this is double buffered, swap the buffers to display what
just got drawn.
   if (gdk_gl_drawable_is_double_buffered(gldrawable))
      gdk_gl_drawable_swap_buffers(gldrawable);
   else
      glFlush();

   gdk_gl_drawable_gl_end(gldrawable);

   return 1;
}

static gboolean keyPress(GtkWidget *widget, GdkEventKey *event, gpointer
data)
{
   //g_print("in keyPress function: %d\n", event->keyval);
   switch(event->keyval)
      {
      case GDK_Up:
         zoom += zoomStep;
         //g_print("up arrow pressed! zoom = %d\n", zoom);      
         break;
      case GDK_Down:
         zoom -= zoomStep;
         //g_print("down arrow pressed! zoom = %d\n", zoom);    
         break;
      }

   //gdk_window_invalidate_rect(widget->window, &widget->allocation,
   //TRUE);
//   gdk_window_invalidate_rect(widget->window,
&widget->allocation,TRUE);
   gtk_widget_queue_draw_area(widget, 0, 0, widget->allocation.width,
widget->allocation.height);

   return FALSE;
}

static gboolean motionCallback(GtkWidget *widget, GdkEventMotion *event)
{
   int x = 0;
   int y = 0;
   int state =0;
   float width, height;

   x = event->x;
   y = event->y;
   state = event->state;

   width = widget->allocation.width;
   height = widget->allocation.height;

   if (state & GDK_BUTTON1_MASK)
      {
         if ((y - prevY) > 0)
            {
               zoom += zoomStep;
            }
         else
            {
               zoom -= zoomStep;
            }

         doZoom = TRUE;
//       g_print("prevX, Y: %d, %d   newX, Y: %d, %d\n", prevX, prevY, x, y);
         //g_print("motion +button1 event at: (%d, %d)\n", x, y);
      }
   else if (state & GDK_BUTTON2_MASK)
      {
      //g_print("motion +button2 event at: (%d, %d)\n", x, y);
         doZoom = TRUE;
      }
   else
      {
         doZoom = TRUE;
      //g_print("motion event at: (%d, %d)\n", x, y);
      }

   prevX = x;
   prevY = y;
   gtk_widget_queue_draw_area(widget, 0, 0, widget->allocation.width,
widget->allocation.height);

}

int main (int argc, char *argv[])
{

  GdkGLConfig *glconfig;
  GtkWidget *window;
  GtkWidget *vbox;
  GtkWidget *drawing_area;
  GtkWidget *button;

  zoom = 45;
  zoomStep = 1;
  doZoom = FALSE;
  prevX = 0;
  prevY = 0;

  // Init GTK & GtkGLExt
  gtk_init (&argc, &argv);
  gtk_gl_init (&argc, &argv);

  // Try double-buffered visual
  glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB
| GDK_GL_MODE_DEPTH 
                                                          | GDK_GL_MODE_DOUBLE));
  if (glconfig == NULL)
    {
      g_print ("*** Cannot find the double-buffered visual.\n");
      g_print ("*** Trying single-buffered visual.\n");

      // Try single-buffered visual
      glconfig =
gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB |
GDK_GL_MODE_DEPTH));
      if (glconfig == NULL)
        {
          g_print ("*** No appropriate OpenGL-capable visual found.\n");
          exit (1);
        }
    }

  // Top-level window.
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Image Display");
  g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK
(gtk_main_quit), NULL);

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), vbox);
  gtk_widget_show (vbox);

  drawing_area = gtk_drawing_area_new ();
  gtk_widget_set_size_request (drawing_area, 512, 512);

  // Set OpenGL-capability to the widget.
  gtk_widget_set_gl_capability
(drawing_area,glconfig,NULL,TRUE,GDK_GL_RGBA_TYPE);

  g_signal_connect_after (G_OBJECT (drawing_area), "realize", G_CALLBACK
(realize), NULL);
  g_signal_connect (G_OBJECT (drawing_area), "configure_event",
G_CALLBACK (configure_event), NULL);
  g_signal_connect (G_OBJECT (drawing_area), "expose_event", G_CALLBACK
(expose_event), NULL);

  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
  gtk_widget_show (drawing_area);

  button = gtk_button_new_with_label ("Quit");
  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK
(gtk_main_quit), NULL);
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  gtk_widget_show (button);

  gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK |
GDK_POINTER_MOTION_MASK | 
                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
  g_signal_connect(G_OBJECT(window), "key_press_event",
G_CALLBACK(keyPress), drawing_area);
  g_signal_connect(G_OBJECT(drawing_area), "motion_notify_event",
G_CALLBACK(motionCallback), NULL);

  gtk_widget_show (window);
  gtk_main ();

  return 0;
}

void LoadGLTextures() 
{
   Image *image1;
    
   // allocate space for texture
   image1 = (Image *) malloc(sizeof(Image));
   if (image1 == NULL) {
        g_print("Error allocating space for image");
        exit(0);
   }

   if (!ImageLoad("schip_smr.bmp", image1)) {
        exit(1);
   }        

   // Create Texture    
   glGenTextures(1, &texture[0]);
   glBindTexture(GL_TEXTURE_2D, texture[0]);   // 2d texture (x and y
size)

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //
scale linearly when image bigger than texture
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //
scale linearly when image smalled than texture

   // 2d texture, level of detail 0 (normal), 3 components (red, green,
blue), x size from image, y size from image, 
   // border 0 (normal), rgb color data, unsigned byte data, and finally
the data itself.
   glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, image1->data);
}

int ImageLoad(char *filename, Image *image) 
{
    FILE *file;
    unsigned long size;                 // size of the image in bytes.
    unsigned long i;                    // standard counter.
    unsigned short int planes;          // number of planes in image
(must be 1) 
    unsigned short int bpp;             // number of bits per pixel
(must be 24)
    char temp;                          // temporary color storage for
bgr-rgb conversion.

    // make sure the file is there.
    if ((file = fopen(filename, "rb"))==NULL)
    {
        g_print("File Not Found : %s\n",filename);
        return 0;
    }
    
    // seek through the bmp header, up to the width/height:
    fseek(file, 18, SEEK_CUR);

    // read the width
    if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
        g_print("Error reading width from %s.\n", filename);
        return 0;
    }
    printf("Width of %s: %lu\n", filename, image->sizeX);
    
    // read the height 
    if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
        g_print("Error reading height from %s.\n", filename);
        return 0;
    }
    g_print("Height of %s: %lu\n", filename, image->sizeY);
    
    // calculate the size (assuming 24 bits or 3 bytes per pixel).
    size = image->sizeX * image->sizeY * 3;

    // read the planes
    if ((fread(&planes, 2, 1, file)) != 1) {
        g_print("Error reading planes from %s.\n", filename);
        return 0;
    }
    if (planes != 1) {
        g_print("Planes from %s is not 1: %u\n", filename, planes);
        return 0;
    }

    // read the bpp
    if ((i = fread(&bpp, 2, 1, file)) != 1) {
        g_print("Error reading bpp from %s.\n", filename);
        return 0;
    }
    if (bpp != 24) {
        g_print("Bpp from %s is not 24: %u\n", filename, bpp);
        return 0;
    }
        
    // seek past the rest of the bitmap header.
    fseek(file, 24, SEEK_CUR);

    // read the data. 
    image->data = (char *) malloc(size);
    if (image->data == NULL) {
        g_print("Error allocating memory for color-corrected image data");
        return 0;       
    }

    if ((i = fread(image->data, size, 1, file)) != 1) {
        g_print("Error reading image data from %s.\n", filename);
        return 0;
    }

    for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
        temp = image->data[i];
        image->data[i] = image->data[i+2];
        image->data[i+2] = temp;
    }
    
    // we're done.
    return 1;
}





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]