Demo-2 <<--PREV            UP --^           NEXT-->>  Demo-4
side4linux, a simple integrated development environment!

GTKCGL3 Demo-3  Running a GTK+ Builder project with an OpenGLtm type widget.

Purpose:  To provide a basic introduction to Panning,Scaling and Rotation of an OpenGLtm type 3D Widget in a GTK+ Builder Project.

Requirements:

Exercise-1: Start the program 'Sample2'.
  1. Open 'side4linux' and click on 'Project>Open Project' in the Main Menu.
  2. Select '--/SIDE/DEMOS/SIDEdemos/GTKCGL3/Sample2/sample2.prf' as in figure-1 below and click on 'Open' in the Dialog Box.


Fig-1
  1. Click on 'Build>Autogen Project' and then click on the Toolbar 'Build' button.
  2. Once the Project is Built, close the project.
  3. 'Project>Close Project'
  4. Note that it will be stored in the 'GTKCGL' section of the 'SIDEdemos' Folder.
  5. Change directory to your new program ( that is '~/SIDE/DEMOS/SIDEdemos/GTKCGL3/Sample2/src/'  ).
  6.   and run the program in a terminal,  ( in my case that is 'db@wks1:~/Data/Projects/SIDE/DEMOS/SIDEdemos/GTKCGL3/Sample2/src/$ ./sample2'  ).
  7.   Note: Do not forget the 'dot forward slash' which says look in the 'current' directory for the program.
  8. This brings up the program 'sample2' as in figure-2.
  9. Look at the text behind the program ( a good place to start when something does not work as expected ) and see the startup output generated.

Draw3D_CheckForOpenGL, OpenGL is supported
Trying local 'glade' file
trying to GladeXML open |test -e ../sample2.glade|
systemError = 0 Trying local 'glade' file
Local 'glade' file found!

Opening 'sample2' number of arguements = 1

 opening string is './sample2'
get fences failed: -1
param: 6, val: 0
GLworld_CreateWorld Select = 0
                        <--------- We have managed to create an OpenGL World to 'draw' in!
Draw3D_SetCurrentWorld, currentWorld = 0
Insert 'GLworld1' glworld into GTK widget
In main.c, WorldContainer = 'hbox2'
Draw3D_InsertWorld, trying to add 'GLworld1' World
Draw3D_InsertWorld, trying to show 'GLworld1' World
Draw3D_InsertWorld, trying to add callbacks to 'GLworld1' World
Draw3D_InsertWorld, trying to set events in 'GLworld1' World
Draw3D_InsertWorld, exit.
                                <--------- We have managed to insert our OpenGL World into the GTK 'holder' widget!
Draw3D:world_expose_event, entering                <--------- The 'expose' event is a callback that activates if our GL World becomes visible.
Draw3d:blackWorlds, enter
Draw3d:blackWorlds, enter
entering  Draw3D_ClearCurrentWorldToBlack
entering GLworld_ClearWorldToBlack, select = 0
done GLworld_ClearWorldToBlack
leaving  Draw3D_ClearCurrentWorldToBlack
done GLworld_CaptureDisplayImage
Draw3d:blackWorlds, image captured
Draw3d:blackWorlds, recreate all GL display images
Draw3d:reshapeWorld[0]
                                   <--------- The 'reshape' event is a callback that activates if our GL World changes shape.
Draw3D:reshapeWorld, Attempt to ClearAllWorldsToBlack
Draw3d:reshapeWorld, exit
Draw3d:blackWorlds, enter
entering  Draw3D_ClearCurrentWorldToBlack
entering GLworld_ClearWorldToBlack, select = 0
done GLworld_ClearWorldToBlack
leaving  Draw3D_ClearCurrentWorldToBlack
done GLworld_CaptureDisplayImage
                  <--------- The 'Display Image' is used to repaint our GL World if the 'holder' widget is moved or painted over.
Draw3d:blackWorlds, image captured
Draw3d:blackWorlds, recreate all GL display images
Draw3D:world_expose_event, entering


So as you can see the 'Draw3D' commands ( in libdraw3dS4L ) have setup our GL World widget ready for user interaction.

Also note,

  Expand the program to Full Screen ( click the square top right of the program window ) then,
     click on the buttons ( one at a time from the left, hover over the tool buttons with the mouse to read the tool tips! ) and observe....



Fig-2


RdW :
Draws a cube in 'Wireframe' mode.                     
RdS :
Draws a cube in 'Surface' mode.
Clr : Clears the screen of drawn artifacts.
Z+ : Zooms into the screen.
Z- : Zooms out of the screen.
ZA : Fits the cube to the screen.
PL : Pans left.
PR : Pans right.
PU : Pans up.
PD : Pans down.
RXC : Rotates the cube clockwise around its X axis.
RXA : Rotates the cube anti-clockwise around its X axis.


Exercise-2: Check some files of interest in the program 'Sample2'.

Open 'main.c' and note,


    // now reset all glworlds allowed by 'MAXWORLDS' defined in libgtkglS4L:gdkgl.h
    // and 'MAXWORLDS_ALLOWED' defined in libdraw3dS4L:Draw3D.c

    Draw3D_ResetAllWorlds();

    // create all needed glworlds
    Draw3D_CreateWorld(GLworld1);

    while(g_main_context_iteration(NULL,FALSE)); // use this line to force completion of command if needed!

    Draw3D_SetCurrentWorldIndex(GLworld1);
    gtk_widget_set_size_request(Draw3D_GetCurrentWorld(),200,200); // set minimum size of our GL widget

    // Insert "GLworld1" glworld into GTK widget "hbox2"
     glWorld1Container = Draw3D_InsertWorld(getWorldContainer("hbox2"),"hbox2","GLworld1",GLworld1);

    gtk_widget_show(mainWindow);
    gtk_main();


Open 'callbacks.c' and note,

void gtkQuit() // no parameter type since it is a callback function
{
  //remove the OpenGL widget first!
  Draw3D_SetCurrentWorldIndex(GLworld1);
  gtk_container_remove(GTK_CONTAINER(glWorld1Container),Draw3D_GetCurrentWorld());
  // then quit the GTK loop.
  gtk_main_quit();
  g_print("Program Terminated by user!\n");
}


Open 'Callbacks/callbacksTransformToolbar.c' and note,

Callback functions set up using Glade-3

void on_toolbuttonClearGLarea_clicked()                 // no parameter types since they are callback functions
void on_toolbuttonReDrawWireframe_clicked()
void on_toolbuttonReDrawSurface_clicked()
void on_toolbuttonZoomIn_clicked()
void on_toolbuttonZoomOut_clicked()
void on_toolbuttonZoomAll_clicked()
void on_toolbuttonPanLeft_clicked()
void on_toolbuttonPanRight_clicked()
void on_toolbuttonPanUp_clicked()
void on_toolbuttonPanDown_clicked()
void on_toolbuttonRotateXclockwise_clicked()
void on_toolbuttonRotateXantiClockwise_clicked()
void on_toolbuttonRotateYclockwise_clicked()
void on_toolbuttonRotateYantiClockwise_clicked()
void on_toolbuttonRotateZclockwise_clicked()
void on_toolbuttonRotateZantiClockwise_clicked()
void on_toolbuttonFaceXfront_clicked()
void on_toolbuttonFaceXrear_clicked()
void on_toolbuttonFaceYfront_clicked()
void on_toolbuttonFaceYrear_clicked()
void on_toolbuttonFaceZfront_clicked()
void on_toolbuttonFaceZrear_clicked()

Open 'Draw.c' and note,

void Draw_Display(void)  // draws the display either in 'wireframe' or 'surface' mode
{
  Draw3D_ClearCurrentWorld(0.1,0.1,0.7); // nice blue background

  if(Draw3D_GetDrawMode()==WIREFRAME)
  {
    drawDisplayInWireframeMode();
    // capture the drawn image needed during window 'repainting'
    // e.g. when another window passes overhead.
    Draw3D_CaptureDisplayImage();
  }

  if(Draw3D_GetDrawMode()==SURFACE)
  {
    drawDisplayInSurfaceMode();
    // capture the drawn image needed during window 'repainting'
    // e.g. when another window passes overhead.
    Draw3D_CaptureDisplayImage();
  }
}


Exercise-3: Check some interactive routines of interest in the program 'Sample2'.
Some things useful are provided by the 'libdraw3d' library when your GL World is created such as automatic 'repainting' of the screen when there is another window passed over it or when the GL World widget is moved partially off screen. Try masking or moving the program yourself and see the messages generated in the terminal window behind the program such as,

Draw3D:world_expose_event, entering
Draw3D:world_expose_event, entering
Draw3D:world_expose_event, entering
Draw3D:world_expose_event, entering

Also try clicking a mouse button over the GL World widget and see the co-ordinates that are returned for you to use as in figure-3.


Fig-3

Open 'libdraw3d/Draw3D.c' and note,


//====================== useful mouse movement & button clicking functions ===========================

int Draw3D_CheckForMouseClickSinceLastChecked(int *mouseX,int *mouseY)

{ // greater than 0 if the mouse buttons have been clicked since last time
   // with the 2d x/y co-ordinates inside the GL World window when clicked.
  int result=FALSE;

  if(ScreenMouseButtonNumberPressed > 0)
  {
    result = ScreenMouseButtonNumberPressed; // the last mouse button pressed since last query
    ScreenMouseButtonNumberPressed = 0;      // reset
    *mouseX = ScreenCurrentClickedCursorPositionX;
    *mouseY = ScreenCurrentClickedCursorPositionY;
  }
  return(result);
}

int Draw3D_HasMouseMovedOnScreen(void)
{ // returns TRUE if mouse has moved in the GL window since last call
  int result=FALSE;

  if((ScreenCurrentCursorPositionX != previousScreenCurrentCursorPositionX)||
    (ScreenCurrentCursorPositionY != previousScreenCurrentCursorPositionY))
  {
    previousScreenCurrentCursorPositionX = ScreenCurrentCursorPositionX; // update
    previousScreenCurrentCursorPositionY = ScreenCurrentCursorPositionY; // update
    result = TRUE;
  }
  return(result);
}

void Draw3D_CurrentMousePositionOnScreen(int *mouseX,int *mouseY)
{ // returns the current position of mouse on screen
   *mouseX = previousScreenCurrentCursorPositionX;
   *mouseY = previousScreenCurrentCursorPositionY;
}

Now the callback signals are generated by,

GtkWidget* Draw3D_InsertWorld()

  g_signal_connect(GTK_OBJECT(newWorld), "configure_event",G_CALLBACK(reshapeWorld),NULL);
  g_signal_connect(GTK_OBJECT(newWorld),  "motion_notify_event",G_CALLBACK(world_motion_notify_event),NULL);
  g_signal_connect(GTK_OBJECT(newWorld),  "button_press_event",G_CALLBACK(world_button_press_event),NULL);
  g_signal_connect(G_OBJECT(newWorld),       "expose_event",G_CALLBACK(world_expose_event_callback),NULL);

  gtk_widget_add_events(GTK_WIDGET(newWorld),GDK_LEAVE_NOTIFY_MASK
                                                                                 | GDK_BUTTON_PRESS_MASK
                                                                                 | GDK_POINTER_MOTION_MASK);

And the callback signals are serviced by the following callback functions,

static gboolean reshapeWorld();                           <-- when window changes size.
static gboolean world_motion_notify_event();       <-- when mouse moves.
static gboolean world_button_press_event();        <-- when mouse button clicked.
static gboolean world_expose_event_callback();  <-- when something else paints on top of the widget ( needs an image
saved with Draw3D_CaptureDisplayImage(); ).


Note: To speed up the display you can remove the extra messages generated by commenting
         out the 'debug' defines and rebuilding the Project.

//#define debugDraw3d   ( in 'libdraw3dS4L/Draw3D.c' )
//#define debugGLworld
  ( in 'libdraw3dS4L/GLworld.c' )



Summary: Manipulating images within a 3D Visual Project built using side4linux and Glade-3.


We will provide other demos as 'side4linux' develops to cover GTK+ visual programming and integration into a real world machine controller.

GUI interface made with Gtk and Glade GUI demo built with Glade