Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

ATTRACTEURS DE FAMILLES DE CONTRACTIONS EN ÉCRAN DE VEILLE


Information sur la source

Catégorie :Graphique Classé sous : OpenGl, GLUT, Fractales, IFS, AFC Niveau : Débutant Date de création : 07/01/2008 Date de mise à jour : 13/01/2008 14:55:27 Vu / téléchargé: 3 051 / 115

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (16)
Ajouter un commentaire et/ou une note

Description

Cliquez pour voir la capture en taille normale
Bonjour à tous,

c'est mon tout premier programme en C posté ici, donc un peu d'indulgence      ;-)

Il s'agit d'un programme de démonstration OpenGl/GLUT qui affiche une famille d'IFS (Iterated Function System) d'une manière que l'auteur (moi!) espère harmonieuse. Ce sont des ensembles fractaux, colorés et animés dans le temps.

Le programme essaie d'adapter la qualité (complexité) de l'image aux performances de la machine, ainsi que la densité de l'image pour qu'elle reste à peu près uniforme. Au démarrage l'image est peu détaillée, elle va progressivement le devenir au fur et à mesure que le programme détecte que les performances de la machine sont suffisantes pour suivre (en général au bout d'une quinzaine de secondes).

Il ne faut pas demander plus de frames par secondes que la fréquence de l'écran en mode DoubleBuffered (sinon le programme va croire que la machine rame et diminuer la qualité).

Le source a été pensé pour pouvoir aussi être compilé en tant qu'écran de veille (uniquement sous Windows): il suffit de définir
#define SCREENSAVER
pour que ça le compile en écran de veille (il faudra aussi changer l'extension du fichier compilé en .scr, et faire un clic droit dessus pour l'installer sous Windows).

En mode normal (pas SCREENSAVER) ou en mode configuration de l'écran de veille il faut appuyer sur ESCAPE pour afficher/cacher le menu. Les paramètres peuvent être enregistrés dans un fichier ini du même nom que le programme, et automatiquement chargés au démarrage (si le fichier existe).

Il y a encore deux options de compilation supplémentaire: USE_TEXTURE et USE_MULTIPLE_TEXTURES, la seconde nécessite la première. Avec USE_TEXTURE il est possibe de faire un motion blur plus "smooth" utilisant une texture. La seconde nécessite OpenGl 1.1 au moins, et utilise 2 textures pour le motion blur et le blending par couches, afin de permettre un filtrage des couleurs plus riche. À réserver aux cartes graphiques récentes...

Noter que pour pouvoir compiler il faut que vous ayez installé GLUT. Par exemple comme expliqué ici sous dev-cpp: http://people.bath.ac.uk/ab8lam/computing/DevCpp.htm.
Ou encore pour d'autres compilateurs:
http://www.math.u-psud.fr/~feuvrier/enseignement/2007/M2/site005.html
En théorie le source compile tant sous Windows que sous Linux (à condition de mettre les bonnes lib, comme indiqué dans les liens).

J'ai mis le .exe (renommé en .ex_) et le .scr (l'écran de veille compilé) dans le zip au cas où...

Si vous avez des commentaires, n'hésitez pas!
 

Source

  • #define USE_COS_TABLE
  • #define USE_TEXTURE
  • #define USE_MULTIPLE_TEXTURES
  • //#define SCREENSAVER
  • #include <stdlib.h>
  • #include <stdio.h>
  • #include <math.h>
  • #include <time.h>
  • #include "glut_import.h"
  • #include "menu.h"
  • /*********************************************************************
  • * CONSTANTS *
  • *********************************************************************/
  • #define FPS_COUNTER_TRIGGER 15
  • #define FPS_COUNTER_SMOOTH 0.3
  • #define PROXY_SIZE 32
  • #define PROXY_QUALITY 5
  • #define MIN_COLOR (10./256.)
  • #define MIN_POINT_COUNT 300
  • #define INI_FILENAME "AFC.ini"
  • #ifdef USE_MULTIPLE_TEXTURES
  • # ifndef USE_TEXTURE
  • # error You cannot specify USE_MULTIPLE_TEXTURES without specifying USE_TEXTURE
  • # endif
  • # define INVALID_TEXTURE_INDEX 0xFFFFFFFF
  • #endif
  • /*********************************************************************
  • * PLATFORM *
  • *********************************************************************/
  • #ifdef __WIN32__
  • # ifdef SCREENSAVER
  • # define SCREENSAVER_MODE_SHOW 0x1
  • # define SCREENSAVER_MODE_CONFIGURE 0x2
  • # define SCREENSAVER_MODE_PREVIEW 0x4
  • # define MAX_SCREENSAVER_MOUSE_OFFSET 10
  • # endif
  • # include <windows.h>
  • # define SLEEP(_DELAY) Sleep(_DELAY)
  • # define TIME_GRANULARITY 12
  • #else
  • # ifdef SCREENSAVER
  • # error Usage of SCREENSAVER reserved for Windows
  • # endif
  • # include <unistd.h>
  • # define SLEEP(_DELAY) usleep(1000*_DELAY)
  • # define TIME_GRANULARITY 6
  • #endif
  • /*********************************************************************
  • * COSINE TABLE SUPPORT *
  • *********************************************************************/
  • #ifdef USE_COS_TABLE
  • # define COS_TABLE_QUALITY 0x1000
  • float CosTable[COS_TABLE_QUALITY];
  • void initCos(void){
  • int i;
  • for (i=0;i<COS_TABLE_QUALITY;i++)
  • CosTable[i]=cos(PI*i/COS_TABLE_QUALITY);
  • }
  • float cosTable(float x){
  • int n;
  • if (x<0)
  • x=-x;
  • n=((int) roundf(COS_TABLE_QUALITY*x/PI)) % (2*COS_TABLE_QUALITY);
  • if (n<COS_TABLE_QUALITY)
  • return CosTable[n];
  • else
  • return CosTable[2*COS_TABLE_QUALITY-1-n];
  • }
  • # define COS(_X) cosTable((_X))
  • # define SIN(_X) cosTable((_X)-0.5*PI)
  • #else
  • # define COS(_X) cos((_X))
  • # define SIN(_X) sin((_X))
  • #endif
  • /*********************************************************************
  • * MACROS *
  • *********************************************************************/
  • #define ASSERT(_X,_S) if (!(_X)) {printf("%s\n",_S);exit(-1);}
  • #define MEMCHECK(_X) if (!(_X)) {printf("Memory allocation failed\n");exit(-1);}
  • /*********************************************************************
  • * TYPES *
  • *********************************************************************/
  • typedef struct{
  • int Count,Degree;
  • float *Matrix;
  • } transformation;
  • #ifdef USE_TEXTURE
  • typedef struct{
  • # ifdef USE_MULTIPLE_TEXTURES
  • unsigned int Index;
  • # endif
  • int ImageWidth,ImageHeight,Width,Height;
  • } texture;
  • #endif
  • #pragma pack(push,1)
  • #pragma pack(1)
  • typedef struct{
  • unsigned char R,G,B,A;
  • float X,Y,Z;
  • } point;
  • #pragma pack(pop)
  • /*********************************************************************
  • * APPLICATION DATA *
  • *********************************************************************/
  • struct {
  • struct {
  • int Index,Width,Height,FullScreen,DesiredFullScreen,DoubleBuffered,DesiredDoubleBuffered,MultiSample,DesiredMultiSample,ChangeMode;
  • #ifdef SCREENSAVER
  • int ScreenSaverMode,MouseX,MouseY;
  • #endif
  • #ifdef USE_TEXTURE
  • texture TextureMotion;
  • # ifdef USE_MULTIPLE_TEXTURES
  • texture TextureAccum;
  • # endif
  • #endif
  • } Window;
  • struct {
  • int Tick,PeriodStart,PeriodLength,TickTime;
  • float Elasticity,Map,FPS,DesiredFPS;
  • } Time;
  • struct {
  • transformation T1,T2;
  • int MinDegree,MaxDegree;
  • } Transformations;
  • struct {
  • int Count,DesiredCount,Rounded;
  • float Size;
  • point *Data;
  • } Points;
  • struct {
  • float Alpha,SpaceFrequency,TimeFrequency;
  • } ColorMap;
  • struct {
  • int BlendMethod,LimitCPUUsage,MotionBlur,Accumulation;
  • float Luminance,Sharpness,Attenuation;
  • } Display;
  • struct {
  • float Density;
  • char sFrame[64],sTime[64],sFPS[64],sPointCount[64],sDensity[64],sPointSize[64],sAlpha[64],sCycle[64],sAttractor1[64],sAttractor2[64];
  • } Statistics;
  • menu *MainMenu;
  • } ApplicationData={
  • {-1,1,1,0,0,1,1,0,0,0
  • #ifdef SCREENSAVER
  • ,0,-1,-1
  • #endif
  • #ifdef USE_TEXTURE
  • # ifdef USE_MULTIPLE_TEXTURES
  • ,{INVALID_TEXTURE_INDEX,0,0,0,0},{INVALID_TEXTURE_INDEX,0,0,0,0}
  • # else
  • ,{0,0,0,0}
  • # endif
  • #endif
  • },
  • {0,0,5000,0,5,0,50,40},
  • {{0,0,NULL},{0,0,NULL},0,20},
  • {0,2*MIN_POINT_COUNT,1,1,NULL},
  • {0,1,1},
  • {0,0,0,0,1,1,0.1},
  • {0,"","","","","","","","","",""}
  • };
  • /*********************************************************************
  • * FUNCTIONS *
  • *********************************************************************/
  • void evolveWindow(void);
  • void evolveAlloc(void);
  • void evolveTime(void);
  • void evolvePoints(void);
  • void evolveProxy(void);
  • void evolveColorMap(void);
  • void evolve(void);
  • void displayFunc(void);
  • void reshapeFunc(int,int);
  • void idleFunc(void);
  • void keyboardFunc(unsigned char,int,int);
  • void specialFunc(int,int,int);
  • void mouseFunc(int,int,int,int);
  • #ifdef SCREENSAVER
  • void passiveMotionFunc(int,int);
  • #endif
  • void readIniFile(void);
  • void writeIniFile(void);
  • void fullScreenChange(int);
  • void fullScreenParamChange(int);
  • void doubleBufferedChange(int);
  • void multiSampleChange(int);
  • #ifdef USE_TEXTURE
  • void motionBlurChange(int);
  • #endif
  • void desiredFPSChange(int);
  • void limitCPUUsageChange(int);
  • void resetExecute(void);
  • void saveExecute(void);
  • void quitExecute(void);
  • void roundedPointsChange(int);
  • void blendMethodChange(int);
  • void luminanceChange(float);
  • void sharpnessChange(float);
  • void attenuationChange(float);
  • void spaceFrequencyChange(float);
  • void timeFrequencyChange(float);
  • void periodChange(float);
  • void elasticityChange(float);
  • void minDegreeChange(int);
  • void maxDegreeChange(int);
  • /*********************************************************************
  • * MENU DESIGN *
  • *********************************************************************/
  • SEPARATOR(Separator);
  • CHECKBOX(CheckBoxFullScreen,"Fullscreen (F)",0,fullScreenChange);
  • static char *ListBoxResolution_Items[6]={"default","320x240","640x480","800x600","1024x768","1280x1024"};
  • LISTBOX(ListBoxResolution,"Fullscreen resolution :",0,ListBoxResolution_Items,fullScreenParamChange);
  • static char *ListBoxBPP_Items[4]={"default","16","24","32"};
  • LISTBOX(ListBoxBPP,"Fullscreen color depth (BPP) :",0,ListBoxBPP_Items,fullScreenParamChange);
  • static char *ListBoxFrequency_Items[11]={"default","50","60","65","70","72","75","80","85","90","100"};
  • LISTBOX(ListBoxFrequency,"Fullscreen refresh rate (Hz) :",0,ListBoxFrequency_Items,fullScreenParamChange);
  • CHECKBOX(CheckBoxDoubleBuffered,"Double buffered (D)",1,doubleBufferedChange);
  • CHECKBOX(CheckBoxMultiSample,"Multi sample (M)",0,multiSampleChange);
  • #ifdef USE_TEXTURE
  • # ifdef USE_MULTIPLE_TEXTURES
  • static char *ListBoxMotionBlur_Items[7]={"Single buffer","Double buffer","Triple buffer (2x filter)",
  • "Triple buffer (3x filter)","Triple buffer (4x filter)","Triple buffer (5x filter)",
  • "Triple buffer (6x filter)"};
  • LISTBOX(ListBoxMotionBlur,"Motion blur",1,ListBoxMotionBlur_Items,motionBlurChange);
  • # else
  • CHECKBOX(CheckBoxMotionBlur,"High quality motion blur",1,motionBlurChange);
  • # endif
  • #endif
  • ITRACKBAR(FTrackBarDesiredFPS,"Requested frame rate: %d",5,120,40,1,desiredFPSChange);
  • CHECKBOX(CheckBoxLimitCPUUsage,"Limit CPU usage",0,limitCPUUsageChange);
  • #ifdef SCREENSAVER
  • STATICTEXT(StaticTextReset,"Reset settings (R)",1,resetExecute);
  • STATICTEXT(StaticTextSave,"Save settings and exit (S)",1,saveExecute);
  • STATICTEXT(StaticTextQuit,"Cancel (Q)",1,quitExecute);
  • # ifdef USE_TEXTURE
  • static menuitem *MenuPageAFC_Items[14]={
  • # else
  • static menuitem *MenuPageAFC_Items[13]={
  • # endif
  • #else
  • STATICTEXT(StaticTextSave,"Save settings (S)",1,saveExecute);
  • STATICTEXT(StaticTextReset,"Reset settings",1,resetExecute);
  • STATICTEXT(StaticTextQuit,"Quit (Q)",1,quitExecute);
  • # ifdef USE_TEXTURE
  • static menuitem *MenuPageAFC_Items[15]={
  • # else
  • static menuitem *MenuPageAFC_Items[14]={
  • # endif
  • #endif
  • &CheckBoxFullScreen,
  • &ListBoxResolution,
  • &ListBoxBPP,
  • &ListBoxFrequency,
  • &Separator,
  • &CheckBoxDoubleBuffered,
  • &CheckBoxMultiSample,
  • #ifdef USE_TEXTURE
  • # ifdef USE_MULTIPLE_TEXTURES
  • &ListBoxMotionBlur,
  • # else
  • &CheckBoxMotionBlur,
  • # endif
  • #endif
  • &FTrackBarDesiredFPS,
  • &CheckBoxLimitCPUUsage,
  • &Separator,
  • #ifdef SCREENSAVER
  • &StaticTextReset,
  • &StaticTextSave,
  • &StaticTextQuit
  • #else
  • &StaticTextSave,
  • &StaticTextReset,
  • &Separator,
  • &StaticTextQuit
  • #endif
  • };
  • MENUPAGE(MenuPageAFC,"AFC Version 1.0",MenuPageAFC_Items);
  • CHECKBOX(CheckBoxRoundedPoints,"Rounded points",1,roundedPointsChange);
  • static char *ListBoxBlendMethod_Items[3]={"Logarithmic","Linear","Maximum"};
  • LISTBOX(ListBoxBlendMethod,"Blend color method :",0,ListBoxBlendMethod_Items,blendMethodChange);
  • FTRACKBAR(FTrackBarLuminance,"Luminance : %.0f%%",0,200,100,1,luminanceChange);
  • FTRACKBAR(FTrackBarSharpness,"Sharpness : %.0f%%",0,200,100,1,sharpnessChange);
  • FTRACKBAR(FTrackBarAttenuation,"Attenuation : %.1f%%",0.1,100,10,0.1,attenuationChange);
  • FTRACKBAR(FTrackBarSpaceFrequency,"Colormap space frequency : %.2f",0,50,1,0.02,spaceFrequencyChange);
  • FTRACKBAR(FTrackBarTimeFrequency,"Colormap time frequency : %.2f",0,20,1,0.02,timeFrequencyChange);
  • static menuitem *MenuPageDisplay_Items[9]={
  • &CheckBoxRoundedPoints,
  • &ListBoxBlendMethod,
  • &Separator,
  • &FTrackBarLuminance,
  • &FTrackBarSharpness,
  • &FTrackBarAttenuation,
  • &Separator,
  • &FTrackBarSpaceFrequency,
  • &FTrackBarTimeFrequency
  • };
  • MENUPAGE(MenuPageDisplay,"DISPLAY",MenuPageDisplay_Items);
  • FTRACKBAR(FTrackBarPeriod,"Cycle length : %.1f sec",0.5,20,5,0.1,periodChange);
  • FTRACKBAR(FTrackBarElasticity,"Cycle elasticity : %.1f",0.1,30,5,0.1,elasticityChange);
  • ITRACKBAR(ITrackBarMinDegree,"Min attractor degree : %d",3,15,6,1,minDegreeChange);
  • ITRACKBAR(ITrackBarMaxDegree,"Max attractor degree : %d",3,15,6,1,maxDegreeChange);
  • static menuitem *MenuPageAttractor_Items[4]={&FTrackBarPeriod,&FTrackBarElasticity,&ITrackBarMinDegree,&ITrackBarMaxDegree};
  • MENUPAGE(MenuPageAttractor,"ATTRACTOR",MenuPageAttractor_Items);
  • STATICTEXT(StaticTextFrame,ApplicationData.Statistics.sFrame,0,NULL);
  • STATICTEXT(StaticTextTime,ApplicationData.Statistics.sTime,0,NULL);
  • STATICTEXT(StaticTextFPS,ApplicationData.Statistics.sFPS,0,NULL);
  • STATICTEXT(StaticTextPointCount,ApplicationData.Statistics.sPointCount,0,NULL);
  • STATICTEXT(StaticTextDensity,ApplicationData.Statistics.sDensity,0,NULL);
  • STATICTEXT(StaticTextPointSize,ApplicationData.Statistics.sPointSize,0,NULL);
  • STATICTEXT(StaticTextAlpha,ApplicationData.Statistics.sAlpha,0,NULL);
  • STATICTEXT(StaticTextCycle,ApplicationData.Statistics.sCycle,0,NULL);
  • STATICTEXT(StaticTextAttractor1,ApplicationData.Statistics.sAttractor1,0,NULL);
  • STATICTEXT(StaticTextAttractor2,ApplicationData.Statistics.sAttractor2,0,NULL);
  • static menuitem *MenuPageStatistics_Items[12]={
  • &StaticTextFrame,
  • &StaticTextTime,
  • &StaticTextFPS,
  • &Separator,
  • &StaticTextPointCount,
  • &StaticTextDensity,
  • &StaticTextPointSize,
  • &StaticTextAlpha,
  • &Separator,
  • &StaticTextCycle,
  • &StaticTextAttractor1,
  • &StaticTextAttractor2
  • };
  • MENUPAGE(MenuPageStatistics," STATISTICS ",MenuPageStatistics_Items);
  • static menupage *MainMenu_Pages[4]={&MenuPageAFC,&MenuPageDisplay,&MenuPageAttractor,&MenuPageStatistics};
  • MENU(MainMenu,MainMenu_Pages);
  • /*********************************************************************
  • * UTILITIES *
  • *********************************************************************/
  • int pgcd(int x,int y){
  • if (y)
  • return pgcd(y,x%y);
  • else
  • return x;
  • }
  • int ppcm(int x,int y){
  • return (x*y)/pgcd(x,y);
  • }
  • int nextPowerOfTwo(int x){
  • int u=1;
  • while (u<x)
  • u*=2;//<<=1;
  • return u;
  • }
  • float mapExp(float x,float t){
  • if (x<0.5)
  • return 0.5*pow(2*x,t);
  • else
  • return 1-0.5*pow(2-2*x,t);
  • }
  • /*********************************************************************
  • * TEXTURE UTILITIES *
  • *********************************************************************/
  • #ifdef USE_TEXTURE
  • void copyTexture(texture *T){
  • # ifdef USE_MULTIPLE_TEXTURES
  • if (T->Index==INVALID_TEXTURE_INDEX)
  • glGenTextures(1,&T->Index);
  • glBindTexture(GL_TEXTURE_2D,T->Index);
  • # endif
  • if (ApplicationData.Window.Width!=T->ImageWidth || ApplicationData.Window.Height!=T->ImageHeight){
  • T->ImageWidth=ApplicationData.Window.Width;
  • T->ImageHeight=ApplicationData.Window.Height;
  • T->Width=nextPowerOfTwo(T->ImageWidth);
  • T->Height=nextPowerOfTwo(T->ImageHeight);
  • glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,T->Width,T->Height,0,GL_RGB,GL_UNSIGNED_BYTE,NULL);
  • }
  • glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,T->ImageWidth,T->ImageHeight);
  • }
  • int paintTexture(texture *T,int Mode){
  • # ifdef USE_MULTIPLE_TEXTURES
  • if (T->Index!=INVALID_TEXTURE_INDEX && T->Width && T->Height){
  • # else
  • if (T->Width && T->Height){
  • # endif
  • float u=(float) T->ImageWidth/T->Width,v=(float) T->ImageHeight/T->Height;
  • glPushAttrib(GL_ALL_ATTRIB_BITS);
  • glPushMatrix();
  • # ifdef USE_MULTIPLE_TEXTURES
  • glBindTexture(GL_TEXTURE_2D,T->Index);
  • # endif
  • glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  • glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  • glEnable(GL_TEXTURE_2D);
  • glBegin(GL_QUADS);
  • glTexCoord2f(0,0);
  • glVertex2f(-1,-1);
  • glTexCoord2f(0,v);
  • glVertex2f(-1,1);
  • glTexCoord2f(u,v);
  • glVertex2f(1,1);
  • glTexCoord2f(u,0);
  • glVertex2f(1,-1);
  • glEnd();
  • glDisable(GL_TEXTURE_2D);
  • glPopMatrix();
  • glPopAttrib();
  • return 1;
  • }
  • return 0;
  • }
  • void deleteTexture(texture *T){
  • # ifdef USE_MULTIPLE_TEXTURES
  • if (T->Index!=INVALID_TEXTURE_INDEX){
  • glDeleteTextures(1,&T->Index);
  • T->Index=INVALID_TEXTURE_INDEX;
  • # endif
  • T->Width=0;
  • T->Height=0;
  • T->ImageWidth=0;
  • T->ImageHeight=0;
  • # ifdef USE_MULTIPLE_TEXTURES
  • }
  • # endif
  • }
  • #endif
  • /*********************************************************************
  • * AFFINE TRANSFORMATIONS *
  • *********************************************************************/
  • void allocTransformation(transformation *t){
  • int i,*T;
  • if (ApplicationData.Transformations.MaxDegree==ApplicationData.Transformations.MinDegree)
  • t->Degree=ApplicationData.Transformations.MinDegree;
  • else
  • t->Degree=ApplicationData.Transformations.MinDegree+(rand() % (1+ApplicationData.Transformations.MaxDegree-ApplicationData.Transformations.MinDegree));
  • t->Count=t->Degree-(rand() % (t->Degree/2));
  • if (t->Count==t->Degree)
  • t->Count--;
  • MEMCHECK(T=(int *) calloc(t->Degree,sizeof(int)));
  • MEMCHECK(t->Matrix=(float *) malloc(6*t->Count*sizeof(float)));
  • for (i=0;i<t->Count;i++){
  • float o=2*PI*(rand() % t->Degree)/t->Degree,u=(rand() % 2)-0.5,v=-0.5;
  • int k=-1,j=1+(rand() % (t->Degree-i));
  • t->Matrix[6*i]=u*cos(o);
  • t->Matrix[6*i+1]=-v*sin(o);
  • t->Matrix[6*i+3]=u*sin(o);
  • t->Matrix[6*i+4]=v*cos(o);
  • while (j){
  • k++;
  • if (!T[k])
  • j--;
  • }
  • T[k]=1;
  • o=PI*(1.+2*k)/t->Degree;
  • t->Matrix[6*i+2]=0.5*cos(o);
  • t->Matrix[6*i+5]=0.5*sin(o);
  • }
  • free(T);
  • }
  • void freeTransformation(transformation *t){
  • free(t->Matrix);
  • t->Count=0;
  • }
  • void applyTransformation(transformation *t,int r,float *x,float *y){
  • float u=t->Matrix[6*r]*(*x)+t->Matrix[6*r+1]*(*y)+t->Matrix[6*r+2];
  • *y=t->Matrix[6*r+3]*(*x)+t->Matrix[6*r+4]*(*y)+t->Matrix[6*r+5];
  • *x=u;
  • }
  • /*********************************************************************
  • * WINDOW *
  • *********************************************************************/
  • void createWindow(void){
  • if (ApplicationData.Window.Index==-1){
  • int m=GLUT_RGBA;
  • char s[64]="";
  • if (ApplicationData.Window.DesiredDoubleBuffered)
  • m|=GLUT_DOUBLE;
  • ApplicationData.Window.DoubleBuffered=ApplicationData.Window.DesiredDoubleBuffered;
  • if (ApplicationData.Window.DesiredMultiSample)
  • m|=GLUT_MULTISAMPLE;
  • ApplicationData.Window.MultiSample=ApplicationData.Window.DesiredMultiSample;
  • glutInitDisplayMode(m);
  • if (ApplicationData.Window.DesiredFullScreen){
  • if (ListBoxResolution.Data.ListBox->ItemIndex)
  • strcat(s,ListBoxResolution.Data.ListBox->Items[ListBoxResolution.Data.ListBox->ItemIndex]);
  • if (ListBoxBPP.Data.ListBox->ItemIndex){
  • strcat(s,":");
  • strcat(s,ListBoxBPP.Data.ListBox->Items[ListBoxBPP.Data.ListBox->ItemIndex]);
  • }
  • if (ListBoxFrequency.Data.ListBox->ItemIndex){
  • strcat(s,"@");
  • strcat(s,ListBoxFrequency.Data.ListBox->Items[ListBoxFrequency.Data.ListBox->ItemIndex]);
  • }
  • if (*s){
  • glutGameModeString(s);
  • if (!glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)){
  • printf("Unsupported display mode (%s). Fullscreen has been canceled.\n",s);
  • ApplicationData.Window.DesiredFullScreen=0;
  • }
  • }
  • }
  • CheckBoxFullScreen.Data.CheckBox->Checked=ApplicationData.Window.DesiredFullScreen;
  • if (ApplicationData.Window.DesiredFullScreen)
  • ApplicationData.Window.Index=glutEnterGameMode();
  • else {
  • glutInitWindowSize(640,480);
  • glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-640)/2,(glutGet(GLUT_SCREEN_HEIGHT)-480)/2);
  • ApplicationData.Window.Index=glutCreateWindow("AFC");
  • }
  • ApplicationData.Window.FullScreen=ApplicationData.Window.DesiredFullScreen;
  • ApplicationData.Window.ChangeMode=0;
  • #ifdef USE_TEXTURE
  • deleteTexture(&ApplicationData.Window.TextureMotion);
  • # ifdef USE_MULTIPLE_TEXTURES
  • deleteTexture(&ApplicationData.Window.TextureAccum);
  • # endif
  • #endif
  • #ifdef SCREENSAVER
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
  • glutSetCursor(GLUT_CURSOR_NONE);
  • else
  • #endif
  • glutSetCursor(GLUT_CURSOR_CROSSHAIR);
  • glutDisplayFunc(displayFunc);
  • glutReshapeFunc(reshapeFunc);
  • glutIdleFunc(idleFunc);
  • glutKeyboardFunc(keyboardFunc);
  • glutSpecialFunc(specialFunc);
  • glutMouseFunc(mouseFunc);
  • #ifdef SCREENSAVER
  • glutPassiveMotionFunc(passiveMotionFunc);
  • #endif
  • }
  • }
  • void destroyWindow(void){
  • if (ApplicationData.Window.Index!=-1){
  • if (ApplicationData.Window.FullScreen)
  • glutLeaveGameMode();
  • else
  • glutDestroyWindow(ApplicationData.Window.Index);
  • }
  • ApplicationData.Window.Index=-1;
  • }
  • /*********************************************************************
  • * ANIMATION CORE *
  • *********************************************************************/
  • float u1,u2,u3,u4,u5,u6;
  • void evolveWindow(void){
  • if (ApplicationData.Window.MultiSample^ApplicationData.Window.DesiredMultiSample ||
  • ApplicationData.Window.DoubleBuffered^ApplicationData.Window.DesiredDoubleBuffered ||
  • ApplicationData.Window.FullScreen^ApplicationData.Window.DesiredFullScreen ||
  • ApplicationData.Window.ChangeMode) {
  • destroyWindow();
  • createWindow();
  • }
  • }
  • void evolveAlloc(void){
  • if (ApplicationData.Points.Count!=ApplicationData.Points.DesiredCount){
  • int i;
  • MEMCHECK(ApplicationData.Points.Data=(point *) realloc(ApplicationData.Points.Data,ApplicationData.Points.DesiredCount*sizeof(point)));
  • if (!ApplicationData.Points.Count){
  • float o=2*PI*rand()/RAND_MAX,r=(float) rand()/RAND_MAX;
  • ApplicationData.Points.Data[0].X=r*cos(o);
  • ApplicationData.Points.Data[0].Y=r*sin(o);
  • ApplicationData.Points.Data[0].Z=0;
  • ApplicationData.Points.Data[0].A=255;
  • }
  • for (i=ApplicationData.Points.Count;i<ApplicationData.Points.DesiredCount;i++)
  • ApplicationData.Points.Data[i]=ApplicationData.Points.Data[0];
  • ApplicationData.Points.Count=ApplicationData.Points.DesiredCount;
  • }
  • }
  • void evolveTime(void){
  • int t=glutGet(GLUT_ELAPSED_TIME),u=(t-ApplicationData.Time.PeriodStart)/ApplicationData.Time.PeriodLength;
  • while (u--){
  • freeTransformation(&ApplicationData.Transformations.T1);
  • ApplicationData.Transformations.T1=ApplicationData.Transformations.T2;
  • allocTransformation(&ApplicationData.Transformations.T2);
  • ApplicationData.Time.PeriodStart+=ApplicationData.Time.PeriodLength;
  • }
  • ApplicationData.Time.Map=mapExp((float) (t-ApplicationData.Time.PeriodStart)/ApplicationData.Time.PeriodLength,ApplicationData.Time.Elasticity);
  • if ((++ApplicationData.Time.Tick & FPS_COUNTER_TRIGGER)==FPS_COUNTER_TRIGGER){
  • char s[64];
  • float r;
  • ApplicationData.Time.FPS=(1-FPS_COUNTER_SMOOTH)*1000*(1+FPS_COUNTER_TRIGGER)/(t+1-ApplicationData.Time.TickTime)+FPS_COUNTER_SMOOTH*ApplicationData.Time.FPS;
  • ApplicationData.Time.TickTime=t;
  • r=ApplicationData.Time.FPS/ApplicationData.Time.DesiredFPS;
  • if (r>1.05)
  • ApplicationData.Points.DesiredCount+=ApplicationData.Points.DesiredCount*(1-1/r);
  • if (r<0.95)
  • ApplicationData.Points.DesiredCount-=ApplicationData.Points.DesiredCount*(1-r);
  • if (ApplicationData.Points.DesiredCount<MIN_POINT_COUNT){
  • ApplicationData.Points.DesiredCount=MIN_POINT_COUNT;
  • printf("Your system is TOO SLOW to run this program at the requested frame rate. Please lower it to improve image quality (its value MUST be less than the screen refresh rate if you are using double buffered mode, since the display cannot go faster than the screen in this case).\n");
  • }
  • sprintf(s,"AFC (%.0f FPS , %d points)\0",ApplicationData.Time.FPS,ApplicationData.Points.Count);
  • glutSetWindowTitle(s);
  • }
  • }
  • void evolvePoints(void){
  • int i;
  • for (i=0;i<ApplicationData.Points.Count;i++){
  • int r=rand(),r1=r % ApplicationData.Transformations.T1.Count,r2=r % ApplicationData.Transformations.T2.Count;
  • point *p=ApplicationData.Points.Data+i;
  • float u=p->X,v=p->Y,s=ApplicationData.Time.Map,t=1-ApplicationData.Time.Map;
  • applyTransformation(&ApplicationData.Transformations.T1,r1,&p->X,&p->Y);
  • applyTransformation(&ApplicationData.Transformations.T2,r2,&u,&v);
  • p->X=t*p->X+s*u;
  • p->Y=t*p->Y+s*v;
  • p->Z=0.2*p->Z+0.8*(t*r1+s*r2);
  • p->R=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u1*p->Z+u4));
  • p->G=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u2*p->Z+u5));
  • p->B=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u3*p->Z+u6));
  • }
  • }
  • void evolveProxy(void){
  • int i,j,k=0,T[PROXY_SIZE][PROXY_SIZE];
  • float U[2]={1,1},u=0;
  • float r=(float) (1+ApplicationData.Window.Width*ApplicationData.Window.Height)/(1+ApplicationData.Points.Count);
  • for (i=0;i<PROXY_SIZE;i++)
  • for (j=0;j<PROXY_SIZE;j++)
  • T[i][j]=0;
  • i=PROXY_SIZE*PROXY_SIZE*PROXY_QUALITY;
  • if (i>=ApplicationData.Points.Count)
  • i=ApplicationData.Points.Count-1;
  • for (;i>=0;i--)
  • T[(int) (PROXY_SIZE*(ApplicationData.Points.Data[i].X+1)*0.4999)][(int) (PROXY_SIZE*(ApplicationData.Points.Data[i].Y+1)*0.4999)]++;
  • for (i=0;i<PROXY_SIZE;i++)
  • for (j=0;j<PROXY_SIZE;j++)
  • if (T[i][j])
  • k++;
  • ApplicationData.Statistics.Density=(float) k/(PROXY_SIZE*PROXY_SIZE);
  • ApplicationData.Points.Size=(2.01-ApplicationData.Display.Sharpness)*sqrt(ApplicationData.Statistics.Density*r);
  • if (ApplicationData.Points.Rounded){
  • glGetFloatv(GL_POINT_SIZE_RANGE,U);
  • if (U[1]>U[0]+0.01){
  • ApplicationData.Points.Size*=0.5*PI;
  • if (ApplicationData.Points.Size<U[0])
  • ApplicationData.Points.Size=U[0];
  • if (ApplicationData.Points.Size>U[1])
  • ApplicationData.Points.Size=U[1];
  • glGetFloatv(GL_POINT_SIZE_GRANULARITY,&u);
  • if (u>0)
  • ApplicationData.Points.Size=U[0]+roundf((ApplicationData.Points.Size-U[0])/u)*u;
  • } else
  • ApplicationData.Points.Size=U[0];
  • } else
  • ApplicationData.Points.Size=roundf(ApplicationData.Points.Size);
  • if (ApplicationData.Points.Size<1)
  • ApplicationData.Points.Size=1;
  • if (ApplicationData.Display.BlendMethod<2){
  • ApplicationData.ColorMap.Alpha=ApplicationData.Display.Attenuation*ApplicationData.Display.Luminance*r*ApplicationData.Statistics.Density/pow(ApplicationData.Points.Size,2);
  • if (ApplicationData.ColorMap.Alpha>1)
  • ApplicationData.ColorMap.Alpha=1;
  • if (ApplicationData.Display.MotionBlur>=2)
  • ApplicationData.ColorMap.Alpha=sqrt(ApplicationData.ColorMap.Alpha);
  • if (ApplicationData.ColorMap.Alpha<MIN_COLOR)
  • ApplicationData.ColorMap.Alpha=MIN_COLOR;
  • } else
  • ApplicationData.ColorMap.Alpha=ApplicationData.Display.Luminance;
  • }
  • void evolveColorMap(void){
  • float t=0.001*ApplicationData.ColorMap.TimeFrequency*glutGet(GLUT_ELAPSED_TIME);
  • u1=2+cos(+0.12*t);
  • u2=2+cos(+0.13*t);
  • u3=2+cos(-0.16*t);
  • u4=+1.9*(t+cos(+1.0*t));
  • u5=+1.4*(t-cos(-1.2*t));
  • u6=-1.1*(t+cos(-1.4*t));
  • }
  • void evolveStatistics(void){
  • if (ApplicationData.MainMenu->Active){
  • int t=glutGet(GLUT_ELAPSED_TIME)/1000;
  • sprintf(ApplicationData.Statistics.sFrame,"Frame : 0x%X",ApplicationData.Time.Tick);
  • sprintf(ApplicationData.Statistics.sTime,"Time : %.2d:%.2d:%.2d",t/3600,(t/60) % 60,t % 60);
  • sprintf(ApplicationData.Statistics.sFPS,"FPS : %.0f",ApplicationData.Time.FPS);
  • sprintf(ApplicationData.Statistics.sPointCount,"Points count : %d",ApplicationData.Points.Count);
  • sprintf(ApplicationData.Statistics.sDensity,"Surface : %.0f%%",ApplicationData.Statistics.Density*100);
  • sprintf(ApplicationData.Statistics.sPointSize,"Point size : %.2f",ApplicationData.Points.Size);
  • sprintf(ApplicationData.Statistics.sAlpha,"Alpha : %.1f%%",ApplicationData.ColorMap.Alpha*100);
  • sprintf(ApplicationData.Statistics.sCycle,"Cycle : %.0f%%",ApplicationData.Time.Map*100);
  • sprintf(ApplicationData.Statistics.sAttractor1,"Attractor #1 : %d/%d",ApplicationData.Transformations.T1.Count,ApplicationData.Transformations.T1.Degree);
  • sprintf(ApplicationData.Statistics.sAttractor2,"Attractor #2 : %d/%d",ApplicationData.Transformations.T2.Count,ApplicationData.Transformations.T2.Degree);
  • }
  • }
  • void evolve(void){
  • evolveWindow();
  • evolveAlloc();
  • evolveTime();
  • evolvePoints();
  • evolveProxy();
  • evolveColorMap();
  • evolveStatistics();
  • }
  • /*********************************************************************
  • * GLUT CALLBACKS *
  • *********************************************************************/
  • void displayFunc(void){
  • float t=glutGet(GLUT_ELAPSED_TIME);
  • glEnable(GL_BLEND);
  • glPushAttrib(GL_ALL_ATTRIB_BITS);
  • glPointSize(ApplicationData.Points.Size);
  • if (ApplicationData.Points.Rounded)
  • glEnable(GL_POINT_SMOOTH);
  • else
  • glDisable(GL_POINT_SMOOTH);
  • #ifdef USE_TEXTURE
  • switch (ApplicationData.Display.MotionBlur){
  • case 0:
  • #endif
  • glBlendFunc(GL_ZERO,GL_ONE_MINUS_SRC_ALPHA);
  • glColor4f(0,0,0,ApplicationData.Display.Attenuation);
  • glRectf(-1,-1,1,1);
  • #ifdef USE_TEXTURE
  • break;
  • case 1:
  • glBlendFunc(GL_ONE,GL_ZERO);
  • glColor3f(1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation);
  • if (!paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE))
  • glClear(GL_COLOR_BUFFER_BIT);
  • break;
  • }
  • #endif
  • switch(ApplicationData.Display.BlendMethod){
  • case 0:
  • glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
  • break;
  • case 1:
  • glBlendFunc(GL_ONE,GL_ONE);
  • break;
  • case 2:
  • glBlendFunc(GL_ONE,GL_ZERO);
  • break;
  • }
  • glInterleavedArrays(GL_C4UB_V2F,sizeof(point),ApplicationData.Points.Data);
  • #ifdef USE_TEXTURE
  • switch (ApplicationData.Display.MotionBlur){
  • int i;
  • case 0:
  • case 1:
  • #endif
  • glDrawArrays(GL_POINTS,0,ApplicationData.Points.Count);
  • #ifdef USE_TEXTURE
  • break;
  • # ifdef USE_MULTIPLE_TEXTURES
  • default:{
  • float f=ApplicationData.Display.BlendMethod<2?ApplicationData.ColorMap.Alpha:ApplicationData.Display.Attenuation/ApplicationData.Display.MotionBlur;///ApplicationData.Display.MotionBlur;
  • for (i=0;i<ApplicationData.Display.MotionBlur;i++){
  • int a=i*ApplicationData.Points.Count/ApplicationData.Display.MotionBlur,b=(i+1)*ApplicationData.Points.Count/ApplicationData.Display.MotionBlur-a;
  • glClear(GL_COLOR_BUFFER_BIT);
  • glDrawArrays(GL_POINTS,a,b);
  • glPushAttrib(GL_ALL_ATTRIB_BITS);
  • copyTexture(&ApplicationData.Window.TextureAccum);
  • glBlendFunc(GL_ONE,GL_ZERO);
  • if (i){
  • glColor3f(1,1,1);
  • paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE);
  • } else {
  • glColor3f(1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation);
  • if (!paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE))
  • glClear(GL_COLOR_BUFFER_BIT);
  • }
  • glColor3f(f,f,f);
  • glBlendFunc(GL_ONE,GL_ONE);
  • paintTexture(&ApplicationData.Window.TextureAccum,GL_MODULATE);
  • if (i<ApplicationData.Display.MotionBlur)
  • copyTexture(&ApplicationData.Window.TextureMotion);
  • glPopAttrib();
  • }
  • break;
  • }
  • # endif
  • }
  • #endif
  • glPopAttrib();
  • menuDisplay(ApplicationData.MainMenu,ApplicationData.Window.Width,ApplicationData.Window.Height);
  • #ifdef USE_TEXTURE
  • switch (ApplicationData.Display.MotionBlur){
  • case 0:
  • break;
  • case 1:
  • copyTexture(&ApplicationData.Window.TextureMotion);
  • break;
  • # ifdef USE_MULTIPLE_TEXTURES
  • default:
  • copyTexture(&ApplicationData.Window.TextureMotion);
  • break;
  • # endif
  • }
  • #endif
  • glFlush();
  • glutSwapBuffers();
  • }
  • void reshapeFunc(int width,int height){
  • if (!(ApplicationData.Window.Width=width))
  • ApplicationData.Window.Width=1;
  • if (!(ApplicationData.Window.Height=height))
  • ApplicationData.Window.Height=1;
  • glViewport(0,0,width,height);
  • }
  • void idleFunc(void){
  • evolve();
  • glutPostRedisplay();
  • if (ApplicationData.Display.LimitCPUUsage)
  • SLEEP(TIME_GRANULARITY);
  • }
  • void keyboardFunc(unsigned char key,int x,int y){
  • #ifdef SCREENSAVER
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
  • exit(0);
  • #endif
  • switch (key){
  • case 'd':
  • ApplicationData.Window.DesiredDoubleBuffered=!ApplicationData.Window.DesiredDoubleBuffered;
  • CheckBoxDoubleBuffered.Data.CheckBox->Checked=ApplicationData.Window.DesiredDoubleBuffered;
  • break;
  • case 'f':
  • ApplicationData.Window.DesiredFullScreen=!ApplicationData.Window.DesiredFullScreen;
  • CheckBoxFullScreen.Data.CheckBox->Checked=ApplicationData.Window.DesiredFullScreen;
  • break;
  • case 'm':
  • ApplicationData.Window.DesiredMultiSample=!ApplicationData.Window.DesiredMultiSample;
  • CheckBoxMultiSample.Data.CheckBox->Checked=ApplicationData.Window.DesiredMultiSample;
  • break;
  • case 'q':
  • quitExecute();
  • break;
  • #ifdef SCREENSAVER
  • case 'r':
  • resetExecute();
  • break;
  • #endif
  • case 's':
  • saveExecute();
  • break;
  • default:
  • menuKeyboard(ApplicationData.MainMenu,key);
  • }
  • }
  • void specialFunc(int key,int x,int y){
  • #ifdef SCREENSAVER
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
  • exit(0);
  • #endif
  • menuSpecial(ApplicationData.MainMenu,key);
  • }
  • void mouseFunc(int button,int state,int x,int y){
  • int i;
  • float u=1-2.*x/ApplicationData.Window.Width,v=1-2.*y/ApplicationData.Window.Height;
  • #ifdef SCREENSAVER
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
  • exit(0);
  • #endif
  • for (i=0;i<ApplicationData.Points.Count;i++){
  • ApplicationData.Points.Data[i].X=u;
  • ApplicationData.Points.Data[i].Y=v;
  • }
  • };
  • #ifdef SCREENSAVER
  • void passiveMotionFunc(int x,int y){
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW){
  • if (ApplicationData.Window.MouseX==-1){
  • ApplicationData.Window.MouseX=x;
  • ApplicationData.Window.MouseY=y;
  • } else {
  • if (abs(ApplicationData.Window.MouseX-x)+abs(ApplicationData.Window.MouseY-y)>MAX_SCREENSAVER_MOUSE_OFFSET)
  • exit(0);
  • }
  • }
  • };
  • #endif
  • /*********************************************************************
  • * INI FILE *
  • *********************************************************************/
  • void readIniFile(void){
  • FILE *f;
  • if (f=fopen(INI_FILENAME,"r")){
  • menuLoad(ApplicationData.MainMenu,f);
  • fclose(f);
  • } else
  • printf("Cannot read file "INI_FILENAME"\n");
  • menuInit(ApplicationData.MainMenu);
  • }
  • void writeIniFile(void){
  • FILE *f;
  • if (f=fopen(INI_FILENAME,"w")){
  • menuSave(ApplicationData.MainMenu,f);
  • fclose(f);
  • } else
  • printf("Cannot write file" INI_FILENAME "\n");
  • }
  • /*********************************************************************
  • * MENU CALLBACKS *
  • *********************************************************************/
  • void fullScreenChange(int checked){
  • #ifdef SCREENSAVER
  • if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
  • ApplicationData.Window.DesiredFullScreen=1;
  • else
  • #endif
  • ApplicationData.Window.DesiredFullScreen=checked;
  • }
  • void fullScreenParamChange(int index){
  • if (ApplicationData.Window.FullScreen)
  • ApplicationData.Window.ChangeMode=1;
  • }
  • void doubleBufferedChange(int checked){
  • ApplicationData.Window.DesiredDoubleBuffered=checked;
  • }
  • void multiSampleChange(int checked){
  • ApplicationData.Window.DesiredMultiSample=checked;
  • }
  • #ifdef USE_TEXTURE
  • # ifdef USE_MULTIPLE_TEXTURES
  • void motionBlurChange(int index){
  • ApplicationData.Display.MotionBlur=index;
  • }
  • # else
  • void motionBlurChange(int checked){
  • ApplicationData.Display.MotionBlur=checked;
  • }
  • # endif
  • #endif
  • void desiredFPSChange(int position){
  • ApplicationData.Time.DesiredFPS=position;
  • }
  • void limitCPUUsageChange(int checked){
  • ApplicationData.Display.LimitCPUUsage=checked;
  • }
  • void resetExecute(void){
  • FILE *f;
  • if (f=fopen(INI_FILENAME,"w")){
  • fclose(f);
  • printf("Settings reset, restart the application\n");
  • }
  • #ifdef SCREENSAVER
  • exit(0);
  • #endif
  • }
  • void saveExecute(void){
  • writeIniFile();
  • #ifdef SCREENSAVER
  • exit(0);
  • #endif
  • }
  • void quitExecute(void){
  • exit(0);
  • }
  • void roundedPointsChange(int checked){
  • ApplicationData.Points.Rounded=checked;
  • }
  • void blendMethodChange(int index){
  • ApplicationData.Display.BlendMethod=index;
  • }
  • void luminanceChange(float position){
  • ApplicationData.Display.Luminance=position*0.01;
  • }
  • void sharpnessChange(float position){
  • ApplicationData.Display.Sharpness=position*0.01;
  • }
  • void attenuationChange(float position){
  • ApplicationData.Display.Attenuation=position*0.01;
  • }
  • void spaceFrequencyChange(float position){
  • ApplicationData.ColorMap.SpaceFrequency=position;
  • }
  • void timeFrequencyChange(float position){
  • ApplicationData.ColorMap.TimeFrequency=position;
  • }
  • void periodChange(float position){
  • ApplicationData.Time.PeriodLength=1000*position;
  • }
  • void elasticityChange(float position){
  • ApplicationData.Time.Elasticity=position;
  • }
  • void minDegreeChange(int position){
  • if (position>ApplicationData.Transformations.MaxDegree)
  • ITrackBarMinDegree.Data.ITrackBar->Position=ApplicationData.Transformations.MaxDegree;
  • else
  • ApplicationData.Transformations.MinDegree=position;
  • }
  • void maxDegreeChange(int position){
  • if (position<ApplicationData.Transformations.MinDegree)
  • ITrackBarMaxDegree.Data.ITrackBar->Position=ApplicationData.Transformations.MaxDegree;
  • else
  • ApplicationData.Transformations.MaxDegree=position;
  • }
  • /*********************************************************************
  • * MAIN PROGRAM *
  • *********************************************************************/
  • #ifdef SCREENSAVER
  • int strcmpleft(char *s,char *t){
  • while (*s && *s==*t){
  • s++;
  • t++;
  • }
  • return !*s;
  • }
  • int findstr(char *s,char *T[]){
  • char *t;
  • while (t=*(T++))
  • if (strcmpleft(t,s))
  • return 1;
  • return 0;
  • }
  • int screenSaverMode(int argc,char *argv[]){
  • char *sConfigureFlags[7]={"-C","/C","C","-c","/c","c",NULL},*sPreviewFlags[7]={"-P","/P","P","-p","/p","p",NULL};
  • int i;
  • for (i=1;i<argc;i++){
  • if (findstr(argv[i],sConfigureFlags))
  • return SCREENSAVER_MODE_CONFIGURE;
  • if (findstr(argv[i],sPreviewFlags))
  • return SCREENSAVER_MODE_PREVIEW;
  • }
  • return SCREENSAVER_MODE_SHOW;
  • }
  • #endif
  • int main(int argc,char *argv[]){
  • #ifdef SCREENSAVER
  • switch(ApplicationData.Window.ScreenSaverMode=screenSaverMode(argc,argv)){
  • case SCREENSAVER_MODE_CONFIGURE:
  • MainMenu.Active=1;
  • break;
  • case SCREENSAVER_MODE_PREVIEW:
  • return 0;
  • }
  • #endif
  • srand(time(NULL));
  • #ifdef USE_COS_TABLE
  • initCos();
  • #endif
  • ApplicationData.MainMenu=&MainMenu;
  • readIniFile();
  • allocTransformation(&ApplicationData.Transformations.T1);
  • allocTransformation(&ApplicationData.Transformations.T2);
  • glutInit(&argc,argv);
  • createWindow();
  • printf("Entering main loop, press [Escape] for menu, use arrows to navigate.\n");
  • glutMainLoop();
  • return 0;
  • }
#define USE_COS_TABLE
#define USE_TEXTURE
#define USE_MULTIPLE_TEXTURES
//#define SCREENSAVER

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "glut_import.h"
#include "menu.h"

/*********************************************************************
 * CONSTANTS                                                         *
 *********************************************************************/

#define FPS_COUNTER_TRIGGER 15
#define FPS_COUNTER_SMOOTH 0.3

#define PROXY_SIZE 32
#define PROXY_QUALITY 5

#define MIN_COLOR (10./256.)
#define MIN_POINT_COUNT 300

#define INI_FILENAME "AFC.ini"

#ifdef USE_MULTIPLE_TEXTURES
#  ifndef USE_TEXTURE
#    error You cannot specify USE_MULTIPLE_TEXTURES without specifying USE_TEXTURE
#  endif
#  define INVALID_TEXTURE_INDEX 0xFFFFFFFF
#endif

/*********************************************************************
 * PLATFORM                                                          *
 *********************************************************************/

#ifdef __WIN32__
#  ifdef SCREENSAVER
#    define SCREENSAVER_MODE_SHOW 0x1
#    define SCREENSAVER_MODE_CONFIGURE 0x2
#    define SCREENSAVER_MODE_PREVIEW 0x4
#    define MAX_SCREENSAVER_MOUSE_OFFSET 10
#  endif
#  include <windows.h>
#  define SLEEP(_DELAY) Sleep(_DELAY)
#  define TIME_GRANULARITY 12
#else
#  ifdef SCREENSAVER
#    error Usage of SCREENSAVER reserved for Windows
#  endif
#  include <unistd.h>
#  define SLEEP(_DELAY) usleep(1000*_DELAY)
#  define TIME_GRANULARITY 6
#endif

/*********************************************************************
 * COSINE TABLE SUPPORT                                              *
 *********************************************************************/

#ifdef USE_COS_TABLE
#  define COS_TABLE_QUALITY 0x1000
  float CosTable[COS_TABLE_QUALITY];
  void initCos(void){
    int i;
    for (i=0;i<COS_TABLE_QUALITY;i++)
      CosTable[i]=cos(PI*i/COS_TABLE_QUALITY);
  }
  float cosTable(float x){
    int n;
    if (x<0)
      x=-x;
    n=((int) roundf(COS_TABLE_QUALITY*x/PI)) % (2*COS_TABLE_QUALITY);
    if (n<COS_TABLE_QUALITY)
      return CosTable[n];
    else
      return CosTable[2*COS_TABLE_QUALITY-1-n];
  }
#  define COS(_X) cosTable((_X))
#  define SIN(_X) cosTable((_X)-0.5*PI)
#else
#  define COS(_X) cos((_X))
#  define SIN(_X) sin((_X))
#endif

/*********************************************************************
 * MACROS                                                            *
 *********************************************************************/

#define ASSERT(_X,_S) if (!(_X)) {printf("%s\n",_S);exit(-1);}
#define MEMCHECK(_X) if (!(_X)) {printf("Memory allocation failed\n");exit(-1);}

/*********************************************************************
 * TYPES                                                             *
 *********************************************************************/

typedef struct{
  int Count,Degree;
  float *Matrix;
} transformation;

#ifdef USE_TEXTURE
typedef struct{
#  ifdef USE_MULTIPLE_TEXTURES
  unsigned int Index;
#  endif
  int ImageWidth,ImageHeight,Width,Height;
} texture;
#endif

#pragma pack(push,1)
  #pragma pack(1)
  typedef struct{
    unsigned char R,G,B,A;
    float X,Y,Z;
  } point;
#pragma pack(pop)

/*********************************************************************
 * APPLICATION DATA                                                  *
 *********************************************************************/

struct {
  struct {
    int Index,Width,Height,FullScreen,DesiredFullScreen,DoubleBuffered,DesiredDoubleBuffered,MultiSample,DesiredMultiSample,ChangeMode;
#ifdef SCREENSAVER
    int ScreenSaverMode,MouseX,MouseY;
#endif
#ifdef USE_TEXTURE
    texture TextureMotion;
#  ifdef USE_MULTIPLE_TEXTURES
    texture TextureAccum;
#  endif
#endif
  } Window;
  struct {
    int Tick,PeriodStart,PeriodLength,TickTime;
    float Elasticity,Map,FPS,DesiredFPS;
  } Time;
  struct {
    transformation T1,T2;
    int MinDegree,MaxDegree;
  } Transformations;
  struct {
    int Count,DesiredCount,Rounded;
    float Size;
    point *Data;
  } Points;
  struct {
    float Alpha,SpaceFrequency,TimeFrequency;
  } ColorMap;
  struct {
    int BlendMethod,LimitCPUUsage,MotionBlur,Accumulation;
    float Luminance,Sharpness,Attenuation;
  } Display;
  struct {
    float Density;
    char sFrame[64],sTime[64],sFPS[64],sPointCount[64],sDensity[64],sPointSize[64],sAlpha[64],sCycle[64],sAttractor1[64],sAttractor2[64];
  } Statistics;
  menu *MainMenu;
} ApplicationData={
  {-1,1,1,0,0,1,1,0,0,0
#ifdef SCREENSAVER
    ,0,-1,-1
#endif
#ifdef USE_TEXTURE
#  ifdef USE_MULTIPLE_TEXTURES
    ,{INVALID_TEXTURE_INDEX,0,0,0,0},{INVALID_TEXTURE_INDEX,0,0,0,0}
#  else
    ,{0,0,0,0}
#  endif
#endif
  },
  {0,0,5000,0,5,0,50,40},
  {{0,0,NULL},{0,0,NULL},0,20},
  {0,2*MIN_POINT_COUNT,1,1,NULL},
  {0,1,1},
  {0,0,0,0,1,1,0.1},
  {0,"","","","","","","","","",""}
};

/*********************************************************************
 * FUNCTIONS                                                         *
 *********************************************************************/

void evolveWindow(void);
void evolveAlloc(void);
void evolveTime(void);
void evolvePoints(void);
void evolveProxy(void);
void evolveColorMap(void);
void evolve(void);

void displayFunc(void);
void reshapeFunc(int,int);
void idleFunc(void);
void keyboardFunc(unsigned char,int,int);
void specialFunc(int,int,int);
void mouseFunc(int,int,int,int);
#ifdef SCREENSAVER
void passiveMotionFunc(int,int);
#endif

void readIniFile(void);
void writeIniFile(void);

void fullScreenChange(int);
void fullScreenParamChange(int);
void doubleBufferedChange(int);
void multiSampleChange(int);
#ifdef USE_TEXTURE
void motionBlurChange(int);
#endif
void desiredFPSChange(int);
void limitCPUUsageChange(int);
void resetExecute(void);
void saveExecute(void);
void quitExecute(void);

void roundedPointsChange(int);
void blendMethodChange(int);
void luminanceChange(float);
void sharpnessChange(float);
void attenuationChange(float);
void spaceFrequencyChange(float);
void timeFrequencyChange(float);

void periodChange(float);
void elasticityChange(float);
void minDegreeChange(int);
void maxDegreeChange(int);

/*********************************************************************
 * MENU DESIGN                                                     *
 *********************************************************************/

SEPARATOR(Separator);

CHECKBOX(CheckBoxFullScreen,"Fullscreen (F)",0,fullScreenChange);
static char *ListBoxResolution_Items[6]={"default","320x240","640x480","800x600","1024x768","1280x1024"};
LISTBOX(ListBoxResolution,"Fullscreen resolution :",0,ListBoxResolution_Items,fullScreenParamChange);
static char *ListBoxBPP_Items[4]={"default","16","24","32"};
LISTBOX(ListBoxBPP,"Fullscreen color depth (BPP) :",0,ListBoxBPP_Items,fullScreenParamChange);
static char *ListBoxFrequency_Items[11]={"default","50","60","65","70","72","75","80","85","90","100"};
LISTBOX(ListBoxFrequency,"Fullscreen refresh rate (Hz) :",0,ListBoxFrequency_Items,fullScreenParamChange);
CHECKBOX(CheckBoxDoubleBuffered,"Double buffered (D)",1,doubleBufferedChange);
CHECKBOX(CheckBoxMultiSample,"Multi sample (M)",0,multiSampleChange);
#ifdef USE_TEXTURE
#  ifdef USE_MULTIPLE_TEXTURES
static char *ListBoxMotionBlur_Items[7]={"Single buffer","Double buffer","Triple buffer (2x filter)",
                                         "Triple buffer (3x filter)","Triple buffer (4x filter)","Triple buffer (5x filter)",
                                         "Triple buffer (6x filter)"};
LISTBOX(ListBoxMotionBlur,"Motion blur",1,ListBoxMotionBlur_Items,motionBlurChange);
#  else
CHECKBOX(CheckBoxMotionBlur,"High quality motion blur",1,motionBlurChange);
#  endif
#endif
ITRACKBAR(FTrackBarDesiredFPS,"Requested frame rate: %d",5,120,40,1,desiredFPSChange);
CHECKBOX(CheckBoxLimitCPUUsage,"Limit CPU usage",0,limitCPUUsageChange);
#ifdef SCREENSAVER
STATICTEXT(StaticTextReset,"Reset settings (R)",1,resetExecute);
STATICTEXT(StaticTextSave,"Save settings and exit (S)",1,saveExecute);
STATICTEXT(StaticTextQuit,"Cancel (Q)",1,quitExecute);
#  ifdef USE_TEXTURE
static menuitem *MenuPageAFC_Items[14]={
#  else
static menuitem *MenuPageAFC_Items[13]={
#  endif
#else
STATICTEXT(StaticTextSave,"Save settings (S)",1,saveExecute);
STATICTEXT(StaticTextReset,"Reset settings",1,resetExecute);
STATICTEXT(StaticTextQuit,"Quit (Q)",1,quitExecute);
#  ifdef USE_TEXTURE
static menuitem *MenuPageAFC_Items[15]={
#  else
static menuitem *MenuPageAFC_Items[14]={
#  endif
#endif
  &CheckBoxFullScreen,
  &ListBoxResolution,
  &ListBoxBPP,
  &ListBoxFrequency,
  &Separator,
  &CheckBoxDoubleBuffered,
  &CheckBoxMultiSample,
#ifdef USE_TEXTURE
#  ifdef USE_MULTIPLE_TEXTURES
  &ListBoxMotionBlur,
#  else
  &CheckBoxMotionBlur,
#  endif
#endif
  &FTrackBarDesiredFPS,
  &CheckBoxLimitCPUUsage,
  &Separator,
#ifdef SCREENSAVER
  &StaticTextReset,
  &StaticTextSave,
  &StaticTextQuit
#else
  &StaticTextSave,
  &StaticTextReset,
  &Separator,
  &StaticTextQuit
#endif
};
MENUPAGE(MenuPageAFC,"AFC Version 1.0",MenuPageAFC_Items);

CHECKBOX(CheckBoxRoundedPoints,"Rounded points",1,roundedPointsChange);
static char *ListBoxBlendMethod_Items[3]={"Logarithmic","Linear","Maximum"};
LISTBOX(ListBoxBlendMethod,"Blend color method :",0,ListBoxBlendMethod_Items,blendMethodChange);
FTRACKBAR(FTrackBarLuminance,"Luminance : %.0f%%",0,200,100,1,luminanceChange);
FTRACKBAR(FTrackBarSharpness,"Sharpness : %.0f%%",0,200,100,1,sharpnessChange);
FTRACKBAR(FTrackBarAttenuation,"Attenuation : %.1f%%",0.1,100,10,0.1,attenuationChange);
FTRACKBAR(FTrackBarSpaceFrequency,"Colormap space frequency : %.2f",0,50,1,0.02,spaceFrequencyChange);
FTRACKBAR(FTrackBarTimeFrequency,"Colormap time frequency : %.2f",0,20,1,0.02,timeFrequencyChange);
static menuitem *MenuPageDisplay_Items[9]={
  &CheckBoxRoundedPoints,
  &ListBoxBlendMethod,
  &Separator,
  &FTrackBarLuminance,
  &FTrackBarSharpness,
  &FTrackBarAttenuation,
  &Separator,
  &FTrackBarSpaceFrequency,
  &FTrackBarTimeFrequency
};
MENUPAGE(MenuPageDisplay,"DISPLAY",MenuPageDisplay_Items);

FTRACKBAR(FTrackBarPeriod,"Cycle length : %.1f sec",0.5,20,5,0.1,periodChange);
FTRACKBAR(FTrackBarElasticity,"Cycle elasticity : %.1f",0.1,30,5,0.1,elasticityChange);
ITRACKBAR(ITrackBarMinDegree,"Min attractor degree : %d",3,15,6,1,minDegreeChange);
ITRACKBAR(ITrackBarMaxDegree,"Max attractor degree : %d",3,15,6,1,maxDegreeChange);
static menuitem *MenuPageAttractor_Items[4]={&FTrackBarPeriod,&FTrackBarElasticity,&ITrackBarMinDegree,&ITrackBarMaxDegree};
MENUPAGE(MenuPageAttractor,"ATTRACTOR",MenuPageAttractor_Items);

STATICTEXT(StaticTextFrame,ApplicationData.Statistics.sFrame,0,NULL);
STATICTEXT(StaticTextTime,ApplicationData.Statistics.sTime,0,NULL);
STATICTEXT(StaticTextFPS,ApplicationData.Statistics.sFPS,0,NULL);
STATICTEXT(StaticTextPointCount,ApplicationData.Statistics.sPointCount,0,NULL);
STATICTEXT(StaticTextDensity,ApplicationData.Statistics.sDensity,0,NULL);
STATICTEXT(StaticTextPointSize,ApplicationData.Statistics.sPointSize,0,NULL);
STATICTEXT(StaticTextAlpha,ApplicationData.Statistics.sAlpha,0,NULL);
STATICTEXT(StaticTextCycle,ApplicationData.Statistics.sCycle,0,NULL);
STATICTEXT(StaticTextAttractor1,ApplicationData.Statistics.sAttractor1,0,NULL);
STATICTEXT(StaticTextAttractor2,ApplicationData.Statistics.sAttractor2,0,NULL);
static menuitem *MenuPageStatistics_Items[12]={
  &StaticTextFrame,
  &StaticTextTime,
  &StaticTextFPS,
  &Separator,
  &StaticTextPointCount,
  &StaticTextDensity,
  &StaticTextPointSize,
  &StaticTextAlpha,
  &Separator,
  &StaticTextCycle,
  &StaticTextAttractor1,
  &StaticTextAttractor2
};
MENUPAGE(MenuPageStatistics,"      STATISTICS      ",MenuPageStatistics_Items);

static menupage *MainMenu_Pages[4]={&MenuPageAFC,&MenuPageDisplay,&MenuPageAttractor,&MenuPageStatistics};
MENU(MainMenu,MainMenu_Pages);

/*********************************************************************
 * UTILITIES                                                         *
 *********************************************************************/

int pgcd(int x,int y){
  if (y)
    return pgcd(y,x%y);
  else
    return x;
}

int ppcm(int x,int y){
  return (x*y)/pgcd(x,y);
}

int nextPowerOfTwo(int x){
  int u=1;
  while (u<x)
    u*=2;//<<=1;
  return u;
}

float mapExp(float x,float t){
  if (x<0.5)
    return 0.5*pow(2*x,t);
  else
    return 1-0.5*pow(2-2*x,t);
}

/*********************************************************************
 * TEXTURE UTILITIES                                                 *
 *********************************************************************/

#ifdef USE_TEXTURE
void copyTexture(texture *T){
#  ifdef USE_MULTIPLE_TEXTURES
  if (T->Index==INVALID_TEXTURE_INDEX)
    glGenTextures(1,&T->Index);
  glBindTexture(GL_TEXTURE_2D,T->Index);
#  endif
  if (ApplicationData.Window.Width!=T->ImageWidth || ApplicationData.Window.Height!=T->ImageHeight){
    T->ImageWidth=ApplicationData.Window.Width;
    T->ImageHeight=ApplicationData.Window.Height;
    T->Width=nextPowerOfTwo(T->ImageWidth);
    T->Height=nextPowerOfTwo(T->ImageHeight);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,T->Width,T->Height,0,GL_RGB,GL_UNSIGNED_BYTE,NULL);
  }
  glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,T->ImageWidth,T->ImageHeight);
}

int paintTexture(texture *T,int Mode){
#  ifdef USE_MULTIPLE_TEXTURES
  if (T->Index!=INVALID_TEXTURE_INDEX && T->Width && T->Height){
#  else
  if (T->Width && T->Height){
#  endif
    float u=(float) T->ImageWidth/T->Width,v=(float) T->ImageHeight/T->Height;
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glPushMatrix();
#  ifdef USE_MULTIPLE_TEXTURES
    glBindTexture(GL_TEXTURE_2D,T->Index);
#  endif
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
    glTexCoord2f(0,0);
    glVertex2f(-1,-1);
    glTexCoord2f(0,v);
    glVertex2f(-1,1);
    glTexCoord2f(u,v);
    glVertex2f(1,1);
    glTexCoord2f(u,0);
    glVertex2f(1,-1);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
    glPopAttrib();
    return 1;
  }
  return 0;
}

void deleteTexture(texture *T){
#  ifdef USE_MULTIPLE_TEXTURES
  if (T->Index!=INVALID_TEXTURE_INDEX){
    glDeleteTextures(1,&T->Index);
    T->Index=INVALID_TEXTURE_INDEX;
#  endif
    T->Width=0;
    T->Height=0;
    T->ImageWidth=0;
    T->ImageHeight=0;
#  ifdef USE_MULTIPLE_TEXTURES
  }
#  endif
}
#endif

/*********************************************************************
 * AFFINE TRANSFORMATIONS                                            *
 *********************************************************************/

void allocTransformation(transformation *t){
  int i,*T;
  if (ApplicationData.Transformations.MaxDegree==ApplicationData.Transformations.MinDegree)
    t->Degree=ApplicationData.Transformations.MinDegree;
  else
    t->Degree=ApplicationData.Transformations.MinDegree+(rand() % (1+ApplicationData.Transformations.MaxDegree-ApplicationData.Transformations.MinDegree));
  t->Count=t->Degree-(rand() % (t->Degree/2));
  if (t->Count==t->Degree)
    t->Count--;
  MEMCHECK(T=(int *) calloc(t->Degree,sizeof(int)));
  MEMCHECK(t->Matrix=(float *) malloc(6*t->Count*sizeof(float)));
  for (i=0;i<t->Count;i++){
    float o=2*PI*(rand() % t->Degree)/t->Degree,u=(rand() % 2)-0.5,v=-0.5;
    int k=-1,j=1+(rand() % (t->Degree-i));
    t->Matrix[6*i]=u*cos(o);
    t->Matrix[6*i+1]=-v*sin(o);
    t->Matrix[6*i+3]=u*sin(o);
    t->Matrix[6*i+4]=v*cos(o);
    while (j){
      k++;
      if (!T[k])
        j--;
    }
    T[k]=1;
    o=PI*(1.+2*k)/t->Degree;
    t->Matrix[6*i+2]=0.5*cos(o);
    t->Matrix[6*i+5]=0.5*sin(o);
  }
  free(T);
}

void freeTransformation(transformation *t){
  free(t->Matrix);
  t->Count=0;
}

void applyTransformation(transformation *t,int r,float *x,float *y){
  float u=t->Matrix[6*r]*(*x)+t->Matrix[6*r+1]*(*y)+t->Matrix[6*r+2];
  *y=t->Matrix[6*r+3]*(*x)+t->Matrix[6*r+4]*(*y)+t->Matrix[6*r+5];
  *x=u;
}

/*********************************************************************
 * WINDOW                                                            *
 *********************************************************************/

void createWindow(void){
  if (ApplicationData.Window.Index==-1){
    int m=GLUT_RGBA;
    char s[64]="";
    if (ApplicationData.Window.DesiredDoubleBuffered)
      m|=GLUT_DOUBLE;
    ApplicationData.Window.DoubleBuffered=ApplicationData.Window.DesiredDoubleBuffered;
    if (ApplicationData.Window.DesiredMultiSample)
      m|=GLUT_MULTISAMPLE;
    ApplicationData.Window.MultiSample=ApplicationData.Window.DesiredMultiSample;
    glutInitDisplayMode(m);
    if (ApplicationData.Window.DesiredFullScreen){
      if (ListBoxResolution.Data.ListBox->ItemIndex)
        strcat(s,ListBoxResolution.Data.ListBox->Items[ListBoxResolution.Data.ListBox->ItemIndex]);
      if (ListBoxBPP.Data.ListBox->ItemIndex){
        strcat(s,":");
        strcat(s,ListBoxBPP.Data.ListBox->Items[ListBoxBPP.Data.ListBox->ItemIndex]);
      }
      if (ListBoxFrequency.Data.ListBox->ItemIndex){
        strcat(s,"@");
        strcat(s,ListBoxFrequency.Data.ListBox->Items[ListBoxFrequency.Data.ListBox->ItemIndex]);
      }
      if (*s){
        glutGameModeString(s);
        if (!glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)){
          printf("Unsupported display mode (%s). Fullscreen has been canceled.\n",s);
          ApplicationData.Window.DesiredFullScreen=0;
        }
      }
    }
    CheckBoxFullScreen.Data.CheckBox->Checked=ApplicationData.Window.DesiredFullScreen;
    if (ApplicationData.Window.DesiredFullScreen)
      ApplicationData.Window.Index=glutEnterGameMode();
    else {
      glutInitWindowSize(640,480);
      glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-640)/2,(glutGet(GLUT_SCREEN_HEIGHT)-480)/2);
      ApplicationData.Window.Index=glutCreateWindow("AFC");
    }
    ApplicationData.Window.FullScreen=ApplicationData.Window.DesiredFullScreen;
    ApplicationData.Window.ChangeMode=0;
#ifdef USE_TEXTURE
    deleteTexture(&ApplicationData.Window.TextureMotion);
#  ifdef USE_MULTIPLE_TEXTURES
    deleteTexture(&ApplicationData.Window.TextureAccum);
#  endif
#endif
#ifdef SCREENSAVER
    if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
      glutSetCursor(GLUT_CURSOR_NONE);
    else
#endif
      glutSetCursor(GLUT_CURSOR_CROSSHAIR);
    glutDisplayFunc(displayFunc);
    glutReshapeFunc(reshapeFunc);
    glutIdleFunc(idleFunc);
    glutKeyboardFunc(keyboardFunc);
    glutSpecialFunc(specialFunc);
    glutMouseFunc(mouseFunc);
#ifdef SCREENSAVER
    glutPassiveMotionFunc(passiveMotionFunc);
#endif
  }
}

void destroyWindow(void){
  if (ApplicationData.Window.Index!=-1){
    if (ApplicationData.Window.FullScreen)                                     
      glutLeaveGameMode();     
    else
      glutDestroyWindow(ApplicationData.Window.Index);
  }
  ApplicationData.Window.Index=-1;
}

/*********************************************************************
 * ANIMATION CORE                                                    *
 *********************************************************************/

float u1,u2,u3,u4,u5,u6;

void evolveWindow(void){
  if (ApplicationData.Window.MultiSample^ApplicationData.Window.DesiredMultiSample ||
      ApplicationData.Window.DoubleBuffered^ApplicationData.Window.DesiredDoubleBuffered ||
      ApplicationData.Window.FullScreen^ApplicationData.Window.DesiredFullScreen ||
      ApplicationData.Window.ChangeMode) {
    destroyWindow();
    createWindow();
  }
}

void evolveAlloc(void){
  if (ApplicationData.Points.Count!=ApplicationData.Points.DesiredCount){
    int i;
    MEMCHECK(ApplicationData.Points.Data=(point *) realloc(ApplicationData.Points.Data,ApplicationData.Points.DesiredCount*sizeof(point)));
    if (!ApplicationData.Points.Count){
      float o=2*PI*rand()/RAND_MAX,r=(float) rand()/RAND_MAX;
      ApplicationData.Points.Data[0].X=r*cos(o);
      ApplicationData.Points.Data[0].Y=r*sin(o);
      ApplicationData.Points.Data[0].Z=0;
      ApplicationData.Points.Data[0].A=255;
    }
    for (i=ApplicationData.Points.Count;i<ApplicationData.Points.DesiredCount;i++)
      ApplicationData.Points.Data[i]=ApplicationData.Points.Data[0];
    ApplicationData.Points.Count=ApplicationData.Points.DesiredCount;
  }
}

void evolveTime(void){
  int t=glutGet(GLUT_ELAPSED_TIME),u=(t-ApplicationData.Time.PeriodStart)/ApplicationData.Time.PeriodLength;
  while (u--){
    freeTransformation(&ApplicationData.Transformations.T1);
    ApplicationData.Transformations.T1=ApplicationData.Transformations.T2;
    allocTransformation(&ApplicationData.Transformations.T2);
    ApplicationData.Time.PeriodStart+=ApplicationData.Time.PeriodLength;
  }
  ApplicationData.Time.Map=mapExp((float) (t-ApplicationData.Time.PeriodStart)/ApplicationData.Time.PeriodLength,ApplicationData.Time.Elasticity);
  if ((++ApplicationData.Time.Tick & FPS_COUNTER_TRIGGER)==FPS_COUNTER_TRIGGER){
    char s[64];
    float r;
    ApplicationData.Time.FPS=(1-FPS_COUNTER_SMOOTH)*1000*(1+FPS_COUNTER_TRIGGER)/(t+1-ApplicationData.Time.TickTime)+FPS_COUNTER_SMOOTH*ApplicationData.Time.FPS;
    ApplicationData.Time.TickTime=t;
    r=ApplicationData.Time.FPS/ApplicationData.Time.DesiredFPS;
    if (r>1.05)
      ApplicationData.Points.DesiredCount+=ApplicationData.Points.DesiredCount*(1-1/r);
    if (r<0.95)
      ApplicationData.Points.DesiredCount-=ApplicationData.Points.DesiredCount*(1-r);
    if (ApplicationData.Points.DesiredCount<MIN_POINT_COUNT){
      ApplicationData.Points.DesiredCount=MIN_POINT_COUNT;
      printf("Your system is TOO SLOW to run this program at the requested frame rate. Please lower it to improve image quality (its value MUST be less than the screen refresh rate if you are using double buffered mode, since the display cannot go faster than the screen in this case).\n");
    }
    sprintf(s,"AFC (%.0f FPS , %d points)\0",ApplicationData.Time.FPS,ApplicationData.Points.Count);
    glutSetWindowTitle(s);
  }
}

void evolvePoints(void){
  int i;
  for (i=0;i<ApplicationData.Points.Count;i++){
    int r=rand(),r1=r % ApplicationData.Transformations.T1.Count,r2=r % ApplicationData.Transformations.T2.Count;
    point *p=ApplicationData.Points.Data+i;
    float u=p->X,v=p->Y,s=ApplicationData.Time.Map,t=1-ApplicationData.Time.Map;
    applyTransformation(&ApplicationData.Transformations.T1,r1,&p->X,&p->Y);
    applyTransformation(&ApplicationData.Transformations.T2,r2,&u,&v);
    p->X=t*p->X+s*u;
    p->Y=t*p->Y+s*v;
    p->Z=0.2*p->Z+0.8*(t*r1+s*r2);
    p->R=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u1*p->Z+u4));
    p->G=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u2*p->Z+u5));
    p->B=85.*ApplicationData.ColorMap.Alpha*(2+COS(ApplicationData.ColorMap.SpaceFrequency*u3*p->Z+u6));
  }
}

void evolveProxy(void){
  int i,j,k=0,T[PROXY_SIZE][PROXY_SIZE];
  float U[2]={1,1},u=0;
  float r=(float) (1+ApplicationData.Window.Width*ApplicationData.Window.Height)/(1+ApplicationData.Points.Count);
  for (i=0;i<PROXY_SIZE;i++)
    for (j=0;j<PROXY_SIZE;j++)
      T[i][j]=0;
  i=PROXY_SIZE*PROXY_SIZE*PROXY_QUALITY;
  if (i>=ApplicationData.Points.Count)
    i=ApplicationData.Points.Count-1;
  for (;i>=0;i--)
    T[(int) (PROXY_SIZE*(ApplicationData.Points.Data[i].X+1)*0.4999)][(int) (PROXY_SIZE*(ApplicationData.Points.Data[i].Y+1)*0.4999)]++;
  for (i=0;i<PROXY_SIZE;i++)
    for (j=0;j<PROXY_SIZE;j++)
      if (T[i][j])
        k++;
  ApplicationData.Statistics.Density=(float) k/(PROXY_SIZE*PROXY_SIZE);
  ApplicationData.Points.Size=(2.01-ApplicationData.Display.Sharpness)*sqrt(ApplicationData.Statistics.Density*r);
  if (ApplicationData.Points.Rounded){
    glGetFloatv(GL_POINT_SIZE_RANGE,U);
    if (U[1]>U[0]+0.01){
      ApplicationData.Points.Size*=0.5*PI;
      if (ApplicationData.Points.Size<U[0])
        ApplicationData.Points.Size=U[0];
      if (ApplicationData.Points.Size>U[1])
        ApplicationData.Points.Size=U[1];
      glGetFloatv(GL_POINT_SIZE_GRANULARITY,&u);
      if (u>0)
        ApplicationData.Points.Size=U[0]+roundf((ApplicationData.Points.Size-U[0])/u)*u;
    } else
      ApplicationData.Points.Size=U[0];
  } else
    ApplicationData.Points.Size=roundf(ApplicationData.Points.Size);
  if (ApplicationData.Points.Size<1)
    ApplicationData.Points.Size=1;
  if (ApplicationData.Display.BlendMethod<2){
    ApplicationData.ColorMap.Alpha=ApplicationData.Display.Attenuation*ApplicationData.Display.Luminance*r*ApplicationData.Statistics.Density/pow(ApplicationData.Points.Size,2);
    if (ApplicationData.ColorMap.Alpha>1)
      ApplicationData.ColorMap.Alpha=1;
    if (ApplicationData.Display.MotionBlur>=2)
      ApplicationData.ColorMap.Alpha=sqrt(ApplicationData.ColorMap.Alpha);
    if (ApplicationData.ColorMap.Alpha<MIN_COLOR)
      ApplicationData.ColorMap.Alpha=MIN_COLOR;
  } else
    ApplicationData.ColorMap.Alpha=ApplicationData.Display.Luminance;
}

void evolveColorMap(void){
  float t=0.001*ApplicationData.ColorMap.TimeFrequency*glutGet(GLUT_ELAPSED_TIME);
  u1=2+cos(+0.12*t);
  u2=2+cos(+0.13*t);
  u3=2+cos(-0.16*t);
  u4=+1.9*(t+cos(+1.0*t));
  u5=+1.4*(t-cos(-1.2*t));
  u6=-1.1*(t+cos(-1.4*t));
}

void evolveStatistics(void){
  if (ApplicationData.MainMenu->Active){
    int t=glutGet(GLUT_ELAPSED_TIME)/1000;
    sprintf(ApplicationData.Statistics.sFrame,"Frame : 0x%X",ApplicationData.Time.Tick);
    sprintf(ApplicationData.Statistics.sTime,"Time : %.2d:%.2d:%.2d",t/3600,(t/60) % 60,t % 60);
    sprintf(ApplicationData.Statistics.sFPS,"FPS : %.0f",ApplicationData.Time.FPS);
    sprintf(ApplicationData.Statistics.sPointCount,"Points count : %d",ApplicationData.Points.Count);
    sprintf(ApplicationData.Statistics.sDensity,"Surface : %.0f%%",ApplicationData.Statistics.Density*100);
    sprintf(ApplicationData.Statistics.sPointSize,"Point size : %.2f",ApplicationData.Points.Size);
    sprintf(ApplicationData.Statistics.sAlpha,"Alpha : %.1f%%",ApplicationData.ColorMap.Alpha*100);
    sprintf(ApplicationData.Statistics.sCycle,"Cycle : %.0f%%",ApplicationData.Time.Map*100);
    sprintf(ApplicationData.Statistics.sAttractor1,"Attractor #1 : %d/%d",ApplicationData.Transformations.T1.Count,ApplicationData.Transformations.T1.Degree);
    sprintf(ApplicationData.Statistics.sAttractor2,"Attractor #2 : %d/%d",ApplicationData.Transformations.T2.Count,ApplicationData.Transformations.T2.Degree);
  }
}

void evolve(void){
  evolveWindow();
  evolveAlloc();
  evolveTime();
  evolvePoints();
  evolveProxy();
  evolveColorMap();
  evolveStatistics();
}

/*********************************************************************
 * GLUT CALLBACKS                                                    *
 *********************************************************************/

void displayFunc(void){
  float t=glutGet(GLUT_ELAPSED_TIME);
  glEnable(GL_BLEND);
  glPushAttrib(GL_ALL_ATTRIB_BITS);
  glPointSize(ApplicationData.Points.Size);
  if (ApplicationData.Points.Rounded)
    glEnable(GL_POINT_SMOOTH);
  else
    glDisable(GL_POINT_SMOOTH);
#ifdef USE_TEXTURE
  switch (ApplicationData.Display.MotionBlur){
    case 0:
#endif
      glBlendFunc(GL_ZERO,GL_ONE_MINUS_SRC_ALPHA);
      glColor4f(0,0,0,ApplicationData.Display.Attenuation);
      glRectf(-1,-1,1,1);
#ifdef USE_TEXTURE
      break;
    case 1:
      glBlendFunc(GL_ONE,GL_ZERO);
      glColor3f(1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation);
      if (!paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE))
        glClear(GL_COLOR_BUFFER_BIT);
      break;
  }
#endif
  switch(ApplicationData.Display.BlendMethod){
    case 0:
      glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
      break;
    case 1:
      glBlendFunc(GL_ONE,GL_ONE);
      break;
    case 2:
      glBlendFunc(GL_ONE,GL_ZERO);
      break;
  }
  glInterleavedArrays(GL_C4UB_V2F,sizeof(point),ApplicationData.Points.Data);
#ifdef USE_TEXTURE
  switch (ApplicationData.Display.MotionBlur){
    int i;
    case 0:
    case 1:
#endif
      glDrawArrays(GL_POINTS,0,ApplicationData.Points.Count);
#ifdef USE_TEXTURE
      break;
#  ifdef USE_MULTIPLE_TEXTURES
    default:{
      float f=ApplicationData.Display.BlendMethod<2?ApplicationData.ColorMap.Alpha:ApplicationData.Display.Attenuation/ApplicationData.Display.MotionBlur;///ApplicationData.Display.MotionBlur;
      for (i=0;i<ApplicationData.Display.MotionBlur;i++){
        int a=i*ApplicationData.Points.Count/ApplicationData.Display.MotionBlur,b=(i+1)*ApplicationData.Points.Count/ApplicationData.Display.MotionBlur-a;
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_POINTS,a,b);
        glPushAttrib(GL_ALL_ATTRIB_BITS);
        copyTexture(&ApplicationData.Window.TextureAccum);
        glBlendFunc(GL_ONE,GL_ZERO);
        if (i){
          glColor3f(1,1,1);
          paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE);
        } else {
          glColor3f(1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation,1-ApplicationData.Display.Attenuation);
          if (!paintTexture(&ApplicationData.Window.TextureMotion,GL_MODULATE))
            glClear(GL_COLOR_BUFFER_BIT);
        }
        glColor3f(f,f,f);
        glBlendFunc(GL_ONE,GL_ONE);
        paintTexture(&ApplicationData.Window.TextureAccum,GL_MODULATE);
        if (i<ApplicationData.Display.MotionBlur)
          copyTexture(&ApplicationData.Window.TextureMotion);
        glPopAttrib();
      }
      break;
      }
#  endif
  }
#endif
  glPopAttrib();
  menuDisplay(ApplicationData.MainMenu,ApplicationData.Window.Width,ApplicationData.Window.Height);
#ifdef USE_TEXTURE
  switch (ApplicationData.Display.MotionBlur){
    case 0:
      break;
    case 1:
      copyTexture(&ApplicationData.Window.TextureMotion);
      break;
#  ifdef USE_MULTIPLE_TEXTURES
    default:
      copyTexture(&ApplicationData.Window.TextureMotion);
      break;
#  endif
  }
#endif
  glFlush();
  glutSwapBuffers();
}

void reshapeFunc(int width,int height){
  if (!(ApplicationData.Window.Width=width))
    ApplicationData.Window.Width=1;
  if (!(ApplicationData.Window.Height=height))
    ApplicationData.Window.Height=1;
  glViewport(0,0,width,height);
}

void idleFunc(void){
  evolve();
  glutPostRedisplay();
  if (ApplicationData.Display.LimitCPUUsage)
    SLEEP(TIME_GRANULARITY);
}

void keyboardFunc(unsigned char key,int x,int y){
#ifdef SCREENSAVER
  if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
    exit(0);
#endif
  switch (key){
    case 'd':
      ApplicationData.Window.DesiredDoubleBuffered=!ApplicationData.Window.DesiredDoubleBuffered;
      CheckBoxDoubleBuffered.Data.CheckBox->Checked=ApplicationData.Window.DesiredDoubleBuffered;
      break;
    case 'f':
      ApplicationData.Window.DesiredFullScreen=!ApplicationData.Window.DesiredFullScreen;
      CheckBoxFullScreen.Data.CheckBox->Checked=ApplicationData.Window.DesiredFullScreen;
      break;
    case 'm':
      ApplicationData.Window.DesiredMultiSample=!ApplicationData.Window.DesiredMultiSample;
      CheckBoxMultiSample.Data.CheckBox->Checked=ApplicationData.Window.DesiredMultiSample;
      break;
    case 'q':
      quitExecute();
      break;
#ifdef SCREENSAVER
    case 'r':
      resetExecute();
      break;
#endif
    case 's':
      saveExecute();
      break;
    default:
      menuKeyboard(ApplicationData.MainMenu,key);
  }
}

void specialFunc(int key,int x,int y){
#ifdef SCREENSAVER
  if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
    exit(0);
#endif
  menuSpecial(ApplicationData.MainMenu,key);
}

void mouseFunc(int button,int state,int x,int y){
  int i;
  float u=1-2.*x/ApplicationData.Window.Width,v=1-2.*y/ApplicationData.Window.Height;
#ifdef SCREENSAVER
  if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
    exit(0);
#endif
  for (i=0;i<ApplicationData.Points.Count;i++){
    ApplicationData.Points.Data[i].X=u;
    ApplicationData.Points.Data[i].Y=v;
  }
};

#ifdef SCREENSAVER
void passiveMotionFunc(int x,int y){
  if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW){
    if (ApplicationData.Window.MouseX==-1){
      ApplicationData.Window.MouseX=x;
      ApplicationData.Window.MouseY=y;
    } else {
      if (abs(ApplicationData.Window.MouseX-x)+abs(ApplicationData.Window.MouseY-y)>MAX_SCREENSAVER_MOUSE_OFFSET)
        exit(0);
    }
  }
};
#endif


/*********************************************************************
 * INI FILE                                                          *
 *********************************************************************/

void readIniFile(void){
  FILE *f;
  if (f=fopen(INI_FILENAME,"r")){
    menuLoad(ApplicationData.MainMenu,f);
    fclose(f);
  } else
    printf("Cannot read file "INI_FILENAME"\n");
  menuInit(ApplicationData.MainMenu);
}

void writeIniFile(void){
  FILE *f;
  if (f=fopen(INI_FILENAME,"w")){
    menuSave(ApplicationData.MainMenu,f);
    fclose(f);
  } else
    printf("Cannot write file" INI_FILENAME "\n");
}

/*********************************************************************
 * MENU CALLBACKS                                                    *
 *********************************************************************/

void fullScreenChange(int checked){
#ifdef SCREENSAVER
  if (ApplicationData.Window.ScreenSaverMode==SCREENSAVER_MODE_SHOW)
    ApplicationData.Window.DesiredFullScreen=1;
  else
#endif
    ApplicationData.Window.DesiredFullScreen=checked;
}

void fullScreenParamChange(int index){
  if (ApplicationData.Window.FullScreen)
    ApplicationData.Window.ChangeMode=1;
}

void doubleBufferedChange(int checked){
  ApplicationData.Window.DesiredDoubleBuffered=checked;
}

void multiSampleChange(int checked){
  ApplicationData.Window.DesiredMultiSample=checked;
}

#ifdef USE_TEXTURE
#  ifdef USE_MULTIPLE_TEXTURES
void motionBlurChange(int index){
  ApplicationData.Display.MotionBlur=index;
}
#  else
void motionBlurChange(int checked){
  ApplicationData.Display.MotionBlur=checked;
}
#  endif
#endif

void desiredFPSChange(int position){
  ApplicationData.Time.DesiredFPS=position;
}

void limitCPUUsageChange(int checked){
  ApplicationData.Display.LimitCPUUsage=checked;
}

void resetExecute(void){
  FILE *f;
  if (f=fopen(INI_FILENAME,"w")){
    fclose(f);
    printf("Settings reset, restart the application\n");
  }
#ifdef SCREENSAVER
  exit(0);
#endif
}

void saveExecute(void){
  writeIniFile();
#ifdef SCREENSAVER
  exit(0);
#endif
}

void quitExecute(void){
  exit(0);
}

void roundedPointsChange(int checked){
  ApplicationData.Points.Rounded=checked;
}

void blendMethodChange(int index){
  ApplicationData.Display.BlendMethod=index;
}

void luminanceChange(float position){
  ApplicationData.Display.Luminance=position*0.01;
}

void sharpnessChange(float position){
  ApplicationData.Display.Sharpness=position*0.01;
}

void attenuationChange(float position){
  ApplicationData.Display.Attenuation=position*0.01;
}

void spaceFrequencyChange(float position){
  ApplicationData.ColorMap.SpaceFrequency=position;
}

void timeFrequencyChange(float position){
  ApplicationData.ColorMap.TimeFrequency=position;
}

void periodChange(float position){
  ApplicationData.Time.PeriodLength=1000*position;
}

void elasticityChange(float position){
  ApplicationData.Time.Elasticity=position;
}

void minDegreeChange(int position){
  if (position>ApplicationData.Transformations.MaxDegree)
    ITrackBarMinDegree.Data.ITrackBar->Position=ApplicationData.Transformations.MaxDegree;
  else
    ApplicationData.Transformations.MinDegree=position;
}

void maxDegreeChange(int position){
  if (position<ApplicationData.Transformations.MinDegree)
    ITrackBarMaxDegree.Data.ITrackBar->Position=ApplicationData.Transformations.MaxDegree;
  else
    ApplicationData.Transformations.MaxDegree=position;
}

/*********************************************************************
 * MAIN PROGRAM                                                      *
 *********************************************************************/

#ifdef SCREENSAVER
int strcmpleft(char *s,char *t){
  while (*s && *s==*t){
    s++;
    t++;
  }
  return !*s;
}

int findstr(char *s,char *T[]){
  char *t;
  while (t=*(T++))
    if (strcmpleft(t,s))
      return 1;
  return 0;
}

int screenSaverMode(int argc,char *argv[]){
  char *sConfigureFlags[7]={"-C","/C","C","-c","/c","c",NULL},*sPreviewFlags[7]={"-P","/P","P","-p","/p","p",NULL};
  int i;
  for (i=1;i<argc;i++){
    if (findstr(argv[i],sConfigureFlags))
      return SCREENSAVER_MODE_CONFIGURE;
    if (findstr(argv[i],sPreviewFlags))
      return SCREENSAVER_MODE_PREVIEW;
  }
  return SCREENSAVER_MODE_SHOW;
}
#endif

int main(int argc,char *argv[]){
#ifdef SCREENSAVER
  switch(ApplicationData.Window.ScreenSaverMode=screenSaverMode(argc,argv)){
    case SCREENSAVER_MODE_CONFIGURE:
      MainMenu.Active=1;
      break;
    case SCREENSAVER_MODE_PREVIEW:
      return 0;
  }
#endif
  srand(time(NULL));
#ifdef USE_COS_TABLE
  initCos();
#endif
  ApplicationData.MainMenu=&MainMenu;
  readIniFile();
  allocTransformation(&ApplicationData.Transformations.T1);
  allocTransformation(&ApplicationData.Transformations.T2);
  glutInit(&argc,argv);
  createWindow();
  printf("Entering main loop, press [Escape] for menu, use arrows to navigate.\n");
  glutMainLoop();
  return 0;
}

Conclusion

Signification des options:

[Options générales]
-Fullscreen: active/désactive le mode full screen, avec possibilité de spécifier le mode d'affichage
-Double buffered: indique si la fenêtre est doublebuffered (moins de clignotements)
-Multi sample: active le mode multisample (lignes et points plus lisses)
-Motion blur: indique le degré de lissage temporel
-Requested frame rate: nombre d'images par secondes désirées (éviter de dépasser la fréquence de l'écran lorsque la fenêtre est double buffered)
-Limit CPU usage: tente de limiter un peu la consommation de resources
-Save settings: enregistre tout dans un fichier ini
-Reset settings: remet à zéro le fichier ini (nécessite de redémarrer le programme pour être pris en compte)
-Quit: quitter

[Display]
-Rounded points: indique si les points doivent être antialiasés (plus lisses)
-Blend color method: indique quelle méthode de mélange de couleurs utiliser
-Luminance: brillance globale de l'affichage
-Sharpness: détail de l'attracteur
-Attenuation: atténuation temporelle du motion blur
-Colormap space frequency: fréquence spatiale (nombre de couleurs simultanées) de la palette de couleurs
-Colormap time frequency: fréquence temporelle (variation dans le temps) de la palette

[Attractor]
-Cycle length: longueur du cycle de transfert d'un attracteur à l'autre
-Cycle elasticity: "élasticité" du transfert (oscillations plus ou moins brusques)
-Min attractor degree: complexité minimale des attracteurs
-Max attractor degree: complexité maximale des attracteurs



 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

07 janvier 2008 15:20:45 :
Typo dans le code
07 janvier 2008 18:50:59 :
J'avais oublié de renommer le .exe en .ex_
13 janvier 2008 14:55:27 :
Options supplémentaires, utilisation de textures pour le motion blur et l'accumulation des densités de couleur.

Commentaires et avis

signaler à un administrateur
Commentaire de tit_toinou le 08/01/2008 19:06:11 10/10

Salut,
des Fractales Linéaires !
Y'en a tellement ! tu les génères aléatoirement ?
Où sont les sierpinski, la fougère.. ?
En tout cas j'adore, c'est très beau et très fluide !

signaler à un administrateur
Commentaire de Forman le 08/01/2008 21:24:19

Salut,
content que ça te plaise!

C'est la fonction allocTransformation qui se charge de générer la matrice des applications affines utilisées pour l'attracteur.

Les fractales sont définies à partir d'un polygone régulier P de centre O à n côtés (n>=4). On considère:
-r l'homothétie de rapport 1/2
-T l'ensemble des translations qui transforment O en l'un des sommets de P (il y en a n)
-I le groupe des isométries qui laissent O invariant (il y en a 2*(n+1))
-k un entier compris entre n/2 et n

L'attracteur est défini en prenant k applications affines f1,...,fk contractantes obtenues en composant les 3 applications r, tj et ij (fj = r o tj o ij) où, pour 1<=j<=k:
-ij est une isométrie quelconque de I
-tj est une translation de T (mais on en choisit une différente pour chacune des f1,...,fk)

Pour k fixé ça laisse n!*(2n+2)^k/((n-k)!) choix possibles pour les k contractions.

Pour calculer le nombre total d'attracteurs que le programme peut représenter, il faut sommer cette quantité pour 4<=n<=nmax et n/2<=k<=n-1 où nmax est le degré maximal de l'attracteur (qu'on peut changer dans le menu). Par défaut nmax vaut 6, ce qui fait un total de plus de 800 millions d'attracteurs différents (en théorie) mais certains sont comptés plusieurs fois (à une rotation/symétrie près). Je crois que le nombre total (sans compter ceux qui sont identiques à une isométrie près) est proche de 50 millions (mais je n'ai pas vérifié en détails).

Les sierspinskis apparaissent parfois, il faut être patient      :-)
La fougère par contre, je ne crois pas qu'elle puisse apparaitre étant données les familles de contractions utilisées...

À tout instant il y a un mélange de 2 attracteurs générés comme expliqué plus haut, au début de la période c'est le premier, puis on évolue continument vers le second, puis à la fin de la période le second devient le premier, un nouvel attracteur est généré à la place du second et on recommence.

signaler à un administrateur
Commentaire de Forman le 08/01/2008 21:42:13

Je viens de me rendre compte qu'il y avait un problème sur les machines rapides: l'intensité des points de l'image est définie par la "densité" de l'attracteur sur ce pixel, l'effet est obtenu en accumulant des intensités lumineuses. Lorsqu'il y a beaucoup de points, la densité est automatiquement corrigée pour que la somme ne dépasse pas l'intensité maximale que l'écran peut afficher. Or, si le nombre de points à accumuler sur un même pixel devient grand, sa couleur prend des valeurs qui deviennent très petites (plus petite que l'échantillonage colorimétrique de l'écran, c'est à dire au maximum 1/256), donc les couleurs deviennent moins jolies et les effets de variation de la palette sont saccadés.

Si j'ai le temps je corrigerai ce problème en accumulant des couches de textures.

signaler à un administrateur
Commentaire de PADYVEN le 12/01/2008 16:59:10

Super pour un debutant tu te debrouille pas mal
rien a ajouté

signaler à un administrateur
Commentaire de misterVe le 14/01/2008 11:53:54

J'arrive pas à lancer ni l'exe ni le scr, "cannot read AFC.ini", c'est normal? Comment faire?

signaler à un administrateur
Commentaire de Forman le 14/01/2008 12:33:43

Bonjour,

le message "cannot read AFC.ini" est normal (c'est le fichier d'option, il n'existe pas tant que tu ne les as pas enregistrées au moins une fois) et ne devrait pas empêcher le programme de se lancer.

Peux-tu être plus précis? Qu'est-ce qu'il se passe exactement? Est-ce que ça affiche juste ce message et ça quitte, ou est-ce que tu vois une fenêtre apparaitre, ou encore un autre message d'erreur, ou rien du tout et le programme se termine?

signaler à un administrateur
Commentaire de misterVe le 29/01/2008 09:57:53

L'interface dos me répond "cannot read AFC.ini" et un message d'erreur "erreur du programme" apparaît :

"AFC.exe a généré des erreurs et sera fermé par Windows. Vous devrez redémarer le programme. Un journal des erreurs est en cours de création."

et pis fini, fermeture des fenêtres

signaler à un administrateur
Commentaire de Forman le 29/01/2008 15:29:38

C'est vraiment bizarre, je n'ai jamais vu ça avec ce programme. Est-ce que c'est l'exe que je fournis dans le zip, ou l'as-tu recompilé toi-même?

signaler à un administrateur
Commentaire de Forman le 29/01/2008 15:30:27

"Un journal des erreurs est en cours de création"
est-ce qu'il y a effectivement des traces plus détaillées quelque part?

signaler à un administrateur
Commentaire de misterVe le 29/01/2008 19:31:35

J'utilise l'exe fourni. Je ne sais pas où aller chercher le journal des erreurs...
Si tu sais où il est je pourrais te le donner.

signaler à un administrateur
Commentaire de misterVe le 29/01/2008 19:35:34

C bon je sais d'où vient l'erreur : ton prog marche très bien chez moi mais pas sur le PC de mon taf, qui n'a pas de carte 3D et donc pas OpenGL. Dsl ! ;)

signaler à un administrateur
Commentaire de Forman le 29/01/2008 22:59:19

Effectivement, ça ne risquait pas de fonctionner, alors        ;-)

signaler à un administrateur
Commentaire de misterVe le 30/01/2008 14:33:10

En tt cas, chapeau, super prog! 10/10

signaler à un administrateur
Commentaire de tit_toinou le 22/03/2008 16:14:05

Salut Forman,
alors voila je t'explique mon problème :
avant quand j'avais testé ton programme, il allait très vite et maintenant j'ai changé de pc (pas tous les composants, mais il est beaucoup mieux) et voila que je me retrouve avec un message YOUR SYSTEM IS TOO SLOW dans la console...
y'a une image par seconde ! que faire?

signaler à un administrateur
Commentaire de Forman le 22/03/2008 17:49:09

Il faut peut-être regarder au niveau des drivers de ta carte graphique. Peut-être n'as tu pas installé les derniers?

Si ta carte graphique est au moins aussi bien qu'avant, je ne vois pas d'autre explication. Es-tu sous Windows?

signaler à un administrateur
Commentaire de tit_toinou le 23/03/2008 10:19:04

Salut,
oui je suis sur Windows XP.
En fait j'ai gardé la même install de windows (donc mêmes pilotes, mêmes fichiers) sans changer la carte graphique ! La je viens de réinstaller les derniers, ton programme est rapide ! :)
Merci!

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

glut - openGL [ par loss ] Quels sont les fichiers necessaires pour utiliser glut(je compile avec VC++)?Ou est ce que je peux les telecharger?Merci d avance. Gestion de la souris OpenGL SANS GLUT [ par Xentor ] Comment faire pour connaitre le déplacement de la souris sans utiliser Glut ? (Savoir si on la déplace en haut, à gauche, etc...) J'ai fait plusieurs OpenGl, glut et Dev c++ 4 [ par fabienGL ] J'envoie un message car je passait au moin 3 heures sur le forums j'ai essayé tout ce ki à était di mé rien à faire ... j'utilise DEV C++ 4 et je sui OpenGl & glut avec Dev c++ 4 et WinXP [ par fabienGL ] J'envoie un message car je passait au moin 3 heures sur le forums j'ai essayé tout ce ki à était di mé rien à faire ... j'utilise DEV C++ 4 et j'ai Wi glut et opengl [ par MiTcH37 ] voila ce que j'ai lorsque je compile un prog avec du glut.h...C:\DOCUME~2\Mitch1\LOCALS~1\Temp\cc6Pbaaa.o(.text+0xcc):souris2.cpp: undefined reference opengl [ par MiTcH37 ] J'aimerais bien faire de l'opengl, mais ça marche pas... voila ce que j'ai lorsque je compile un prog avec du glut.h...C:\DOCUME~2\Mitch1\LOCALS~1\Tem devc++ [ par MiTcH37 ] qqun se sert de devc++ ?J'aimerais bien faire de l'opengl, mais ça marche pas... &gt; &gt; &gt; &gt; voila ce que j'ai lorsque je compile un prog avec erreur de compile d une source opengl utilisant glut [ par kribler ] KR!Bl3Rg lerreur suivante qui s afffiche :LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16quelqun pourrai maidermerci d Pb Dev C++ 5 et OpenGl [ par guillaume21 ] J'ai installé glut avec Dev c++ 5. J'ai mis glut.h dans include, glut32.lib dans lib et le dll dans system32 (et mem ds lib lol).J'ai aussi ajouté les Mélanger OpenGL et Glut [ par tintin72 ] SalutJ'aimerai me servir des fonctions d'entrée clavier/souris proposées par Glut, mais j'ai vu que Glut s'initialise avec une fonction main façon C.i


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 19,329 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.