Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Examples

logo.cc

GtkGLExt logo demo.

// -*- C++ -*-
/*
 * logo.cc:
 * GtkGLExt logo demo.
 *
 * written by Naofumi Yasufuku  <naofumi@users.sourceforge.net>
 */

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>

#include <GL/gl.h>
#include <GL/glu.h>

#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#endif

#include "logo.h"

//
// logo_draw_*() functions.
//
namespace LogoModel {
  #include "logo-model.h"
}

//
// Trackball utilities.
//
namespace Trackball {
  extern "C" {
    #include "trackball.h"
  }
}

#define DIG_2_RAD (G_PI / 180.0)
#define RAD_2_DIG (180.0 / G_PI)


//
// OpenGL frame buffer configuration utilities.
//

struct GLConfigUtil
{
  static void print_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig,
                              const char* attrib_str,
                              int attrib,
                              bool is_boolean);

  static void examine_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig);
};

//
// Print a configuration attribute.
//
void GLConfigUtil::print_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig,
                                   const char* attrib_str,
                                   int attrib,
                                   bool is_boolean)
{
  int value;

  if (glconfig->get_attrib(attrib, value))
    {
      std::cout << attrib_str << " = ";
      if (is_boolean)
        std::cout << (value == true ? "true" : "false") << std::endl;
      else
        std::cout << value << std::endl;
    }
  else
    {
      std::cout << "*** Cannot get "
                << attrib_str
                << " attribute value\n";
    }
}

//
// Print configuration attributes.
//
void GLConfigUtil::examine_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig)
{
  std::cout << "\nOpenGL visual configurations :\n\n";

  std::cout << "glconfig->is_rgba() = "
            << (glconfig->is_rgba() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->is_double_buffered() = "
            << (glconfig->is_double_buffered() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->is_stereo() = "
            << (glconfig->is_stereo() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->has_alpha() = "
            << (glconfig->has_alpha() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->has_depth_buffer() = "
            << (glconfig->has_depth_buffer() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->has_stencil_buffer() = "
            << (glconfig->has_stencil_buffer() ? "true" : "false")
            << std::endl;
  std::cout << "glconfig->has_accum_buffer() = "
            << (glconfig->has_accum_buffer() ? "true" : "false")
            << std::endl;

  std::cout << std::endl;

  print_gl_attrib(glconfig, "Gdk::GL::USE_GL",           Gdk::GL::USE_GL,           true);
  print_gl_attrib(glconfig, "Gdk::GL::BUFFER_SIZE",      Gdk::GL::BUFFER_SIZE,      false);
  print_gl_attrib(glconfig, "Gdk::GL::LEVEL",            Gdk::GL::LEVEL,            false);
  print_gl_attrib(glconfig, "Gdk::GL::RGBA",             Gdk::GL::RGBA,             true);
  print_gl_attrib(glconfig, "Gdk::GL::DOUBLEBUFFER",     Gdk::GL::DOUBLEBUFFER,     true);
  print_gl_attrib(glconfig, "Gdk::GL::STEREO",           Gdk::GL::STEREO,           true);
  print_gl_attrib(glconfig, "Gdk::GL::AUX_BUFFERS",      Gdk::GL::AUX_BUFFERS,      false);
  print_gl_attrib(glconfig, "Gdk::GL::RED_SIZE",         Gdk::GL::RED_SIZE,         false);
  print_gl_attrib(glconfig, "Gdk::GL::GREEN_SIZE",       Gdk::GL::GREEN_SIZE,       false);
  print_gl_attrib(glconfig, "Gdk::GL::BLUE_SIZE",        Gdk::GL::BLUE_SIZE,        false);
  print_gl_attrib(glconfig, "Gdk::GL::ALPHA_SIZE",       Gdk::GL::ALPHA_SIZE,       false);
  print_gl_attrib(glconfig, "Gdk::GL::DEPTH_SIZE",       Gdk::GL::DEPTH_SIZE,       false);
  print_gl_attrib(glconfig, "Gdk::GL::STENCIL_SIZE",     Gdk::GL::STENCIL_SIZE,     false);
  print_gl_attrib(glconfig, "Gdk::GL::ACCUM_RED_SIZE",   Gdk::GL::ACCUM_RED_SIZE,   false);
  print_gl_attrib(glconfig, "Gdk::GL::ACCUM_GREEN_SIZE", Gdk::GL::ACCUM_GREEN_SIZE, false);
  print_gl_attrib(glconfig, "Gdk::GL::ACCUM_BLUE_SIZE",  Gdk::GL::ACCUM_BLUE_SIZE,  false);
  print_gl_attrib(glconfig, "Gdk::GL::ACCUM_ALPHA_SIZE", Gdk::GL::ACCUM_ALPHA_SIZE, false);

  std::cout << std::endl;
}


//
// Logo classes.
//

namespace Logo
{

  //
  // View class implementation.
  //

  const float View::NEAR_CLIP   = 2.0;
  const float View::FAR_CLIP    = 60.0;

  const float View::INIT_POS_X  = 0.0;
  const float View::INIT_POS_Y  = 0.0;
  const float View::INIT_POS_Z  = -30.0;

  const float View::INIT_AXIS_X = 1.0;
  const float View::INIT_AXIS_Y = 0.0;
  const float View::INIT_AXIS_Z = 0.0;
  const float View::INIT_ANGLE  = 20.0;

  const float View::INIT_SCALE  = 1.0;

  const float View::SCALE_MAX   = 2.0;
  const float View::SCALE_MIN   = 0.5;

  View::View()
    : m_Scale(INIT_SCALE), m_BeginX(0.0), m_BeginY(0.0)
  {
    reset();
  }

  View::~View()
  {
  }

  void View::frustum(int w, int h)
  {
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w > h) {
      float aspect = static_cast<float>(w) / static_cast<float>(h);
      glFrustum(-aspect, aspect, -1.0, 1.0, NEAR_CLIP, FAR_CLIP);
    } else {
      float aspect = static_cast<float>(h) / static_cast<float>(w);
      glFrustum(-1.0, 1.0, -aspect, aspect, NEAR_CLIP, FAR_CLIP);
    }

    glMatrixMode(GL_MODELVIEW);
  }

  void View::xform()
  {
    glTranslatef(m_Pos[0], m_Pos[1], m_Pos[2]);

    glScalef(m_Scale, m_Scale, m_Scale);

    float m[4][4];
    Trackball::build_rotmatrix(m, m_Quat);
    glMultMatrixf(&m[0][0]);
  }

  void View::reset()
  {
    m_Pos[0] = INIT_POS_X;
    m_Pos[1] = INIT_POS_Y;
    m_Pos[2] = INIT_POS_Z;

    float sine = sin(0.5 * INIT_ANGLE * DIG_2_RAD);
    m_Quat[0] = INIT_AXIS_X * sine;
    m_Quat[1] = INIT_AXIS_Y * sine;
    m_Quat[2] = INIT_AXIS_Z * sine;
    m_Quat[3] = cos(0.5 * INIT_ANGLE * DIG_2_RAD);

    m_Scale = INIT_SCALE;
  }

  bool View::on_button_press_event(GdkEventButton* event,
                                   Scene* scene)
  {
    m_BeginX = event->x;
    m_BeginY = event->y;

    // don't block
    return false;
  }

  bool View::on_motion_notify_event(GdkEventMotion* event,
                                    Scene* scene)
  {
    if (scene == 0)
      return false;

    float w = scene->get_width();
    float h = scene->get_height();
    float x = event->x;
    float y = event->y;
    float d_quat[4];
    bool redraw = false;

    // Rotation.
    if (event->state & GDK_BUTTON1_MASK) {
      Trackball::trackball(d_quat,
                           (2.0 * m_BeginX - w) / w,
                           (h - 2.0 * m_BeginY) / h,
                           (2.0 * x - w) / w,
                           (h - 2.0 * y) / h);
      Trackball::add_quats(d_quat, m_Quat, m_Quat);
      redraw = true;
    }

    // Scaling.
    if (event->state & GDK_BUTTON2_MASK) {
      m_Scale = m_Scale * (1.0 + (y - m_BeginY) / h);
      if (m_Scale > SCALE_MAX)
        m_Scale = SCALE_MAX;
      else if (m_Scale < SCALE_MIN)
        m_Scale = SCALE_MIN;
      redraw = true;
    }

    m_BeginX = x;
    m_BeginY = y;

    if (redraw && !scene->anim_is_enabled())
      scene->invalidate();

    // don't block
    return false;
  }


  //
  // Model class implementation.
  //

  const float Model::MAT_SPECULAR[4]  = { 0.5, 0.5, 0.5, 1.0 };
  const float Model::MAT_SHININESS[1] = { 10.0 };
  const float Model::MAT_BLACK[4]     = { 0.0, 0.0, 0.0, 1.0 };
  const float Model::MAT_RED[4]       = { 1.0, 0.0, 0.0, 1.0 };
  const float Model::MAT_GREEN[4]     = { 0.0, 1.0, 0.0, 1.0 };
  const float Model::MAT_BLUE[4]      = { 0.0, 0.0, 1.0, 1.0 };

  const unsigned int Model::DEFAULT_ROT_COUNT = 100;

  static float AXIS_X[3] = { 1.0, 0.0, 0.0 };
  static float AXIS_Y[3] = { 0.0, 1.0, 0.0 };
  static float AXIS_Z[3] = { 0.0, 0.0, 1.0 };

  const Model::RotMode Model::ROT_MODE[] = {
    { AXIS_X,  1.0 },
    { AXIS_Y,  1.0 },
    { AXIS_X,  1.0 },
    { AXIS_Z,  1.0 },
    { AXIS_X,  1.0 },
    { AXIS_Y, -1.0 },
    { AXIS_X,  1.0 },
    { AXIS_Z, -1.0 },
    { 0,       0.0 }  // terminator
  };

  Model::Model(unsigned int rot_count,
               bool enable_anim)
    : m_RotCount(rot_count),
      m_EnableAnim(enable_anim), m_Mode(0), m_Counter(0)
  {
    reset_anim();
  }

  Model::~Model()
  {
  }

  void Model::init_gl()
  {
    glEnable(GL_CULL_FACE);

    glPushMatrix();

    glMaterialfv(GL_FRONT, GL_SPECULAR, MAT_SPECULAR);
    glMaterialfv(GL_FRONT, GL_SHININESS, MAT_SHININESS);

    /* Center black cube. */
    glNewList(CUBE, GL_COMPILE);
      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
      LogoModel::logo_draw_cube();
    glEndList();

    /* Forward "G". */
    glNewList(G_FORWARD, GL_COMPILE);
      glDisable(GL_CULL_FACE);
      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLUE);
      LogoModel::logo_draw_g_plane();
    glEnable(GL_CULL_FACE);

    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
      LogoModel::logo_draw_g();
    glEndList();

    /* Backward "G". */
    glNewList(G_BACKWARD, GL_COMPILE);
      glPushMatrix();
        glRotatef(180.0, 1.0, 0.0, 0.0);

        glDisable(GL_CULL_FACE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLUE);
        LogoModel::logo_draw_g_plane();
        glEnable(GL_CULL_FACE);

        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
        LogoModel::logo_draw_g();

      glPopMatrix();
    glEndList();

    /* Forward "T". */
    glNewList(T_FORWARD, GL_COMPILE);
      glDisable(GL_CULL_FACE);
      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_RED);
      LogoModel::logo_draw_t_plane();
      glEnable(GL_CULL_FACE);

      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
      LogoModel::logo_draw_t();
    glEndList();

    /* Backward "T". */
    glNewList(T_BACKWARD, GL_COMPILE);
      glPushMatrix();
        glRotatef(180.0, 1.0, 0.0, 0.0);

        glDisable(GL_CULL_FACE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_RED);
        LogoModel::logo_draw_t_plane();
        glEnable(GL_CULL_FACE);

        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
        LogoModel::logo_draw_t();

      glPopMatrix();
    glEndList();

    /* Forward "K". */
    glNewList(K_FORWARD, GL_COMPILE);
      glDisable(GL_CULL_FACE);
      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_GREEN);
      LogoModel::logo_draw_k_plane();
      glEnable(GL_CULL_FACE);

      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
      LogoModel::logo_draw_k();
    glEndList();

    /* Backward "K". */
    glNewList(K_BACKWARD, GL_COMPILE);
      glPushMatrix();
        glRotatef(180.0, 0.0, 0.0, 1.0);

        glDisable(GL_CULL_FACE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_GREEN);
        LogoModel::logo_draw_k_plane();
        glEnable(GL_CULL_FACE);

        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
        LogoModel::logo_draw_k();
      glPopMatrix();
    glEndList();

    glPopMatrix();

    glEnable(GL_NORMALIZE);
  }

  void Model::draw()
  {
    // Init GL context.
    static bool initialized = false;
    if (!initialized) {
      init_gl();
      initialized = true;
    }

    // Animation.
    if (m_EnableAnim) {
      if (m_Counter == m_RotCount) {
        if (ROT_MODE[++m_Mode].axis == 0)
          m_Mode = 0;
        m_Counter = 0;
      }

      float d_quat[4];
      Trackball::axis_to_quat(ROT_MODE[m_Mode].axis,
                              ROT_MODE[m_Mode].sign * G_PI_2 / m_RotCount,
                              d_quat);
      Trackball::add_quats(d_quat, m_Quat, m_Quat);

      ++m_Counter;
    }

    // Draw logo model.
    glPushMatrix();
      glTranslatef(m_Pos[0], m_Pos[1], m_Pos[2]);

      float m[4][4];
      Trackball::build_rotmatrix(m, m_Quat);
      glMultMatrixf(&m[0][0]);

      glRotatef(90.0, 1.0, 0.0, 0.0);
      glCallList(CUBE);
      glCallList(G_FORWARD);
      glCallList(G_BACKWARD);
      glCallList(T_FORWARD);
      glCallList(T_BACKWARD);
      glCallList(K_FORWARD);
      glCallList(K_BACKWARD);
    glPopMatrix();
  }

  void Model::reset_anim()
  {
    m_Pos[0] = 0.0;
    m_Pos[1] = 0.0;
    m_Pos[2] = 0.0;

    m_Quat[0] = 0.0;
    m_Quat[1] = 0.0;
    m_Quat[2] = 0.0;
    m_Quat[3] = 1.0;

    m_Mode = 0;
    m_Counter = 0;
  }


  //
  // Scene class implementation.
  //

  const unsigned int Scene::TIMEOUT_INTERVAL = 10;

  const float Scene::CLEAR_COLOR[4] = { 0.5, 0.5, 0.8, 1.0 };
  const float Scene::CLEAR_DEPTH    = 1.0;

  const float Scene::LIGHT0_POSITION[4] = { 0.0, 0.0, 30.0, 0.0 };
  const float Scene::LIGHT0_DIFFUSE[4]  = { 1.0, 1.0, 1.0, 1.0 };
  const float Scene::LIGHT0_SPECULAR[4] = { 1.0, 1.0, 1.0, 1.0 };

  Scene::Scene(unsigned int rot_count,
               bool enable_anim)
    : m_Menu(0), m_Model(rot_count, enable_anim)
  {
    //
    // Configure OpenGL-capable visual.
    //

    Glib::RefPtr<Gdk::GL::Config> glconfig;

    // Try double-buffered visual
    glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB    |
                                       Gdk::GL::MODE_DEPTH  |
                                       Gdk::GL::MODE_DOUBLE);
    if (!glconfig) {
      std::cerr << "*** Cannot find the double-buffered visual.\n"
                << "*** Trying single-buffered visual.\n";

      // Try single-buffered visual
      glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB   |
                                         Gdk::GL::MODE_DEPTH);
      if (!glconfig) {
        std::cerr << "*** Cannot find any OpenGL-capable visual.\n";
        std::exit(1);
      }
    }

    // print frame buffer attributes.
    GLConfigUtil::examine_gl_attrib(glconfig);

    //
    // Set OpenGL-capability to the widget.
    //

    set_gl_capability(glconfig);

    //
    // Add events.
    //
    add_events(Gdk::BUTTON1_MOTION_MASK    |
               Gdk::BUTTON2_MOTION_MASK    |
               Gdk::BUTTON_PRESS_MASK      |
               Gdk::VISIBILITY_NOTIFY_MASK);

    // View transformation signals.
    signal_button_press_event().connect(
      sigc::bind(sigc::mem_fun(m_View, &View::on_button_press_event), this));
    signal_motion_notify_event().connect(
      sigc::bind(sigc::mem_fun(m_View, &View::on_motion_notify_event), this));

    //
    // Popup menu.
    //

    m_Menu = create_popup_menu();
  }

  Scene::~Scene()
  {
  }

  void Scene::on_realize()
  {
    // We need to call the base on_realize()
    Gtk::DrawingArea::on_realize();

    //
    // Get GL::Drawable.
    //

    Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();

    //
    // GL calls.
    //

    // *** OpenGL BEGIN ***
    if (!gldrawable->gl_begin(get_gl_context()))
      return;

    glClearColor(CLEAR_COLOR[0], CLEAR_COLOR[1], CLEAR_COLOR[2], CLEAR_COLOR[3]);
    glClearDepth(CLEAR_DEPTH);

    glLightfv(GL_LIGHT0, GL_POSITION, LIGHT0_POSITION);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  LIGHT0_DIFFUSE);
    glLightfv(GL_LIGHT0, GL_SPECULAR, LIGHT0_SPECULAR);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    glEnable(GL_DEPTH_TEST);

    glShadeModel(GL_SMOOTH);

    gldrawable->gl_end();
    // *** OpenGL END ***
  }

  bool Scene::on_configure_event(GdkEventConfigure* event)
  {
    //
    // Get GL::Drawable.
    //

    Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();

    //
    // GL calls.
    //

    // *** OpenGL BEGIN ***
    if (!gldrawable->gl_begin(get_gl_context()))
      return false;

    m_View.frustum(get_width(), get_height());

    gldrawable->gl_end();
    // *** OpenGL END ***

    return true;
  }

  bool Scene::on_expose_event(GdkEventExpose* event)
  {
    //
    // Get GL::Drawable.
    //

    Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();

    //
    // GL calls.
    //

    // *** OpenGL BEGIN ***
    if (!gldrawable->gl_begin(get_gl_context()))
      return false;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();

    // View transformation.
    m_View.xform();

    // Logo model.
    m_Model.draw();

    // Swap buffers.
    if (gldrawable->is_double_buffered())
      gldrawable->swap_buffers();
    else
      glFlush();

    gldrawable->gl_end();
    // *** OpenGL END ***

    return true;
  }

  bool Scene::on_button_press_event(GdkEventButton* event)
  {
    if (event->button == 3) {
      m_Menu->popup(event->button, event->time);
      return true;
    }

    // don't block
    return false;
  }

  bool Scene::on_map_event(GdkEventAny* event)
  {
    if (m_Model.anim_is_enabled())
      timeout_add();

    return true;
  }

  bool Scene::on_unmap_event(GdkEventAny* event)
  {
    timeout_remove();

    return true;
  }

  bool Scene::on_visibility_notify_event(GdkEventVisibility* event)
  {
    if (m_Model.anim_is_enabled()) {
      if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
        timeout_remove();
      else
        timeout_add();
    }

    return true;
  }

  bool Scene::on_timeout()
  {
    // Invalidate whole window.
    invalidate();
    // Update window synchronously (fast).
    update();

    return true;
  }

  void Scene::timeout_add()
  {
    if (!m_ConnectionTimeout.connected())
      m_ConnectionTimeout = Glib::signal_timeout().connect(
        sigc::mem_fun(*this, &Scene::on_timeout), TIMEOUT_INTERVAL);
  }

  void Scene::timeout_remove()
  {
    if (m_ConnectionTimeout.connected())
      m_ConnectionTimeout.disconnect();
  }

  void Scene::toggle_anim()
  {
    if (m_Model.anim_is_enabled()) {
      m_Model.disable_anim();
      timeout_remove();
    } else {
      m_Model.enable_anim();
      timeout_add();
    }
  }

  void Scene::init_anim()
  {
    m_View.reset();
    m_Model.reset_anim();

    invalidate();
  }

  Gtk::Menu* Scene::create_popup_menu()
  {
    Gtk::Menu* menu = Gtk::manage(new Gtk::Menu());

    Gtk::Menu::MenuList& menu_list = menu->items();

    // Toggle animation
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Toggle Animation",
      sigc::mem_fun(*this, &Scene::toggle_anim)));

    // Init orientation
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Initialize",
      sigc::mem_fun(*this, &Scene::init_anim)));

    // Quit
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Quit",
      sigc::ptr_fun(&Gtk::Main::quit)));    

    return menu;
  }


  //
  // Application class implementation.
  //

  const Glib::ustring Application::APP_NAME = "Logo";

  Application::Application(unsigned int rot_count,
                           bool enable_anim)
    : m_VBox(false, 0), m_Scene(rot_count, enable_anim), m_ButtonQuit("Quit")
  {
    //
    // Top-level window.
    //

    set_title(APP_NAME);

    // Get automatically redrawn if any of their children changed allocation.
    set_reallocate_redraws(true);

    add(m_VBox);

    //
    // Application scene.
    //

    m_Scene.set_size_request(300, 300);

    m_VBox.pack_start(m_Scene);

    //
    // Simple quit button.
    //

    m_ButtonQuit.signal_clicked().connect(
      sigc::mem_fun(*this, &Application::on_button_quit_clicked));

    m_VBox.pack_start(m_ButtonQuit, Gtk::PACK_SHRINK, 0);

    //
    // Show window.
    //

    show_all();
  }

  Application::~Application()
  {
  }

  void Application::on_button_quit_clicked()
  {
    Gtk::Main::quit();
  }

  bool Application::on_key_press_event(GdkEventKey* event)
  {
    switch (event->keyval) {
    case GDK_a:
      m_Scene.toggle_anim();
      break;
    case GDK_i:
      m_Scene.init_anim();
      break;
    case GDK_Escape:
      Gtk::Main::quit();
      break;
    default:
      return true;
    }

    m_Scene.invalidate();

    return true;
  }


} // namespace Logo


//
// Main.
//

int main(int argc, char** argv)
{
  Gtk::Main kit(argc, argv);

  //
  // Init gtkglextmm.
  //

  Gtk::GL::init(argc, argv);

  //
  // Parse arguments.
  //

  unsigned int rot_count = Logo::Model::DEFAULT_ROT_COUNT;
  bool enable_anim = true;

  bool arg_count = false;
  for (int i = 1; i < argc; ++i) {
    if (arg_count)
      rot_count = std::atoi(argv[i]);

    if (std::strcmp(argv[i], "--help") == 0 ||
        std::strcmp(argv[i], "-h") == 0) {
      std::cerr << "Usage: "
                << argv[0]
                << " [-count num] [-noanim] [--help]\n";
      std::exit(0);
    }

    if (std::strcmp(argv[i], "-count") == 0)
      arg_count = true;

    if (std::strcmp(argv[i], "-noanim") == 0)
      enable_anim = false;
  }

  //
  // Query OpenGL extension version.
  //

  int major, minor;
  Gdk::GL::query_version(major, minor);
  std::cout << "OpenGL extension version - "
            << major << "." << minor << std::endl;

  //
  // Instantiate and run the application.
  //

  Logo::Application application(rot_count, enable_anim);

  kit.run(application);

  return 0;
}

Generated on Mon Feb 27 18:46:52 2006 for gtkglextmm by  doxygen 1.4.4