Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
477 lines (356 sloc) 12.3 KB
/****************************************************************************
GLUI User Interface Toolkit
---------------------------
glui_rotation - GLUI_Rotation control class
--------------------------------------------------
Copyright (c) 1998 Paul Rademacher
WWW: https://github.com/libglui/glui
Issues: https://github.com/libglui/glui/issues
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*****************************************************************************/
#include "GL/glui.h"
#include "arcball.h"
#include "algebra3.h"
#include "tinyformat.h"
/*************************** GLUI_Rotation::iaction_mouse_down_handler() ***/
int GLUI_Rotation::iaction_mouse_down_handler( int local_x, int local_y )
{
copy_float_array_to_ball();
init_ball();
local_y = (int) floor(2.0 * ball->center[1] - local_y);
ball->mouse_down( local_x, local_y );
/* printf( "%d %d - %f %f\n", local_x, local_y, ball->center[0], ball->center[1] ); */
copy_ball_to_float_array();
spinning = false;
return false;
}
/*********************** GLUI_Rotation::iaction_mouse_up_handler() **********/
int GLUI_Rotation::iaction_mouse_up_handler( int local_x, int local_y,
bool inside )
{
copy_float_array_to_ball();
ball->mouse_up();
return false;
}
/******************* GLUI_Rotation::iaction_mouse_held_down_handler() ******/
int GLUI_Rotation::iaction_mouse_held_down_handler( int local_x, int local_y,
bool inside)
{
if ( NOT glui )
return 0;
copy_float_array_to_ball();
local_y = (int) floor(2.0 * ball->center[1] - local_y);
/* printf( "%d %d\n", local_x, local_y ); */
ball->mouse_motion( local_x, local_y, 0,
(glui->curr_modifiers & GLUT_ACTIVE_ALT) != 0,
(glui->curr_modifiers & GLUT_ACTIVE_CTRL) != 0 );
copy_ball_to_float_array();
if ( can_spin )
spinning = true;
return false;
}
/******************** GLUI_Rotation::iaction_draw_active_area_persp() **************/
void GLUI_Rotation::iaction_draw_active_area_persp()
{
/********** arcball *******/
copy_float_array_to_ball();
setup_texture();
setup_lights();
glEnable(GL_CULL_FACE );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
mat4 tmp_rot = *ball->rot_ptr;
glMultMatrixf( (float*) &tmp_rot[0][0] );
/*** Draw the checkered box ***/
/*glDisable( GL_TEXTURE_2D ); */
draw_ball(1.35); // 1.96 );
glPopMatrix();
glBindTexture(GL_TEXTURE_2D,0); /* unhook our checkerboard texture */
glDisable( GL_TEXTURE_2D );
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
}
/******************** GLUI_Rotation::iaction_draw_active_area_ortho() **********/
void GLUI_Rotation::iaction_draw_active_area_ortho()
{
float radius;
radius = (float)(h-22)/2.0; /*MIN((float)w/2.0, (float)h/2.0); */
/********* Draw emboss circles around arcball control *********/
int k;
glLineWidth( 1.0 );
glBegin( GL_LINE_LOOP);
for( k=0; k<60; k++ ) {
float phi = 2*M_PI*(float)k/60.0;
vec2 p( cos(phi) * (2.0 + radius), sin(phi) * (2.0 + radius));
if ( p[1] < -p[0] ) glColor3ub( 128,128,128 );
else glColor3ub( 255,255,255 );
glVertex2fv((float*)&p[0]);
}
glEnd();
glBegin( GL_LINE_LOOP);
for( k=0; k<60; k++ ) {
float phi = 2*M_PI*(float)k/60.0;
vec2 p( cos(phi) * (1.0 + radius), sin(phi) * (1.0 + radius));
if ( enabled ) {
if ( p[1] < -p[0] ) glColor3ub( 0,0,0);
else glColor3ub( 192,192,192);
}
else
{
if ( p[1] < -p[0] ) glColor3ub( 180,180,180);
else glColor3ub( 192,192,192);
}
glVertex2fv((float*)&p[0]);
}
glEnd();
}
/******************************** GLUI_Rotation::iaction_dump() **********/
void GLUI_Rotation::iaction_dump( FILE *output )
{
}
/******************** GLUI_Rotation::iaction_special_handler() **********/
int GLUI_Rotation::iaction_special_handler( int key,int modifiers )
{
return false;
}
/********************************** GLUI_Rotation::init_ball() **********/
void GLUI_Rotation::init_ball()
{
/*printf( "%f %f %f", float( MIN(w/2,h/2)), (float) w/2, (float) h/2 ); */
ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)),
(float) 2.0*(h-18) );
/*ball->set_damping( .05 ); */
/*float( MIN(w/2,h/2))*2.0 ); */
/* ball->reset_mouse(); */
}
/****************************** GLUI_Rotation::setup_texture() *********/
void GLUI_Rotation::setup_texture()
{
static GLuint tex=0u;
GLenum t=GL_TEXTURE_2D;
glEnable(t);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glColor3f( 1.0, 1.0, 1.0 );
if (tex!=0u) {
/* (OSL 2006/06) Just use glBindTexture to avoid having to re-upload the whole checkerboard every frame. */
glBindTexture(t,tex);
return;
} /* Else need to make a new checkerboard texture */
glGenTextures(1,&tex);
glBindTexture(t,tex);
glEnable(t);
unsigned int i, j;
int dark, light; /*** Dark and light colors for ball checkerboard ***/
/* Note: you can change the number of checkers across there sphere in draw_ball */
#define CHECKBOARD_SIZE 64 /* pixels across whole texture */
#define CHECKBOARD_REPEAT 32u /* pixels across one black/white sector */
unsigned char texture_image[CHECKBOARD_SIZE] [CHECKBOARD_SIZE] [3];
unsigned char c;
for( i=0; i<CHECKBOARD_SIZE; i++ )
{
for( j=0; j<CHECKBOARD_SIZE; j++ )
{
dark = 110;
light = 220;
if ((((i/CHECKBOARD_REPEAT)&0x1)==0) ^ (((j/CHECKBOARD_REPEAT)&0x1)==0))
c = light;
else
c = dark;
texture_image[i][j][0] = c;
texture_image[i][j][1] = c;
texture_image[i][j][2] = c;
}
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexParameteri( t, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( t, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( t, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( t, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
gluBuild2DMipmaps(t, GL_RGB, CHECKBOARD_SIZE, CHECKBOARD_SIZE,
GL_RGB, GL_UNSIGNED_BYTE, texture_image);
/* Add some mipmapping LOD bias, to keep sphere texture sharp */
float bias=-0.5;
/* glTexEnvf(TEXTURE_FILTER_CONTROL_EXT,TEXTURE_LOD_BIAS_EXT,bias); */
/* glTexParameteri( t, GL_TEXTURE_MAX_LEVEL,1);*/
glTexEnvf(0x8500,0x8501,bias); /* <- numeric version for older OpenGL headers */
/* Cap out the mipmap level, to prevent blurring on horizon */
glTexParameteri(t, 0x813D, 1);
if (glGetError()) {
/* Ignore errors in setting funky texture state-- go with defaults.
If somebody knows how to check OpenGL 1.2 before doing this, please do!
*/
}
}
/****************************** GLUI_Rotation::setup_lights() ***********/
void GLUI_Rotation::setup_lights()
{
glEnable( GL_LIGHTING );
/* if ( enabled )
glEnable( GL_LIGHTING );
else
glDisable( GL_LIGHTING );*/
glEnable(GL_LIGHT0);
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE );
glEnable(GL_COLOR_MATERIAL);
GLfloat light0_position[] = {-1.f, 1.f, 1.0f, 0.0f};
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
if (enabled) { /* enabled colors */
GLfloat light0_ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat light0_diffuse[] = {1.f, 1.f, 1.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
}
else { /* disabled colors */
GLfloat light0_ambient[] = {0.6f, 0.6f, 0.6f, 1.0f};
GLfloat light0_diffuse[] = {0.2f, 0.2f, 0.2f, 1.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
}
}
/****************************** GLUI_Rotation::draw_ball() **************/
void GLUI_Rotation::draw_ball( float radius )
{
if ( NOT can_draw() )
return;
if (quadObj == NULL) quadObj = gluNewQuadric();
if (quadObj) {
gluQuadricDrawStyle(quadObj, GLU_FILL);
gluQuadricNormals(quadObj, GLU_SMOOTH);
gluQuadricTexture(quadObj, true );
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
double checkerTiles=2.0; /* black-white checker tiles across whole sphere */
glScalef(checkerTiles,checkerTiles,1.0);
gluSphere(quadObj, radius, 32, 16);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
}
/****************************** GLUI_Rotation::reset() **********/
void GLUI_Rotation::reset()
{
ball->init(); /** reset quaternion, etc. **/
ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)),
(float) 2.0*(h-18) );
set_spin( this->damping );
copy_ball_to_float_array();
translate_and_draw_front();
output_live(true); /*** Output live and draw main grx window ***/
}
/****************************** GLUI_Rotation::needs_idle() *********/
bool GLUI_Rotation::needs_idle() const
{
return can_spin;
}
/****************************** GLUI_Rotation::idle() ***************/
void GLUI_Rotation::idle()
{
spinning = ball->is_spinning?true:false;
if ( can_spin AND spinning ) {
copy_float_array_to_ball();
ball->idle();
*ball->rot_ptr = *ball->rot_ptr * ball->rot_increment;
mat4 tmp_rot;
tmp_rot = *ball->rot_ptr;
copy_ball_to_float_array();
draw_active_area_only = true;
translate_and_draw_front();
draw_active_area_only = false;
output_live(true); /** output live and update gfx **/
}
else {
}
}
/********************** GLUI_Rotation::copy_float_array_to_ball() *********/
void GLUI_Rotation::copy_float_array_to_ball()
{
int i;
float *fp_src, *fp_dst;
fp_src = &float_array_val[0];
fp_dst = &((*ball->rot_ptr)[0][0]);
for( i=0; i<16; i++ ) {
*fp_dst = *fp_src;
fp_src++;
fp_dst++;
}
}
/********************** GLUI_Rotation::copy_ball_to_float_array() *********/
void GLUI_Rotation::copy_ball_to_float_array()
{
mat4 tmp_rot;
tmp_rot = *ball->rot_ptr;
set_float_array_val( (float*) &tmp_rot[0][0] );
}
/************************ GLUI_Rotation::set_spin() **********************/
void GLUI_Rotation::set_spin( float damp_factor )
{
if ( damp_factor == 0.0 )
can_spin = false;
else
can_spin = true;
ball->set_damping( 1.0 - damp_factor );
this->damping = damp_factor;
}
/************** GLUI_Rotation::GLUI_Rotation() ********************/
GLUI_Rotation::GLUI_Rotation( GLUI_Node *parent,
const GLUI_String &name, float *value_ptr,
int id,
GLUI_CB cb )
{
common_init();
set_ptr_val( value_ptr );
user_id = id;
set_name( name );
callback = cb;
parent->add_control( this );
init_live();
/*** Init the live 4x4 matrix. This is different than the standard
live variable behavior, since the original value of the 4x4 matrix
is ignored and reset to Identity ***/
/*
NO! WVB
if ( value_ptr != NULL ) {
int i, j, index;
for( i=0; i<4; i++ ) {
for( j=0; j<4; j++ ) {
index = i*4+j;
if ( i==j )
value_ptr[index] = 1.0;
else
value_ptr[index] = 0.0;
}
}
}
*/
/*init_ball(); */
}
/************** GLUI_Rotation::common_init() ********************/
void GLUI_Rotation::common_init()
{
name = tfm::format("Rotation: %p", this );
// type = GLUI_CONTROL_ROTATION;
w = GLUI_ROTATION_WIDTH;
h = GLUI_ROTATION_HEIGHT;
can_activate = true;
live_type = GLUI_LIVE_FLOAT_ARRAY;
float_array_size = 16;
quadObj = NULL;
alignment = GLUI_ALIGN_CENTER;
can_spin = false;
spinning = false;
damping = 0.0;
ball = new Arcball;
reset();
}