Bazaar/FTGL_Demo : a demo application for FTGL library

git-svn-id: svn://ultimatepp.org/upp/trunk@3872 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
micio 2011-09-17 17:41:26 +00:00
parent 97367a3496
commit 2c4e23d3d8
13 changed files with 2154 additions and 0 deletions

View file

@ -0,0 +1,542 @@
#include "FTGLCtrl.h"
FTGLCtrl::FTGLCtrl() : trackBall(this)
{
mode = INTERACTIVE;
currentFont = FTGL_EXTRUDE;
myString =
"OpenGL is a powerful software interface for graphics "
"hardware that allows graphics programmers to produce high-quality "
"color images of 3D objects. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
"MNOPQRSTUVWXYZ0123456789";
totalFonts = 0;
layouts.Add(new FTSimpleLayout);
currentLayout = 0;
OX = -100;
OY = 200;
#ifdef PLATFORM_OSX11
SetFontFiles(Vector<String>()
<< "/System/Library/Fonts/Helvetica.dfont",
<< "/System/Library/Fonts/Geneva.dfont"
;
#elif defined(WIN32)
SetFontFiles(Vector<String>()
<< "C:\\WINDOWS\\Fonts\\arial.ttf"
);
#elif defined(PLATFORM_LINUX)
SetFontFiles(Vector<String>()
<< "/usr/share/fonts/truetype/msttcorefonts/arial.ttf"
);
#else
#error "UNSUPPORTED PLATFORM -- ADD HERE DEFAULT FONTS"
#endif
initialLineLength = 300.0f;
FTSimpleLayout &sl = (FTSimpleLayout &)layouts.Top();
sl.SetLineLength(initialLineLength);
sl.SetFont(&fonts[currentFont]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.13, 0.17, 0.32, 0.0);
glColor3f(1.0, 1.0, 1.0);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POLYGON_OFFSET_LINE);
glPolygonOffset(1.0, 1.0); // ????
SetCamera();
}
bool FTGLCtrl::Key(dword key, int count)
{
FTSimpleLayout *l = NULL;
// If the currentLayout is a SimpleLayout store a pointer in l
if(hasLayout() && (dynamic_cast <FTSimpleLayout *>(&layouts[currentLayout])))
l = (FTSimpleLayout *)&layouts[currentLayout];
switch (key)
{
case K_ESCAPE:
GetMainWindow()->Break();
break;
case K_RETURN:
if(mode == EDITING)
mode = INTERACTIVE;
else
mode = EDITING;
break;
case K_TAB:
if(l)
{
// Decrement the layout
switch (l->GetAlignment())
{
case FTGL::ALIGN_LEFT:
l->SetAlignment(FTGL::ALIGN_RIGHT);
break;
case FTGL::ALIGN_RIGHT:
l->SetAlignment(FTGL::ALIGN_CENTER);
break;
case FTGL::ALIGN_CENTER:
l->SetAlignment(FTGL::ALIGN_JUSTIFY);
break;
case FTGL::ALIGN_JUSTIFY:
l->SetAlignment(FTGL::ALIGN_LEFT);
break;
}
}
break;
case K_UP:
currentFont = (GetFace()*NumStyles + (currentFont + 1) % NumStyles) % totalFonts;
break;
case K_DOWN:
currentFont = (GetFace()*NumStyles + (currentFont + NumStyles - 1) % NumStyles) % totalFonts;
break;
case K_LEFT:
fonts[currentFont].FaceSize(fonts[currentFont].FaceSize() - 1);
break;
case K_RIGHT:
fonts[currentFont].FaceSize(fonts[currentFont].FaceSize() + 1);
break;
case K_PAGEUP:
currentFont = (currentFont + NumStyles) % totalFonts;
break;
case K_PAGEDOWN:
currentFont = (currentFont + totalFonts - NumStyles) % totalFonts;
break;
case K_HOME:
currentLayout = (currentLayout + 1) % layouts.GetCount();
break;
case K_END:
currentLayout = (currentLayout + layouts.GetCount() - 1) % layouts.GetCount();
break;
case K_F1:
case K_F10:
// If the current layout is simple decrement its line length
if (l)
l->SetLineLength(l->GetLineLength() - 10.0f);
break;
case K_F2:
case K_F11:
// If the current layout is simple increment its line length
if (l)
l->SetLineLength(l->GetLineLength() + 10.0f);
break;
default:
if(mode == EDITING)
{
if(isprint(key))
myString << (char)key;
else if(key == K_BACKSPACE && myString.GetCount() > 0)
myString.Trim(myString.GetCount() - 1);
}
break;
}
// If the current layout is a SimpleLayout, update its font.
if(l)
l->SetFont(&fonts[currentFont]);
Refresh();
Sync();
return true;
}
void FTGLCtrl::SetUpLighting()
{
// Set up lighting.
float light1_ambient[4] = { 1.0, 1.0, 1.0, 1.0 };
float light1_diffuse[4] = { 1.0, 0.9, 0.9, 1.0 };
float light1_specular[4] = { 1.0, 0.7, 0.7, 1.0 };
float light1_position[4] = { -1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glEnable(GL_LIGHT1);
float light2_ambient[4] = { 0.2, 0.2, 0.2, 1.0 };
float light2_diffuse[4] = { 0.9, 0.9, 0.9, 1.0 };
float light2_specular[4] = { 0.7, 0.7, 0.7, 1.0 };
float light2_position[4] = { 1.0, -1.0, -1.0, 0.0 };
glLightfv(GL_LIGHT2, GL_AMBIENT, light2_ambient);
glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse);
glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular);
glLightfv(GL_LIGHT2, GL_POSITION, light2_position);
//glEnable(GL_LIGHT2);
float front_emission[4] = { 0.3, 0.2, 0.1, 0.0 };
float front_ambient[4] = { 0.2, 0.2, 0.2, 0.0 };
float front_diffuse[4] = { 0.95, 0.95, 0.8, 0.0 };
float front_specular[4] = { 0.6, 0.6, 0.6, 0.0 };
glMaterialfv(GL_FRONT, GL_EMISSION, front_emission);
glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 16.0);
glColor4fv(front_diffuse);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glEnable(GL_CULL_FACE);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
}
void FTGLCtrl::SetFontFiles(Vector<String> const &files)
{
// copy font file names, it's needed later...
fontFiles <<= files;
// The total number of fonts is styles * faces
totalFonts = files.GetCount() * NumStyles;
// Instantiate and configure named fonts
for(int i = 0; i < files.GetCount(); i++)
{
fonts.Add(new FTBitmapFont(files[i]));
fonts.Add(new FTPixmapFont(files[i]));
fonts.Add(new FTOutlineFont(files[i]));
fonts.Add(new FTPolygonFont(files[i]));
fonts.Add(new FTExtrudeFont(files[i]));
fonts.Add(new FTTextureFont(files[i]));
for(int x = 0; x < NumStyles; ++x)
{
int j = i * NumStyles + x;
if(fonts[j].Error())
{
Exclamation(Format("Failed to open font %s", fontFiles[i]));
exit(1);
}
if(!fonts[j].FaceSize(24))
{
Exclamation("Failed to set size");
exit(1);
}
fonts[j].Depth(20);
fonts[j].CharMap(ft_encoding_unicode);
}
}
infoFont = new FTPixmapFont(files[0]);
if(infoFont->Error())
{
Exclamation(Format("Failed to open font %s\n", files[0]));
exit(1);
}
infoFont->FaceSize(18);
}
void FTGLCtrl::RenderFontmetrics()
{
FTBBox bbox;
float x1, y1, z1, x2, y2, z2;
// If there is a layout, use it to compute the bbox, otherwise query as
// a string.
if(hasLayout())
bbox = layouts[currentLayout].BBox(myString);
else
bbox = fonts[currentFont].BBox(myString);
x1 = bbox.Lower().Xf(); y1 = bbox.Lower().Yf(); z1 = bbox.Lower().Zf();
x2 = bbox.Upper().Xf(); y2 = bbox.Upper().Yf(); z2 = bbox.Upper().Zf();
// Draw the bounding box
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // GL_ONE_MINUS_SRC_ALPHA
glColor3f(0.0, 1.0, 0.0);
// Draw the front face
glBegin(GL_LINE_LOOP);
glVertex3f(x1, y1, z1);
glVertex3f(x1, y2, z1);
glVertex3f(x2, y2, z1);
glVertex3f(x2, y1, z1);
glEnd();
// Draw the back face
if((GetStyle() == FTGL_EXTRUDE) && (z1 != z2))
{
glBegin(GL_LINE_LOOP);
glVertex3f(x1, y1, z2);
glVertex3f(x1, y2, z2);
glVertex3f(x2, y2, z2);
glVertex3f(x2, y1, z2);
glEnd();
// Join the faces
glBegin(GL_LINES);
glVertex3f(x1, y1, z1);
glVertex3f(x1, y1, z2);
glVertex3f(x1, y2, z1);
glVertex3f(x1, y2, z2);
glVertex3f(x2, y2, z1);
glVertex3f(x2, y2, z2);
glVertex3f(x2, y1, z1);
glVertex3f(x2, y1, z2);
glEnd();
}
// Render layout-specific metrics
if(!hasLayout())
{
// There is no layout. Draw the baseline, Ascender and Descender
glBegin(GL_LINES);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(fonts[currentFont].Advance(myString), 0.0, 0.0);
glVertex3f(0.0, fonts[currentFont].Ascender(), 0.0);
glVertex3f(0.0, fonts[currentFont].Descender(), 0.0);
glEnd();
}
else if (dynamic_cast <FTSimpleLayout *>(&layouts[currentLayout]))
{
float lineWidth = ((FTSimpleLayout const &)layouts[currentLayout]).GetLineLength();
// The layout is a SimpleLayout. Render guides that mark the edges
// of the wrap region.
glColor3f(0.5, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0, 10000, 0);
glVertex3f(0, -10000, 0);
glVertex3f(lineWidth, 10000, 0);
glVertex3f(lineWidth, -10000, 0);
glEnd();
}
// Draw the origin
glColor3f(1.0, 0.0, 0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
void FTGLCtrl::RenderFontInfo()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, GetSize().cx, 0, GetSize().cy);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw mode
glColor3f(1.0, 1.0, 1.0);
glRasterPos2f(20.0f , GetSize().cy - (20.0f + infoFont->Ascender()));
switch(mode)
{
case EDITING:
infoFont->Render("Edit Mode");
break;
case INTERACTIVE:
break;
}
// draw font type
glRasterPos2i(20 , 20);
switch(GetStyle())
{
case FTGL_BITMAP:
infoFont->Render("Bitmap Font");
break;
case FTGL_PIXMAP:
infoFont->Render("Pixmap Font");
break;
case FTGL_OUTLINE:
infoFont->Render("Outline Font");
break;
case FTGL_POLYGON:
infoFont->Render("Polygon Font");
break;
case FTGL_EXTRUDE:
infoFont->Render("Extruded Font");
break;
case FTGL_TEXTURE:
infoFont->Render("Texture Font");
break;
}
glRasterPos2f(20.0f , 20.0f + infoFont->Ascender() - infoFont->Descender());
infoFont->Render(fontFiles[GetFace()]);
// If the current layout is a SimpleLayout, output the alignemnt mode
if(hasLayout() && (dynamic_cast <FTSimpleLayout *>(&layouts[currentLayout])))
{
glRasterPos2f(20.0f , 20.0f + 2*(infoFont->Ascender() - infoFont->Descender()));
// Output the alignment mode of the layout
switch (((FTSimpleLayout const &)layouts[currentLayout]).GetAlignment())
{
case FTGL::ALIGN_LEFT:
infoFont->Render("Align Left");
break;
case FTGL::ALIGN_RIGHT:
infoFont->Render("Align Right");
break;
case FTGL::ALIGN_CENTER:
infoFont->Render("Align Center");
break;
case FTGL::ALIGN_JUSTIFY:
infoFont->Render("Align Justified");
break;
}
}
}
void FTGLCtrl::Paint0(void)
{
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
case FTGL_OUTLINE:
break;
case FTGL_POLYGON:
glDisable(GL_BLEND);
SetUpLighting();
break;
case FTGL_EXTRUDE:
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
SetUpLighting();
break;
case FTGL_TEXTURE:
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
SetUpLighting();
glNormal3f(0.0, 0.0, 1.0);
break;
}
glColor3f(1.0, 1.0, 1.0);
// If you do want to switch the color of bitmaps rendered with glBitmap,
// you will need to explicitly call glRasterPos (or its ilk) to lock
// in a changed current color.
// If there is an active layout use it to render the font
if (hasLayout())
layouts[currentLayout].Render(myString);
else
fonts[currentFont].Render(myString);
RenderFontmetrics();
RenderFontInfo();
}
void FTGLCtrl::SetCamera(void)
{
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, GetSize().cx, 0, GetSize().cy);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
break;
case FTGL_OUTLINE:
case FTGL_POLYGON:
case FTGL_EXTRUDE:
case FTGL_TEXTURE:
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(90, (float)GetSize().cx / (float)GetSize().cy, 1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, (float)GetSize().cy / 2.0f, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
break;
}
}
void FTGLCtrl::Layout()
{
glMatrixMode (GL_MODELVIEW);
glViewport (0, 0, GetSize().cx, GetSize().cy);
glLoadIdentity();
SetCamera();
trackBall.Reshape(GetSize().cx, GetSize().cy);
GLCtrl::Layout();
}
void FTGLCtrl::GLPaint()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SetCamera();
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
glRasterPos2i((long)(GetSize().cx / 2 + OX), (long)(GetSize().cy / 2 + OY));
glTranslatef(GetSize().cx / 2 + OX, GetSize().cy / 2 + OY, 0.0);
break;
case FTGL_OUTLINE:
case FTGL_POLYGON:
case FTGL_EXTRUDE:
case FTGL_TEXTURE:
glTranslatef(OX, OY, 0);
trackBall.Matrix();
break;
}
glPushMatrix();
Paint0();
glPopMatrix();
}

View file

@ -0,0 +1,70 @@
#ifndef _FTGL_Demo_FTGLCtrl_h_
#define _FTGL_Demo_FTGLCtrl_h_
#include <CtrlLib/CtrlLib.h>
#include <GLCtrl/GLCtrl.h>
#include <FTGL/ftgl.h>
#include "TrackBall.h"
using namespace Upp;
class FTGLCtrl : public GLCtrl
{
private:
TrackBall trackBall;
typedef enum { FTGL_BITMAP, FTGL_PIXMAP, FTGL_OUTLINE, FTGL_POLYGON, FTGL_EXTRUDE, FTGL_TEXTURE, NumStyles } Styles;
typedef enum { EDITING = 1, INTERACTIVE } Modes;
Modes mode;
Vector<String> fontFiles;
int currentFont;
// array containing all fonts
Array<FTFont> fonts;
int totalFonts;
One<FTPixmapFont> infoFont;
Array<FTLayout> layouts;
int currentLayout;
bool hasLayout(void) { return currentLayout >= 0 && currentLayout < layouts.GetCount(); }
// displayed string
String myString;
void SetUpLighting();
void SetUpFonts(int numFontFiles);
void RenderFontmetrics();
void RenderFontInfo();
void SetCamera();
void Paint0(void);
int GetStyle() { return currentFont % NumStyles; }
int GetFace() { return currentFont / NumStyles; }
float OX;
float OY;
float initialLineLength;
protected:
virtual void GLPaint();
virtual Image MouseEvent(int event, Point p, int zdelta, dword keyflags) { return trackBall.MouseEvent(event, p, zdelta, keyflags); }
virtual bool Key(dword key, int count);
virtual void Layout();
public:
typedef FTGLCtrl CLASSNAME;
void SetFontFiles(Vector<String> const &files);
FTGLCtrl();
};
#endif

View file

@ -0,0 +1,14 @@
#include "FTGLDemo.h"
FTGLDemo::FTGLDemo()
{
Add(ftglCtrl.SizePos());
}
GUI_APP_MAIN
{
FTGLDemo ftglDemo;
ftglDemo.Sizeable().Zoomable().MinimizeBox();
ftglDemo.Run();
}

View file

@ -0,0 +1,18 @@
#ifndef _FTGL_Demo_FTGLDemo_h_
#define _FTGL_Demo_FTGLDemo_h_
#include "FTGLCtrl.h"
class FTGLDemo : public TopWindow
{
typedef FTGLDemo CLASSNAME;
private:
FTGLCtrl ftglCtrl;
public:
FTGLDemo();
};
#endif

View file

@ -0,0 +1,693 @@
/*
* FTGLDemo - advanced demo for FTGL, the OpenGL font library
*
* Copyright (c) 2001-2004 Henry Maddocks <ftgl@opengl.geek.nz>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined HAVE_GL_GLUT_H
# include <GL/glut.h>
#elif defined HAVE_GLUT_GLUT_H
# include <GLUT/glut.h>
#else
# error GLUT headers not present
#endif
#include <FTGL/ftgl.h>
#include "tb.h"
// YOU'LL PROBABLY WANT TO CHANGE THESE
#if defined FONT_FILE
char const *defaultFonts[] = { FONT_FILE };
const int NumDefaultFonts = 1;
#elif defined __APPLE_CC__
char const *defaultFonts[] = { "/System/Library/Fonts/Helvetica.dfont",
"/System/Library/Fonts/Geneva.dfont" };
const int NumDefaultFonts = 2;
#elif defined WIN32
char const *defaultFonts[] = { "C:\\WINNT\\Fonts\\arial.ttf" };
const int NumDefaultFonts = 1;
#else
// Put your font files here if configure did not find any.
char const *defaultFonts[] = { };
const int NumDefaultFonts = 0;
#endif
/* Set this to 1 to build a Mac os app (ignore the command line args). */
#ifndef IGNORE_ARGV
# define IGNORE_ARGV 0
#endif /* IGNORE_ARGV */
#define EDITING 1
#define INTERACTIVE 2
#define FTGL_BITMAP 0
#define FTGL_PIXMAP 1
#define FTGL_OUTLINE 2
#define FTGL_POLYGON 3
#define FTGL_EXTRUDE 4
#define FTGL_TEXTURE 5
const int NumStyles = 6;
char const * const *fontfiles;
int current_font = FTGL_EXTRUDE;
GLint w_win = 640, h_win = 480;
int mode = INTERACTIVE;
int carat = 0;
FTSimpleLayout simpleLayout;
FTLayout *layouts[] = { &simpleLayout, NULL };
int currentLayout = 0;
const int NumLayouts = 2;
const float InitialLineLength = 300.0f;
const float OX = -100;
const float OY = 200;
//wchar_t myString[16] = { 0x6FB3, 0x9580};
char myString[4096];
int totalFonts;
static FTFont** fonts;
static FTPixmapFont* infoFont;
void SetCamera(void);
inline int GetStyle()
{
return current_font % NumStyles;
}
inline int GetFace()
{
return current_font / NumStyles;
}
void setUpLighting()
{
// Set up lighting.
float light1_ambient[4] = { 1.0, 1.0, 1.0, 1.0 };
float light1_diffuse[4] = { 1.0, 0.9, 0.9, 1.0 };
float light1_specular[4] = { 1.0, 0.7, 0.7, 1.0 };
float light1_position[4] = { -1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glEnable(GL_LIGHT1);
float light2_ambient[4] = { 0.2, 0.2, 0.2, 1.0 };
float light2_diffuse[4] = { 0.9, 0.9, 0.9, 1.0 };
float light2_specular[4] = { 0.7, 0.7, 0.7, 1.0 };
float light2_position[4] = { 1.0, -1.0, -1.0, 0.0 };
glLightfv(GL_LIGHT2, GL_AMBIENT, light2_ambient);
glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse);
glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular);
glLightfv(GL_LIGHT2, GL_POSITION, light2_position);
//glEnable(GL_LIGHT2);
float front_emission[4] = { 0.3, 0.2, 0.1, 0.0 };
float front_ambient[4] = { 0.2, 0.2, 0.2, 0.0 };
float front_diffuse[4] = { 0.95, 0.95, 0.8, 0.0 };
float front_specular[4] = { 0.6, 0.6, 0.6, 0.0 };
glMaterialfv(GL_FRONT, GL_EMISSION, front_emission);
glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 16.0);
glColor4fv(front_diffuse);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glEnable(GL_CULL_FACE);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
}
void setUpFonts(int numFontFiles)
{
// The total number of fonts is styles * faces
totalFonts = numFontFiles*NumStyles;
// Allocate an array to hold all fonts
fonts = new FTFont *[totalFonts];
// Instantiate and configure named fonts
for(int i = 0; i < numFontFiles; i++)
{
fonts[i*NumStyles + FTGL_BITMAP] = new FTBitmapFont(fontfiles[i]);
fonts[i*NumStyles + FTGL_PIXMAP] = new FTPixmapFont(fontfiles[i]);
fonts[i*NumStyles + FTGL_OUTLINE] = new FTOutlineFont(fontfiles[i]);
fonts[i*NumStyles + FTGL_POLYGON] = new FTPolygonFont(fontfiles[i]);
fonts[i*NumStyles + FTGL_EXTRUDE] = new FTExtrudeFont(fontfiles[i]);
fonts[i*NumStyles + FTGL_TEXTURE] = new FTTextureFont(fontfiles[i]);
for(int x = 0; x < NumStyles; ++x)
{
int j = i * NumStyles + x;
if(fonts[j]->Error())
{
fprintf(stderr, "Failed to open font %s\n", fontfiles[i]);
exit(1);
}
if(!fonts[j]->FaceSize(24))
{
fprintf(stderr, "Failed to set size\n");
exit(1);
}
fonts[j]->Depth(20);
fonts[j]->CharMap(ft_encoding_unicode);
}
}
infoFont = new FTPixmapFont(fontfiles[0]);
if(infoFont->Error())
{
fprintf(stderr, "Failed to open font %s\n", fontfiles[0]);
exit(1);
}
infoFont->FaceSize(18);
strcpy(myString, "OpenGL is a powerful software interface for graphics "
"hardware that allows graphics programmers to produce high-quality "
"color images of 3D objects. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
"MNOPQRSTUVWXYZ0123456789");
}
void renderFontmetrics()
{
FTBBox bbox;
float x1, y1, z1, x2, y2, z2;
// If there is a layout, use it to compute the bbox, otherwise query as
// a string.
if(layouts[currentLayout])
bbox = layouts[currentLayout]->BBox(myString);
else
bbox = fonts[current_font]->BBox(myString);
x1 = bbox.Lower().Xf(); y1 = bbox.Lower().Yf(); z1 = bbox.Lower().Zf();
x2 = bbox.Upper().Xf(); y2 = bbox.Upper().Yf(); z2 = bbox.Upper().Zf();
// Draw the bounding box
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // GL_ONE_MINUS_SRC_ALPHA
glColor3f(0.0, 1.0, 0.0);
// Draw the front face
glBegin(GL_LINE_LOOP);
glVertex3f(x1, y1, z1);
glVertex3f(x1, y2, z1);
glVertex3f(x2, y2, z1);
glVertex3f(x2, y1, z1);
glEnd();
// Draw the back face
if((GetStyle() == FTGL_EXTRUDE) && (z1 != z2))
{
glBegin(GL_LINE_LOOP);
glVertex3f(x1, y1, z2);
glVertex3f(x1, y2, z2);
glVertex3f(x2, y2, z2);
glVertex3f(x2, y1, z2);
glEnd();
// Join the faces
glBegin(GL_LINES);
glVertex3f(x1, y1, z1);
glVertex3f(x1, y1, z2);
glVertex3f(x1, y2, z1);
glVertex3f(x1, y2, z2);
glVertex3f(x2, y2, z1);
glVertex3f(x2, y2, z2);
glVertex3f(x2, y1, z1);
glVertex3f(x2, y1, z2);
glEnd();
}
// Render layout-specific metrics
if(!layouts[currentLayout])
{
// There is no layout. Draw the baseline, Ascender and Descender
glBegin(GL_LINES);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(fonts[current_font]->Advance(myString), 0.0, 0.0);
glVertex3f(0.0, fonts[current_font]->Ascender(), 0.0);
glVertex3f(0.0, fonts[current_font]->Descender(), 0.0);
glEnd();
}
else if (layouts[currentLayout]
&& (dynamic_cast <FTSimpleLayout *>(layouts[currentLayout])))
{
float lineWidth = ((FTSimpleLayout *)layouts[currentLayout])->GetLineLength();
// The layout is a SimpleLayout. Render guides that mark the edges
// of the wrap region.
glColor3f(0.5, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0, 10000, 0);
glVertex3f(0, -10000, 0);
glVertex3f(lineWidth, 10000, 0);
glVertex3f(lineWidth, -10000, 0);
glEnd();
}
// Draw the origin
glColor3f(1.0, 0.0, 0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
void renderFontInfo()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w_win, 0, h_win);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw mode
glColor3f(1.0, 1.0, 1.0);
glRasterPos2f(20.0f , h_win - (20.0f + infoFont->Ascender()));
switch(mode)
{
case EDITING:
infoFont->Render("Edit Mode");
break;
case INTERACTIVE:
break;
}
// draw font type
glRasterPos2i(20 , 20);
switch(GetStyle())
{
case FTGL_BITMAP:
infoFont->Render("Bitmap Font");
break;
case FTGL_PIXMAP:
infoFont->Render("Pixmap Font");
break;
case FTGL_OUTLINE:
infoFont->Render("Outline Font");
break;
case FTGL_POLYGON:
infoFont->Render("Polygon Font");
break;
case FTGL_EXTRUDE:
infoFont->Render("Extruded Font");
break;
case FTGL_TEXTURE:
infoFont->Render("Texture Font");
break;
}
glRasterPos2f(20.0f , 20.0f + infoFont->Ascender() - infoFont->Descender());
infoFont->Render(fontfiles[GetFace()]);
// If the current layout is a SimpleLayout, output the alignemnt mode
if(layouts[currentLayout]
&& (dynamic_cast <FTSimpleLayout *>(layouts[currentLayout])))
{
glRasterPos2f(20.0f , 20.0f + 2*(infoFont->Ascender() - infoFont->Descender()));
// Output the alignment mode of the layout
switch (((FTSimpleLayout *)layouts[currentLayout])->GetAlignment())
{
case FTGL::ALIGN_LEFT:
infoFont->Render("Align Left");
break;
case FTGL::ALIGN_RIGHT:
infoFont->Render("Align Right");
break;
case FTGL::ALIGN_CENTER:
infoFont->Render("Align Center");
break;
case FTGL::ALIGN_JUSTIFY:
infoFont->Render("Align Justified");
break;
}
}
}
void do_display (void)
{
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
case FTGL_OUTLINE:
break;
case FTGL_POLYGON:
glDisable(GL_BLEND);
setUpLighting();
break;
case FTGL_EXTRUDE:
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
setUpLighting();
break;
case FTGL_TEXTURE:
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
setUpLighting();
glNormal3f(0.0, 0.0, 1.0);
break;
}
glColor3f(1.0, 1.0, 1.0);
// If you do want to switch the color of bitmaps rendered with glBitmap,
// you will need to explicitly call glRasterPos (or its ilk) to lock
// in a changed current color.
// If there is an active layout use it to render the font
if (layouts[currentLayout])
{
layouts[currentLayout]->Render(myString);
}
else
{
fonts[current_font]->Render(myString);
}
renderFontmetrics();
renderFontInfo();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SetCamera();
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
glRasterPos2i((long)(w_win / 2 + OX), (long)(h_win / 2 + OY));
glTranslatef(w_win / 2 + OX, h_win / 2 + OY, 0.0);
break;
case FTGL_OUTLINE:
case FTGL_POLYGON:
case FTGL_EXTRUDE:
case FTGL_TEXTURE:
glTranslatef(OX, OY, 0);
tbMatrix();
break;
}
glPushMatrix();
do_display();
glPopMatrix();
glutSwapBuffers();
}
void myinit(int numFontFiles)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.13, 0.17, 0.32, 0.0);
glColor3f(1.0, 1.0, 1.0);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POLYGON_OFFSET_LINE);
glPolygonOffset(1.0, 1.0); // ????
SetCamera();
tbInit(GLUT_LEFT_BUTTON);
tbAnimate(GL_FALSE);
setUpFonts(numFontFiles);
// Configure the SimpleLayout
simpleLayout.SetLineLength(InitialLineLength);
simpleLayout.SetFont(fonts[current_font]);
}
void parsekey(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(0);
break;
case 13:
if(mode == EDITING)
{
mode = INTERACTIVE;
}
else
{
mode = EDITING;
carat = 0;
}
break;
case '\t':
// If current layout is a SimpleLayout, change its alignment properties
if(layouts[currentLayout]
&& (dynamic_cast <FTSimpleLayout *>(layouts[currentLayout])))
{
FTSimpleLayout *l = (FTSimpleLayout *)layouts[currentLayout];
// Decrement the layout
switch (l->GetAlignment())
{
case FTGL::ALIGN_LEFT:
l->SetAlignment(FTGL::ALIGN_RIGHT);
break;
case FTGL::ALIGN_RIGHT:
l->SetAlignment(FTGL::ALIGN_CENTER);
break;
case FTGL::ALIGN_CENTER:
l->SetAlignment(FTGL::ALIGN_JUSTIFY);
break;
case FTGL::ALIGN_JUSTIFY:
l->SetAlignment(FTGL::ALIGN_LEFT);
break;
}
}
break;
default:
if(mode == INTERACTIVE)
{
myString[0] = key;
myString[1] = 0;
}
else
{
myString[carat] = key;
myString[carat + 1] = 0;
carat = carat > 2000 ? 2000 : carat + 1;
}
break;
}
glutPostRedisplay();
}
void parseSpecialKey(int key, int x, int y)
{
FTSimpleLayout *l = NULL;
// If the currentLayout is a SimpleLayout store a pointer in l
if(layouts[currentLayout]
&& (dynamic_cast <FTSimpleLayout *>(layouts[currentLayout])))
{
l = (FTSimpleLayout *)layouts[currentLayout];
}
switch (key)
{
case GLUT_KEY_UP:
current_font = (GetFace()*NumStyles + (current_font + 1)%NumStyles)%totalFonts;
break;
case GLUT_KEY_DOWN:
current_font = (GetFace()*NumStyles + (current_font + NumStyles - 1)%NumStyles)%totalFonts;
break;
case GLUT_KEY_LEFT:
fonts[current_font]->FaceSize(fonts[current_font]->FaceSize() - 1);
break;
case GLUT_KEY_RIGHT:
fonts[current_font]->FaceSize(fonts[current_font]->FaceSize() + 1);
break;
case GLUT_KEY_PAGE_UP:
current_font = (current_font + NumStyles)%totalFonts;
break;
case GLUT_KEY_PAGE_DOWN:
current_font = (current_font + totalFonts - NumStyles)%totalFonts;
break;
case GLUT_KEY_HOME:
currentLayout = (currentLayout + 1)%NumLayouts;
break;
case GLUT_KEY_END:
currentLayout = (currentLayout + NumLayouts - 1)%NumLayouts;
break;
case GLUT_KEY_F1:
case GLUT_KEY_F10:
// If the current layout is simple decrement its line length
if (l) l->SetLineLength(l->GetLineLength() - 10.0f);
break;
case GLUT_KEY_F2:
case GLUT_KEY_F11:
// If the current layout is simple increment its line length
if (l) l->SetLineLength(l->GetLineLength() + 10.0f);
break;
}
// If the current layout is a SimpleLayout, update its font.
if(l)
{
l->SetFont(fonts[current_font]);
}
glutPostRedisplay();
}
void motion(int x, int y)
{
tbMotion(x, y);
}
void mouse(int button, int state, int x, int y)
{
tbMouse(button, state, x, y);
}
void myReshape(int w, int h)
{
glMatrixMode (GL_MODELVIEW);
glViewport (0, 0, w, h);
glLoadIdentity();
w_win = w;
h_win = h;
SetCamera();
tbReshape(w_win, h_win);
}
void SetCamera(void)
{
switch(GetStyle())
{
case FTGL_BITMAP:
case FTGL_PIXMAP:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w_win, 0, h_win);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
break;
case FTGL_OUTLINE:
case FTGL_POLYGON:
case FTGL_EXTRUDE:
case FTGL_TEXTURE:
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(90, (float)w_win / (float)h_win, 1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, (float)h_win / 2.0f, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
break;
}
}
int main(int argc, char *argv[])
{
int numFontFiles;
if((argc >= 2) && !IGNORE_ARGV)
{
fontfiles = (char const * const *)argv + 1;
numFontFiles = argc - 1;
}
else
{
fontfiles = defaultFonts;
numFontFiles = NumDefaultFonts;
}
if(!fontfiles[0])
{
fprintf(stderr, "At least one font file must be specified on the command line\n");
exit(1);
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
glutInitWindowPosition(50, 50);
glutInitWindowSize(w_win, h_win);
glutCreateWindow("FTGL TEST");
glutDisplayFunc(display);
glutKeyboardFunc(parsekey);
glutSpecialFunc(parseSpecialKey);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutReshapeFunc(myReshape);
glutIdleFunc(display);
myinit(numFontFiles);
glutMainLoop();
return 0;
}

View file

@ -0,0 +1,18 @@
uses
FTGL,
CtrlLib,
GLCtrl;
file
trackball.c,
trackball.h,
TrackBall.h,
TrackBall.cpp,
FTGLCtrl.h,
FTGLCtrl.cpp,
FTGLDemo.h,
FTGLDemo.cpp;
mainconfig
"" = "GUI";

View file

@ -0,0 +1,98 @@
#include "TrackBall.h"
#include "trackball.h"
#include <GL/glut.h>
void TrackBall::_Animate(void)
{
add_quats(lastquat, curquat, curquat);
owner->Refresh();
owner->Sync();
if(enableAnimCb)
owner->SetTimeCallback(10, THISBACK(_Animate));
}
void TrackBall::_StartMotion(int x, int y, Time time)
{
enableAnimCb = false;
tracking = true;
lastTime = time;
beginx = x;
beginy = y;
}
void TrackBall::_StopMotion(Time time)
{
tracking = false;
if (time == lastTime && animate)
{
enableAnimCb = true;
_Animate();
}
else
if (animate)
enableAnimCb = false;
}
void TrackBall::Animate(bool a)
{
animate = a;
}
void TrackBall::Matrix(void)
{
GLfloat m[4][4];
build_rotmatrix(m, curquat);
glMultMatrixf(&m[0][0]);
}
void TrackBall::Reshape(int w, int h)
{
width = w;
height = h;
}
// mouse event handler
Image TrackBall::MouseEvent(int event, Point p, int zdelta, dword keyflags)
{
// mouse up/down starts and stop motion
if ((event & Ctrl::BUTTON) == button && (event & Ctrl::ACTION) == Ctrl::DOWN)
_StartMotion(p.x, p.y, GetSysTime());
else
if ((event & Ctrl::BUTTON) == button && (event & Ctrl::ACTION) == Ctrl::UP)
_StopMotion(GetSysTime());
// mouse move do the animation, if we're tracking
else if((event & Ctrl::ACTION) == Ctrl::MOUSEMOVE)
{
if (tracking)
{
trackball(
lastquat,
(2.0 * beginx - width) / width,
(height - 2.0 * beginy) / height,
(2.0 * p.x - width) / width,
(height - 2.0 * p.y) / height
);
beginx = p.x;
beginy = p.y;
animate = true;
lastTime = GetSysTime();
_Animate();
}
}
return Image();
}
TrackBall::TrackBall(Ctrl *ow)
{
owner = ow;
button = Ctrl::LEFT;
tracking = false;
animate = false;
trackball(curquat, 0.0, 0.0, 0.0, 0.0);
enableAnimCb = false;
}

View file

@ -0,0 +1,50 @@
#ifndef _FTGL_Demo_TrackBall_h_
#define _FTGL_Demo_TrackBall_h_
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
class TrackBall
{
private:
Ctrl *owner;
Time lastTime;
float curquat[4];
float lastquat[4];
int beginx, beginy;
int width;
int height;
int button;
bool tracking;
bool animate;
void _Animate(void);
void _StartMotion(int x, int y, Time time);
void _StopMotion(Time time);
bool enableAnimCb;
protected:
public:
typedef TrackBall CLASSNAME;
void Matrix(void);
void Reshape(int width, int height);
void Animate(bool animate);
void SetButton(int but = Ctrl::LEFT) { button = but; }
virtual Image MouseEvent(int event, Point p, int zdelta, dword keyflags);
TrackBall(Ctrl *owner);
};
#endif

6
bazaar/FTGL_Demo/init Normal file
View file

@ -0,0 +1,6 @@
#ifndef _FTGL_Demo_icpp_init_stub
#define _FTGL_Demo_icpp_init_stub
#include "FTGL/init"
#include "CtrlLib/init"
#include "GLCtrl/init"
#endif

131
bazaar/FTGL_Demo/tb.c Normal file
View file

@ -0,0 +1,131 @@
/*
* Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes.
*/
#include "config.h"
#include <math.h>
#include <assert.h>
#if defined HAVE_GL_GLUT_H
# include <GL/glut.h>
#elif defined HAVE_GLUT_GLUT_H
# include <GLUT/glut.h>
#else
# error GLUT headers not present
#endif
#include "tb.h"
#include "trackball.h"
/* globals */
static GLuint tb_lasttime;
float curquat[4];
float lastquat[4];
int beginx, beginy;
static GLuint tb_width;
static GLuint tb_height;
static GLint tb_button = -1;
static GLboolean tb_tracking = GL_FALSE;
static GLboolean tb_animate = GL_TRUE;
static void
_tbAnimate(void)
{
add_quats(lastquat, curquat, curquat);
glutPostRedisplay();
}
static void
_tbStartMotion(int x, int y, int time)
{
assert(tb_button != -1);
glutIdleFunc(0);
tb_tracking = GL_TRUE;
tb_lasttime = time;
beginx = x;
beginy = y;
}
static void
_tbStopMotion(unsigned time)
{
assert(tb_button != -1);
tb_tracking = GL_FALSE;
if (time == tb_lasttime && tb_animate) {
glutIdleFunc(_tbAnimate);
} else {
if (tb_animate) {
glutIdleFunc(0);
}
}
}
void
tbAnimate(GLboolean animate)
{
tb_animate = animate;
}
void
tbInit(GLuint button)
{
tb_button = button;
trackball(curquat, 0.0, 0.0, 0.0, 0.0);
}
void
tbMatrix(void)
{
GLfloat m[4][4];
assert(tb_button != -1);
build_rotmatrix(m, curquat);
glMultMatrixf(&m[0][0]);
}
void
tbReshape(int width, int height)
{
assert(tb_button != -1);
tb_width = width;
tb_height = height;
}
void
tbMouse(int button, int state, int x, int y)
{
assert(tb_button != -1);
if (state == GLUT_DOWN && button == tb_button)
_tbStartMotion(x, y, glutGet(GLUT_ELAPSED_TIME));
else if (state == GLUT_UP && button == tb_button)
_tbStopMotion(glutGet(GLUT_ELAPSED_TIME));
}
void
tbMotion(int x, int y)
{
if (tb_tracking) {
trackball(lastquat,
(2.0 * beginx - tb_width) / tb_width,
(tb_height - 2.0 * beginy) / tb_height,
(2.0 * x - tb_width) / tb_width,
(tb_height - 2.0 * y) / tb_height
);
beginx = x;
beginy = y;
tb_animate = 1;
tb_lasttime = glutGet(GLUT_ELAPSED_TIME);
_tbAnimate();
}
}

103
bazaar/FTGL_Demo/tb.h Normal file
View file

@ -0,0 +1,103 @@
/*
* Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes.
*
*
* Usage:
*
* o call tbInit() in before any other tb call
* o call tbReshape() from the reshape callback
* o call tbMatrix() to get the trackball matrix rotation
* o call tbStartMotion() to begin trackball movememt
* o call tbStopMotion() to stop trackball movememt
* o call tbMotion() from the motion callback
* o call tbAnimate(GL_TRUE) if you want the trackball to continue
* spinning after the mouse button has been released
* o call tbAnimate(GL_FALSE) if you want the trackball to stop
* spinning after the mouse button has been released
*
* Typical setup:
*
*
void
init(void)
{
tbInit(GLUT_MIDDLE_BUTTON);
tbAnimate(GL_TRUE);
. . .
}
void
reshape(int width, int height)
{
tbReshape(width, height);
. . .
}
void
display(void)
{
glPushMatrix();
tbMatrix();
. . . draw the scene . . .
glPopMatrix();
}
void
mouse(int button, int state, int x, int y)
{
tbMouse(button, state, x, y);
. . .
}
void
motion(int x, int y)
{
tbMotion(x, y);
. . .
}
int
main(int argc, char** argv)
{
. . .
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
. . .
}
*
* */
/* functions */
#ifdef __cplusplus
extern "C" {
#endif
void
tbInit(GLuint button);
void
tbMatrix(void);
void
tbReshape(int width, int height);
void
tbMouse(int button, int state, int x, int y);
void
tbMotion(int x, int y);
void
tbAnimate(GLboolean animate);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,326 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* Trackball code:
*
* Implementation of a virtual trackball.
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
*
* Vector manip code:
*
* Original code from:
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
*
* Much mucking with by:
* Gavin Bell
*/
#include <math.h>
#include "trackball.h"
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
#define TRACKBALLSIZE (0.4f)
/*
* Local function prototypes (not defined in trackball.h)
*/
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float [4]);
static void
vzero(float *v)
{
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
}
static void
vset(float *v, float x, float y, float z)
{
v[0] = x;
v[1] = y;
v[2] = z;
}
static void
vsub(const float *src1, const float *src2, float *dst)
{
dst[0] = src1[0] - src2[0];
dst[1] = src1[1] - src2[1];
dst[2] = src1[2] - src2[2];
}
static void
vcopy(const float *v1, float *v2)
{
register int i;
for (i = 0 ; i < 3 ; i++)
v2[i] = v1[i];
}
static void
vcross(const float *v1, const float *v2, float *cross)
{
float temp[3];
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
vcopy(temp, cross);
}
static float
vlength(const float *v)
{
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
static void
vscale(float *v, float div)
{
v[0] *= div;
v[1] *= div;
v[2] *= div;
}
static void
vnormal(float *v)
{
vscale(v,1.0f/vlength(v));
}
static float
vdot(const float *v1, const float *v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
static void
vadd(const float *src1, const float *src2, float *dst)
{
dst[0] = src1[0] + src2[0];
dst[1] = src1[1] + src2[1];
dst[2] = src1[2] + src2[2];
}
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void
trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
{
float a[3]; /* Axis of rotation */
float phi; /* how much to rotate about axis */
float p1[3], p2[3], d[3];
float t;
if (p1x == p2x && p1y == p2y) {
/* Zero rotation */
vzero(q);
q[3] = 1.0;
return;
}
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
/*
* Now, we want the cross product of P1 and P2
*/
vcross(p2,p1,a);
/*
* Figure out how much to rotate around that axis.
*/
vsub(p1,p2,d);
t = vlength(d) / (2.0f*TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0f) t = 1.0f;
if (t < -1.0f) t = -1.0f;
phi = 2.0f * asin(t);
axis_to_quat(a,phi,q);
}
/*
* Given an axis and angle, compute quaternion.
*/
void
axis_to_quat(float a[3], float phi, float q[4])
{
vnormal(a);
vcopy(a,q);
vscale(q,sin(phi/2.0f));
q[3] = cos(phi/2.0f);
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
static float
tb_project_to_sphere(float r, float x, float y)
{
float d, t, z;
d = sqrt(x*x + y*y);
if (d < r * 0.70710678118654752440f) { /* Inside sphere */
z = sqrt(r*r - d*d);
} else { /* On hyperbola */
t = r / 1.41421356237309504880f;
z = t*t / d;
}
return z;
}
/*
* Given two rotations, e1 and e2, expressed as quaternion rotations,
* figure out the equivalent single rotation and stuff it into dest.
*
* This routine also normalizes the result every RENORMCOUNT times it is
* called, to keep error from creeping in.
*
* NOTE: This routine is written so that q1 or q2 may be the same
* as dest (or each other).
*/
#define RENORMCOUNT 97
void
add_quats(float q1[4], float q2[4], float dest[4])
{
static int count=0;
float t1[4], t2[4], t3[4];
float tf[4];
vcopy(q1,t1);
vscale(t1,q2[3]);
vcopy(q2,t2);
vscale(t2,q1[3]);
vcross(q2,q1,t3);
vadd(t1,t2,tf);
vadd(t3,tf,tf);
tf[3] = q1[3] * q2[3] - vdot(q1,q2);
dest[0] = tf[0];
dest[1] = tf[1];
dest[2] = tf[2];
dest[3] = tf[3];
if (++count > RENORMCOUNT) {
count = 0;
normalize_quat(dest);
}
}
/*
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
* If they don't add up to 1.0, dividing by their magnitued will
* renormalize them.
*
* Note: See the following for more information on quaternions:
*
* - Shoemake, K., Animating rotation with quaternion curves, Computer
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
* graphics, The Visual Computer 5, 2-13, 1989.
*/
static void
normalize_quat(float q[4])
{
int i;
float mag;
mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
for (i = 0; i < 4; i++) q[i] /= mag;
}
/*
* Build a rotation matrix, given a quaternion rotation.
*
*/
void
build_rotmatrix(float m[4][4], float q[4])
{
m[0][0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]);
m[0][1] = 2.0f * (q[0] * q[1] - q[2] * q[3]);
m[0][2] = 2.0f * (q[2] * q[0] + q[1] * q[3]);
m[0][3] = 0.0f;
m[1][0] = 2.0f * (q[0] * q[1] + q[2] * q[3]);
m[1][1]= 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]);
m[1][2] = 2.0f * (q[1] * q[2] - q[0] * q[3]);
m[1][3] = 0.0f;
m[2][0] = 2.0f * (q[2] * q[0] - q[1] * q[3]);
m[2][1] = 2.0f * (q[1] * q[2] + q[0] * q[3]);
m[2][2] = 1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]);
m[2][3] = 0.0f;
m[3][0] = 0.0f;
m[3][1] = 0.0f;
m[3][2] = 0.0f;
m[3][3] = 1.0f;
}

View file

@ -0,0 +1,85 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* trackball.h
* A virtual trackball implementation
* Written by Gavin Bell for Silicon Graphics, November 1988.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Pass the x and y coordinates of the last and current positions of
* the mouse, scaled so they are from (-1.0 ... 1.0).
*
* The resulting rotation is returned as a quaternion rotation in the
* first paramater.
*/
void
trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
/*
* Given two quaternions, add them together to get a third quaternion.
* Adding quaternions to get a compound rotation is analagous to adding
* translations to get a compound translation. When incrementally
* adding rotations, the first argument here should be the new
* rotation, the second and third the total rotation (which will be
* over-written with the resulting new total rotation).
*/
void
add_quats(float *q1, float *q2, float *dest);
/*
* A useful function, builds a rotation matrix in Matrix based on
* given quaternion.
*/
void
build_rotmatrix(float m[4][4], float q[4]);
/*
* This function computes a quaternion based on an axis (defined by
* the given vector) and an angle about which to rotate. The angle is
* expressed in radians. The result is put into the third argument.
*/
void
axis_to_quat(float a[3], float phi, float q[4]);
#ifdef __cplusplus
}
#endif