From 6cdf88141ebc1ab77ee9bc735a3a9a21834d9537 Mon Sep 17 00:00:00 2001 From: Emanuel Haupt Date: Wed, 4 Oct 2006 10:54:05 +0000 Subject: Add ffff, a fast mandelbrot fractal generator with features such as: * OpenGL * realtime zoom * SSE/AltiVec QuadPixel * SSE2/3DNow! DualPixel calc * FPU per pixel calc * GPU asm (Fragment/Vertex) calc * multiprocessor support * benchmarking * optimized assembler code! This port uses the standard mandelbrot fractal at near-Xaos speed. Yet every pixel is computed. There is also an interesting parameter ray algoritymn using your 3D card. A 3D card is strongly recommended for screen speed and additional coprocessing power. WWW: http://sourceforge.net/projects/ffff/ PR: 103441 Submitted by: rossiya@gmail.com --- graphics/Makefile | 1 + graphics/ffff/Makefile | 49 ++ graphics/ffff/distinfo | 3 + graphics/ffff/files/patch-FFFF3.cpp | 39 ++ graphics/ffff/files/patch-extensions.cpp | 56 ++ graphics/ffff/files/patch-hole.cpp.save | 1125 ++++++++++++++++++++++++++++++ graphics/ffff/pkg-descr | 18 + 7 files changed, 1291 insertions(+) create mode 100644 graphics/ffff/Makefile create mode 100644 graphics/ffff/distinfo create mode 100644 graphics/ffff/files/patch-FFFF3.cpp create mode 100644 graphics/ffff/files/patch-extensions.cpp create mode 100644 graphics/ffff/files/patch-hole.cpp.save create mode 100644 graphics/ffff/pkg-descr (limited to 'graphics') diff --git a/graphics/Makefile b/graphics/Makefile index 1a59f2480ba2..531afe06544f 100644 --- a/graphics/Makefile +++ b/graphics/Makefile @@ -118,6 +118,7 @@ SUBDIR += f-spot SUBDIR += fbm SUBDIR += feh + SUBDIR += ffff SUBDIR += fig2pstricks SUBDIR += fig2sxd SUBDIR += figurine diff --git a/graphics/ffff/Makefile b/graphics/ffff/Makefile new file mode 100644 index 000000000000..e8c256a0623b --- /dev/null +++ b/graphics/ffff/Makefile @@ -0,0 +1,49 @@ +# Ports collection makefile for: ffff +# Date created: Sep 20, 2006 +# Whom: rossiya@gmail.com +# +# $FreeBSD$ +# + +PORTNAME= ffff +PORTVERSION= 323 +CATEGORIES= graphics +MASTER_SITES= ${MASTER_SITE_SOURCEFORGE_EXTENDED} +MASTER_SITE_SUBDIR= ${PORTNAME} +DISTNAME= FFFF${PORTVERSION}-src + +MAINTAINER= rossiya@gmail.com +COMMENT= A fast mandelbrot fractal generator + +LIB_DEPENDS= glut.4:${PORTSDIR}/graphics/libglut + +USE_DOS2UNIX= yes +USE_GCC= 3.2+ +USE_GL= yes +USE_XLIB= yes +USE_ZIP= yes + +SOURCE= FFFF3 FragmentProgram FragmentProgramARB10 GPUProgram \ + PixelBuffer VertexProgram VertexProgramATI VertexProgramNV \ + extensions vpext + +CXXFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/GL ${PTHREAD_CFLAGS} \ + -D__linux__ +LDFLAGS+= -L${X11BASE}/lib ${PTHREAD_LIBS} -lglut -lGL -lXext -lX11 -lXmu \ + -lGLU -lm + +PLIST_FILES= bin/ffff + +# contains x86 assembler +ONLY_FOR_ARCHS= i386 + +do-build: +.for f in ${SOURCE} + ${CXX} ${CXXFLAGS} -c ${WRKSRC}/${f}.cpp -o ${WRKSRC}/${f}.obj +.endfor + ${CXX} ${LDFLAGS} ${SOURCE:C/(.*)/${WRKSRC}\/\1.obj/} -o ${WRKSRC}/${PORTNAME} + +do-install: + ${INSTALL_PROGRAM} ${WRKSRC}/${PORTNAME} ${PREFIX}/bin + +.include diff --git a/graphics/ffff/distinfo b/graphics/ffff/distinfo new file mode 100644 index 000000000000..049ca195be29 --- /dev/null +++ b/graphics/ffff/distinfo @@ -0,0 +1,3 @@ +MD5 (FFFF323-src.zip) = ba5c63ccedfb61f5ceea431286d6d749 +SHA256 (FFFF323-src.zip) = 4781384b4c285fe61f19ba776d4a656fd5e809b9a88198a0705c8f7ca7dca715 +SIZE (FFFF323-src.zip) = 127442 diff --git a/graphics/ffff/files/patch-FFFF3.cpp b/graphics/ffff/files/patch-FFFF3.cpp new file mode 100644 index 000000000000..518a3de7ffe1 --- /dev/null +++ b/graphics/ffff/files/patch-FFFF3.cpp @@ -0,0 +1,39 @@ +--- ./FFFF3.cpp.orig Wed Oct 4 11:21:15 2006 ++++ ./FFFF3.cpp Wed Oct 4 11:21:35 2006 +@@ -24,6 +24,7 @@ + ... and all the others who kindly sent code, fixes, suggestions and feedback ! + *******************************************************************/ + ++int get_nprocs() {return 1;} + + // WARNING: This source is a real mess ! :))) + // WARNING: This is only meant as some "portable" glue for assembly. +@@ -70,7 +71,7 @@ + #include + #include + #include +- #include ++// #include + #else + #include "GL/glut.h" + #include "GL/gl.h" +@@ -381,7 +382,8 @@ + } + #endif + +- avail_SSE = checkSSE(); ++ //avail_SSE = checkSSE(); ++ avail_SSE = 1; + if (avail_SSE) { + #if defined(__APPLE__) && __BIG_ENDIAN__ + // PowerPC +@@ -397,7 +399,8 @@ + printf("Switching to machine code FPU mode.\n"); + } + +- avail_SSE2 = checkSSE2(); ++ //avail_SSE2 = checkSSE2(); ++ avail_SSE2 = 1; + if (avail_SSE2) { + #if defined (sgi) + printf("MIPS dual FPU units supported.\n"); diff --git a/graphics/ffff/files/patch-extensions.cpp b/graphics/ffff/files/patch-extensions.cpp new file mode 100644 index 000000000000..53375fc7b180 --- /dev/null +++ b/graphics/ffff/files/patch-extensions.cpp @@ -0,0 +1,56 @@ +--- ./extensions.cpp.orig Wed Oct 4 11:21:15 2006 ++++ ./extensions.cpp Wed Oct 4 11:21:58 2006 +@@ -1,5 +1,18 @@ + #include + #include ++#include ++#include ++#include ++#include ++#include ++ ++//typedef void (*__GLXextFuncPtr)(void); ++//extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *); ++extern __GLXextFuncPtr glXGetProcAddressARB (GLubyte *); ++//extern void ((*(glXGetProcAddressARB))(const GLubyte *procName))( void ); ++//extern void (*glXGetProcAddressARB( GLubyte *))( void ); ++ ++__GLXextFuncPtr glXGetProcAddressARB(unsigned char*){} + + #ifdef __APPLE__ + #include +@@ -96,18 +109,26 @@ + { + #if defined(__APPLE__) || defined(__linux__) + // GL_ARB_multitexture +- pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glActiveTextureARB"); +- pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glClientActiveTextureARB"); ++// pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glActiveTextureARB"); ++ pfglActiveTextureARB = (glActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glActiveTextureARB"); ++// pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glClientActiveTextureARB"); ++ pfglClientActiveTextureARB = (glClientActiveTextureARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glClientActiveTextureARB"); + if (!pfglActiveTextureARB) return false; + if (!pfglClientActiveTextureARB) return false; + + // GL_ARB_fragment_program +- pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGenProgramsARB"); +- pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glDeleteProgramsARB"); +- pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glBindProgramARB"); +- pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramStringARB"); +- pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramEnvParameter4fARB"); +- pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGetProgramivARB"); ++// pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGenProgramsARB"); ++ pfglGenProgramsARB = (glGenProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glGenProgramsARB"); ++// pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glDeleteProgramsARB"); ++ pfglDeleteProgramsARB = (glDeleteProgramsARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glDeleteProgramsARB"); ++// pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glBindProgramARB"); ++ pfglBindProgramARB = (glBindProgramARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glBindProgramARB"); ++// pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramStringARB"); ++ pfglProgramStringARB = (glProgramStringARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glProgramStringARB"); ++// pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glProgramEnvParameter4fARB"); ++ pfglProgramEnvParameter4fARB = (glProgramEnvParameter4fARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glProgramEnvParameter4fARB"); ++// pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR const*)"glGetProgramivARB"); ++ pfglGetProgramivARB = (glGetProgramivARBProcPtr) GLGETPROCADDRESS((GLCHAR *)"glGetProgramivARB"); + if (!pfglGenProgramsARB) return false; + if (!pfglDeleteProgramsARB) return false; + if (!pfglBindProgramARB) return false; diff --git a/graphics/ffff/files/patch-hole.cpp.save b/graphics/ffff/files/patch-hole.cpp.save new file mode 100644 index 000000000000..461f5d0ad20f --- /dev/null +++ b/graphics/ffff/files/patch-hole.cpp.save @@ -0,0 +1,1125 @@ +--- ./hole.cpp.save.orig Wed Oct 4 11:21:15 2006 ++++ ./hole.cpp.save Wed Oct 4 11:22:13 2006 +@@ -0,0 +1,1122 @@ ++// ---------------------- ++// OpenGL Black Hole Simulator. ++// ++// Written by and Copyright Chris Halsall (chalsall@chalsall.com). ++// First published on the O'Reilly Network on Linux.com ++// (oreilly.linux.com). September 2000. All rights reserved. ++// ++// This code is licensed under the GNU GPL Version 2.0. ++// See (URL: http://www.gnu.org/copyleft/gpl.html ) for details. ++// ++// Coded to the groovy tunes of Fluke: Risotto. ++// ++// Dedicated to Stephen W. Hawking, one of the greatest explorers ++// of our time. ++ ++#define PROGRAM_TITLE "O'Reilly Net: Black Hole -- C.Halsall" ++ ++ ++#include // Always a good idea. ++#include // For RAND_MAX. ++#include // For our FPS stats. ++#include // For M_PI ++#include // OpenGL itself. ++#include // GLU support library. ++#include // GLUT support library. ++ ++ ++// A quick macro to populate a 1x3 vector array. ++#define ourVectInit(a,x,y,z) { (a)[0]=x; (a)[1]=y; (a)[2]=z; } ++ ++// Structure to hold all the data for each particle. ++typedef struct { ++ int Running; ++ float Pos[3]; // Position. ++ float Vel[3]; // Velocity. ++ float Grav[3]; // Acceleration. ++ float Color[3]; ++} Particle; ++ ++ ++// ------ ++// Some global variables. ++ ++// Window and Texture IDs, Window sizes. ++int Texture_ID; ++int Window_ID; ++int Window_Width=640; ++int Window_Height=480; ++ ++// We'll request a sphere from the GLU library at run-time. ++struct GLUquadric *Black_Hole; ++ ++// "Name" for first (and only) OpenGL display list. ++#define STAR_FIELD 1 ++ ++ ++// Pointer for allocated array of Particles. ++Particle *Parts; ++ ++// Particle status variables. ++int Parts_Running=0; ++int Parts_Allocated=0; ++int Parts_LastUnused=1; ++ ++// Number of parts initially in the system. Make sure there's at least ++// one over a hundred (101, 801), so our Root particle doesn't get deleted. ++int Parts_Num = 801; ++ ++float Parts_Brightness = 0.15; ++ ++ ++// Drawing flags. ++int Draw_Axis = 0; ++int Draw_Vectors = 0; ++int Draw_Stars = 1; ++int Heads_Up = 0; ++int Texture_On = 1; ++ ++ ++// Particle Gun variables. ++float Gun_PX = 0; ++float Gun_PY = 0; ++float Gun_PZ = 4; ++ ++float Gun_VX =-0.135; ++float Gun_VY = 0.0125; ++float Gun_VZ = 0.0; ++float Gun_R = 0.005; ++float Gun_OffR = 0.050; ++ ++// Backwards firing and off-target probabilities. ++float Gun_Back = 0.9, Gun_Off = 0.9; ++ ++// '.' key toggels between keypad adjusting gun position and eject vect. ++int Gun_Control = 1; ++ ++ ++// Orbit and motion settings. ++int On_Orbit=1; ++int Move_Enable=1; ++int Move_Step=0; ++ ++// Observer initial placement. ++float Obs_Angle=114.0; ++float Obs_Height=.2; ++float Obs_Dist=4.6; ++ ++// Calculated observer location. ++float Obs[3]; ++ ++// How quickly do the orbits decay? ++// Lower number (limit 1) is faster decay. ++ ++int Decay_Factor = 6000; ++ ++// The force of gravity exterted by the black hole. ++float Grav = 0.075; ++ ++// Somewhat arbitrary values for Event and Escape horizons. ++ ++#define EVENT_HORIZON_GRAV .5 ++ ++#define ESCAPE_HORIZON 30 ++#define ESCAPE_HORIZON_SQR (ESCAPE_HORIZON * ESCAPE_HORIZON) ++ ++ ++// ------ ++// Frames per second (FPS) statistic variables and routine. ++ ++#define FRAME_RATE_SAMPLES 50 ++int FrameCount=0; ++float FrameRate=0; ++ ++static void ourDoFPS( ++ void ++) ++{ ++ static clock_t last=0; ++ clock_t now; ++ float delta; ++ ++ if (++FrameCount >= FRAME_RATE_SAMPLES) { ++ now = clock(); ++ delta= (now - last) / (float) CLOCKS_PER_SEC; ++ last = now; ++ ++ FrameRate = FRAME_RATE_SAMPLES / delta; ++ FrameCount = 0; ++ } ++} ++ ++ ++// ------ ++// String rendering routine; leverages on GLUT routine. ++ ++static void ourPrintString( ++ void *font, ++ char *str ++) ++{ ++ int i,l=strlen(str); ++ ++ for(i=0;i Num) ++ Parts_LastUnused = Num; ++ ++ Parts_Running = 0; ++ for (i = 0; i < Num; i++) ++ if (P[i].Running) ++ Parts_Running++; ++ ++ Parts_Allocated = Num; ++ Parts = P; ++ ++ return P; ++} ++ ++ ++// ------ ++// Function to return a random floating number between 0 and the passed ++// parameter. ++ ++float ourRand( ++ float Max ++) ++{ ++ return( (Max * rand()) / RAND_MAX ); ++} ++ ++ ++// ------ ++// Builds a Display List containing a random star field. ++// ++// Note: this could also be done by calculating the star points in this ++// routine, which would be faster than having OpenGL perform two ++// rotations (matrix multiplications) for each star. However, this ++// technique is simpler and faster for the programmer, and demonstrates ++// how successive transformations can be a powerful tool. ++ ++void ourBuildStarfield( ++ int Stars ++) ++{ ++ int Cnt; ++ ++ glNewList(STAR_FIELD, GL_COMPILE); ++ ++ glMatrixMode(GL_MODELVIEW); ++ glPushMatrix(); ++ ++ for ( Cnt = 0; Cnt < Stars; Cnt++) { ++ ++ // Vary the color for each star. ++ glColor4f( ++ 0.8 + ourRand(0.2), ++ 0.8 + ourRand(0.2), ++ 0.8 + ourRand(0.2), ++ .95); ++ ++ // Vary the size. Ensure integer sizes to avoid alias shimmering. ++ glPointSize(ourRand(2) > 1 ? 1.0 : 2.0); ++ ++ // Spin your Universe, round and round.... ++ glRotatef(ourRand(100),0.0f,1.0f,0.0f); ++ glRotatef(ourRand(100),1.0f,0.0f,0.0f); ++ ++ glBegin(GL_POINTS); ++ glVertex3f(15.0, 0.0f, 0.0f); ++ glEnd(); ++ } ++ ++ glPopMatrix(); ++ glEndList(); ++} ++ ++ ++// ------ ++// Function builds a simple alpha channel texture of a dot, ++// and then creates mipmaps. This could instead load textures from ++// graphics files from disk, or render textures based on external ++// input. ++ ++void ourBuildTextures( ++ void ++) ++{ ++ GLenum gluerr; ++ GLubyte tex[128][128]; ++ int x,y,t; ++ int hole_size = 3300; // ~ == 57.45 ^ 2. ++ ++ // Generate a texture index, then bind it for future operations. ++ glGenTextures(1,&Texture_ID); ++ glBindTexture(GL_TEXTURE_2D,Texture_ID); ++ ++ // Iterate across the texture array. ++ ++ for(y=0;y<128;y++) { ++ for(x=0;x<128;x++) { ++ ++ // Make a round dot in the texture's alpha-channel. ++ ++ // Calculate distance to center (squared). ++ t = (x-64)*(x-64) + (y-64)*(y-64) ; ++ ++ if ( t < hole_size) // Don't take square root; compare squared. ++ tex[x][y]= 240 - (240 * t) / hole_size + ourRand(15); ++ else ++ tex[x][y]=0; // Outside of the dot, it's transparent. ++ ++ } ++ } ++ ++ // The GLU library helps us build MipMaps for our texture. ++ ++ if ((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 1, 128, 128, GL_ALPHA, ++ GL_UNSIGNED_BYTE, (void *)tex))) { ++ ++ fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr)); ++ exit(-1); ++ } ++ ++ // Some pretty standard settings for wrapping and filtering. ++ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); ++ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); ++ ++ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); ++ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); ++ ++ // We start with GL_MODULATE mode. ++ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); ++} ++ ++ ++// ------ ++// Callback routine executed whenever our window is resized. Lets us ++// request the newly appropriate perspective projection matrix for ++// our needs. Try removing the gluPerspective() call to see what happens. ++ ++void cbResizeScene( ++ int Width, ++ int Height ++) ++{ ++ // Let's not core dump, no matter what. ++ if (Height == 0) ++ Height = 1; ++ ++ glViewport(0, 0, Width, Height); ++ ++ glMatrixMode(GL_PROJECTION); ++ glLoadIdentity(); ++ gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.05f,100.0f); ++ ++ glMatrixMode(GL_MODELVIEW); ++ ++ Window_Width = Width; ++ Window_Height = Height; ++} ++ ++ ++// ------ ++// Fires the Particle Gun, or, sets up the passed Particle to be ++// placed at the Particle Gun location, and fired in a direction ++// specified in Gun_Va, with 'a' being "X", "Y", or "Z". ++// ++// The particles are normally fired with a randomness of Gun_R. ++// Occationally (by default 10%) a larger randomness of Gun_OffR is ++// added. Also, 10% of the time, the particles are fired backwards. ++// This is used to introduce a bit of non-uniformity. Gun_R and ++// Gun_OffR can be controled with the '3' and '6', and '/' and '*' ++// keys, respectively. If set to zero, effects are removed. ++ ++static void ourFireParticleGun( ++ Particle *p ++) ++{ ++ float r; ++ int c; ++ int Dir = 1; ++ ++ if (!p->Running) { ++ p->Running=1; ++ Parts_Running++; ++ } ++ ++ if (p == Parts) { // Root part. ++ ourVectInit(p->Color,1,1,0); // Bright Yellow ++ ourVectInit(p->Pos,5.0,0,0); // Location ++ ourVectInit(p->Vel,0,Gun_VY,-Gun_VX*0.95); // Velocity ++ return; ++ } ++ ++ // Regular particle. ++ ++ ourVectInit(p->Pos,Gun_PX,Gun_PY,Gun_PZ); ++ r = Gun_R; ++ ++// This creates a few a very unpredicatable trajectories. It actually ++// works out to be much less than a full 10 percent, as many are eatten ++// or escape within a very short period of time. Only a few enter a ++// stable orbit. ++ ++ if (ourRand(1) > Gun_Off) r += Gun_OffR; ++ ++ if (ourRand(1) > Gun_Back) Dir = -1; ++ ++ ourVectInit(p->Vel, ++ (Gun_VX + r-ourRand(2*r)) * Dir, ++ (Gun_VY + r-ourRand(2*r)) * Dir, ++ (Gun_VZ + r-ourRand(2*r)) * Dir); ++ ++ c = (int)(ourRand(5) + 1.5); // Range of 1 to 6. ++ ++ // The last set of numbers bias the colors to blue. Red is nice too. ++ ++ ourVectInit(p->Color, ++ (c & 0x01 ? 0.9 : 1.0) * 0.7, ++ (c & 0x02 ? 0.9 : 1.0) * 0.7, ++ (c & 0x04 ? 0.9 : 1.0) * 1.0 ++ ); ++} ++ ++ ++// ------ ++// Calculates the next position based on the current velocity vector, ++// then calculates the new velocity vector based on the particle's ++// proximity to the black hole. ++// ++// We do the motion calculation before updating the velocity vector ++// (and calculating the acceleration-because-of-gravity vector) so ++// that our Vector Display option will be correct. If we didn't do ++// this, the gravity vector would not point towards (0,0,0) when ++// we drew it, outside of this function. ++ ++static void ourMoveParticle( ++ Particle *p ++) ++{ ++ float dp2, dsx, dsy, dsz, G, d; ++ ++ // Used to randomly kill and re-create particles. ++ if (p != Parts) ++ if (ourRand(1) > 0.9998) { ++ ourFireParticleGun(p); ++ return; ++ } ++ ++ // We're actually going to move this particle... ++ ++ // We first move it based on the LAST iteration's ++ // calculation of the Velocity... ++ p->Pos[0] += p->Vel[0]; ++ p->Pos[1] += p->Vel[1]; ++ p->Pos[2] += p->Vel[2]; ++ ++ // ...and then proceed to calculate the force of gravity at the new ++ // position, and update our velocity vector. ++ ++ dsx = p->Pos[0] * p->Pos[0]; ++ dsy = p->Pos[1] * p->Pos[1]; ++ dsz = p->Pos[2] * p->Pos[2]; ++ ++ // Calculate the square of the distance. ++ dp2 = dsx + dsy + dsz; ++ ++ if (dp2) { ++ // May wish to scale dp2 (change 1.0); effects gravity gradiant. ++ G = Grav / (dp2 * 1.0); ++ d = sqrt(dp2); ++ } ++ ++ // If the force of gravity is too strong, our algorithim breaks ++ // down and conservation of energy isn't maintained. We consider ++ // this the event horizon, and recycle the particle. ++ if (G > EVENT_HORIZON_GRAV) { ++ ourFireParticleGun(p); ++ return; ++ } ++ ++ if (dp2 > ESCAPE_HORIZON_SQR) { ++ // Particle escaped; lucky it. ++ ourFireParticleGun(p); ++ return; ++ } ++ ++ // OK, this particle is staying in the system. Calculate the ++ // vectors.... ++ ++ // We store the components of the force of gravity for ++ // our Vectors display. Note the negative magnitude; the vector ++ // must point _from_ our particle _towards_ (0,0,0). ++ p->Grav[0] = - G * p->Pos[0] / d; ++ p->Grav[1] = - G * p->Pos[1] / d; ++ p->Grav[2] = - G * p->Pos[2] / d; ++ ++ // Simply add the gravity vector to the current velocity vector. ++ p->Vel[0] += p->Grav[0]; ++ p->Vel[1] += p->Grav[1]; ++ p->Vel[2] += p->Grav[2]; ++ ++ if (p != Parts) { ++ // This handles orbit decay; not correctly, but well enough. ++ // (Decay should be a ratio to the vector length, applied to each ++ // vector component here, rather than each component being effected ++ // based on its individual size. The effect is to circlurize the ++ // orbit, which we want anyway.) ++ ++ p->Vel[0] -= p->Vel[0] / Decay_Factor; ++ p->Vel[1] -= p->Vel[1] / Decay_Factor; ++ p->Vel[2] -= p->Vel[2] / Decay_Factor; ++ } ++} ++ ++ ++// ------ ++// Angle to Radian conversion. ++ ++float ourA2R( ++ float Angle ++) ++{ ++ return Angle * M_PI/180; ++} ++ ++ ++// ------ ++// Calculates the observer's XYZ position from their Distance from ++// the origin, the angle and the height. ++ ++static void ourCalcObs(void) ++{ ++ Obs[0]=Obs_Dist * sin(ourA2R(Obs_Angle)); ++ Obs[1]=Obs_Height; ++ Obs[2]=Obs_Dist * cos(ourA2R(Obs_Angle)); ++} ++ ++ ++// ------ ++// Draws the X, Y, and Z axis lines. ++ ++void ourRenderAxis( ++ void ++) ++{ ++ glBegin(GL_LINES); ++ ++ glColor4f(0.5,0.5,0.0,1.0); // Mid-level yellow. ++ ++ // Three primary axis lines. ++ glVertex3f(100,0,0); ++ glVertex3f(-100,0,0); ++ glVertex3f(0,100,0); ++ glVertex3f(0,-100,0); ++ glVertex3f(0,0,100); ++ glVertex3f(0,0,-100); ++ ++ glColor4f(0.25,0.25,0.0,1.0); // Low-level yellow. ++ ++ // Two pairs of secondary lines for X and Z axis. ++ glVertex3f(100,1,0); ++ glVertex3f(-100,1,0); ++ glVertex3f(100,-1,0); ++ glVertex3f(-100,-1,0); ++ ++ glVertex3f(0,1,100); ++ glVertex3f(0,1,-100); ++ glVertex3f(0,-1,100); ++ glVertex3f(0,-1,-100); ++ ++ glColor4f(0.0,0.5,0.0,1.0); // Mid-level green. ++ ++ // Lable the X axis. ++ glVertex3f(1.0,0.9,0); ++ glVertex3f(1.1,0.8,0); ++ glVertex3f(1.1,0.9,0); ++ glVertex3f(1.0,0.8,0); ++ ++ // And the Z. ++ glVertex3f(0,0.9,1.0); ++ glVertex3f(0,0.9,1.1); ++ glVertex3f(0,0.9,1.1); ++ glVertex3f(0,0.8,1.0); ++ glVertex3f(0,0.8,1.0); ++ glVertex3f(0,0.8,1.1); ++ ++ glEnd(); ++} ++ ++ ++// ------ ++// Draws the Gravity and Velocity Vectors for each active particle. ++ ++void ourRenderVectors( ++ void ++) ++{ ++ int i; ++ ++ glBegin(GL_LINES); ++ ++ for (i=0; iPos[0], Parts->Pos[1],Parts->Pos[2]); ++ glRasterPos2i(6,-16); ++ ourPrintString(GLUT_BITMAP_HELVETICA_12,buf); ++ ++ // And the Root Particle's velocity. ++ sprintf(buf,"RootV: ( %-.4f, %-.4f, %-.4f)", ++ Parts->Vel[0], Parts->Vel[1],Parts->Vel[2]); ++ glRasterPos2i(6,-32); ++ ourPrintString(GLUT_BITMAP_HELVETICA_12,buf); ++ ++ // Done with this special projection matrix. Throw it away. ++ glPopMatrix(); ++} ++ ++ ++// ------ ++// Routine which actually does the drawing ++ ++static void cbRenderScene(void) ++{ ++ Particle *p; ++ int i; ++ ++ // For the first few objects, we want full depth-buffer testing. ++ glEnable(GL_DEPTH_TEST); ++ glDepthMask(GL_TRUE); ++ ++ // Clear the screen. ++ glClearColor(0.00,0.00,0.00,1.0); ++ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); ++ ++ // Ensure we're working with the model matrix. ++ glMatrixMode(GL_MODELVIEW); ++ ++ // Reset to 0,0,0; no rotation, no scaling. ++ glLoadIdentity(); ++ ++ // Are we on-orbit, or wandering around? ++ if (On_Orbit) { ++ gluLookAt(Parts->Pos[0],Parts->Pos[1],Parts->Pos[2], ++ 0.0,0.0,0.0, ++ 0.0,1.0,0.0); ++ } else { ++ gluLookAt(Obs[0],Obs[1],Obs[2], ++ 0.0,0.0,0.0, ++ 0.0,1.0,0.0); ++ } ++ ++ // No texturing. ++ glDisable(GL_TEXTURE_2D); ++ ++ // Black holes are BLACK! ++ glColor4f(0.0,0.0,0,1.0); ++ gluSphere(Black_Hole,0.02,8,8); ++ ++ if (Draw_Stars) ++ glCallList(STAR_FIELD); ++ ++ if (Draw_Vectors) ++ ourRenderVectors(); ++ ++ if (Draw_Axis) ++ ourRenderAxis(); ++ ++ // We don't want any of the particles to obscure any others, but ++ // we DO want the black hole to block any particles behind it. ++ // Note that GL_DEPTH_TEST is still enabled. ++ glDepthMask(GL_FALSE); ++ ++ // Enable the dot texture. "Oh no! Not THE DOT!" ++ if (Texture_On) ++ glEnable(GL_TEXTURE_2D); ++ ++ // Iterate through the array of particles, drawing all that are ++ // active. For those that aren't active, 0.03% of the time, we ++ // introduce them into the system. ++ ++ for(i=0; iRunning) { ++ if (Move_Enable && ourRand(1) > 0.9997) ++ ourFireParticleGun(p); ++ } else { ++ // Set the part's color. ++ glColor4f(p->Color[0],p->Color[1],p->Color[2], ++ Parts_Brightness); ++ ++ // Draw two intersecting quads, along XY and ZY axis. ++ glBegin(GL_QUADS); ++ ++ glTexCoord2f(0.0,0.0); ++ glVertex3f(p->Pos[0]-.00,p->Pos[1]-.10,p->Pos[2]-.10); ++ glTexCoord2f(1.0,0.0); ++ glVertex3f(p->Pos[0]-.00,p->Pos[1]+.10,p->Pos[2]-.10); ++ glTexCoord2f(1.0,1.0); ++ glVertex3f(p->Pos[0]-.00,p->Pos[1]+.10,p->Pos[2]+.10); ++ glTexCoord2f(0.0,1.0); ++ glVertex3f(p->Pos[0]-.00,p->Pos[1]-.10,p->Pos[2]+.10); ++ ++ glTexCoord2f(0.0,0.0); ++ glVertex3f(p->Pos[0]-.10,p->Pos[1]-.10,p->Pos[2]-.00); ++ glTexCoord2f(1.0,0.0); ++ glVertex3f(p->Pos[0]-.10,p->Pos[1]+.10,p->Pos[2]-.00); ++ glTexCoord2f(1.0,1.0); ++ glVertex3f(p->Pos[0]+.10,p->Pos[1]+.10,p->Pos[2]+.00); ++ glTexCoord2f(0.0,1.0); ++ glVertex3f(p->Pos[0]+.10,p->Pos[1]-.10,p->Pos[2]+.00); ++ ++ glEnd(); ++ ++ if (Move_Enable) ++ ourMoveParticle(p); ++ } ++ } ++ ++ ++ if (Heads_Up) ++ ourRenderHeadsUp(); ++ ++ // All done drawing. Let's show it. ++ glutSwapBuffers(); ++ ++ // This handles our single-step function. ++ if (Move_Step) ++ Move_Step = Move_Enable = 0; ++ ++ // Collect the FPS statistics. ++ ourDoFPS(); ++} ++ ++ ++// ------ ++// Callback function called when a normal key is pressed. ++ ++void cbKeyPressed( ++ unsigned char key, ++ int x, int y ++) ++{ ++ int t; ++ ++ switch (key) { ++ case 27: ++ case 'q': case 'Q': ++ exit(0); ++ break; ++ ++ // Toggle drawing. ++ case 'a': case 'A': ++ Draw_Axis = !Draw_Axis; ++ break; ++ case 'v': case 'V': ++ Draw_Vectors = !Draw_Vectors; ++ break; ++ case 's': case 'S': ++ Draw_Stars = !Draw_Stars; ++ break; ++ ++ // Adjust particle brightness. ++ case 'b': ++ Parts_Brightness+=0.01; ++ break; ++ case 'B': ++ Parts_Brightness-=0.01; ++ break; ++ ++ // Toggle being on-orbit. ++ case 'o': case 'O': ++ On_Orbit = ! On_Orbit; ++ break; ++ ++ // Toggle Texture. ++ case 't': case 'T': ++ Texture_On = !Texture_On; ++ break; ++ ++ // Impart an impulse on the Root particle. ++ case 'x': ++ Parts->Vel[0]+=.0001; ++ break; ++ case 'X': ++ Parts->Vel[0]-=.0001; ++ break; ++ case 'c': case 'y': ++ Parts->Vel[1]+=.0001; ++ break; ++ case 'C': case 'Y': ++ Parts->Vel[1]-=.0001; ++ break; ++ case 'z': ++ Parts->Vel[2]+=.0001; ++ break; ++ case 'Z': ++ Parts->Vel[2]-=.0001; ++ break; ++ ++ case 'r': case 'R': ++ ourFireParticleGun(Parts); ++ ++ // Single-step through motion calculations. ++ case 'm': ++ Move_Step = 1; ++ Move_Enable = 1; ++ break; ++ ++ // Normal motion. ++ case 'M': ++ Move_Enable= !Move_Enable; ++ break; ++ ++ // Heads up display. ++ case 'h': case 'H': ++ Heads_Up = !Heads_Up; ++ break; ++ ++ // Inject one (or all) free particle(s). ++ case 'i': case 'I': ++ for (t=Parts_LastUnused; t 100) { ++ Parts_Num -= 100; ++ ourAllocParticles(Parts_Num); ++ } ++ break; ++ ++ case '+': ++ Parts_Num += 100; ++ ourAllocParticles(Parts_Num); ++ break; ++ ++ default: ++ printf("No action for %d\n", key); ++ ++ } ++} ++ ++ ++// ------ ++// Callback Function called when a special key is pressed. ++ ++static void cbSpecialKeyPressed(int key, int x, int y) ++{ ++ switch (key) { ++ case GLUT_KEY_PAGE_UP: ++ Obs_Dist -= 0.05f; ++ break; ++ ++ case GLUT_KEY_PAGE_DOWN: ++ Obs_Dist += 0.05f; ++ break; ++ ++ case GLUT_KEY_LEFT: ++ Obs_Angle-=2.0; ++ break; ++ ++ case GLUT_KEY_RIGHT: ++ Obs_Angle+=2.0; ++ break; ++ ++ case GLUT_KEY_DOWN: ++ Obs_Height-=0.05; ++ break; ++ ++ case GLUT_KEY_UP: ++ Obs_Height+=0.06; ++ break; ++ } ++ ++ // We don't know anything changed, but it never hurts. ++ ourCalcObs(); ++} ++ ++ ++// ------ ++// Does everything needed before losing control to the main ++// OpenGL event loop ++ ++void ourInit( ++ int Width, ++ int Height ++) ++{ ++ ourBuildTextures(); ++ ourBuildStarfield(500); ++ ++ glEnable(GL_BLEND); ++ glDisable(GL_ALPHA_TEST); ++ ++ // Enable flat shading -- no need for smooth. ++ glShadeModel(GL_FLAT); ++ ++ // Blending mode used for fire, lit gas, etc. ++ glBlendFunc(GL_SRC_ALPHA,GL_ONE); ++ ++ // Calculate the non-on-orbit observer's position. ++ ourCalcObs(); ++ ++ // Load up the correct perspective matrix; using a callback directly. ++ cbResizeScene(Width, Height); ++ ++ if (!(Black_Hole = gluNewQuadric())) ++ exit; ++ ++ // Allocate our first block of particles. ++ ourAllocParticles(Parts_Num); ++ ++ // Fire off the first (Root) Particle. ++ ourFireParticleGun(Parts); ++ ++} ++ ++ ++// ------ ++// The main() function. Inits OpenGL. Calls our own init function, ++// then passes control onto OpenGL. ++ ++int main(int argc,char **argv) ++{ ++ glutInit(&argc,argv); ++ ++ // To see OpenGL drawing, take out the GLUT_DOUBLE request. ++ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); ++ glutInitWindowSize(Window_Width,Window_Height); ++ ++ // Open a window ++ ++ if (!(Window_ID=glutCreateWindow( PROGRAM_TITLE ))) { ++ fprintf(stderr,"Error opening a window.\n"); ++ exit(-1); ++ } ++ ++ // Register the callback function to do the drawing. ++ glutDisplayFunc(&cbRenderScene); ++ ++ // If there's nothing to do, draw. ++ glutIdleFunc(&cbRenderScene); ++ ++ // It's a good idea to know when our window's resized. ++ glutReshapeFunc(&cbResizeScene); ++ ++ // And let's get some keyboard input. ++ glutKeyboardFunc(&cbKeyPressed); ++ glutSpecialFunc(&cbSpecialKeyPressed); ++ ++ // OK, OpenGL's ready to go. Let's call our own init function. ++ ourInit(Window_Width, Window_Height); ++ ++ // Print out a bit of help dialog. ++ printf("\n" PROGRAM_TITLE "\n\n\ ++Use arrow keys to rotate around or move along Y axis.\n\ ++Page up/down will move observer towards/away from the Y axis.\n\n\ ++'O' toggles observer onto non-decaying orbit of yellow root particle.\n\ ++'H' toggles heads-up-display of various status variables.\n\n\ ++'x'/'X', 'c'/'C', 'z'/'Z' thrusts root particle along X, Y, Z axis\n\ ++in positive/negative directions, respectively; 'R' resets.\n\n\ ++Numerical Keypad controls Particle Gun parameters. '.' key switches\n\ ++between effecting Gun Velocity Vector and Position.\n\n\ ++'+' and '-' add to or remove particles from the system.\n\n\ ++Use first letter of shown display mode settings to alter.\n\n\ ++Q or [Esc] to quit; OpenGL window must have focus for input.\n"); ++ ++ // Pass off control to OpenGL. ++ // Above functions are called as appropriate. ++ glutMainLoop(); ++ ++ // Free our allocated particle array. ++ ourAllocParticles(0); ++ ++ return 1; ++} ++ diff --git a/graphics/ffff/pkg-descr b/graphics/ffff/pkg-descr new file mode 100644 index 000000000000..710a63c73264 --- /dev/null +++ b/graphics/ffff/pkg-descr @@ -0,0 +1,18 @@ +FFFF is a fast mandelbrot fractal generator with features such as: + + * OpenGL + * realtime zoom + * SSE/AltiVec QuadPixel + * SSE2/3DNow! DualPixel calc + * FPU per pixel calc + * GPU asm (Fragment/Vertex) calc + * multiprocessor support + * benchmarking + * optimized assembler code! + +This port uses the standard mandelbrot fractal at near-Xaos speed. Yet every +pixel is computed. There is also an interesting parameter ray algoritymn using +your 3D card. A 3D card is strongly recommended for screen speed and additional +coprocessing power. + +WWW: http://sourceforge.net/projects/ffff/ -- cgit v1.2.3