[BACK]Return to tess.c CVS log [TXT][DIR] Up to [Development] / projects / ogl-sample / main / gfx / samples / glx

File: [Development] / projects / ogl-sample / main / gfx / samples / glx / tess.c (download)

Revision 1.2, Wed Apr 5 06:43:46 2000 UTC (17 years, 6 months ago) by ljp
Branch: MAIN
CVS Tags: tested_with_xf86_3_3, HEAD
Changes since 1.1: +1 -1 lines

Change license version to 1.1.

/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
** 
** http://oss.sgi.com/projects/FreeB
** 
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
** 
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
** 
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
**
** $Date$ $Revision$
** $Header: //depot/main/gfx/samples/glx/tess.c#3 $
*/
#include <GL/glx.h>
#include <GL/glu.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <X11/keysym.h>
#include <assert.h>

static int RGB_SB_attributes[] = {
    GLX_RGBA,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    None,
};

static int RGB_DB_attributes[] = {
    GLX_RGBA,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    GLX_DOUBLEBUFFER,
    GLX_DEPTH_SIZE, 1,
    GLX_STENCIL_SIZE, 1,
    None,
};

static int CI_SB_attributes[] = {
    GLX_DEPTH_SIZE, 1,
    GLX_STENCIL_SIZE, 1,
    None,
};

static int CI_DB_attributes[] = {
    GLX_DOUBLEBUFFER,
    GLX_DEPTH_SIZE, 1,
    GLX_STENCIL_SIZE, 1,
    None,
};

int rgb = 1;
int W = 500;
int H = 500;

/*
** A contour.
*/
struct vert {
    GLdouble v[3];
    struct vert *next;
    GLuint name;
};

/*
** A polygon (multiple contours).
*/
struct polygon {
    struct vert *contour;
    struct polygon *next;
};

#define SELECT_LINE	1
#define SELECT_VERTEX	2

GLuint vertName = 2;
struct polygon *thePoly = NULL;
struct vert *foundVertex = NULL;
int leftDown, middleDown, rightDown;
int tessIt;
int showTess;
int doEdgeFlags;
int gotError;
int doubleBuf = 1;
GLUtesselator *tobj;
Display *dpy;
Window window;
Colormap cmap;

unsigned char font6x10[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x38, 0x38, 0x10, 0x00, 
0x00, 0x00, 0x54, 0x28, 0x54, 0x28, 0x54, 0x28, 0x54, 0x00, 
0x08, 0x08, 0x08, 0x3c, 0x48, 0x48, 0x78, 0x48, 0x48, 0x00, 
0x10, 0x10, 0x18, 0x10, 0x5c, 0x40, 0x60, 0x40, 0x70, 0x00, 
0x24, 0x24, 0x38, 0x24, 0x38, 0x38, 0x40, 0x40, 0x38, 0x00, 
0x20, 0x20, 0x38, 0x20, 0x3c, 0x78, 0x40, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x28, 0x28, 0x38, 0x00, 
0x00, 0x00, 0x7c, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 
0x3c, 0x20, 0x20, 0x20, 0x48, 0x58, 0x68, 0x68, 0x48, 0x00, 
0x08, 0x08, 0x08, 0x08, 0x3c, 0x20, 0x30, 0x48, 0x48, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x10, 0x10, 0x10, 0x10, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10, 0x10, 0x10, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 
0x00, 0x7c, 0x04, 0x08, 0x20, 0x40, 0x20, 0x08, 0x04, 0x00, 
0x00, 0x7c, 0x40, 0x20, 0x08, 0x04, 0x08, 0x20, 0x40, 0x00, 
0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x7c, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x40, 0x20, 0x7c, 0x10, 0x7c, 0x08, 0x04, 0x00, 
0x00, 0x20, 0x6c, 0x38, 0x20, 0x78, 0x20, 0x24, 0x18, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 
0x00, 0x00, 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00, 
0x00, 0x00, 0x10, 0x38, 0x14, 0x38, 0x50, 0x38, 0x10, 0x00, 
0x00, 0x00, 0x48, 0x54, 0x28, 0x10, 0x28, 0x54, 0x24, 0x00, 
0x00, 0x00, 0x34, 0x48, 0x54, 0x20, 0x50, 0x50, 0x20, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x18, 0x00, 
0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 
0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 
0x00, 0x00, 0x00, 0x44, 0x28, 0x7c, 0x28, 0x44, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 
0x00, 0x20, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x10, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x04, 0x00, 
0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 
0x00, 0x00, 0x7c, 0x10, 0x10, 0x10, 0x50, 0x30, 0x10, 0x00, 
0x00, 0x00, 0x7c, 0x40, 0x20, 0x18, 0x04, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x04, 0x18, 0x08, 0x04, 0x7c, 0x00, 
0x00, 0x00, 0x08, 0x08, 0x7c, 0x48, 0x28, 0x18, 0x08, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x04, 0x64, 0x58, 0x40, 0x7c, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x64, 0x58, 0x40, 0x20, 0x18, 0x00, 
0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x08, 0x04, 0x7c, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x30, 0x08, 0x04, 0x34, 0x4c, 0x44, 0x38, 0x00, 
0x00, 0x10, 0x38, 0x10, 0x00, 0x10, 0x38, 0x10, 0x00, 0x00, 
0x00, 0x20, 0x10, 0x18, 0x00, 0x10, 0x38, 0x10, 0x00, 0x00, 
0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00, 
0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x08, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x38, 0x40, 0x58, 0x54, 0x4c, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x28, 0x10, 0x00, 
0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 
0x00, 0x00, 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00, 
0x00, 0x00, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x4c, 0x40, 0x40, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 
0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 
0x00, 0x00, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x44, 0x54, 0x6c, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x40, 0x40, 0x40, 0x78, 0x44, 0x44, 0x78, 0x00, 
0x00, 0x04, 0x38, 0x54, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x44, 0x48, 0x50, 0x78, 0x44, 0x44, 0x78, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x44, 0x38, 0x00, 
0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x10, 0x28, 0x28, 0x28, 0x44, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x28, 0x44, 0x44, 0x00, 
0x00, 0x00, 0x7c, 0x40, 0x20, 0x10, 0x08, 0x04, 0x7c, 0x00, 
0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 
0x00, 0x00, 0x04, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x00, 
0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x30, 0x00, 
0x00, 0x00, 0x3c, 0x44, 0x3c, 0x04, 0x38, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x58, 0x64, 0x44, 0x64, 0x58, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x34, 0x4c, 0x44, 0x4c, 0x34, 0x04, 0x04, 0x00, 
0x00, 0x00, 0x38, 0x40, 0x7c, 0x44, 0x38, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x20, 0x20, 0x20, 0x78, 0x20, 0x24, 0x18, 0x00, 
0x38, 0x44, 0x38, 0x40, 0x30, 0x48, 0x34, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x44, 0x64, 0x58, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x30, 0x00, 0x10, 0x00, 
0x30, 0x48, 0x48, 0x08, 0x08, 0x08, 0x18, 0x00, 0x08, 0x00, 
0x00, 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x40, 0x40, 0x00, 
0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x00, 
0x00, 0x00, 0x44, 0x54, 0x54, 0x54, 0x68, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x44, 0x44, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 
0x40, 0x40, 0x40, 0x58, 0x64, 0x64, 0x58, 0x00, 0x00, 0x00, 
0x04, 0x04, 0x04, 0x34, 0x4c, 0x4c, 0x34, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x40, 0x40, 0x40, 0x64, 0x58, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x78, 0x04, 0x38, 0x40, 0x38, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x24, 0x20, 0x20, 0x78, 0x20, 0x20, 0x00, 
0x00, 0x00, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x10, 0x28, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x28, 0x54, 0x54, 0x44, 0x44, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 
0x38, 0x44, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0x20, 0x10, 0x08, 0x7c, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x0c, 0x10, 0x08, 0x30, 0x08, 0x10, 0x0c, 0x00, 
0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 
0x00, 0x00, 0x60, 0x10, 0x20, 0x18, 0x20, 0x10, 0x60, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x54, 0x24, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

int fontbase;

void initializeFont(void)
{
    int i;

    fontbase=glGenLists(256);
    glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    for (i=0; i<128; i++) {
	glNewList(i+fontbase, GL_COMPILE);
	glBitmap(6, 10, 0.0, 0.0, 6.0, 0.0, font6x10+10*i);
	glEndList();
    }
}

void writeFont(char *string)
{
    glListBase(fontbase);
    glCallLists(strlen(string), GL_BYTE, (unsigned char *) string);
}

void myBegin(GLenum which)
{
    glBegin(which);
}

#define MAXTOBEFREED 100
static struct vert *toBeFreed[MAXTOBEFREED];
static int counter= 0;

void tessPoly(void)
{
    struct polygon *poly;
    struct vert *vert;

    gluTessBeginPolygon(tobj, NULL);
    for (poly=thePoly; poly; poly=poly->next) {
	gluTessBeginContour(tobj);
	for (vert=poly->contour; vert; vert=vert->next) {
	    gluTessVertex(tobj, vert->v, vert->v);
	}
	gluTessEndContour(tobj);
    }
    gluTessEndPolygon(tobj);

    {
       /* up= min(counter,MAXTOBEFREED); */
       int up= (counter < MAXTOBEFREED) ? counter : MAXTOBEFREED;
       int ii;

       /* only free what we saved */
       for (ii= 0; ii< up; ii++) {
	  free( (void *) toBeFreed[ii] );
       }
       if (counter > MAXTOBEFREED) {
	  printf("%d vertices not freed.\n",counter - MAXTOBEFREED); 
       }
       counter= 0;
    }
}

static void edgeFlag(int flag)
{
}

static void Redraw(GLenum mode)
{
    struct polygon *poly;
    struct vert *vert;

    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(3);

    gotError = 0;
    glInitNames();
    if (tessIt) {
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glColor3f(0.5, 0.5, 0.5);
	glIndexf(15);
	tessPoly();
    }
    if (!gotError && showTess) {
	glColor3f(1.0, 1.0, 0.0);
	glIndexf(3);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	tessPoly();
    }
    if (!gotError && doEdgeFlags) {
	glLineWidth(3);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glColor3f(0.0, 0.0, 1.0);
	glIndexf(4);
	gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, &glEdgeFlag);
	tessPoly();
	gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, &edgeFlag);
	glLineWidth(1);
    }

    if (gotError) {
	glColor3f(1.0, 1.0, 1.0);
	glIndexf(7);
	glRasterPos2f(5.0, 15.0);
	glColor3f(0.0, 0.0, 1.0);
	glIndexf(4);
	writeFont((char *) gluErrorString(gotError));
    }

    /* So glLoadName will be legal -- strange semantics */
    glPushName(1);
    for (poly=thePoly; poly; poly=poly->next) {
	glColor3f(0.0, 1.0, 0.0);
	glIndexf(2);
	glLoadName(SELECT_LINE);
	for (vert=poly->contour; vert; vert=vert->next) {
	    glPushName(vert->name);
	    glBegin(GL_LINES);
	    glVertex2dv(vert->v);
	    if (vert->next) {
		glVertex2dv(vert->next->v);
	    } else {
		glVertex2dv(poly->contour->v);
	    }
	    glEnd();
	    glPopName();
	}
	glColor3f(1.0, 0.0, 0.0);
	glIndexf(1);
	glLoadName(SELECT_VERTEX);
	for (vert=poly->contour; vert; vert=vert->next) {
	    glPushName(vert->name);
	    glBegin(GL_POINTS);
	    glVertex2dv(vert->v);
	    glEnd();
	    glPopName();
	}
    }

    if (mode == GL_RENDER) {
	glXSwapBuffers(dpy, window);
    }
}

static void Usage(char *name)
{
    fprintf(stderr, "Usage: %s [-c] [-s]\n",name);
    exit(1);
}

static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
{
    if ((e->type == MapNotify) && (e->xmap.window == (Window) arg)) {
	return GL_TRUE;
    }
    return GL_FALSE;
}

/*
** Create a new contour at x,y.
*/
void newContour(int x, int y)
{
    struct polygon *newPoly;
    struct vert *newCont;
    struct polygon **polyTail;

    newPoly = (struct polygon *) malloc(sizeof(struct polygon));
    newCont = (struct vert *) malloc(sizeof(struct vert));

    polyTail = &thePoly;
    while (*polyTail) {
	polyTail = &((*polyTail)->next);
    }

    *polyTail = newPoly;
    newPoly->next = NULL;
    newPoly->contour = newCont;

    newCont->next = NULL;
    newCont->v[0] = x;
    newCont->v[1] = y;
    newCont->v[2] = 0;
    newCont->name = vertName++;
}

/*
** Create a new edge at this vertex
*/
struct vert *addVertex(struct vert *where, int x, int y)
{
    struct vert *newVert;

    newVert = (struct vert *) malloc(sizeof(struct vert));

    newVert->next = where->next;
    where->next = newVert;
    newVert->v[0] = x;
    newVert->v[1] = y;
    newVert->v[2] = 0;
    newVert->name = vertName++;

    return newVert;
}

void deleteVertex(void)
{
    struct polygon *poly, *poly2;
    struct vert *vert;

    if (!foundVertex) return;

    for (poly=thePoly; poly; poly=poly->next) {
	if (poly->contour == foundVertex) {
	    poly->contour = foundVertex->next;
	    free(foundVertex);
	    foundVertex = NULL;
	    if (poly->contour == NULL) {
		if (poly == thePoly) {
		    thePoly = poly->next;
		    free(poly);
		    return;
		}
		for (poly2=thePoly; poly2; poly2=poly2->next) {
		    if (poly2->next == poly) {
			poly2->next = poly->next;
			free(poly);
			return;
		    }
		}
	    }
	    return;
	}
	for (vert=poly->contour; vert; vert=vert->next) {
	    if (vert->next == foundVertex) {
		vert->next = foundVertex->next;
		free(foundVertex);
		foundVertex = NULL;
		return;
	    }
	}
    }
}

struct vert *lookupVertex(GLuint name)
{
    struct polygon *poly;
    struct vert *vert;

    for (poly=thePoly; poly; poly=poly->next) {
	for (vert=poly->contour; vert; vert=vert->next) {
          if (vert->name == name) return (vert);
	}
    }
    return(NULL);
}

void freePolygon(struct polygon *thePoly)
{
    
    struct polygon *poly, *nextPoly;
    struct vert *vert, *nextVert;

    for (poly=thePoly; poly; poly=nextPoly) {
        nextPoly = poly->next;
	for (vert=poly->contour; vert; vert=nextVert) {
          nextVert = vert->next;
          free(vert);
	}
        free(poly);
    }
}

void findVertex(int x, int y, int type)
{
    static GLuint selectBuf[1000];
    GLint hits;
    GLint viewport[4];
    int i;

    foundVertex = NULL;
    glSelectBuffer(1000, selectBuf);
    (void) glRenderMode(GL_SELECT);
    glInitNames();

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glGetIntegerv(GL_VIEWPORT, viewport);
    gluPickMatrix(x, y, 6, 6, viewport);
    gluOrtho2D(0,W,0,H);
    glMatrixMode(GL_MODELVIEW);

    Redraw(GL_SELECT);

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    hits = glRenderMode(GL_RENDER);
    if (hits <= 0) return;

    /*
    ** Each entry looks like:
    **   count (2)
    **   min z, max z
    **   SELECT_LINE or SELECT_VERTEX
    **   pointer to vertex.
    */

    i = 0;
    while (hits) {
	hits --;
	if (selectBuf[i] == 0) {
	    i+= 3;
	    continue;
	}
	assert(selectBuf[i] == 2);
	i += 3;
	if (selectBuf[i] == type) {
	    foundVertex = lookupVertex(selectBuf[i+1]);
	    return;
	}
	i += 2;
    }
}

void moveVertex(int x, int y)
{
    if (foundVertex) {
	foundVertex->v[0] = x;
	foundVertex->v[1] = y;
    }
}

void errorHandler(GLenum error)
{
    if (gotError) {
	printf("Double errors!?!\n");
    }
    gotError = error;
}

void myEnd(void)
{
    glEnd();
}


static void combine( GLdouble coords[3], struct vert *data[4],
                     GLfloat weight[4], struct vert **dataOut )
{
   struct vert *vertex;
   vertex = (struct vert *) malloc(sizeof(struct vert));

   if (counter < MAXTOBEFREED) {
      toBeFreed[counter]= vertex;
   }
   counter++;

   vertex->v[0] = coords[0];
   vertex->v[1] = coords[1];
   vertex->name = vertName++;
   *dataOut = vertex;
}

static void Init(void)
{
    glViewport(0,0,W,H);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0,W,0,H);
    glMatrixMode(GL_MODELVIEW);

    if (rgb) {
	glClearColor(0,0,0,0);
    } else {
	glClearIndex(0);
    }

    glClear(GL_COLOR_BUFFER_BIT);

    tobj = gluNewTess();
    gluTessCallback(tobj, GLU_TESS_VERTEX, &glVertex2dv);
    gluTessCallback(tobj, GLU_TESS_BEGIN, &myBegin);
    gluTessCallback(tobj, GLU_TESS_END, &myEnd);
    gluTessCallback(tobj, GLU_TESS_ERROR, &errorHandler);
    gluTessCallback(tobj, GLU_TESS_COMBINE, &combine);
    initializeFont();
}

static void setColorMap(void)
{
    XColor *xc;
    long i;

    xc = (XColor *) malloc(16 * sizeof(XColor));
    for (i=0; i<16; i++) {
	xc[i].pixel = i;
	xc[i].red = (i & 1) ? 65535 : 0;
	xc[i].green = (i & 2) ? 65535 : 0;
	xc[i].blue = (i & 4) ? 65535 : 0;
	if (i > 8) {
	    xc[i].red /= 2;
	    xc[i].green /= 2;
	    xc[i].blue /= 2;
	}
	xc[i].flags = DoRed | DoGreen | DoBlue;
    }
    XStoreColors(dpy, cmap, xc, 16);

    free((void *) xc);
}

int main(int argc, char** argv)
{
    XVisualInfo *vi;
    XSetWindowAttributes swa;
    GLXContext cx;
    XEvent event;
    GLboolean needDisplay;
    XColor white;
    int i;

    rgb = 1;
    for (i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            switch (argv[i][1]) {
              case 'c':
                rgb = GL_FALSE;
                break;
	      case 's':
		doubleBuf = 0;
		break;
              default:
                Usage(argv[0]);
            }
        } else {
            Usage(argv[0]);
        }
    }

    dpy = XOpenDisplay(0);
    if (!dpy) {
	fprintf(stderr, "Can't connect to display \"%s\"\n", getenv("DISPLAY"));
	return -1;
    }

    /* compile-time check for GLU 1.2 */
#if !defined(GLU_VERSION_1_2)
#error "This requires GLU 1.2."    
    fprintf(stderr,"%s requires GLU 1.2\n",argv[0]);
    exit(1);
#endif
    /* run-time check for GLU 1.2 */
    {
       int major, minor;
       Bool isGLU_1_2= False;	/* assume GLU is not version 1.2 */

       /* gluGetString() exists iff GLX version >= 1.1 */
       glXQueryVersion(dpy,&major,&minor);
       if (minor > 0 || major > 1) {
	  /* is GLU version 1.2? */
	  const GLubyte *string= gluGetString(GLU_VERSION);
#define GLU_1_2_STRING "1.2"
	  if (strtod((const char *)string,NULL) >= 1.2) {
	     isGLU_1_2= True;	/* GLU version is 1.2 */
	  }
       }
       if (isGLU_1_2 == False) {
	  fprintf(stderr,"%s requires GLU 1.2\n",argv[0]);
	  exit(1);
       }
    }

    vi = glXChooseVisual(dpy, DefaultScreen(dpy),
	    doubleBuf ? (rgb ? RGB_DB_attributes : CI_DB_attributes) :
	    (rgb ? RGB_SB_attributes : CI_SB_attributes));
    if (!vi) {
	fprintf(stderr, "No singlebuffered rgba visual on \"%s\"\n",
		getenv("DISPLAY"));
	return -1;
    }

    cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual,
			   rgb ? AllocNone : AllocAll);
    white.red = ~0;
    white.green = ~0;
    white.blue = ~0;
    XAllocColor(dpy, cmap, &white);

    swa.border_pixel = 0;
    swa.background_pixel = white.pixel;
    swa.colormap = cmap;
    swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask
	| KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
	PointerMotionMask;
    window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 10, 10,
			   W, H,
			   0, vi->depth, InputOutput, vi->visual,
			   CWBackPixel|CWBorderPixel|CWColormap|CWEventMask,
			   &swa);
    XSetWMColormapWindows(dpy, window, &window, 1);
    XMapWindow(dpy, window);
    XIfEvent(dpy, &event, WaitForMapNotify, (char*)window);

    cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
    if (!glXMakeCurrent(dpy, window, cx)) {
	fprintf(stderr, "Can't make window current to context\n");
	return -1;
    }

    if (!rgb) {
	setColorMap();
    }

    Init();

    printf("\n\nc to create a new contour.\n");
    printf("d to delete a vertex.\n");
    printf("t to tessellate and draw the polygon.\n");
    printf("s to show the tessellation.\n");
    printf("e to draw the polygon in Polymode(GL_LINE) with edge flags.\n");
    printf("Left mouse moves a vertex.\n");
    printf("Middle mouse inserts a vertex into a contour.\n");

    leftDown = middleDown = rightDown = GL_FALSE;
    newContour(100, 100);
    findVertex(100, 100, SELECT_VERTEX);
    addVertex(foundVertex, 100, 400);
    findVertex(100, 400, SELECT_VERTEX);
    addVertex(foundVertex, 400, 400);
    findVertex(400, 400, SELECT_VERTEX);
    addVertex(foundVertex, 400, 100);
    foundVertex = NULL;
    for (;;) {
        needDisplay = GL_FALSE;
	do {
	    XNextEvent(dpy, &event);
	    switch (event.type) {
	      case Expose:
                needDisplay = GL_TRUE;	       
		break;
	      case ConfigureNotify:
		W = event.xconfigure.width;
		H = event.xconfigure.height;
		glViewport(0,0,W,H);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0,W,0,H);
		glMatrixMode(GL_MODELVIEW);
                needDisplay = GL_TRUE;
		break;
	      case ButtonPress:
		/* 
		** Only effectively allow one mouse button down at a time.
		*/
		leftDown = middleDown = rightDown = GL_FALSE;
		switch(event.xbutton.button) {
		  case 1:	/* Left - move vertex */
		    findVertex(event.xbutton.x, H - event.xbutton.y, 
			    SELECT_VERTEX);
		    moveVertex(event.xbutton.x, H - event.xbutton.y);
		    leftDown = GL_TRUE;
		    break;
		  case 2:	/* Middle - insert vertex */
		    middleDown = GL_TRUE;
		    findVertex(event.xbutton.x, H - event.xbutton.y, 
			    SELECT_LINE);
		    if (foundVertex) {
			foundVertex = addVertex(foundVertex, 
				event.xbutton.x, H - event.xbutton.y);
		    }
		    break;
		  case 3:	/* Right */
		    rightDown = GL_TRUE;
		    break;
		}
		break;
	      case ButtonRelease:
		switch(event.xbutton.button) {
		  case 1:
		    if (leftDown && foundVertex) {
			moveVertex(event.xbutton.x, H - event.xbutton.y);
			leftDown = GL_FALSE;
			needDisplay = GL_TRUE;
		    } 
		    break;
		  case 2:
		    if (middleDown && foundVertex) {
			moveVertex(event.xbutton.x, H - event.xbutton.y);
			middleDown = GL_FALSE;
			needDisplay = GL_TRUE;
		    }
		    break;
		}
		break;
	      case MotionNotify:
		if (leftDown && foundVertex) {
		    moveVertex(event.xmotion.x, H - event.xmotion.y);
		    needDisplay = GL_TRUE;
		} else if (middleDown && foundVertex) {
		    moveVertex(event.xmotion.x, H - event.xmotion.y);
		    needDisplay = GL_TRUE;
		}
		break;
	      case KeyPress:
		{
		    char buf[100];
		    int rv;
		    KeySym ks;

		    rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0);
		    switch (ks) {
		      case XK_C: case XK_c:
			newContour(event.xkey.x, H - event.xkey.y);
			needDisplay = GL_TRUE;
			break;
		      case XK_D: case XK_d:
			findVertex(event.xbutton.x, H - event.xbutton.y, 
				SELECT_VERTEX);
			if (foundVertex) {
			    deleteVertex();
			    needDisplay = GL_TRUE;
			} 
			break;
		      case XK_T: case XK_t:
			tessIt = 1-tessIt;
			needDisplay = GL_TRUE;
			break;
		      case XK_S: case XK_s:
			showTess = 1-showTess;
			needDisplay = GL_TRUE;
			break;
		      case XK_E: case XK_e:
			doEdgeFlags = 1-doEdgeFlags;
			needDisplay = GL_TRUE;
			break;
		      case XK_Escape:
			gluDeleteTess(tobj);			
			freePolygon(thePoly);
			thePoly = NULL;
#if 0
			XFree(vi);
                        glXMakeCurrent(dpy, None, NULL);
                        glXDestroyContext(dpy, cx);
                        XCloseDisplay(dpy);
#endif
			return 0;
		      default:
			break;
		    }
		}
		break;
	      default:
		break;
	    }
	} while (XPending(dpy) != 0);

	if (needDisplay) {
	    needDisplay = GL_FALSE;
	    Redraw(GL_RENDER);
	}
    }
}