From owner-freebsd-ports-bugs@FreeBSD.ORG Wed Sep 20 21:10:19 2006 Return-Path: X-Original-To: freebsd-ports-bugs@hub.freebsd.org Delivered-To: freebsd-ports-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 86BF316A407 for ; Wed, 20 Sep 2006 21:10:19 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id CCB4443D4C for ; Wed, 20 Sep 2006 21:10:18 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k8KLAITx081193 for ; Wed, 20 Sep 2006 21:10:18 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k8KLAI8v081192; Wed, 20 Sep 2006 21:10:18 GMT (envelope-from gnats) Resent-Date: Wed, 20 Sep 2006 21:10:18 GMT Resent-Message-Id: <200609202110.k8KLAI8v081192@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-ports-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, rossiya@gmail.com Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 565CA16A407 for ; Wed, 20 Sep 2006 21:02:52 +0000 (UTC) (envelope-from myles@peppercon.cologroup.net) Received: from alnrmhc13.comcast.net (alnrmhc13.comcast.net [206.18.177.53]) by mx1.FreeBSD.org (Postfix) with ESMTP id D0C6E43D73 for ; Wed, 20 Sep 2006 21:02:49 +0000 (GMT) (envelope-from myles@peppercon.cologroup.net) Received: from peppercon.cologroup.net (c-24-126-46-137.hsd1.ca.comcast.net[24.126.46.137]) by comcast.net (alnrmhc13) with SMTP id <20060920210246b1300l5lkee>; Wed, 20 Sep 2006 21:02:46 +0000 Received: (qmail 74022 invoked from network); 20 Sep 2006 21:01:41 -0000 Received: from localhost (HELO peppercon.cologroup.net) (127.0.0.1) by localhost with SMTP; 20 Sep 2006 21:01:41 -0000 Received: (from root@localhost) by peppercon.cologroup.net (8.13.4/8.13.1/Submit) id k8KL1fGD074019; Wed, 20 Sep 2006 14:01:41 -0700 (PDT) (envelope-from myles) Message-Id: <200609202101.k8KL1fGD074019@peppercon.cologroup.net> Date: Wed, 20 Sep 2006 14:01:41 -0700 (PDT) From: rossiya@gmail.com To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: ports/103441: New port:math/ffff X-BeenThere: freebsd-ports-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: rossiya@gmail.com List-Id: Ports bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Sep 2006 21:10:19 -0000 >Number: 103441 >Category: ports >Synopsis: New port:math/ffff >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Sep 20 21:10:18 GMT 2006 >Closed-Date: >Last-Modified: >Originator: rossiya >Release: FreeBSD 6.1-RELEASE-p3 i386 >Organization: >Environment: System: FreeBSD peppercon 6.1-RELEASE-p3 FreeBSD 6.1-RELEASE-p3 #0: Sat Aug 12 15:47:47 PDT 2006 root@:/usr/obj/usr/src/sys/MC2 i386 >Description: FFFF is the fastest Win32/OSX/Linux/IRIX Mandelbrot generator. Features OpenGL, realtime zoom, SSE/AltiVec QuadPixel, SSE2/3DNow! DualPixel calc, FPU per pixel calc, GPU asm (Fragment/Vertex) calc, multiprocessor support, and benchmarking. Opt asm code! This port does the standard Mandelbrot at near-Xaos speed, yet every pixel is computed. There is also an interesting parameter ray algorithm using your 3D card. It detects my Nvidia fine. Requires X11 and a 3D card strongly suggested for speed and additional coprocessing power. WWW: http://sourceforge.net/projects/ffff/ >How-To-Repeat: >Fix: --- sendFile begins here --- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # ./Makefile # ./distinfo # ./pkg-descr # ./pkg-plist # ./files # ./files/patch-file # echo x - ./Makefile sed 's/^X//' >./Makefile << 'END-of-./Makefile' X# ex:ts=8 X# Ports collection makefile for: ffff X# Date created: Sep 20, 2006 X# Whom: rossiya X# X# $FreeBSD: ports/math/ffff/Makefile,v 1.16 2006/09/20 10:37:52 ade Exp $ X# X XPORTNAME= ffff XPORTVERSION= 323 XCATEGORIES= math XMASTER_SITES= ${MASTER_SITE_SOURCEFORGE_EXTENDED} XMASTER_SITE_SUBDIR= ${PORTNAME} XDISTNAME= FFFF${PORTVERSION}-src X XMAINTAINER= rossiya@gmail.com XCOMMENT= A Freebsd port of the fast Win32/OSX/Linux/IRIX Mandelbrot generator X XLIB_DEPENDS= glut.4:${PORTSDIR}/graphics/libglut X XUSE_GMAKE= yes XUSE_ZIP= yes XUSE_GL= yes XUSE_XLIB= yes XMAKE_ARGS+= ACLOCAL="${TRUE}" AUTOCONF="${TRUE}" AUTOMAKE="${TRUE}" \ X AUTOHEADER="${TRUE}" X X# contains x86 assembler XONLY_FOR_ARCHS= i386 amd64 X X.undef HAS_CONFIGURE X Xdo-install: X @${INSTALL_PROGRAM} ${WRKSRC}/debug/ffff ${X11BASE}/bin/ X Xpost-install: X.if !defined(NOPORTDOCS) X# ${MKDIR} ${DOCSDIR} X# cd ${WRKSRC} && pwd && ${INSTALL_DATA} -v ${PORTDOCS} ${DOCSDIR} X.endif X ${ECHO_MSG} "===> Program is installed as ${X11BASE}/bin/ffff" \ X && ${ECHO_MSG} " [Some modes don't yet work. Let me know if you have interest/patches]" X X.include END-of-./Makefile echo x - ./distinfo sed 's/^X//' >./distinfo << 'END-of-./distinfo' XMD5 (FFFF323-src.zip) = ba5c63ccedfb61f5ceea431286d6d749 XSHA256 (FFFF323-src.zip) = 4781384b4c285fe61f19ba776d4a656fd5e809b9a88198a0705c8f7ca7dca715 XSIZE (FFFF323-src.zip) = 127442 END-of-./distinfo echo x - ./pkg-descr sed 's/^X//' >./pkg-descr << 'END-of-./pkg-descr' XFFFF is the fastest Win32/OSX/Linux/IRIX Mandelbrot generator. Features OpenGL, Xrealtime zoom, SSE/AltiVec QuadPixel, SSE2/3DNow! DualPixel calc, FPU per Xpixel calc, GPU asm (Fragment/Vertex) calc, multiprocessor support, and Xbenchmarking. Opt asm code! X XThis port does the standard Mandelbrot at near-Xaos speed, yet every pixel is Xcomputed. There is also an interesting parameter ray algoritymn using your X3D card. It detects my Nvidia GeForce FX5500 fine, at any rate. Requires X11 Xand a 3D card strongly suggested for screen speed and additional coprocessing Xpower. X XWWW: http://sourceforge.net/projects/ffff/ END-of-./pkg-descr echo x - ./pkg-plist sed 's/^X//' >./pkg-plist << 'END-of-./pkg-plist' X@cwd /usr/X11R6 Xbin/ffff END-of-./pkg-plist echo c - ./files mkdir -p ./files > /dev/null 2>&1 echo x - ./files/patch-file sed 's/^X//' >./files/patch-file << 'END-of-./files/patch-file' X--- ./extensions.cpp.orig Tue Sep 19 21:06:09 2006 X+++ ./extensions.cpp Thu Sep 7 07:18:59 2006 X@@ -1,6 +1,21 @@ X #include X #include X X+#define __linux__ X+ X+ #include X+ #include X+ #include X+ #include X+ #include X+//typedef void (*__GLXextFuncPtr)(void); X+//extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *); X+extern __GLXextFuncPtr glXGetProcAddressARB (GLubyte *); X+//extern void ((*(glXGetProcAddressARB))(const GLubyte *procName))( void ); X+//extern void (*glXGetProcAddressARB( GLubyte *))( void ); X+ X+__GLXextFuncPtr glXGetProcAddressARB(unsigned char*){} X+ X #ifdef __APPLE__ X #include X #include X@@ -96,18 +111,26 @@ X { X #if defined(__APPLE__) || defined(__linux__) X // GL_ARB_multitexture X- pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glActiveTextureARB"); X- pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glClientActiveTextureARB"); X+// pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glActiveTextureARB"); X+ pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glActiveTextureARB"); X+// pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glClientActiveTextureARB"); X+ pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glClientActiveTextureARB"); X if (!pfglActiveTextureARB) return false; X if (!pfglClientActiveTextureARB) return false; X X // GL_ARB_fragment_program X- pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGenProgramsARB"); X- pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glDeleteProgramsARB"); X- pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glBindProgramARB"); X- pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramStringARB"); X- pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramEnvParameter4fARB"); X- pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGetProgramivARB"); X+// pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGenProgramsARB"); X+ pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glGenProgramsARB"); X+// pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glDeleteProgramsARB"); X+ pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glDeleteProgramsARB"); X+// pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glBindProgramARB"); X+ pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glBindProgramARB"); X+// pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramStringARB"); X+ pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glProgramStringARB"); X+// pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramEnvParameter4fARB"); X+ pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glProgramEnvParameter4fARB"); X+// pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGetProgramivARB"); X+ pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glGetProgramivARB"); X if (!pfglGenProgramsARB) return false; X if (!pfglDeleteProgramsARB) return false; X if (!pfglBindProgramARB) return false; X--- ./FFFF3.cpp.orig Tue Sep 19 21:06:09 2006 X+++ ./FFFF3.cpp Thu Sep 7 21:02:57 2006 X@@ -1,3 +1,4 @@ X+#define __linux__ X /******************************************************************* X FFFF v3.2.3 X X@@ -24,6 +25,7 @@ X ... and all the others who kindly sent code, fixes, suggestions and feedback ! X *******************************************************************/ X X+int get_nprocs() {return 1;} X X // WARNING: This source is a real mess ! :))) X // WARNING: This is only meant as some "portable" glue for assembly. X@@ -70,7 +72,7 @@ X #include X #include X #include X- #include X+// #include X #else X #include "GL/glut.h" X #include "GL/gl.h" X@@ -381,7 +383,8 @@ X } X #endif X X- avail_SSE = checkSSE(); X+ //avail_SSE = checkSSE(); X+ avail_SSE = 1; X if (avail_SSE) { X #if defined(__APPLE__) && __BIG_ENDIAN__ X // PowerPC X@@ -397,7 +400,8 @@ X printf("Switching to machine code FPU mode.\n"); X } X X- avail_SSE2 = checkSSE2(); X+ //avail_SSE2 = checkSSE2(); X+ avail_SSE2 = 1; X if (avail_SSE2) { X #if defined (sgi) X printf("MIPS dual FPU units supported.\n"); X--- ./FragmentProgramARB10.cpp.orig Tue Sep 19 21:06:09 2006 X+++ ./FragmentProgramARB10.cpp Wed Sep 6 23:33:11 2006 X@@ -1,3 +1,4 @@ X+#define __linux__ X #include "FragmentProgramARB10.h" X X #include X--- ./GPUProgram.h.orig Tue Sep 19 21:06:09 2006 X+++ ./GPUProgram.h Wed Sep 6 23:45:32 2006 X@@ -1,4 +1,5 @@ X #pragma once X+#define __linux__ X X #if defined(__APPLE__) X #include X--- ./vpext.cpp.orig Tue Sep 19 21:06:09 2006 X+++ ./vpext.cpp Thu Sep 7 07:01:47 2006 X@@ -1,3 +1,4 @@ X+#define __linux__ X #include "vpext.h" X X // This file includes the declarations of all the VP functions X--- ./Makefile.orig Tue Sep 19 21:06:09 2006 X+++ ./Makefile Tue Sep 19 20:17:05 2006 X@@ -0,0 +1,112 @@ X+MAKE=make X+AR=ar X+ARFLAGS=-rv X+AS=as X+ASFLAGS=-mips4 -64 X+YACC=yacc X+YFLAGS= X+LEX=lex X+LFLAGS= LDFLAGS= X+CC=gcc X+#CC=/usr/local/bin/gcc42 X+#CC=/usr/local/bin/gcc41 X+CFLAGS=-O X+FC=fort77 X+FFLAGS=-O 1 X+GET=get X+GFLAGS= SCCSFLAGS= X+SCCSGETFLAGS=-s X+ X+RM=rm X+#CP=/usr/local/bin/gcc42 X+#CP=/usr/local/bin/gcc41 X+CP=gcc X+MKDIR=mkdir -p X+CHMOD=chmod X+ X+ X+SHELL = /bin/sh X+ X+ASSOURCES=$(wildcard *.s) X+ASOBJ=$(patsubst %.s,$(CFG)/%.o,$(ASSOURCES)) X+ X+SOURCES=$(wildcard *.cpp) X+SOURCES+=$(wildcard *.cxx) X+OBJ_=$(patsubst %.cpp,$(CFG)/%.obj,$(SOURCES)) X+OBJ=$(patsubst %.cxx,$(CFG)/%.objx,$(OBJ_)) X+ X+ifeq ($(CFG),) X+CFG=debug X+endif X+ X+ifeq ($(CFG),release) X+ DBG_FLAG= X+ DEPENDENCIES= X+ OUTDIR=$(CFG) X+ TARGETNAME=$(OUTDIR)/ffff X+# CCFLAGS= -g -O3 -ffast-math -mfpmath=sse,387 -msse2 -msse -mmmx -march=pentium4 X+# CCFLAGS= -g -O6 -funit-at-a-time -funroll-loops -ffast-math -mfpmath=sse -msse2 -msse3 -msse -mmmx -march=pentium4 X+ CCFLAGS= -g -O6 -funit-at-a-time -funroll-loops -ffast-math -mfpmath=sse -msse2 -msse -mmmx -march=pentium4 X+ INCLUDEFLAGS= -I/usr/X11R6/include -I/usr/X11R6/include/GL X+ LINKFLAGS= -L/usr/X11R6/lib -lglut -lGL -lXext -lX11 -lXmu -lGLU -lpthread -lm X+else X+ DBG_FLAG= X+ DEPENDENCIES= X+ OUTDIR=$(CFG) X+ TARGETNAME=$(OUTDIR)/ffff X+# CCFLAGS= -g -O2 -ggdb3 -funit-at-a-time -funroll-loops -ffast-math -mfpmath=sse -msse2 -msse3 -msse -mmmx -march=pentium4 X+ CCFLAGS= -g -ggdb3 -funit-at-a-time -funroll-loops -ffast-math -mfpmath=sse -msse2 -msse3 -msse -mmmx -march=pentium4 X+# CCFLAGS= -ggdb3 -O6 -funit-at-a-time -funroll-loops -ffast-math -mfpmath=sse -msse3 -msse2 -msse -mmmx -march=pentium4 X+ INCLUDEFLAGS= -I/usr/X11R6/include -I/usr/X11R6/include/GL X+ LINKFLAGS= -L/usr/X11R6/lib -lglut -lGL -lXext -lX11 -lXmu -lGLU -lpthread -lm X+endif X+ X+ X+ X+ifneq ($(DEPENDENCIES),) X+ DEPM=$(foreach d,$(DEPENDENCIES),$(join $(dir $(d)), Makefile)) X+ DEPB=$(patsubst %,%.build, $(DEPM)) X+ DEPC=$(patsubst %,%.clean, $(DEPM)) X+endif X+ X+ X+%.build : % X+ -cd $(dir $<) && $(MAKE) -f $(notdir $<) CFG=$(CFG) X+ X+%.clean : % X+ -cd $(dir $<) && $(MAKE) -f $(notdir $<) CFG=$(CFG) clean X+ X+all: deps binaries X+ X+deps: $(DEPB) X+ X+binaries: $(OUTDIR) $(TARGETNAME) X+ $(CHMOD) -R a+rw $(OUTDIR) X+ifeq ($(CFG),release) X+ strip $(TARGETNAME) X+endif X+ X+clean-deps: $(DEPC) X+ X+$(CFG)/%.obj : %.cpp X+ $(CC) -c $(CCFLAGS) $(INCLUDEFLAGS) $< -o $@ X+ X+$(CFG)/%.objx : %.cxx X+ $(CC) -c $(CCFLAGS) $(INCLUDEFLAGS) $< -o $@ X+ X+$(CFG)/%.o : %.s X+ as $(ASFLAGS) $(INCLUDEFLAGS) $< -o $@ X+ X+$(OUTDIR): X+ -$(MKDIR) $(OUTDIR) X+ X+$(TARGETNAME): $(CFG) $(OBJ) $(DEPENDENCIES) X+ $(CC) -o $@ $(OBJ) $(DEPENDENCIES) $(LINKFLAGS) X+ X+rebuild: clean all X+ X+clean: clean-deps X+ -rm -rf core X+ -rm -rf $(TARGETNAME) X+ -rm -rf $(CFG) X+ X--- ./hole.cpp.save.orig Tue Sep 19 21:06:09 2006 X+++ ./hole.cpp.save Thu Sep 7 07:44:39 2006 X@@ -0,0 +1,1122 @@ X+// ---------------------- X+// OpenGL Black Hole Simulator. X+// X+// Written by and Copyright Chris Halsall (chalsall@chalsall.com). X+// First published on the O'Reilly Network on Linux.com X+// (oreilly.linux.com). September 2000. All rights reserved. X+// X+// This code is licensed under the GNU GPL Version 2.0. X+// See (URL: http://www.gnu.org/copyleft/gpl.html ) for details. X+// X+// Coded to the groovy tunes of Fluke: Risotto. X+// X+// Dedicated to Stephen W. Hawking, one of the greatest explorers X+// of our time. X+ X+#define PROGRAM_TITLE "O'Reilly Net: Black Hole -- C.Halsall" X+ X+ X+#include // Always a good idea. X+#include // For RAND_MAX. X+#include // For our FPS stats. X+#include // For M_PI X+#include // OpenGL itself. X+#include // GLU support library. X+#include // GLUT support library. X+ X+ X+// A quick macro to populate a 1x3 vector array. X+#define ourVectInit(a,x,y,z) { (a)[0]=x; (a)[1]=y; (a)[2]=z; } X+ X+// Structure to hold all the data for each particle. X+typedef struct { X+ int Running; X+ float Pos[3]; // Position. X+ float Vel[3]; // Velocity. X+ float Grav[3]; // Acceleration. X+ float Color[3]; X+} Particle; X+ X+ X+// ------ X+// Some global variables. X+ X+// Window and Texture IDs, Window sizes. X+int Texture_ID; X+int Window_ID; X+int Window_Width=640; X+int Window_Height=480; X+ X+// We'll request a sphere from the GLU library at run-time. X+struct GLUquadric *Black_Hole; X+ X+// "Name" for first (and only) OpenGL display list. X+#define STAR_FIELD 1 X+ X+ X+// Pointer for allocated array of Particles. X+Particle *Parts; X+ X+// Particle status variables. X+int Parts_Running=0; X+int Parts_Allocated=0; X+int Parts_LastUnused=1; X+ X+// Number of parts initially in the system. Make sure there's at least X+// one over a hundred (101, 801), so our Root particle doesn't get deleted. X+int Parts_Num = 801; X+ X+float Parts_Brightness = 0.15; X+ X+ X+// Drawing flags. X+int Draw_Axis = 0; X+int Draw_Vectors = 0; X+int Draw_Stars = 1; X+int Heads_Up = 0; X+int Texture_On = 1; X+ X+ X+// Particle Gun variables. X+float Gun_PX = 0; X+float Gun_PY = 0; X+float Gun_PZ = 4; X+ X+float Gun_VX =-0.135; X+float Gun_VY = 0.0125; X+float Gun_VZ = 0.0; X+float Gun_R = 0.005; X+float Gun_OffR = 0.050; X+ X+// Backwards firing and off-target probabilities. X+float Gun_Back = 0.9, Gun_Off = 0.9; X+ X+// '.' key toggels between keypad adjusting gun position and eject vect. X+int Gun_Control = 1; X+ X+ X+// Orbit and motion settings. X+int On_Orbit=1; X+int Move_Enable=1; X+int Move_Step=0; X+ X+// Observer initial placement. X+float Obs_Angle=114.0; X+float Obs_Height=.2; X+float Obs_Dist=4.6; X+ X+// Calculated observer location. X+float Obs[3]; X+ X+// How quickly do the orbits decay? X+// Lower number (limit 1) is faster decay. X+ X+int Decay_Factor = 6000; X+ X+// The force of gravity exterted by the black hole. X+float Grav = 0.075; X+ X+// Somewhat arbitrary values for Event and Escape horizons. X+ X+#define EVENT_HORIZON_GRAV .5 X+ X+#define ESCAPE_HORIZON 30 X+#define ESCAPE_HORIZON_SQR (ESCAPE_HORIZON * ESCAPE_HORIZON) X+ X+ X+// ------ X+// Frames per second (FPS) statistic variables and routine. X+ X+#define FRAME_RATE_SAMPLES 50 X+int FrameCount=0; X+float FrameRate=0; X+ X+static void ourDoFPS( X+ void X+) X+{ X+ static clock_t last=0; X+ clock_t now; X+ float delta; X+ X+ if (++FrameCount >= FRAME_RATE_SAMPLES) { X+ now = clock(); X+ delta= (now - last) / (float) CLOCKS_PER_SEC; X+ last = now; X+ X+ FrameRate = FRAME_RATE_SAMPLES / delta; X+ FrameCount = 0; X+ } X+} X+ X+ X+// ------ X+// String rendering routine; leverages on GLUT routine. X+ X+static void ourPrintString( X+ void *font, X+ char *str X+) X+{ X+ int i,l=strlen(str); X+ X+ for(i=0;i Num) X+ Parts_LastUnused = Num; X+ X+ Parts_Running = 0; X+ for (i = 0; i < Num; i++) X+ if (P[i].Running) X+ Parts_Running++; X+ X+ Parts_Allocated = Num; X+ Parts = P; X+ X+ return P; X+} X+ X+ X+// ------ X+// Function to return a random floating number between 0 and the passed X+// parameter. X+ X+float ourRand( X+ float Max X+) X+{ X+ return( (Max * rand()) / RAND_MAX ); X+} X+ X+ X+// ------ X+// Builds a Display List containing a random star field. X+// X+// Note: this could also be done by calculating the star points in this X+// routine, which would be faster than having OpenGL perform two X+// rotations (matrix multiplications) for each star. However, this X+// technique is simpler and faster for the programmer, and demonstrates X+// how successive transformations can be a powerful tool. X+ X+void ourBuildStarfield( X+ int Stars X+) X+{ X+ int Cnt; X+ X+ glNewList(STAR_FIELD, GL_COMPILE); X+ X+ glMatrixMode(GL_MODELVIEW); X+ glPushMatrix(); X+ X+ for ( Cnt = 0; Cnt < Stars; Cnt++) { X+ X+ // Vary the color for each star. X+ glColor4f( X+ 0.8 + ourRand(0.2), X+ 0.8 + ourRand(0.2), X+ 0.8 + ourRand(0.2), X+ .95); X+ X+ // Vary the size. Ensure integer sizes to avoid alias shimmering. X+ glPointSize(ourRand(2) > 1 ? 1.0 : 2.0); X+ X+ // Spin your Universe, round and round.... X+ glRotatef(ourRand(100),0.0f,1.0f,0.0f); X+ glRotatef(ourRand(100),1.0f,0.0f,0.0f); X+ X+ glBegin(GL_POINTS); X+ glVertex3f(15.0, 0.0f, 0.0f); X+ glEnd(); X+ } X+ X+ glPopMatrix(); X+ glEndList(); X+} X+ X+ X+// ------ X+// Function builds a simple alpha channel texture of a dot, X+// and then creates mipmaps. This could instead load textures from X+// graphics files from disk, or render textures based on external X+// input. X+ X+void ourBuildTextures( X+ void X+) X+{ X+ GLenum gluerr; X+ GLubyte tex[128][128]; X+ int x,y,t; X+ int hole_size = 3300; // ~ == 57.45 ^ 2. X+ X+ // Generate a texture index, then bind it for future operations. X+ glGenTextures(1,&Texture_ID); X+ glBindTexture(GL_TEXTURE_2D,Texture_ID); X+ X+ // Iterate across the texture array. X+ X+ for(y=0;y<128;y++) { X+ for(x=0;x<128;x++) { X+ X+ // Make a round dot in the texture's alpha-channel. X+ X+ // Calculate distance to center (squared). X+ t = (x-64)*(x-64) + (y-64)*(y-64) ; X+ X+ if ( t < hole_size) // Don't take square root; compare squared. X+ tex[x][y]= 240 - (240 * t) / hole_size + ourRand(15); X+ else X+ tex[x][y]=0; // Outside of the dot, it's transparent. X+ X+ } X+ } X+ X+ // The GLU library helps us build MipMaps for our texture. X+ X+ if ((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 1, 128, 128, GL_ALPHA, X+ GL_UNSIGNED_BYTE, (void *)tex))) { X+ X+ fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr)); X+ exit(-1); X+ } X+ X+ // Some pretty standard settings for wrapping and filtering. X+ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); X+ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); X+ X+ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); X+ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); X+ X+ // We start with GL_MODULATE mode. X+ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); X+} X+ X+ X+// ------ X+// Callback routine executed whenever our window is resized. Lets us X+// request the newly appropriate perspective projection matrix for X+// our needs. Try removing the gluPerspective() call to see what happens. X+ X+void cbResizeScene( X+ int Width, X+ int Height X+) X+{ X+ // Let's not core dump, no matter what. X+ if (Height == 0) X+ Height = 1; X+ X+ glViewport(0, 0, Width, Height); X+ X+ glMatrixMode(GL_PROJECTION); X+ glLoadIdentity(); X+ gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.05f,100.0f); X+ X+ glMatrixMode(GL_MODELVIEW); X+ X+ Window_Width = Width; X+ Window_Height = Height; X+} X+ X+ X+// ------ X+// Fires the Particle Gun, or, sets up the passed Particle to be X+// placed at the Particle Gun location, and fired in a direction X+// specified in Gun_Va, with 'a' being "X", "Y", or "Z". X+// X+// The particles are normally fired with a randomness of Gun_R. X+// Occationally (by default 10%) a larger randomness of Gun_OffR is X+// added. Also, 10% of the time, the particles are fired backwards. X+// This is used to introduce a bit of non-uniformity. Gun_R and X+// Gun_OffR can be controled with the '3' and '6', and '/' and '*' X+// keys, respectively. If set to zero, effects are removed. X+ X+static void ourFireParticleGun( X+ Particle *p X+) X+{ X+ float r; X+ int c; X+ int Dir = 1; X+ X+ if (!p->Running) { X+ p->Running=1; X+ Parts_Running++; X+ } X+ X+ if (p == Parts) { // Root part. X+ ourVectInit(p->Color,1,1,0); // Bright Yellow X+ ourVectInit(p->Pos,5.0,0,0); // Location X+ ourVectInit(p->Vel,0,Gun_VY,-Gun_VX*0.95); // Velocity X+ return; X+ } X+ X+ // Regular particle. X+ X+ ourVectInit(p->Pos,Gun_PX,Gun_PY,Gun_PZ); X+ r = Gun_R; X+ X+// This creates a few a very unpredicatable trajectories. It actually X+// works out to be much less than a full 10 percent, as many are eatten X+// or escape within a very short period of time. Only a few enter a X+// stable orbit. X+ X+ if (ourRand(1) > Gun_Off) r += Gun_OffR; X+ X+ if (ourRand(1) > Gun_Back) Dir = -1; X+ X+ ourVectInit(p->Vel, X+ (Gun_VX + r-ourRand(2*r)) * Dir, X+ (Gun_VY + r-ourRand(2*r)) * Dir, X+ (Gun_VZ + r-ourRand(2*r)) * Dir); X+ X+ c = (int)(ourRand(5) + 1.5); // Range of 1 to 6. X+ X+ // The last set of numbers bias the colors to blue. Red is nice too. X+ X+ ourVectInit(p->Color, X+ (c & 0x01 ? 0.9 : 1.0) * 0.7, X+ (c & 0x02 ? 0.9 : 1.0) * 0.7, X+ (c & 0x04 ? 0.9 : 1.0) * 1.0 X+ ); X+} X+ X+ X+// ------ X+// Calculates the next position based on the current velocity vector, X+// then calculates the new velocity vector based on the particle's X+// proximity to the black hole. X+// X+// We do the motion calculation before updating the velocity vector X+// (and calculating the acceleration-because-of-gravity vector) so X+// that our Vector Display option will be correct. If we didn't do X+// this, the gravity vector would not point towards (0,0,0) when X+// we drew it, outside of this function. X+ X+static void ourMoveParticle( X+ Particle *p X+) X+{ X+ float dp2, dsx, dsy, dsz, G, d; X+ X+ // Used to randomly kill and re-create particles. X+ if (p != Parts) X+ if (ourRand(1) > 0.9998) { X+ ourFireParticleGun(p); X+ return; X+ } X+ X+ // We're actually going to move this particle... X+ X+ // We first move it based on the LAST iteration's X+ // calculation of the Velocity... X+ p->Pos[0] += p->Vel[0]; X+ p->Pos[1] += p->Vel[1]; X+ p->Pos[2] += p->Vel[2]; X+ X+ // ...and then proceed to calculate the force of gravity at the new X+ // position, and update our velocity vector. X+ X+ dsx = p->Pos[0] * p->Pos[0]; X+ dsy = p->Pos[1] * p->Pos[1]; X+ dsz = p->Pos[2] * p->Pos[2]; X+ X+ // Calculate the square of the distance. X+ dp2 = dsx + dsy + dsz; X+ X+ if (dp2) { X+ // May wish to scale dp2 (change 1.0); effects gravity gradiant. X+ G = Grav / (dp2 * 1.0); X+ d = sqrt(dp2); X+ } X+ X+ // If the force of gravity is too strong, our algorithim breaks X+ // down and conservation of energy isn't maintained. We consider X+ // this the event horizon, and recycle the particle. X+ if (G > EVENT_HORIZON_GRAV) { X+ ourFireParticleGun(p); X+ return; X+ } X+ X+ if (dp2 > ESCAPE_HORIZON_SQR) { X+ // Particle escaped; lucky it. X+ ourFireParticleGun(p); X+ return; X+ } X+ X+ // OK, this particle is staying in the system. Calculate the X+ // vectors.... X+ X+ // We store the components of the force of gravity for X+ // our Vectors display. Note the negative magnitude; the vector X+ // must point _from_ our particle _towards_ (0,0,0). X+ p->Grav[0] = - G * p->Pos[0] / d; X+ p->Grav[1] = - G * p->Pos[1] / d; X+ p->Grav[2] = - G * p->Pos[2] / d; X+ X+ // Simply add the gravity vector to the current velocity vector. X+ p->Vel[0] += p->Grav[0]; X+ p->Vel[1] += p->Grav[1]; X+ p->Vel[2] += p->Grav[2]; X+ X+ if (p != Parts) { X+ // This handles orbit decay; not correctly, but well enough. X+ // (Decay should be a ratio to the vector length, applied to each X+ // vector component here, rather than each component being effected X+ // based on its individual size. The effect is to circlurize the X+ // orbit, which we want anyway.) X+ X+ p->Vel[0] -= p->Vel[0] / Decay_Factor; X+ p->Vel[1] -= p->Vel[1] / Decay_Factor; X+ p->Vel[2] -= p->Vel[2] / Decay_Factor; X+ } X+} X+ X+ X+// ------ X+// Angle to Radian conversion. X+ X+float ourA2R( X+ float Angle X+) X+{ X+ return Angle * M_PI/180; X+} X+ X+ X+// ------ X+// Calculates the observer's XYZ position from their Distance from X+// the origin, the angle and the height. X+ X+static void ourCalcObs(void) X+{ X+ Obs[0]=Obs_Dist * sin(ourA2R(Obs_Angle)); X+ Obs[1]=Obs_Height; X+ Obs[2]=Obs_Dist * cos(ourA2R(Obs_Angle)); X+} X+ X+ X+// ------ X+// Draws the X, Y, and Z axis lines. X+ X+void ourRenderAxis( X+ void X+) X+{ X+ glBegin(GL_LINES); X+ X+ glColor4f(0.5,0.5,0.0,1.0); // Mid-level yellow. X+ X+ // Three primary axis lines. X+ glVertex3f(100,0,0); X+ glVertex3f(-100,0,0); X+ glVertex3f(0,100,0); X+ glVertex3f(0,-100,0); X+ glVertex3f(0,0,100); X+ glVertex3f(0,0,-100); X+ X+ glColor4f(0.25,0.25,0.0,1.0); // Low-level yellow. X+ X+ // Two pairs of secondary lines for X and Z axis. X+ glVertex3f(100,1,0); X+ glVertex3f(-100,1,0); X+ glVertex3f(100,-1,0); X+ glVertex3f(-100,-1,0); X+ X+ glVertex3f(0,1,100); X+ glVertex3f(0,1,-100); X+ glVertex3f(0,-1,100); X+ glVertex3f(0,-1,-100); X+ X+ glColor4f(0.0,0.5,0.0,1.0); // Mid-level green. X+ X+ // Lable the X axis. X+ glVertex3f(1.0,0.9,0); X+ glVertex3f(1.1,0.8,0); X+ glVertex3f(1.1,0.9,0); X+ glVertex3f(1.0,0.8,0); X+ X+ // And the Z. X+ glVertex3f(0,0.9,1.0); X+ glVertex3f(0,0.9,1.1); X+ glVertex3f(0,0.9,1.1); X+ glVertex3f(0,0.8,1.0); X+ glVertex3f(0,0.8,1.0); X+ glVertex3f(0,0.8,1.1); X+ X+ glEnd(); X+} X+ X+ X+// ------ X+// Draws the Gravity and Velocity Vectors for each active particle. X+ X+void ourRenderVectors( X+ void X+) X+{ X+ int i; X+ X+ glBegin(GL_LINES); X+ X+ for (i=0; iPos[0], Parts->Pos[1],Parts->Pos[2]); X+ glRasterPos2i(6,-16); X+ ourPrintString(GLUT_BITMAP_HELVETICA_12,buf); X+ X+ // And the Root Particle's velocity. X+ sprintf(buf,"RootV: ( %-.4f, %-.4f, %-.4f)", X+ Parts->Vel[0], Parts->Vel[1],Parts->Vel[2]); X+ glRasterPos2i(6,-32); X+ ourPrintString(GLUT_BITMAP_HELVETICA_12,buf); X+ X+ // Done with this special projection matrix. Throw it away. X+ glPopMatrix(); X+} X+ X+ X+// ------ X+// Routine which actually does the drawing X+ X+static void cbRenderScene(void) X+{ X+ Particle *p; X+ int i; X+ X+ // For the first few objects, we want full depth-buffer testing. X+ glEnable(GL_DEPTH_TEST); X+ glDepthMask(GL_TRUE); X+ X+ // Clear the screen. X+ glClearColor(0.00,0.00,0.00,1.0); X+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); X+ X+ // Ensure we're working with the model matrix. X+ glMatrixMode(GL_MODELVIEW); X+ X+ // Reset to 0,0,0; no rotation, no scaling. X+ glLoadIdentity(); X+ X+ // Are we on-orbit, or wandering around? X+ if (On_Orbit) { X+ gluLookAt(Parts->Pos[0],Parts->Pos[1],Parts->Pos[2], X+ 0.0,0.0,0.0, X+ 0.0,1.0,0.0); X+ } else { X+ gluLookAt(Obs[0],Obs[1],Obs[2], X+ 0.0,0.0,0.0, X+ 0.0,1.0,0.0); X+ } X+ X+ // No texturing. X+ glDisable(GL_TEXTURE_2D); X+ X+ // Black holes are BLACK! X+ glColor4f(0.0,0.0,0,1.0); X+ gluSphere(Black_Hole,0.02,8,8); X+ X+ if (Draw_Stars) X+ glCallList(STAR_FIELD); X+ X+ if (Draw_Vectors) X+ ourRenderVectors(); X+ X+ if (Draw_Axis) X+ ourRenderAxis(); X+ X+ // We don't want any of the particles to obscure any others, but X+ // we DO want the black hole to block any particles behind it. X+ // Note that GL_DEPTH_TEST is still enabled. X+ glDepthMask(GL_FALSE); X+ X+ // Enable the dot texture. "Oh no! Not THE DOT!" X+ if (Texture_On) X+ glEnable(GL_TEXTURE_2D); X+ X+ // Iterate through the array of particles, drawing all that are X+ // active. For those that aren't active, 0.03% of the time, we X+ // introduce them into the system. X+ X+ for(i=0; iRunning) { X+ if (Move_Enable && ourRand(1) > 0.9997) X+ ourFireParticleGun(p); X+ } else { X+ // Set the part's color. X+ glColor4f(p->Color[0],p->Color[1],p->Color[2], X+ Parts_Brightness); X+ X+ // Draw two intersecting quads, along XY and ZY axis. X+ glBegin(GL_QUADS); X+ X+ glTexCoord2f(0.0,0.0); X+ glVertex3f(p->Pos[0]-.00,p->Pos[1]-.10,p->Pos[2]-.10); X+ glTexCoord2f(1.0,0.0); X+ glVertex3f(p->Pos[0]-.00,p->Pos[1]+.10,p->Pos[2]-.10); X+ glTexCoord2f(1.0,1.0); X+ glVertex3f(p->Pos[0]-.00,p->Pos[1]+.10,p->Pos[2]+.10); X+ glTexCoord2f(0.0,1.0); X+ glVertex3f(p->Pos[0]-.00,p->Pos[1]-.10,p->Pos[2]+.10); X+ X+ glTexCoord2f(0.0,0.0); X+ glVertex3f(p->Pos[0]-.10,p->Pos[1]-.10,p->Pos[2]-.00); X+ glTexCoord2f(1.0,0.0); X+ glVertex3f(p->Pos[0]-.10,p->Pos[1]+.10,p->Pos[2]-.00); X+ glTexCoord2f(1.0,1.0); X+ glVertex3f(p->Pos[0]+.10,p->Pos[1]+.10,p->Pos[2]+.00); X+ glTexCoord2f(0.0,1.0); X+ glVertex3f(p->Pos[0]+.10,p->Pos[1]-.10,p->Pos[2]+.00); X+ X+ glEnd(); X+ X+ if (Move_Enable) X+ ourMoveParticle(p); X+ } X+ } X+ X+ X+ if (Heads_Up) X+ ourRenderHeadsUp(); X+ X+ // All done drawing. Let's show it. X+ glutSwapBuffers(); X+ X+ // This handles our single-step function. X+ if (Move_Step) X+ Move_Step = Move_Enable = 0; X+ X+ // Collect the FPS statistics. X+ ourDoFPS(); X+} X+ X+ X+// ------ X+// Callback function called when a normal key is pressed. X+ X+void cbKeyPressed( X+ unsigned char key, X+ int x, int y X+) X+{ X+ int t; X+ X+ switch (key) { X+ case 27: X+ case 'q': case 'Q': X+ exit(0); X+ break; X+ X+ // Toggle drawing. X+ case 'a': case 'A': X+ Draw_Axis = !Draw_Axis; X+ break; X+ case 'v': case 'V': X+ Draw_Vectors = !Draw_Vectors; X+ break; X+ case 's': case 'S': X+ Draw_Stars = !Draw_Stars; X+ break; X+ X+ // Adjust particle brightness. X+ case 'b': X+ Parts_Brightness+=0.01; X+ break; X+ case 'B': X+ Parts_Brightness-=0.01; X+ break; X+ X+ // Toggle being on-orbit. X+ case 'o': case 'O': X+ On_Orbit = ! On_Orbit; X+ break; X+ X+ // Toggle Texture. X+ case 't': case 'T': X+ Texture_On = !Texture_On; X+ break; X+ X+ // Impart an impulse on the Root particle. X+ case 'x': X+ Parts->Vel[0]+=.0001; X+ break; X+ case 'X': X+ Parts->Vel[0]-=.0001; X+ break; X+ case 'c': case 'y': X+ Parts->Vel[1]+=.0001; X+ break; X+ case 'C': case 'Y': X+ Parts->Vel[1]-=.0001; X+ break; X+ case 'z': X+ Parts->Vel[2]+=.0001; X+ break; X+ case 'Z': X+ Parts->Vel[2]-=.0001; X+ break; X+ X+ case 'r': case 'R': X+ ourFireParticleGun(Parts); X+ X+ // Single-step through motion calculations. X+ case 'm': X+ Move_Step = 1; X+ Move_Enable = 1; X+ break; X+ X+ // Normal motion. X+ case 'M': X+ Move_Enable= !Move_Enable; X+ break; X+ X+ // Heads up display. X+ case 'h': case 'H': X+ Heads_Up = !Heads_Up; X+ break; X+ X+ // Inject one (or all) free particle(s). X+ case 'i': case 'I': X+ for (t=Parts_LastUnused; t 100) { X+ Parts_Num -= 100; X+ ourAllocParticles(Parts_Num); X+ } X+ break; X+ X+ case '+': X+ Parts_Num += 100; X+ ourAllocParticles(Parts_Num); X+ break; X+ X+ default: X+ printf("No action for %d\n", key); X+ X+ } X+} X+ X+ X+// ------ X+// Callback Function called when a special key is pressed. X+ X+static void cbSpecialKeyPressed(int key, int x, int y) X+{ X+ switch (key) { X+ case GLUT_KEY_PAGE_UP: X+ Obs_Dist -= 0.05f; X+ break; X+ X+ case GLUT_KEY_PAGE_DOWN: X+ Obs_Dist += 0.05f; X+ break; X+ X+ case GLUT_KEY_LEFT: X+ Obs_Angle-=2.0; X+ break; X+ X+ case GLUT_KEY_RIGHT: X+ Obs_Angle+=2.0; X+ break; X+ X+ case GLUT_KEY_DOWN: X+ Obs_Height-=0.05; X+ break; X+ X+ case GLUT_KEY_UP: X+ Obs_Height+=0.06; X+ break; X+ } X+ X+ // We don't know anything changed, but it never hurts. X+ ourCalcObs(); X+} X+ X+ X+// ------ X+// Does everything needed before losing control to the main X+// OpenGL event loop X+ X+void ourInit( X+ int Width, X+ int Height X+) X+{ X+ ourBuildTextures(); X+ ourBuildStarfield(500); X+ X+ glEnable(GL_BLEND); X+ glDisable(GL_ALPHA_TEST); X+ X+ // Enable flat shading -- no need for smooth. X+ glShadeModel(GL_FLAT); X+ X+ // Blending mode used for fire, lit gas, etc. X+ glBlendFunc(GL_SRC_ALPHA,GL_ONE); X+ X+ // Calculate the non-on-orbit observer's position. X+ ourCalcObs(); X+ X+ // Load up the correct perspective matrix; using a callback directly. X+ cbResizeScene(Width, Height); X+ X+ if (!(Black_Hole = gluNewQuadric())) X+ exit; X+ X+ // Allocate our first block of particles. X+ ourAllocParticles(Parts_Num); X+ X+ // Fire off the first (Root) Particle. X+ ourFireParticleGun(Parts); X+ X+} X+ X+ X+// ------ X+// The main() function. Inits OpenGL. Calls our own init function, X+// then passes control onto OpenGL. X+ X+int main(int argc,char **argv) X+{ X+ glutInit(&argc,argv); X+ X+ // To see OpenGL drawing, take out the GLUT_DOUBLE request. X+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); X+ glutInitWindowSize(Window_Width,Window_Height); X+ X+ // Open a window X+ X+ if (!(Window_ID=glutCreateWindow( PROGRAM_TITLE ))) { X+ fprintf(stderr,"Error opening a window.\n"); X+ exit(-1); X+ } X+ X+ // Register the callback function to do the drawing. X+ glutDisplayFunc(&cbRenderScene); X+ X+ // If there's nothing to do, draw. X+ glutIdleFunc(&cbRenderScene); X+ X+ // It's a good idea to know when our window's resized. X+ glutReshapeFunc(&cbResizeScene); X+ X+ // And let's get some keyboard input. X+ glutKeyboardFunc(&cbKeyPressed); X+ glutSpecialFunc(&cbSpecialKeyPressed); X+ X+ // OK, OpenGL's ready to go. Let's call our own init function. X+ ourInit(Window_Width, Window_Height); X+ X+ // Print out a bit of help dialog. X+ printf("\n" PROGRAM_TITLE "\n\n\ X+Use arrow keys to rotate around or move along Y axis.\n\ X+Page up/down will move observer towards/away from the Y axis.\n\n\ X+'O' toggles observer onto non-decaying orbit of yellow root particle.\n\ X+'H' toggles heads-up-display of various status variables.\n\n\ X+'x'/'X', 'c'/'C', 'z'/'Z' thrusts root particle along X, Y, Z axis\n\ X+in positive/negative directions, respectively; 'R' resets.\n\n\ X+Numerical Keypad controls Particle Gun parameters. '.' key switches\n\ X+between effecting Gun Velocity Vector and Position.\n\n\ X+'+' and '-' add to or remove particles from the system.\n\n\ X+Use first letter of shown display mode settings to alter.\n\n\ X+Q or [Esc] to quit; OpenGL window must have focus for input.\n"); X+ X+ // Pass off control to OpenGL. X+ // Above functions are called as appropriate. X+ glutMainLoop(); X+ X+ // Free our allocated particle array. X+ ourAllocParticles(0); X+ X+ return 1; X+} X+ END-of-./files/patch-file exit --- sendFile ends here --- >Release-Note: >Audit-Trail: >Unformatted: