#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"
namespace LogoModel {
#include "logo-model.h"
}
namespace Trackball {
extern "C" {
#include "trackball.h"
}
}
#define DIG_2_RAD (G_PI / 180.0)
#define RAD_2_DIG (180.0 / G_PI)
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);
};
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";
}
}
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;
}
namespace Logo
{
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;
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;
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;
}
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();
return false;
}
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 }
};
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);
glNewList(CUBE, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, MAT_BLACK);
LogoModel::logo_draw_cube();
glEndList();
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();
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();
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();
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();
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();
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()
{
static bool initialized = false;
if (!initialized) {
init_gl();
initialized = true;
}
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;
}
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;
}
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)
{
Glib::RefPtr<Gdk::GL::Config> glconfig;
glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB |
Gdk::GL::MODE_DEPTH |
Gdk::GL::MODE_DOUBLE);
if (glconfig.is_null()) {
std::cerr << "*** Cannot find the double-buffered visual.\n"
<< "*** Trying single-buffered visual.\n";
glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB |
Gdk::GL::MODE_DEPTH);
if (glconfig.is_null()) {
std::cerr << "*** Cannot find any OpenGL-capable visual.\n";
std::exit(1);
}
}
GLConfigUtil::examine_gl_attrib(glconfig);
set_gl_capability(glconfig);
add_events(Gdk::BUTTON1_MOTION_MASK |
Gdk::BUTTON2_MOTION_MASK |
Gdk::BUTTON_PRESS_MASK |
Gdk::VISIBILITY_NOTIFY_MASK);
signal_button_press_event().connect(
SigC::bind(SigC::slot(m_View, &View::on_button_press_event), this));
signal_motion_notify_event().connect(
SigC::bind(SigC::slot(m_View, &View::on_motion_notify_event), this));
m_Menu = create_popup_menu();
}
Scene::~Scene()
{
}
void Scene::on_realize()
{
Gtk::DrawingArea::on_realize();
Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();
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();
}
bool Scene::on_configure_event(GdkEventConfigure* event)
{
Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();
if (!gldrawable->gl_begin(get_gl_context()))
return false;
m_View.frustum(get_width(), get_height());
gldrawable->gl_end();
return true;
}
bool Scene::on_expose_event(GdkEventExpose* event)
{
Glib::RefPtr<Gdk::GL::Drawable> gldrawable = get_gl_drawable();
if (!gldrawable->gl_begin(get_gl_context()))
return false;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
m_View.xform();
m_Model.draw();
if (gldrawable->is_double_buffered())
gldrawable->swap_buffers();
else
glFlush();
gldrawable->gl_end();
return true;
}
bool Scene::on_button_press_event(GdkEventButton* event)
{
if (event->button == 3) {
m_Menu->popup(event->button, event->time);
return true;
}
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();
update();
return true;
}
void Scene::timeout_add()
{
if (!m_ConnectionTimeout.connected())
m_ConnectionTimeout = Glib::signal_timeout().connect(
SigC::slot(*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();
menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Toggle Animation",
SigC::slot(*this, &Scene::toggle_anim)));
menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Initialize",
SigC::slot(*this, &Scene::init_anim)));
menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Quit",
SigC::slot(&Gtk::Main::quit)));
return menu;
}
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")
{
set_title(APP_NAME);
set_reallocate_redraws(true);
add(m_VBox);
m_Scene.set_size_request(300, 300);
m_VBox.pack_start(m_Scene);
m_ButtonQuit.signal_clicked().connect(
SigC::slot(*this, &Application::on_button_quit_clicked));
m_VBox.pack_start(m_ButtonQuit, Gtk::PACK_SHRINK, 0);
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;
}
}
int main(int argc, char** argv)
{
Gtk::Main kit(argc, argv);
Gtk::GL::init(argc, argv);
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;
}
int major, minor;
Gdk::GL::query_version(major, minor);
std::cout << "OpenGL extension version - "
<< major << "." << minor << std::endl;
Logo::Application application(rot_count, enable_anim);
kit.run(application);
return 0;
}