cbec90699f
- creato il progetto in Visual Studio per compilare come libreria statica - modifiche al codice originale per integrarlo nelle nostre librerie.
1477 lines
41 KiB
C++
1477 lines
41 KiB
C++
/*****************************************************************************/
|
|
/* */
|
|
/* F I S T : Fast, Industrial-Strength Triangulation */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* (C) Martin Held */
|
|
/* (C) Universitaet Salzburg, Salzburg, Austria */
|
|
/* */
|
|
/* This code is not in the public domain. All rights reserved! Please make */
|
|
/* sure to read the full copyright statement contained in api_functions.cpp. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef GRAPHICS
|
|
|
|
//Uncomment this to enable text printing in opengl environments
|
|
#define OGL_ENABLE_TEXT
|
|
|
|
#ifdef OGL_ENABLE_TEXT
|
|
#include <stdarg.h>
|
|
int enableText = 0;
|
|
#endif
|
|
|
|
/* */
|
|
/* get standard libraries */
|
|
/* */
|
|
#include <stdio.h>
|
|
|
|
//#define MARTINS_FLASH_DEMO
|
|
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#ifdef MARTINS_FLASH_DEMO
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/* */
|
|
/* get OpenGL include files */
|
|
/* */
|
|
#ifdef __APPLE__
|
|
#include <GLUT/glut.h>
|
|
#else
|
|
#include <GL/glut.h> /* glut.h includes gl.h and glu.h */
|
|
#endif
|
|
|
|
/* */
|
|
/* get my header files */
|
|
/* */
|
|
#include "fpkernel.h"
|
|
#include "martin.h"
|
|
#include "graphics.h"
|
|
#include "ext_appl_defs.h"
|
|
#include "defs.h"
|
|
#include "header.h"
|
|
#include "api_fist.h"
|
|
|
|
|
|
/* */
|
|
/* some global constants */
|
|
/* */
|
|
#define XNumPixel 900
|
|
#define YNumPixel 900
|
|
#define XPosition 0
|
|
#define YPosition 0
|
|
#define Radius 4.0
|
|
#define ESC 27
|
|
|
|
#if !defined(GLUT_WHEEL_UP)
|
|
# define GLUT_WHEEL_UP 3
|
|
# define GLUT_WHEEL_DOWN 4
|
|
#endif
|
|
|
|
/* */
|
|
/* prototypes of functions provided in this file */
|
|
/* */
|
|
void InitializeGraphics(int argc, char *argv[], global_struct *all);
|
|
void ProcessGraphicsEvents(void);
|
|
|
|
|
|
/* */
|
|
/* OpenGL-specific declarations */
|
|
/* */
|
|
static int my_window = NIL;
|
|
#ifdef MARTINS_FLASH_DEMO
|
|
static boolean flash_demo = true;
|
|
static boolean triang_computed = false;
|
|
#endif
|
|
static boolean poly_started = false;
|
|
static boolean zoom = false;
|
|
static boolean query = false;
|
|
static boolean query_seg = false;
|
|
static boolean query_pnt = false;
|
|
static boolean full_screen_mode = false;
|
|
static boolean one_corner_received = false;
|
|
static boolean left_mouse_button_down = false;
|
|
static machine_double xl, yl, xr, yr;
|
|
static machine_double scale, xm, ym;
|
|
static GLint im, jm;
|
|
static coord start, end;
|
|
static GLint pix_i1, pix_j1;
|
|
static GLint x_pos = XPosition, y_pos = YPosition;
|
|
static GLint x_size = XNumPixel, y_size = YNumPixel;
|
|
static GLint width_pxl = XNumPixel, height_pxl = YNumPixel;
|
|
static GLint old_mouse_x, old_mouse_y;
|
|
typedef struct {
|
|
GLdouble r;
|
|
GLdouble g;
|
|
GLdouble b;
|
|
GLdouble a;
|
|
} tcolor;
|
|
static tcolor colors[10];
|
|
static int BGcolor = Black;
|
|
static boolean tri_filled = true;
|
|
typedef enum {quit,
|
|
togglePNT,
|
|
toggleFill,
|
|
zoomIn,
|
|
zoomOut,
|
|
unZoom} oglMenu;
|
|
static global_struct *ogl_all;
|
|
|
|
/* */
|
|
/* OpenGL-specific graphics functions */
|
|
/* */
|
|
|
|
|
|
void FreeGraphics(void)
|
|
{
|
|
if (my_window != NIL)
|
|
glutDestroyWindow(my_window);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ResetRubberLine()
|
|
{
|
|
one_corner_received = false;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void SetUpColorTable(boolean color_graphics)
|
|
{
|
|
int i;
|
|
|
|
if (color_graphics) {
|
|
colors[Green].r = 0.0;
|
|
colors[Green].g = 0.1;
|
|
colors[Green].b = 0.0;
|
|
colors[Green].a = 0.0;
|
|
colors[Blue].r = 0.0;
|
|
colors[Blue].g = 0.0;
|
|
colors[Blue].b = 1.0;
|
|
colors[Blue].a = 0.0;
|
|
colors[White].r = 1.0;
|
|
colors[White].g = 1.0;
|
|
colors[White].b = 1.0;
|
|
colors[White].a = 0.0;
|
|
colors[Red].r = 1.0;
|
|
colors[Red].g = 0.0;
|
|
colors[Red].b = 0.0;
|
|
colors[Red].a = 0.0;
|
|
colors[Cyan].r = 0.0;
|
|
colors[Cyan].g = 1.0;
|
|
colors[Cyan].b = 1.0;
|
|
colors[Cyan].a = 0.0;
|
|
colors[Yellow].r = 1.0;
|
|
colors[Yellow].g = 1.0;
|
|
colors[Yellow].b = 0.0;
|
|
colors[Yellow].a = 0.0;
|
|
colors[Orange].r = 1.0;
|
|
colors[Orange].g = 165.0 / 255.0;
|
|
colors[Orange].b = 0.0;
|
|
colors[Orange].a = 0.0;
|
|
colors[Magenta].r = 1.0;
|
|
colors[Magenta].g = 0.0;
|
|
colors[Magenta].b = 1.0;
|
|
colors[Magenta].a = 0.0;
|
|
colors[Black].r = 0.0;
|
|
colors[Black].g = 0.0;
|
|
colors[Black].b = 0.0;
|
|
colors[Black].a = 0.0;
|
|
colors[NoColor].r = 0.0;
|
|
colors[NoColor].g = 0.0;
|
|
colors[NoColor].b = 0.0;
|
|
colors[NoColor].a = 0.0;
|
|
colors[Gray].r = 0.6;
|
|
colors[Gray].g = 0.6;
|
|
colors[Gray].b = 0.6;
|
|
colors[Gray].a = 0.6;
|
|
BGcolor = Black;
|
|
}
|
|
else {
|
|
for (i = 0; i < NumColors; ++i) {
|
|
colors[i].r = 0.0;
|
|
colors[i].g = 0.0;
|
|
colors[i].b = 0.0;
|
|
colors[i].a = 0.0;
|
|
}
|
|
colors[White].r = 1.0;
|
|
colors[White].g = 1.0;
|
|
colors[White].b = 1.0;
|
|
colors[White].a = 0.0;
|
|
BGcolor = White;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void SetBB(machine_double xl_bb, machine_double yl_bb,
|
|
machine_double xr_bb, machine_double yr_bb)
|
|
{
|
|
xl = xl_bb;
|
|
xr = xr_bb;
|
|
yl = yl_bb;
|
|
yr = yr_bb;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
/* maps world coordinates to window pixels; the origin of the window is */
|
|
/* assumed to be located in the lower-left corner. im and jm denote the */
|
|
/* pixel coordinates of the rectangle's center (with world coordinates xm */
|
|
/* and ym). */
|
|
/* */
|
|
void MapWorldCoordinates(machine_double x, machine_double y, GLint *pix_i, GLint *pix_j)
|
|
{
|
|
*pix_i = im + (x - xm) * scale;
|
|
*pix_j = jm + (y - ym) * scale;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* */
|
|
/* maps window pixels to world coordinates; the origin of the window is */
|
|
/* assumed to be located in the lower-left corner. im and jm denote the */
|
|
/* pixel coordinates of the rectangle's center (with world coordinates xm */
|
|
/* and ym). */
|
|
/* */
|
|
void MapWindowCoordinates(GLint pix_i, GLint pix_j, machine_double *x, machine_double *y)
|
|
{
|
|
*x = ((machine_double) (pix_i - im)) / scale + xm;
|
|
*y = ((machine_double) (pix_j - jm)) / scale + ym;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void AdjustClipCoords(void)
|
|
{
|
|
MapWindowCoordinates(0, 0, &xl, &yl);
|
|
MapWindowCoordinates(width_pxl, height_pxl, &xr, &yr);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void InitializeMapping(void)
|
|
{
|
|
machine_double scale_x, scale_y;
|
|
|
|
/* */
|
|
/* compute a scale factor such that the real-world data inside the */
|
|
/* bounding box [xl,xr] times [yl,yr] fits nicely into a window of size */
|
|
/* width_pxl times height_pxl, without causing distortion. */
|
|
/* */
|
|
scale_x = (machine_double) width_pxl / (ZERO_D + xr - xl);
|
|
scale_y = (machine_double) height_pxl / (ZERO_D + yr - yl);
|
|
if (scale_x <= scale_y) scale = scale_x;
|
|
else scale = scale_y;
|
|
assert(scale > 0.0);
|
|
|
|
/* */
|
|
/* obtain the coordinates of the center in real-world and screen space */
|
|
/* */
|
|
xm = (xl + xr) / 2.0;
|
|
ym = (yl + yr) / 2.0;
|
|
im = width_pxl / 2;
|
|
jm = height_pxl / 2;
|
|
|
|
/* */
|
|
/* adjust the bounding box such that it reflects the real-world region */
|
|
/* that will be visible on the screen */
|
|
/* */
|
|
AdjustClipCoords();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void DefineCamera(void)
|
|
{
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluOrtho2D(xl, xr, yl, yr);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void DefineView(void)
|
|
{
|
|
InitializeMapping();
|
|
|
|
DefineCamera();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void UpdateScaleData(void)
|
|
{
|
|
machine_double delta_x, delta_y;
|
|
|
|
delta_x = (TO_MDOUBLE(ogl_all->bb_max.x) - TO_MDOUBLE(ogl_all->bb_min.x)) / 16.0;
|
|
delta_y = (TO_MDOUBLE(ogl_all->bb_max.y) - TO_MDOUBLE(ogl_all->bb_min.y)) / 16.0;
|
|
|
|
SetBB(TO_MDOUBLE(ogl_all->bb_min.x - delta_x), TO_MDOUBLE(ogl_all->bb_min.y - delta_y),
|
|
TO_MDOUBLE(ogl_all->bb_max.x + delta_x), TO_MDOUBLE(ogl_all->bb_max.y + delta_y));
|
|
DefineView();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void FlushDisplay(void)
|
|
{
|
|
//glFlush();
|
|
glutSwapBuffers();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void DrawRectangle(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
|
|
GLdouble r1, GLdouble g1, GLdouble b1, GLdouble a1,
|
|
GLdouble r2, GLdouble g2, GLdouble b2, GLdouble a2,
|
|
boolean filled,
|
|
GLint stipple_factor, GLushort stipple_pattern)
|
|
{
|
|
if (filled) {
|
|
glColor4d(r1, g1, b1, a1);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
glRectd(x1, y1, x2, y2);
|
|
glLineWidth(2.0);
|
|
}
|
|
|
|
glColor4d(r2, g2, b2, a2);
|
|
if (stipple_pattern != 0xFFFF) {
|
|
glEnable(GL_LINE_STIPPLE);
|
|
glLineStipple(stipple_factor, stipple_pattern);
|
|
glLineWidth(1.0);
|
|
}
|
|
else {
|
|
glDisable(GL_LINE_STIPPLE);
|
|
}
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex2d(x1, y1);
|
|
glVertex2d(x2, y1);
|
|
glVertex2d(x2, y2);
|
|
glVertex2d(x1, y2);
|
|
glEnd();
|
|
glLineWidth(1.0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void DrawRect(coord pnt1, coord pnt2, int obj_color,
|
|
boolean filled, GLint stipple_factor, GLushort stipple_pattern)
|
|
{
|
|
DrawRectangle(pnt1.x, pnt1.y,
|
|
pnt2.x, pnt2.y,
|
|
colors[obj_color].r, colors[obj_color].g,
|
|
colors[obj_color].b, colors[obj_color].a,
|
|
colors[obj_color].r, colors[obj_color].g,
|
|
colors[obj_color].b, colors[obj_color].a,
|
|
filled, stipple_factor, stipple_pattern);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawTriangle(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
|
|
GLdouble x3, GLdouble y3,
|
|
GLdouble r1, GLdouble g1, GLdouble b1, GLdouble a1,
|
|
GLdouble r2, GLdouble g2, GLdouble b2, GLdouble a2,
|
|
boolean filled,
|
|
GLint stipple_factor, GLushort stipple_pattern)
|
|
{
|
|
if (filled) {
|
|
glColor4d(r2, g2, b2, a2);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex2d(x1, y1);
|
|
glVertex2d(x2, y2);
|
|
glVertex2d(x3, y3);
|
|
glEnd();
|
|
glLineWidth(0.0);
|
|
}
|
|
|
|
glColor4d(r1, g1, b1, a1);
|
|
if (stipple_pattern != 0xFFFF) {
|
|
glEnable(GL_LINE_STIPPLE);
|
|
glLineStipple(stipple_factor, stipple_pattern);
|
|
glLineWidth(1.0);
|
|
}
|
|
else {
|
|
glDisable(GL_LINE_STIPPLE);
|
|
}
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex2d(x1, y1);
|
|
glVertex2d(x2, y2);
|
|
glVertex2d(x3, y3);
|
|
glEnd();
|
|
glLineWidth(1.0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void DrawTri(point pnt1, point pnt2, point pnt3, int color1, int color2)
|
|
{
|
|
DrawTriangle(TO_MDOUBLE(pnt1.x), TO_MDOUBLE(pnt1.y), TO_MDOUBLE(pnt2.x),
|
|
TO_MDOUBLE(pnt2.y), TO_MDOUBLE(pnt3.x), TO_MDOUBLE(pnt3.y),
|
|
colors[color1].r, colors[color1].g,
|
|
colors[color1].b, colors[color1].a,
|
|
colors[color2].r, colors[color2].g,
|
|
colors[color2].b, colors[color2].a,
|
|
tri_filled, 1, 0xFFFF);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void DrawSegment(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
|
|
GLdouble r, GLdouble g, GLdouble b, GLdouble a,
|
|
GLdouble line_width,
|
|
GLint stipple_factor, GLushort stipple_pattern)
|
|
{
|
|
glColor4d(r, g, b, a);
|
|
glLineWidth(line_width);
|
|
if (stipple_pattern != 0xFFFF) {
|
|
glEnable(GL_LINE_STIPPLE);
|
|
glLineStipple(stipple_factor, stipple_pattern);
|
|
}
|
|
else {
|
|
glDisable(GL_LINE_STIPPLE);
|
|
}
|
|
glBegin(GL_LINES);
|
|
glVertex2d(x1, y1);
|
|
glVertex2d(x2, y2);
|
|
glEnd();
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
void DrawSeg(point pnt1, point pnt2, int color)
|
|
{
|
|
DrawSegment(TO_MDOUBLE(pnt1.x), TO_MDOUBLE(pnt1.y),
|
|
TO_MDOUBLE(pnt2.x), TO_MDOUBLE(pnt2.y),
|
|
colors[color].r, colors[color].g,
|
|
colors[color].b, colors[color].a,
|
|
1.0, 1, 0xFFFF);
|
|
return;
|
|
}
|
|
|
|
|
|
void DrawPoint(GLdouble x1, GLdouble y1,
|
|
GLdouble r, GLdouble g, GLdouble b, GLdouble a,
|
|
GLfloat pnt_size)
|
|
{
|
|
glColor4d(r, g, b, a);
|
|
glPointSize(pnt_size);
|
|
glBegin(GL_POINTS);
|
|
glVertex2d(x1, y1);
|
|
glEnd();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void DrawPnt(point pnt, int color)
|
|
{
|
|
DrawPoint(TO_MDOUBLE(pnt.x), TO_MDOUBLE(pnt.y),
|
|
colors[color].r, colors[color].g,
|
|
colors[color].b, colors[color].a, Radius);
|
|
return;
|
|
}
|
|
|
|
void DrawText(point pnt, int color, char* text)
|
|
{
|
|
char *c;
|
|
|
|
glColor4d(colors[color].r, colors[color].g, colors[color].b, colors[color].a);
|
|
glRasterPos2f(TO_MDOUBLE(pnt.x), TO_MDOUBLE(pnt.y));
|
|
|
|
for (c=text; *c != '\0'; c++)
|
|
{
|
|
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c);
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void QuickDisplay()
|
|
{
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
Redraw(ogl_all);
|
|
|
|
/* */
|
|
/* draw "rubber bands" to indicate objects that are currently been drawn */
|
|
/* by moving the mouse */
|
|
/* */
|
|
if (one_corner_received) {
|
|
if (zoom) {
|
|
DrawRect(start, end, Magenta, false, 1, 0x00FF);
|
|
}
|
|
else if (poly_started) {
|
|
DrawSegment(start.x, start.y,
|
|
end.x, end.y,
|
|
colors[PolyColor].r,
|
|
colors[PolyColor].g,
|
|
colors[PolyColor].b,
|
|
colors[PolyColor].a, 1.0, 1, 0x00FF);
|
|
}
|
|
}
|
|
|
|
glutSwapBuffers();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ResetGraphicsData(void)
|
|
{
|
|
one_corner_received = false;
|
|
zoom = false;
|
|
query = false;
|
|
poly_started = false;
|
|
|
|
if (ogl_all->rt_opt.graphics) {
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void UnZoom(void)
|
|
{
|
|
UpdateScaleData();
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ZoomOut(void)
|
|
{
|
|
scale *= 0.5;
|
|
AdjustClipCoords();
|
|
DefineCamera();
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ZoomIn(void)
|
|
{
|
|
scale *= 2.0;
|
|
AdjustClipCoords();
|
|
DefineCamera();
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
void ZoomInOnMouse(GLint mouse_x, GLint mouse_y) {
|
|
|
|
double delta_x, delta_y;
|
|
|
|
delta_x = (xr - xl)/width_pxl;
|
|
|
|
delta_y = (yr - yl)/height_pxl;
|
|
|
|
xr += (mouse_x - width_pxl/2)*delta_x;
|
|
xl += (mouse_x - width_pxl/2)*delta_x;
|
|
|
|
yr -= (mouse_y - height_pxl/2)*delta_y;
|
|
yl -= (mouse_y - height_pxl/2)*delta_y;
|
|
|
|
DefineView();
|
|
ZoomIn();
|
|
|
|
delta_x = (xr - xl)/width_pxl;
|
|
delta_y = (yr - yl)/height_pxl;
|
|
|
|
xr -= (mouse_x - width_pxl/2)*delta_x;
|
|
xl -= (mouse_x - width_pxl/2)*delta_x;
|
|
old_mouse_x = mouse_x;
|
|
|
|
yr += (mouse_y - height_pxl/2)*delta_y;
|
|
yl += (mouse_y - height_pxl/2)*delta_y;
|
|
old_mouse_y = mouse_y;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
}
|
|
|
|
void ZoomOutOnMouse(GLint mouse_x, GLint mouse_y) {
|
|
|
|
double delta_x, delta_y;
|
|
|
|
delta_x = (xr - xl)/width_pxl;
|
|
|
|
delta_y = (yr - yl)/height_pxl;
|
|
|
|
xr += (mouse_x - width_pxl/2)*delta_x;
|
|
xl += (mouse_x - width_pxl/2)*delta_x;
|
|
|
|
yr -= (mouse_y - height_pxl/2)*delta_y;
|
|
yl -= (mouse_y - height_pxl/2)*delta_y;
|
|
|
|
DefineView();
|
|
ZoomOut();
|
|
|
|
delta_x = (xr - xl)/width_pxl;
|
|
delta_y = (yr - yl)/height_pxl;
|
|
|
|
xr -= (mouse_x - width_pxl/2)*delta_x;
|
|
xl -= (mouse_x - width_pxl/2)*delta_x;
|
|
old_mouse_x = mouse_x;
|
|
|
|
yr += (mouse_y - height_pxl/2)*delta_y;
|
|
yl += (mouse_y - height_pxl/2)*delta_y;
|
|
old_mouse_y = mouse_y;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
}
|
|
|
|
|
|
void ScrollLeft(void)
|
|
{
|
|
machine_double delta;
|
|
|
|
delta = (xr - xl) / 8.0;
|
|
xr -= delta;
|
|
xl -= delta;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ScrollRight(void)
|
|
{
|
|
machine_double delta;
|
|
|
|
delta = (xr - xl) / 8.0;
|
|
xr += delta;
|
|
xl += delta;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ScrollUp(void)
|
|
{
|
|
machine_double delta;
|
|
|
|
delta = (yr - yl) / 8.0;
|
|
yr += delta;
|
|
yl += delta;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ScrollDown(void)
|
|
{
|
|
machine_double delta;
|
|
|
|
delta = (yr - yl) / 8.0;
|
|
yr -= delta;
|
|
yl -= delta;
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void TrackLine(GLint pix_i2, GLint pix_j2, machine_double *x1, machine_double *y1,
|
|
machine_double *x2, machine_double *y2)
|
|
{
|
|
MapWindowCoordinates(pix_i1, pix_j1, x1, y1);
|
|
MapWindowCoordinates(pix_i2, pix_j2, x2, y2);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrackRectangle(GLint pix_i2, GLint pix_j2, machine_double *x1, machine_double *y1,
|
|
machine_double *x2, machine_double *y2)
|
|
{
|
|
if (pix_i1 == pix_i2) pix_i2 += 1;
|
|
if (pix_j1 == pix_j2) pix_j2 += 1;
|
|
if (pix_i1 < pix_i2) {
|
|
if (pix_j1 < pix_j2) {
|
|
MapWindowCoordinates(pix_i1, pix_j1, x1, y1);
|
|
MapWindowCoordinates(pix_i2, pix_j2, x2, y2);
|
|
}
|
|
else {
|
|
MapWindowCoordinates(pix_i1, pix_j2, x1, y1);
|
|
MapWindowCoordinates(pix_i2, pix_j1, x2, y2);
|
|
}
|
|
}
|
|
else {
|
|
if (pix_j1 < pix_j2) {
|
|
MapWindowCoordinates(pix_i2, pix_j1, x1, y1);
|
|
MapWindowCoordinates(pix_i1, pix_j2, x2, y2);
|
|
}
|
|
else {
|
|
MapWindowCoordinates(pix_i2, pix_j2, x1, y1);
|
|
MapWindowCoordinates(pix_i1, pix_j1, x2, y2);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ZoomToRegion(GLint pix_i2, GLint pix_j2)
|
|
{
|
|
machine_double new_xl, new_xr, new_yl, new_yr;
|
|
|
|
if (one_corner_received) {
|
|
TrackRectangle(pix_i2, pix_j2, &new_xl, &new_yl, &new_xr, &new_yr);
|
|
SetBB(new_xl, new_yl, new_xr, new_yr);
|
|
DefineView();
|
|
|
|
zoom = false;
|
|
one_corner_received = false;
|
|
|
|
glutPostRedisplay();
|
|
}
|
|
else {
|
|
pix_i1 = pix_i2;
|
|
pix_j1 = pix_j2;
|
|
one_corner_received = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void ToggleScreenMode(void)
|
|
{
|
|
full_screen_mode = !full_screen_mode;
|
|
if (full_screen_mode) {
|
|
/* */
|
|
/* save current parameters and go to full-screen mode */
|
|
/* */
|
|
x_pos = glutGet((GLenum)GLUT_WINDOW_X);
|
|
y_pos = glutGet((GLenum)GLUT_WINDOW_Y);
|
|
x_size = glutGet((GLenum)GLUT_WINDOW_WIDTH);
|
|
y_size = glutGet((GLenum)GLUT_WINDOW_HEIGHT);
|
|
glutFullScreen();
|
|
width_pxl = glutGet((GLenum)GLUT_WINDOW_WIDTH);
|
|
height_pxl = glutGet((GLenum)GLUT_WINDOW_HEIGHT);
|
|
}
|
|
else {
|
|
/* */
|
|
/* restore old settings */
|
|
/* */
|
|
glutReshapeWindow(x_size, y_size);
|
|
glutPositionWindow(x_pos, y_pos);
|
|
width_pxl = x_size;
|
|
height_pxl = y_size;
|
|
}
|
|
|
|
glViewport(0, 0, width_pxl, height_pxl);
|
|
DefineView();
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ClosePolygon(global_struct *all, int curr_loop, boolean *new_input)
|
|
{
|
|
iolistdef *iolist = &all->c_iolist;
|
|
datadef *data = &all->c_data;
|
|
listdef *list = &all->c_list;
|
|
redrawdef *redraw = &all->c_redraw;
|
|
|
|
if (iolist->new_pnts >= 3) {
|
|
assert(iolist->first_pnt >= 0);
|
|
assert(iolist->first_pnt != iolist->last_pnt);
|
|
assert(iolist->last_pnt >= 0);
|
|
AddEdgeToBuffer(redraw, iolist->last_pnt, iolist->first_pnt, PolyColor);
|
|
DrawSeg(data->points[iolist->last_pnt],
|
|
data->points[iolist->first_pnt],
|
|
PolyColor);
|
|
*new_input = true;
|
|
DeleteHook(list, curr_loop);
|
|
}
|
|
else {
|
|
DecrementLoops(list);
|
|
if (iolist->new_pnts >= 1) {
|
|
DecrementPoints(data);
|
|
DecrementPntBuffer(redraw);
|
|
}
|
|
if (iolist->new_pnts == 2) {
|
|
DecrementPoints(data);
|
|
DecrementPntBuffer(redraw);
|
|
DecrementEdgeBuffer(redraw);
|
|
}
|
|
FIST_Warning("No polygon to close!");
|
|
}
|
|
iolist->first_pnt = NIL;
|
|
iolist->last_pnt = NIL;
|
|
iolist->new_pnts = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void HandleKeyPress(unsigned char key, GLint pix_i1, GLint pix_j1)
|
|
{
|
|
(void) pix_i1;
|
|
(void) pix_j1;
|
|
|
|
zoom = false;
|
|
|
|
switch (key) {
|
|
case '?':
|
|
/* */
|
|
/* prepare for interactive debug query */
|
|
/* */
|
|
query = true;
|
|
break;
|
|
case 'c':
|
|
case 'C':
|
|
/* */
|
|
/* close polygon */
|
|
/* */
|
|
if (poly_started) {
|
|
poly_started = false;
|
|
one_corner_received = false;
|
|
ClosePolygon(ogl_all, ogl_all->curr_loop_main, &ogl_all->new_input);
|
|
glutPostRedisplay();
|
|
}
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
/* */
|
|
/* delete; clear drawing canvas and reset all variables */
|
|
/* */
|
|
ResetAll(ogl_all);
|
|
break;
|
|
#ifdef EXPR_WRAPPER
|
|
case 'e' :
|
|
case 'E' :
|
|
/* */
|
|
/* toogle the returncore variable */
|
|
/* */
|
|
returncore = !returncore;
|
|
break;
|
|
#endif
|
|
case 'f':
|
|
case 'F':
|
|
/* */
|
|
/* toggle the filling of the triangles */
|
|
/* */
|
|
tri_filled = !tri_filled;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 'h':
|
|
case 'H':
|
|
/* */
|
|
/* print help message */
|
|
/* */
|
|
Help();
|
|
EvalError();
|
|
break;
|
|
case 'i':
|
|
case 'I':
|
|
/* */
|
|
/* zoom in */
|
|
/* */
|
|
ZoomIn();
|
|
break;
|
|
case 'm':
|
|
case 'M':
|
|
/* */
|
|
/* toggle the drawing of the vertex markers */
|
|
/* */
|
|
ogl_all->draw_pnts = !ogl_all->draw_pnts;
|
|
glutPostRedisplay();
|
|
break;
|
|
case '1':
|
|
/* */
|
|
/* toggle the drawing of the vertex markers */
|
|
/* */
|
|
ogl_all->draw_point_idx = !ogl_all->draw_point_idx;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
/* */
|
|
/* zoom out */
|
|
/* */
|
|
ZoomOut();
|
|
break;
|
|
case 'p':
|
|
case 'P':
|
|
/* */
|
|
/* read data from the graphics window */
|
|
/* */
|
|
if (query) {
|
|
query = false;
|
|
query_pnt = true;
|
|
}
|
|
else {
|
|
/* */
|
|
/* start new polygon */
|
|
/* */
|
|
query = false;
|
|
one_corner_received = false;
|
|
if (!poly_started) {
|
|
poly_started = true;
|
|
ogl_all->curr_loop_main = MakeLoopHeader(&ogl_all->c_list);
|
|
ResetRubberLine();
|
|
}
|
|
}
|
|
break;
|
|
case 'q':
|
|
case 'Q':
|
|
case ESC:
|
|
/* */
|
|
/* termination of program */
|
|
/* */
|
|
StatisticsFIST(ogl_all);
|
|
FIST_TerminateProgram(ogl_all);
|
|
FreeGraphics();
|
|
exit(0);
|
|
break;
|
|
case 'r' :
|
|
case 'R' :
|
|
/* */
|
|
/* refresh window */
|
|
/* */
|
|
glutPostRedisplay();
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
if (query) {
|
|
query = false;
|
|
query_seg = true;
|
|
}
|
|
break;
|
|
case 't':
|
|
case 'T':
|
|
/* */
|
|
/* compute triangulation */
|
|
/* */
|
|
one_corner_received = false;
|
|
query = false;
|
|
if (!ogl_all->done) {
|
|
if (poly_started) {
|
|
ClosePolygon(ogl_all, ogl_all->curr_loop_main,
|
|
&ogl_all->new_input);
|
|
poly_started = false;
|
|
glutPostRedisplay();
|
|
}
|
|
Compute(ogl_all);
|
|
}
|
|
ogl_all->new_input = false;
|
|
if (ogl_all->done) glutPostRedisplay();
|
|
else FlushDisplay();
|
|
break;
|
|
case 'u':
|
|
case 'U':
|
|
/* */
|
|
/* unzoom */
|
|
/* */
|
|
UnZoom();
|
|
break;
|
|
case 'z':
|
|
case 'Z':
|
|
/* */
|
|
/* prepare for zooming */
|
|
/* */
|
|
zoom = true;
|
|
query = false;
|
|
poly_started = false;
|
|
one_corner_received = false;
|
|
break;
|
|
default:
|
|
FIST_Warning("HandleKeyPress() - unknown key pressed!\n");
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void IdleFunction(void)
|
|
{
|
|
#ifdef MARTINS_FLASH_DEMO
|
|
if (flash_demo) {
|
|
if (triang_computed) {
|
|
sleep(3);
|
|
HandleKeyPress('q', 0, 0);
|
|
}
|
|
else {
|
|
if (ogl_all->c_data.num_pnts < 10000) sleep(1);
|
|
triang_computed = true;
|
|
HandleKeyPress('t', 0, 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void HandleMouseMotion(GLint mouse_x, GLint mouse_y)
|
|
{
|
|
GLint pix_j2 = height_pxl - mouse_y;
|
|
double delta_x, delta_y;
|
|
if (one_corner_received) {
|
|
if (zoom) {
|
|
TrackRectangle(mouse_x, pix_j2, &start.x, &start.y, &end.x, &end.y);
|
|
glutPostRedisplay();
|
|
}
|
|
else if (poly_started) {
|
|
TrackLine(mouse_x, pix_j2, &start.x, &start.y, &end.x, &end.y);
|
|
glutPostRedisplay();
|
|
}
|
|
} else if(left_mouse_button_down) {
|
|
delta_x = (xr - xl)/width_pxl;
|
|
delta_y = (yr - yl)/height_pxl;
|
|
|
|
if(old_mouse_x - mouse_x != 0) {
|
|
xr += delta_x*(old_mouse_x - mouse_x);
|
|
xl += delta_x*(old_mouse_x - mouse_x);
|
|
old_mouse_x = mouse_x;
|
|
}
|
|
if(old_mouse_y - mouse_y != 0) {
|
|
yr -= delta_y*(old_mouse_y - mouse_y);
|
|
yl -= delta_y*(old_mouse_y - mouse_y);
|
|
old_mouse_y = mouse_y;
|
|
}
|
|
|
|
DefineView();
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleReshape(GLint width, GLint height)
|
|
{
|
|
width_pxl = width;
|
|
height_pxl = height;
|
|
glViewport(0, 0, width_pxl, height_pxl);
|
|
DefineView();
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void HandleSpecialKeys(int key, GLint pix_i1, GLint pix_j1)
|
|
{
|
|
(void) pix_i1;
|
|
(void) pix_j1;
|
|
|
|
switch (key) {
|
|
case GLUT_KEY_F1:
|
|
/* */
|
|
/* toggle full-screen mode */
|
|
/* */
|
|
ToggleScreenMode();
|
|
break;
|
|
case GLUT_KEY_LEFT:
|
|
/* */
|
|
/* scroll to the left */
|
|
/* */
|
|
ScrollLeft();
|
|
break;
|
|
case GLUT_KEY_UP:
|
|
/* */
|
|
/* scroll to the left */
|
|
/* */
|
|
ScrollUp();
|
|
break;
|
|
case GLUT_KEY_RIGHT:
|
|
/* */
|
|
/* scroll to the left */
|
|
/* */
|
|
ScrollRight();
|
|
break;
|
|
case GLUT_KEY_DOWN:
|
|
/* */
|
|
/* scroll to the left */
|
|
/* */
|
|
ScrollDown();
|
|
break;
|
|
default:
|
|
FIST_Warning("HandleSpecialKeys() - key of unkown type!\n");
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void HandleMenu(int item)
|
|
{
|
|
switch (item) {
|
|
case quit:
|
|
HandleKeyPress('q', 0, 0);
|
|
break;
|
|
case zoomIn:
|
|
HandleKeyPress('i', 0, 0);
|
|
break;
|
|
case zoomOut:
|
|
HandleKeyPress('o', 0, 0);
|
|
break;
|
|
case unZoom:
|
|
HandleKeyPress('u', 0, 0);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void HandleZoomMenu(int item)
|
|
{
|
|
switch (item) {
|
|
case zoomIn:
|
|
HandleKeyPress('i', 0, 0);
|
|
break;
|
|
case zoomOut:
|
|
HandleKeyPress('o', 0, 0);
|
|
break;
|
|
case unZoom:
|
|
HandleKeyPress('u', 0, 0);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void ChangeMenuItem(boolean *item_flag, const char* menuString, int item)
|
|
{
|
|
char my_string[100];
|
|
|
|
my_string[0] = '\0';
|
|
strcat(my_string, menuString);
|
|
if (*item_flag) {
|
|
*item_flag = false;
|
|
strcat(my_string, ": on");
|
|
glutChangeToMenuEntry(item, my_string, item);
|
|
}
|
|
else {
|
|
*item_flag = true;
|
|
strcat(my_string, ": off");
|
|
glutChangeToMenuEntry(item, my_string, item);
|
|
}
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleViewMenu(int item)
|
|
{
|
|
switch (item) {
|
|
case togglePNT:
|
|
ChangeMenuItem(&ogl_all->draw_pnts, "Points/vertices", togglePNT);
|
|
break;
|
|
case toggleFill:
|
|
ChangeMenuItem(&tri_filled, "Triangles filled", toggleFill);
|
|
break;
|
|
}
|
|
|
|
glutPostRedisplay();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ProcessMouseClick(global_struct *all, int curr_loop, int x, int y)
|
|
{
|
|
iolistdef *iolist = &all->c_iolist;
|
|
listdef *list = &all->c_list;
|
|
redrawdef *redraw = &all->c_redraw;
|
|
datadef *data = &all->c_data;
|
|
machine_double xc1, yc1;
|
|
int i;
|
|
list_ind ind;
|
|
|
|
MapWindowCoordinates(x, y, &xc1, &yc1);
|
|
#ifdef EXT_APPL_SITES
|
|
i = StorePnt(data, xc1, yc1, eas_NIL);
|
|
#else
|
|
i = StorePnt(data, xc1, yc1);
|
|
#endif
|
|
AddPntToBuffer(redraw, i, PntsColor);
|
|
end.x = xc1;
|
|
end.y = yc1;
|
|
if (iolist->first_pnt < 0) {
|
|
iolist->first_pnt = i;
|
|
iolist->last_pnt = i;
|
|
iolist->last_ind = list->loops[curr_loop];
|
|
start = end;
|
|
}
|
|
else {
|
|
AddEdgeToBuffer(redraw, iolist->last_pnt, i, PolyColor);
|
|
DrawSeg(data->points[iolist->last_pnt], data->points[i], PolyColor);
|
|
iolist->last_pnt = i;
|
|
}
|
|
DrawPnt(data->points[i], PntsColor);
|
|
|
|
ind = MakeNode(list, i);
|
|
InsertAfter(list, iolist->last_ind, ind);
|
|
iolist->last_ind = ind;
|
|
|
|
++iolist->new_pnts;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleMouseButton(int button, int state, GLint pix_i2, GLint pix_j2)
|
|
{
|
|
// double x2, y2;
|
|
|
|
switch (button) {
|
|
case GLUT_LEFT_BUTTON :
|
|
if(state == GLUT_UP) {
|
|
left_mouse_button_down = false;
|
|
pix_j2 = height_pxl - pix_j2;
|
|
if (zoom) {
|
|
ZoomToRegion(pix_i2, pix_j2);
|
|
}
|
|
/*
|
|
else if (query_pnt || query_seg || query_nde) {
|
|
MapWindowCoordinates(pix_i2, pix_j2, &x2, &y2);
|
|
if (query_pnt) FindClosestPnt(x2, y2);
|
|
else if (query_seg) FindClosestSeg(x2, y2);
|
|
query_pnt = query_seg = query = false;
|
|
glutPostRedisplay();
|
|
}
|
|
*/
|
|
else if (poly_started) {
|
|
/* */
|
|
/* read mouse input from graphics window */
|
|
/* */
|
|
ProcessMouseClick(ogl_all, ogl_all->curr_loop_main,
|
|
pix_i2, pix_j2);
|
|
one_corner_received = true;
|
|
pix_i1 = pix_i2;
|
|
pix_j1 = pix_j2;
|
|
FlushDisplay();
|
|
//glutPostRedisplay();
|
|
}
|
|
} else if(state == GLUT_DOWN) {
|
|
/* pan scene round with the left mouse button */
|
|
left_mouse_button_down = true;
|
|
old_mouse_x = pix_i2;
|
|
old_mouse_y = pix_j2;
|
|
}
|
|
break;
|
|
|
|
case GLUT_WHEEL_UP:
|
|
if (state != GLUT_UP) {
|
|
ZoomInOnMouse(pix_i2, pix_j2);
|
|
}
|
|
break;
|
|
|
|
case GLUT_WHEEL_DOWN:
|
|
if (state != GLUT_UP) {
|
|
ZoomOutOnMouse(pix_i2, pix_j2);
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void InitializeGraphics(int argc, char *argv[], global_struct *all)
|
|
{
|
|
int mainMenu, zoomMenu, viewMenu;
|
|
char window_name[80];
|
|
|
|
/* */
|
|
/* make the structure "all" known to my graphics routines */
|
|
/* */
|
|
ogl_all = all;
|
|
|
|
/* */
|
|
/* graphics start-up */
|
|
/* */
|
|
glutInit(&argc, argv); /* init OpenGL */
|
|
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); /* double buffering,
|
|
and RGB colors */
|
|
/* */
|
|
/* set window position and size */
|
|
/* */
|
|
glutInitWindowSize(width_pxl, height_pxl);/* XNumPixel x YNumPixel window */
|
|
glutInitWindowPosition(x_pos, y_pos); /* upper-left corner of window */
|
|
|
|
/* */
|
|
/* window creation */
|
|
/* */
|
|
sprintf(window_name,
|
|
"%9s %3s (C) M. Held %9s",
|
|
FIST_GetProgName(), FIST_GetProgVersion(), FIST_GetProgYear());
|
|
my_window = glutCreateWindow(window_name);
|
|
if (ogl_all->rt_opt.full_screen) {
|
|
glutFullScreen(); /* Go to full screen */
|
|
width_pxl = glutGet((GLenum)GLUT_WINDOW_WIDTH);
|
|
height_pxl = glutGet((GLenum)GLUT_WINDOW_HEIGHT);
|
|
full_screen_mode = true;
|
|
}
|
|
|
|
/* */
|
|
/* init graphics variables */
|
|
/* */
|
|
SetUpColorTable(ogl_all->rt_opt.color_graphics);
|
|
glViewport(0, 0, width_pxl, height_pxl);
|
|
glClearColor(colors[BGcolor].r, /* set background color */
|
|
colors[BGcolor].g,
|
|
colors[BGcolor].b,
|
|
colors[BGcolor].a);
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_POINT_SMOOTH);
|
|
glLineWidth(1.0);
|
|
|
|
/* */
|
|
/* initialize the bounding box of the data */
|
|
/* */
|
|
ogl_all->bb_min.x = xl = 0.0;
|
|
ogl_all->bb_min.y = yl = 0.0;
|
|
ogl_all->bb_max.x = xr = (machine_double) width_pxl;
|
|
ogl_all->bb_max.y = yr = (machine_double) height_pxl;
|
|
SetBoundingBox(&ogl_all->c_data, &ogl_all->bb_min, &ogl_all->bb_max);
|
|
UpdateScaleData();
|
|
|
|
old_mouse_x = (int)width_pxl/2;
|
|
old_mouse_y = (int)height_pxl/2;
|
|
glutWarpPointer(old_mouse_x, old_mouse_y);
|
|
|
|
/* */
|
|
/* input event selection */
|
|
/* */
|
|
glutDisplayFunc(QuickDisplay);
|
|
glutKeyboardFunc(HandleKeyPress);
|
|
glutReshapeFunc(HandleReshape);
|
|
glutMouseFunc(HandleMouseButton);
|
|
glutMotionFunc(HandleMouseMotion);
|
|
glutPassiveMotionFunc(HandleMouseMotion);
|
|
glutSpecialFunc(HandleSpecialKeys);
|
|
#ifdef MARTINS_FLASH_DEMO
|
|
if (flash_demo) glutIdleFunc(IdleFunction);
|
|
#endif
|
|
|
|
/* */
|
|
/* create menus */
|
|
/* */
|
|
zoomMenu = glutCreateMenu(HandleZoomMenu);
|
|
glutAddMenuEntry("Zoom in", zoomIn);
|
|
glutAddMenuEntry("Zoom out", zoomOut);
|
|
glutAddMenuEntry("Unzoom", unZoom);
|
|
viewMenu = glutCreateMenu(HandleViewMenu);
|
|
if (ogl_all->draw_pnts) glutAddMenuEntry("Points/vertices: off", togglePNT);
|
|
else glutAddMenuEntry("Points/vertices: on", togglePNT);
|
|
if (tri_filled) glutAddMenuEntry("Triangles filled: off", toggleFill);
|
|
else glutAddMenuEntry("Triangles filled: on", toggleFill);
|
|
mainMenu = glutCreateMenu(HandleMenu);
|
|
glutAddSubMenu("Zoom in/out", zoomMenu);
|
|
glutAddSubMenu("Toggle display parameters", viewMenu);
|
|
glutAddMenuEntry("Quit", quit);
|
|
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
|
(void) mainMenu;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ProcessGraphicsEvents(void)
|
|
{
|
|
UpdateScaleData();
|
|
|
|
glutMainLoop(); /* OpenGL's event-handling loop */
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#endif /* GRAPHICS */
|
|
|
|
|