Attracteurs de familles de contractions en écran de veille

Description

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 / Exemple :


#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

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.