Je vous propose un exercice ou plutôt un jeu consistant à coder un effet de plasma.
Pour avoir un apercu, une vidéo
C'est visuellement plutôt sympa, et très abordable niveau C.
On va commencer par le type de plasma le plus simple, celui basé sur un cycle de couleur.
Pour que tous monde puisse participer, je vais d'abord essayer d'expliquer le principe.
Le principe :
Sur une forme statique, on fait évoluer la palette pour créer une impression de mouvement.
Les ingrédients:
Il faut une palette cyclique comme celle ci par exemple...
Notez que les bords gauche et droit sont identiques.
On peut générer des palettes cycliques de plusieurs façons.
en faisant varier la teinte(hue) dans un espace colorimétrique HSV
utiliser des fonctions mathématiques péridodique(sinus par exemple...)
Dans un premier temps, le plus simple est de travailler avec des surface ayant une profondeur de 8bpp et une palette.
Pour les librairies comme la SFML qui ne permettent de travailler qu'en "true color", il faudra simuler une palette en stockant les valeurs dans un tableau.
Ensuite, il faut générer une forme statique...
Pour ça, une méthode est d'appliquer une fonction à chaque pixel de notre surface...
Exemple en en utilisant la fonctions sinus.
On sait que cette fonction varie de -1 à 1 sur l'intervalle [0, pi]. C'est très bien, mais nous, on souhaite obtenir une composante RGB(une valeur comprise entre 0 et 255)...
Comment faire ? C'est simple...
Pour une valeur a donnée
sin(a) est dans l'intervalle [-1, 1]
127 * sin(a) est dans l'intervalle [-127, 127]
128 + 127 * sin(a) est dans l'inervalle [0, 255].
Gagné.
En pratique on peut avoir des fonctions : appliquée à 1 axe
f(x) = 128 + 127 * sin(x)
f(y) = 128 + 127 * sin(y) appliquée à 2 axes
f(x, y) = 128 + 127 * sin(x + y)
f(x, y) = sqrt(x * x + y * y)
Comme vous pouvez le voir l'utilisation des sinus n'est pas une obligation.
Un petit exemple, pour avoir un aperçu des formes générées...
#include <SDL.h>
#include <math.h>
void putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Uint8 f1(Sint16 a, Sint16 b)
{
return 128 + 127 * sin(a / 16.0);
}
Uint8 f2(Sint16 a, Sint16 b)
{
return 128 + 127 * sin(b / 16.0);
}
Uint8 f3(Sint16 a, Sint16 b)
{
return 128 + 127 * sin((a + b) / 16.0);
}
Uint8 f4(Sint16 a, Sint16 b)
{
return 128 + 127 * sin(sqrt(a * a + b * b) / 16.0);
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y, Uint8(*f)(Sint16, Sint16))
{
Uint8 color = f(x, y);
putPixel(s, x, y, color);
}
void draw(SDL_Surface *s, Uint8(*f)(Sint16, Sint16))
{
Sint16 x, y;
if ( SDL_MUSTLOCK(s) )
if ( SDL_LockSurface(s) < 0 )
{
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
exit (EXIT_FAILURE);
}
for(y = 0; y < s->h; ++y)
for(x = 0; x < s->w; ++x)
applyPlasma(s, x, y, f);
if (SDL_MUSTLOCK(s))
SDL_UnlockSurface(s);
}
void setPalette(SDL_Surface *s)
{
SDL_Color colors[256];
int i;
for(i = 0; i < 256; i++)
{
colors[i].r = i;
colors[i].g = colors[i].r;
colors[i].b = colors[i].r;
}
SDL_SetColors(s, colors, 0 , 256);
}
int main (int argc, char* argv[])
{
typedef struct
{
Uint8 (*fun)(Sint16, Sint16);
}t_fun;
t_fun functions[] = {f1, f2, f3, f4};
size_t nFun = sizeof functions / sizeof *functions;
size_t curFun = 0;
SDL_bool done = SDL_FALSE;
SDL_Surface *screen;
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError() );
return EXIT_FAILURE;
}
screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_HWPALETTE);
if(screen == NULL)
{
fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
setPalette(screen);
draw(screen, functions[0].fun);
while (!done)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
done = SDL_TRUE;
break;
case SDL_KEYDOWN:
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE :
done = SDL_TRUE;
break;
case SDLK_SPACE:
curFun++;
curFun %= nFun;
draw(screen, functions[curFun].fun);
break;
default:
break;
}
}
}
}
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
L'astuce pour avoir des formes moins monotones consiste à additionner le résultat de plusieurs fonctions. Mais attention, il faut prendre garde à ce que la somme soit dans l'intervalle[0, 255].
Là encore, plusieurs méthodes.
Un exemple avec l'addition de 2 fonctions...
Soit on s'arrange pour que f1 et f2 retourne une valeur dans l'intervalle[0, 128], soit on divise la somme par 2, tout simplement.
Je commence donc en vous proposant un plasma, avec les fonctions présentées plus haut, et avec une palette en dégardé de gris(r, g, b de même valeur).
#include <SDL.h>
#include <math.h>
#define PI 3.14159265
#define PI2 6.28318531
#define TICK_INTERVAL 20
#define SHIFT_SPEED 2
Uint32 time_left(Uint32 nextTime)
{
Uint32 now = SDL_GetTicks();
return nextTime <= now ? 0 : nextTime - now;
}
void putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Uint8 f1(Sint16 a)
{
return 128 + 127 * sin(a / 16.0);
}
Uint8 f2(Sint16 b)
{
return 128 + 127 * sin(b / 16.0);
}
Uint8 f3(Sint16 a, Sint16 b)
{
return 128 + 127 * sin((a + b) / 32.0);
}
Uint8 f4(Sint16 a, Sint16 b)
{
return 128 + 127 * sin(sqrt(a * a + b * b) / 16.0);
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y)
{
Uint8 color = (f1(x) + f2(y) + f3(x, y) + f4(x, y)) / 4;
putPixel(s, x, y, color);
}
void init(SDL_Surface *s)
{
Sint16 x, y;
if ( SDL_MUSTLOCK(s) )
if ( SDL_LockSurface(s) < 0 )
{
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
exit (EXIT_FAILURE);
}
for(y = 0; y < s->h; ++y)
for(x = 0; x < s->w; ++x)
applyPlasma(s, x, y);
if (SDL_MUSTLOCK(s))
SDL_UnlockSurface(s);
}
void setPalette(SDL_Surface *s, Uint8 shift)
{
SDL_Color colors[256];
int i;
/* Décalage */
double f = SHIFT_SPEED * (2 * PI * shift / 256);
for(i = 0; i < 256; i++)
{
double angle = i * PI / 128.0 + f;
colors[i].r = 128 + 127 * sin(angle);
colors[i].g = colors[i].r;
colors[i].b = colors[i].r;
}
SDL_SetColors(s, colors, 0 , 256);
}
int main (int argc, char* argv[])
{
SDL_bool done = SDL_FALSE;
SDL_Surface *screen;
Uint32 nextTime;
Uint8 shift = 0;
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError() );
return EXIT_FAILURE;
}
screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_HWPALETTE);
if(screen == NULL)
{
fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
init(screen);
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while (!done)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
done = SDL_TRUE;
break;
case SDL_KEYDOWN:
{
if (event.key.keysym.sym == SDLK_ESCAPE)
done = SDL_TRUE;
break;
}
}
}
/* On actualise la palette enfonction du décalage actuel */
setPalette(screen, shift);
/* On augmente le décalage */
shift++;
/* On maintient le décalage dans la plage 0 - 255 */
shift %= 256;/* -> /*shift &= 0xff c'est plus geek! */
/* On patiente avent le prochain affichage */
SDL_Delay(time_left(nextTime));
nextTime += TICK_INTERVAL;
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
Avec ces petits trucs, vous pouvez arriver à avoir des résultats bluffants.
Variez les palettes, testez des fonctions...
Postez vos créations ici, avec peut être une miniature du résultat si c'est possible.
En éspérant voir bientôt pleins de jolis plasmas dans ce topic.
a+
Et n'hésitez pas si vous avez la moindre question...
A vrai dire l'aléatoire je l'ai tenté vraiment parce que j'arrivais pas à avoir un bon rendu
Sinon en modifiant un peu mes fonctions j'arrive à ce résultat :
Le code :
#include <SDL.h>
#include <math.h>
#define PI 3.14159265
#define PI2 6.28318531
#define TICK_INTERVAL 20
#define SHIFT_SPEED 2
void fatal_error(char *msg, char *error) {
fprintf(stderr, "%s: %s\n", msg, error);
exit(EXIT_FAILURE);
}
Uint32 time_left(Uint32 nextTime)
{
Uint32 now = SDL_GetTicks();
return nextTime <= now ? 0 : nextTime - now;
}
void putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Uint8 rond(Sint16 x, Sint16 y) {
return (x * x + y * y) % 256;
}
Uint8 carre(Sint16 x, Sint16 y) {
return (x * y) % 256;
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y)
{
Uint8 color = (rond(x, y) + carre(x, y)) / 2;
putPixel(s, x, y, color);
}
void init_screen(SDL_Surface *s)
{
Sint16 x, y;
if ( SDL_MUSTLOCK(s) )
if ( SDL_LockSurface(s) < 0 )
fatal_error("Can't lock screen", SDL_GetError());
for(y = 0; y < s->h; ++y)
for(x = 0; x < s->w; ++x)
applyPlasma(s, x, y);
if (SDL_MUSTLOCK(s))
SDL_UnlockSurface(s);
}
void setPalette(SDL_Surface *s, Uint8 shift)
{
SDL_Color colors[256];
int i;
/* Décalage */
double f = SHIFT_SPEED * (2 * PI * shift / 256);
for(i = 0; i < 256; i++)
{
double angle = i * PI / 128.0 + f;
colors[i].r = 128 + 127 * sin(angle);
colors[i].g = colors[i].r;
colors[i].b = colors[i].r;
}
SDL_SetColors(s, colors, 0 , 256);
}
SDL_Surface * init(void) {
SDL_Surface *screen;
if (SDL_Init( SDL_INIT_VIDEO ) < 0)
fatal_error("Unable to init SDL", SDL_GetError());
screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_HWPALETTE);
if(screen == NULL)
fatal_error("Unable to set 640x480 video", SDL_GetError());
return screen;
}
int main (int argc, char* argv[])
{
SDL_Surface *screen = init();
SDL_bool done = SDL_FALSE;
Uint32 nextTime;
Uint8 shift = 0;
srand(time(NULL));
init_screen(screen);
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while (!done)
{
SDL_Event event;
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE)
done = SDL_TRUE;
/* On actualise la palette enfonction du décalage actuel */
setPalette(screen, shift);
/* On augmente le décalage */
shift++;
/* On maintient le décalage dans la plage 0 - 255 */
shift %= 256;/* -> /*shift &= 0xff c'est plus geek! */
/* On patiente avent le prochain affichage */
SDL_Delay(time_left(nextTime));
nextTime += TICK_INTERVAL;
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
Pour la couleur j'ai essayé mais j'ai toujours les mêmes variantes et c'est pas forcement joli joli je vais tenter autre chose
Jouer un peu avec SDL_SetColors
2 fonctions, c'est a peine assez...
Malgré tout, tu peux obtenir ça
#include <SDL.h>
#include <math.h>
#include <time.h>
#define PI 3.14159265
#define PI2 6.28318531
#define TICK_INTERVAL 20
#define SHIFT_SPEED 2
void fatal_error(char *msg, char *error) {
fprintf(stderr, "%s: %s\n", msg, error);
exit(EXIT_FAILURE);
}
Uint32 time_left(Uint32 nextTime)
{
Uint32 now = SDL_GetTicks();
return nextTime <= now ? 0 : nextTime - now;
}
void putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Uint8 rond(Sint16 x, Sint16 y) {
return (x * x + y * y) / 32.0;
}
Uint8 carre(Sint16 x, Sint16 y) {
return (x * y) / 64.0;
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y)
{
Uint8 color = (rond(x, y) + carre(x, y)) / 2;
putPixel(s, x, y, color);
}
void init_screen(SDL_Surface *s)
{
Sint16 x, y;
if ( SDL_MUSTLOCK(s) )
if ( SDL_LockSurface(s) < 0 )
fatal_error("Can't lock screen", SDL_GetError());
for(y = 0; y < s->h; ++y)
for(x = 0; x < s->w; ++x)
applyPlasma(s, x, y);
if (SDL_MUSTLOCK(s))
SDL_UnlockSurface(s);
}
void setPalette(SDL_Surface *s, Uint8 shift)
{
SDL_Color colors[256];
int i;
/* Décalage */
double f = SHIFT_SPEED * (2 * PI * shift / 256);
for(i = 0; i < 256; i++)
{
double angle = i * PI / 128.0 + f;
colors[i].r = 128 + 127 * cos(i * PI / 128 + f);
colors[i].g = 128 + 127 * sin(i * PI / 128 + f) ;
colors[i].b = 128 - 127 * cos(i * PI / 128 + f);
}
SDL_SetColors(s, colors, 0 , 256);
}
SDL_Surface * init(void) {
SDL_Surface *screen;
if (SDL_Init( SDL_INIT_VIDEO ) < 0)
fatal_error("Unable to init SDL", SDL_GetError());
screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_HWPALETTE);
if(screen == NULL)
fatal_error("Unable to set 640x480 video", SDL_GetError());
return screen;
}
int main (int argc, char* argv[])
{
SDL_Surface *screen = init();
SDL_bool done = SDL_FALSE;
Uint32 nextTime;
Uint8 shift = 0;
srand(time(NULL));
init_screen(screen);
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while (!done)
{
SDL_Event event;
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE)
done = SDL_TRUE;
/* On actualise la palette enfonction du décalage actuel */
setPalette(screen, shift);
/* On augmente le décalage */
shift++;
/* On maintient le décalage dans la plage 0 - 255 */
shift %= 256;/* -> /*shift &= 0xff c'est plus geek! */
/* On patiente avent le prochain affichage */
SDL_Delay(time_left(nextTime));
nextTime += TICK_INTERVAL;
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
Ce n'est pas si mal...
Essaye de cumuler plus de fonctions.
Sinon rien qu'avec les 4 malheureuses fonctions que j'ai montré et une palette sympa, on fait des trucs de warrior...
Et merci pour ta participation...
Je me rend compte que je n'ai pas été très clair sur la création des fonctions...
prenons la fonction f(x) = sin(2 * PI * x / SCR_W)
Les fonctions de <math.h> travaillent avec des angles en radian.
Ici, je découpe mon cercle en SCR_W parties.
la plage 0 à 2 * PI s'étendra de 0 à SCR_W.
en multipliant l'angle je change la fréquence...
f(x) = sin((2 * PI * x / SCR_W) * fréquence)
Un autre pour la route. Et peux être pour vous donner envie d'essayer.
#include <SDL.h>
#include <math.h>
#define SCR_W 640
#define SCR_H 480
#define PI 3.14159265
#define PI2 6.28318531
#define TICK_INTERVAL 20
/* Vitesses des décalages appliqué aux composantes RGB */
#define R_SHIFT_SPEED 1
#define G_SHIFT_SPEED 2
#define B_SHIFT_SPEED 3
#define dist(a, b)(sqrt((a) * (a) + (b) * (b)))
Uint32 time_left(Uint32 nextTime)
{
Uint32 now = SDL_GetTicks();
return nextTime <= now ? 0 : nextTime - now;
}
void putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch (bpp)
{
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
}
else
{
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Uint8 f1(Sint16 x, Sint16 y)
{
return 128 + 127 * sin(dist(SCR_W / 2.0 - x, SCR_H / 2.0 - y) / 32.0);
}
Uint8 f2(Sint16 x)
{
return 128 + 127 * sin(x * PI2 / SCR_W);
}
Uint8 f3(Sint16 y)
{
return 128 + 127 * sin(y * PI2 / SCR_H);
}
Uint8 f4(Sint16 x, Sint16 y)
{
return 128 + 127 * sin((x + y) * PI2 / (SCR_W + SCR_H));
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y)
{
Uint8 color = (f1(x, y) + f2(x) + f3(y) + f4(x, y))/ 4;
putPixel(s, x, y, color);
}
void init(SDL_Surface *s)
{
Sint16 x, y;
if ( SDL_MUSTLOCK(s) )
if ( SDL_LockSurface(s) < 0 )
{
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
exit (EXIT_FAILURE);
}
for (y = 0; y < s->h; ++y)
for (x = 0; x < s->w; ++x)
applyPlasma(s, x, y);
if (SDL_MUSTLOCK(s))
SDL_UnlockSurface(s);
}
void setPalette(SDL_Surface *s, Uint8 shift)
{
SDL_Color colors[256];
int i;
for (i = 0; i < 256; i++)
{
double f = PI2 * ((shift + i) % 256) / 256;
colors[i].r = 128 + 127 * sin(R_SHIFT_SPEED * f);
colors[i].g = 128 + 127 * sin(G_SHIFT_SPEED * f);
colors[i].b = 128 + 127 * sin(B_SHIFT_SPEED * f);
}
SDL_SetColors(s, colors, 0 , 256);
}
int main (int argc, char* argv[])
{
SDL_bool done = SDL_FALSE;
SDL_Surface *screen;
Uint32 nextTime;
Uint8 shift = 0;
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError() );
return EXIT_FAILURE;
}
screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE | SDL_HWPALETTE);
if (screen == NULL)
{
fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
init(screen);
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while (!done)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
done = SDL_TRUE;
break;
case SDL_KEYDOWN:
{
if (event.key.keysym.sym == SDLK_ESCAPE)
done = SDL_TRUE;
break;
}
}
}
/* On actualise la palette enfonction du décalage actuel */
setPalette(screen, shift);
/* On augmente le décalage */
shift++;
/* On maintient le décalage dans la plage 0 - 255 */
shift %= 256;/* -> shift &= 0xff c'est plus geek! */
/* On patiente avent le prochain affichage */
SDL_Delay(time_left(nextTime));
nextTime += TICK_INTERVAL;
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
Bon, détérage de topic, mais sa m'a bien fait triper ce p'tit "jeu", alors je poste mon image...
Je n'ai pas utiliser la technique de la palette, mais directement des variations des composantes RGB de chaque pixel.
A chaque démarrage, les couleurs sont choisies au hasard, ainsi que la vitesse de progression que chaque composante RGB, l'amplitude de la fonction periodique_pi, la fréquence de la fonction periodique_pi, ect...
On peut facilement changer la fonction de la fonction periodique_pi, il faut juste qu'elle soit comprise entre -1 et 1 quelque soit le float passé en paramètre. La fonction fmod peut être pratique... La valeur de f est "propotionnée" à PI (i.e. que l'on peut considérer que f est la paramètre d'une fonction PI périodique par rapport à l'écran...)
Le R avance horizontalement, le G verticalement et le B latéralement. Dans mes exemples, les fonction pour R, G et B sont identiques.
Avec periodique_pi: returnsinf(f);
Avec periodique_pi: f=fmod(f,2*M_PI);returnf/(M_PI)-1;
On peux aussi tester sin(f*50): style à carreau très sympa... ect...
Voir faire des fonctions pour R, G, B différentes ect...
C'est un peu une variante à la palette, on est moins contraint, car on peut vraiment faire une fonction par couleur.
Le problème en faisant une moyenne, c'est qu'on aura plus souvent des valeurs proches de la médiane si la distribution des fonctions est égale sur toutes ses valeurs de retour. (c'est pareil avec les dés : il est plus facile d'avoir 7 avec 2 dés que d'avoir 2 ou 12)
Plutôt que de faire une moyenne, pourquoi ne pas faire un modulo avec une palette de couleurs dont la fin rejoint le début. (il vaut mieux compter plus de 3 fonctions différentes pour avoir un rendu acceptable au niveau des couleurs).
Ou encore, pourquoi ne pas utiliser 4 fonctions différentes : 3 pour avoir une fonction par couleur et une dernière fonction pour la luminosité.
Je n'ai pas "le courage" de coder ça mais pourquoi ne pas utiliser des fonctions plus complexes puisque c'est du statique ?
Un exemple éventuel : <math>\(\text{rouge : }\frac{e^{(x+y) \times coef_1}+e^{(-x-y) \times coef_2}}{2} + rand(-2,2)\)</math> <math>\(\text{vert : }\frac{e^{(x-y) \times coef_3}-e^{(-x+y) \times coef_4}}{2} + rand(-2,2)\)</math> <math>\(\text{bleu : }arctan(x+y)\times coef_5 + rand(-2,2)\)</math> <math>\(\text{luminosite : }(x - x_1)^2 + (y - y_1)^2 - (x - x_2)^2 - (y - y_2)^2\)</math>
Des coefficients peuvent être pris au hasard ou calculés en fonction de l'image. Ne pas oublier de faire un modulo si ça dépasse.
Pour la luminosité, il s'agit de faire une différence entre la distance au carré entre un point et un autre.
La randomisation ne doit pas être trop grande pour éviter les sauts brutaux entre les différentes couleurs. Une autre manière de faire cette randomisation serait de prendre le rand des valeurs en haut et à gauche du pixel considérer et d'ajouter +- 1 à la moyenne de ce random.
Alors AstroB ce que tu fais n'est plus trop un plasma(visuellement), mais c'est très sympa.
fmin et fmax, tu trouves ça ou? c'est inconnu chez moi.
@Alienore: effectivement, rien n'empêche d'utiliser des fonctions plus complexes.
Même si on était pas en "statique", on pourrait en précalculant. (même pas sur qu'aujourd'hui ce soit nécessaire.).
D'ailleurs sur le premier post je donne un lien pour tester des fonctions.
edit: ce n'était pas dans le premier post lien
Et un un lien sympa pour tester des fonctions.
En fait, ce qui est présenté c'est juste un amuse bouche, un cycle de couleur.
Un vrai plasma consiste au "mélange" de différentes surfaces basées sur des fonctions, chacune se déplaçant selon son propre schéma.
Au départ je voulais le présenter mais vu le succès ahurissant du topic, j'ai stoppé.
Finalement, je prendrais peut être le temps de présenter ce plasma.
Il suffit d'ajouter des points centraux aux différentes fonctions et de déplacer ces points petit à petit au cours du temps pour avoir un schéma pour chaque surface. Il suffit ensuite d'appliquer les bonnes couleurs pour chaque surface.
Il suffit d'ajouter des points centraux aux différentes fonctions et de déplacer ces points petit à petit au cours du temps pour avoir un schéma pour chaque surface. Il suffit ensuite d'appliquer les bonnes couleurs pour chaque surface.
Oui, ce n'est pas vraiment du plasma, mais c'était en fait plus pour montrer une "autre" manière qu'avec la palette cyclique, à savoir en agissant sur chaque composante de la couleur. Après on peut même ajouter des arguments aux fonctions periodic_2piX, tel que la position en x et y, et du coup, ne plus les nommer periodic_2piX mais juste colorX(x, y). J'avais juste fait un exemple simple avec 2-3 fonctions que j'avais sous la main pour m'amuser!
Après comme le suggère Alienore, mais en allant même "plus loin" (i.e. plus réaliser), et même en dynamique, pour avoir quelquechose "d'ultra réaliste", il faudrai utiliser l'équation de la chaleur, que l'on va discrétiser... j'ai trouver un petit site sympa qui rappel (à ceux qui aurait oublié leurs cours de méthodes numériques et consort), comme faire la dicrétisation avec les conditions aux limites (qui dans le cas du plasma peuvent également être placée en interne ect...)
Si on veut pas s'emmerder avec la physique, votre idée est pas mal non plus (et assez proche "thermodynamiquement parlant"), si j'ai bien compris, j'en déduit l'algo suivant:
- On prend un certain nombre de cercles (de différentes taille) avec comme paramètre 3 chiffres (la puissance de R, G et B de chaque)
- On fixe le fond à noir au début
- On se fait se déplacer "aléatoirement" (disont la trajectoire est aléatoire mais une fois dans l'écran elle reste droite jusqu'à sortie)
- Pour chaque x et y, si un cercle est présent, on augment chacune de ses composantes d'un certain nombre (fonction de la "puissance" fournie par le cercle), sinon, on décrémente d'un certain nombre (puissance "dissipée").
Si j'ai le temps, je coderai un petit truc...
fmin et fmax, c'est min et max, mais qui renvoie un float
fmin et fmax, c'est min et max, mais qui renvoie un float
C'est du C99. Je ne connssais pas ces fonctions.
Citation : AstroB
Si j'ai le temps, je coderai un petit truc...
Ne te prive surtout pas.
Par contre on ne travaille pas forcément avec des cercles, mais avec n'importe quel type de forme.
Je vais en coder un en dynamique de mon coté(sans trop de maths. :-°).
Alors le static, c'est pour l'initialiser à "maintenant" et garder la valeur en mémoire pour la prochaine exécution, comme ça en faisant += TICK_INTERVAL, la comparaison reste bonne... si tu enlève le static, tu va avoir tout le temps nextTime = now => pas de delay... mais cela devrait marcher quand même! En fait, il me semble qu'en une version du C, les static doivent etre initialisés à une valeur constante, ce qui expliquerai que ton compilo gueule, car comme c'est une fonction, c'est non constant... y'a moyenne de contourner, ou alors tu met :
Pour l'écran noir, c'est parce qu'il démarre à noir, puis il s'éclaire par les boules... il faut attendre un peu... (qq cycle) et comem sa rame pas mal, ça peu prendre du temps selon ton ordi... Remplace les INIT_X de 0 à 127 par exemple (sa devrait alors être gris...)
On pourrait en faire un globale également.
Je viens de voir un truc
#define TICK_INTERVAL 100
Tu cherches à avoir 10 frames par secondes, c'est voulu?
Et oui ça rame! Sur mon ordi je dois faire du 2 fps
C'est dommage. Faire les calculs en temps réel c'est très couteux.
Je vais voir à essayer de précalculer.
edit: voila.
Ca rame beaucoup moins. C'est très joli comme effet en tout cas.
Tu m'excusera j'ai recodé à ma sauce pour bien comprendre ce que tu souhaitait faire.
J'ai également modifié pour compiler en C90.
#include <SDL/SDL.h>
#include <time.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 20
#define NB_SHAPE 50
#define DEC_R -1
#define DEC_G -1
#define DEC_B -1
#define SHAPE_R (SCR_H/6)
#define SHAPE_COLOR_INC 10
#define SHAPE_POS_INC 3
#define SQUARE(a)((a) * (a))
#define MAX(a, b)((a) > (b) ? (a) : (b))
#define MIN(a, b)((a) < (b) ? (a) : (b))
#define RANDOM(a) ((a) * rand() / (RAND_MAX + 1.0))
#define SET_IN_RANGE(value, min, max)(MIN( MAX( value, min ), max ))
/* Shape -------------------------------------------------------------------- */
typedef struct struct_shape {
unsigned char *data;
int x, y;
int r;
int r_inc, g_inc, b_inc;
int x_inc, y_inc;
} Shape;
/* -------------------------------------------------------------------------- */
static int isAtDistance( int x, int y, int x1, int y1, int distance )
{
return SQUARE( x - x1 ) + SQUARE( y - y1 ) < SQUARE( distance );
}
/* -------------------------------------------------------------------------- */
void Shape_fill( Shape *self )
{
int x, y;
int r = self->r;
int d = r * 2;
for( y = 0; y < d; ++y )
for( x = 0; x < d; ++x )
self->data[y * d + x] = isAtDistance( x, y, r, r, r ) ;
}
Shape* Shape_new( void )
{
Shape *p_new = malloc( sizeof * p_new );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new" );
exit( EXIT_FAILURE );
}
p_new->r = RANDOM( SHAPE_R );
p_new->data = malloc( 4 * SQUARE( p_new->r ) * sizeof * p_new->data );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new data" );
exit( EXIT_FAILURE );
}
/* Coordonnées */
p_new->x = RANDOM( SCR_W );
p_new->y = RANDOM( SCR_H );
/* Incrément pour les composantes RGB */
p_new->r_inc = RANDOM( SHAPE_COLOR_INC );
p_new->g_inc = RANDOM( SHAPE_COLOR_INC );
p_new->b_inc = RANDOM( SHAPE_COLOR_INC );
/* Vitesse en x et y */
do
{
p_new->x_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
p_new->y_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
} while( !p_new->x_inc && !p_new->y_inc );
Shape_fill( p_new );
return p_new;
}
void Shape_delete( Shape **self )
{
if( *self )
free( ( *self )->data ), ( *self )->data = NULL;
free( *self ), *self = NULL;
}
void Shape_update( Shape *self )
{
self->x += self->x_inc;
self->y += self->y_inc;
}
void Shape_display( Shape *self )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
int d = self->r * 2;
for( y = 0; y < d && self->y + y < s->h; y++ )
{
if( self->y + y >= 0 )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + ( self->y + y ) * s->pitch );
for( x = 0; x < d && self->x + x < s->w; x++ )
{
if( x + self->x >= 0 && self->data[y * d + x] )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x + self->x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( r + self->r_inc, 0, 255 );
g = SET_IN_RANGE( g + self->g_inc, 0, 255 );
b = SET_IN_RANGE( b + self->b_inc, 0, 255 );
*( offset + x + self->x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
}
}
/* ShapeArray --------------------------------------------------------------- */
Shape** ShapeArray_new( int n )
{
Shape **p_new = malloc( n * sizeof * p_new );
int i;
for( i = 0; i < n; i++ )
p_new[i] = Shape_new();
return p_new;
}
void ShapeArray_update( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
{
int d = shps[i]->r * 2;
Shape_update( shps[i] );
if( shps[i]->x + d < 0
|| shps[i]->x - d >= SCR_W
|| shps[i]->y + d < 0
|| shps[i]->y - d >= SCR_H )
{
Shape_delete( &shps[i] );
shps[i] = Shape_new();
}
}
}
void ShapeArray_display( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_display( shps[i] );
}
void ShapeArray_delete( Shape ***shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_delete( &( *shps )[i] );
free( *shps ), *shps = NULL;
}
Uint32 time_left( Uint32 *nxtTime )
{
Uint32 now = SDL_GetTicks();
return *nxtTime <= now ? 0 : *nxtTime - now;
}
void smooth( void )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
for( y = 0; y < s->h; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = 0; x < s->w; x++ )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( DEC_R + r, 0, 255 );
g = SET_IN_RANGE( DEC_G + g, 0, 255 );
b = SET_IN_RANGE( DEC_B + b, 0, 255 );
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
int main ( int argc, char* argv[] )
{
SDL_Surface *screen = NULL;
Uint32 startTime, nextTime;
Uint32 currentFrame = 0;
Shape **shapes;
srand( time( NULL ) );
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
exit( EXIT_FAILURE );
screen = SDL_SetVideoMode( SCR_W, SCR_H, 32, SDL_SWSURFACE );
if( screen == NULL )
exit( EXIT_FAILURE );
shapes = ShapeArray_new( NB_SHAPE );
SDL_FillRect( screen, NULL, 0 );
startTime = 0;
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while( !SDL_QuitRequested() )
{
ShapeArray_update( shapes, NB_SHAPE );
smooth();
ShapeArray_display( shapes, NB_SHAPE );
SDL_Delay( time_left( &nextTime ) );
SDL_Flip( screen );
nextTime += TICK_INTERVAL;
currentFrame++;
}
printf( "%.2f fps\n", currentFrame * 1000.0 / ( SDL_GetTicks() - startTime ) );
ShapeArray_delete( &shapes, NB_SHAPE );
SDL_Quit();
( void )argc;
( void )argv;
return 0;
}
J'aimerais bien voir plus d'idées comme celle là. screenshot
Si déja tu passes le nextTime en paramètre, limite pas besoin d'un pointeur (sauf p-e la temps de recopie de la valeur dans une variable locale?), j'avais fais pour faire tous le calcul du temps dans time_left directement... mais à priori, il faut soit passer en paramètre (comme tu as fait), soit utiliser l'astuce avec "first_time".
Sinon, bravo pour le précalculé, je n'avais jamais expérimenté çà avant... j'ai bien compris l'histoire de l'allocution dynamique, mais elle n'a "rien" à voir avec le pré-calcul, le pré-calcul ne concerne que "data" et le fait de savoir si le cercle est présent à tel position x;y, ou j'ai manqué une étape.
PS:
1/ Pour compiler chez moi, il manque les cast de pointeurs lors des malloc (mais après ça marche)
2/ sizeof(*p_new->data) est équivalent ) sizeof *p_new->data si j'ai bien compris, j'aurais après un 2e truc!
Je remet le code avec les cast (si qq'un a un compilo capricieux comme le mien) et en une version "carrée" limite plus jolie je trouve (après les gouts hein!)... => un look très "micro chip"
#include <SDL/SDL.h>
#include <time.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 20
#define NB_SHAPE 50
#define DEC_R -1
#define DEC_G -1
#define DEC_B -1
#define SHAPE_R (SCR_H/6)
#define SHAPE_COLOR_INC 3
#define SHAPE_POS_INC 3
#define SQUARE(a)((a) * (a))
#define MAX(a, b)((a) > (b) ? (a) : (b))
#define MIN(a, b)((a) < (b) ? (a) : (b))
#define RANDOM(a) ((a) * rand() / (RAND_MAX + 1.0))
#define SET_IN_RANGE(value, min, max)(MIN( MAX( value, min ), max ))
/* Shape -------------------------------------------------------------------- */
typedef struct struct_shape {
unsigned char *data;
int x, y;
int r;
int r_inc, g_inc, b_inc;
int x_inc, y_inc;
} Shape;
/* -------------------------------------------------------------------------- */
static int isAtDistance( int x, int y, int x1, int y1, int distance )
{
return 1; // SQUARE( x - x1 ) + SQUARE( y - y1 ) < SQUARE( distance );
}
/* -------------------------------------------------------------------------- */
void Shape_fill( Shape *self )
{
int x, y;
int r = self->r;
int d = r * 2;
for( y = 0; y < d; ++y )
for( x = 0; x < d; ++x )
self->data[y * d + x] = isAtDistance( x, y, r, r, r ) ;
}
Shape* Shape_new( void )
{
Shape *p_new = (Shape*) malloc( sizeof * p_new );
int vertical;
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new" );
exit( EXIT_FAILURE );
}
p_new->r = RANDOM( SHAPE_R );
p_new->data = (unsigned char*) malloc( 4 * SQUARE( p_new->r ) * sizeof * p_new->data );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new data" );
exit( EXIT_FAILURE );
}
/* Coordonnées */
p_new->x = RANDOM( SCR_W );
p_new->y = RANDOM( SCR_H );
/* Incrément pour les composantes RGB */
p_new->r_inc = RANDOM( SHAPE_COLOR_INC );
p_new->g_inc = RANDOM( SHAPE_COLOR_INC );
p_new->b_inc = RANDOM( SHAPE_COLOR_INC );
/* Vitesse en x et y */
vertical = RANDOM(2);
if(vertical)
do
{
p_new->x_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
p_new->y_inc = 0;
} while(!p_new->x_inc);
else
do
{
p_new->x_inc = 0;
p_new->y_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
} while(!p_new->y_inc);
Shape_fill( p_new );
return p_new;
}
void Shape_delete( Shape **self )
{
if( *self )
free( ( *self )->data ), ( *self )->data = NULL;
free( *self ), *self = NULL;
}
void Shape_update( Shape *self )
{
self->x += self->x_inc;
self->y += self->y_inc;
}
void Shape_display( Shape *self )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
int d = self->r * 2;
for( y = 0; y < d && self->y + y < s->h; y++ )
{
if( self->y + y >= 0 )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + ( self->y + y ) * s->pitch );
for( x = 0; x < d && self->x + x < s->w; x++ )
{
if( x + self->x >= 0 && self->data[y * d + x] )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x + self->x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( r + self->r_inc, 0, 255 );
g = SET_IN_RANGE( g + self->g_inc, 0, 255 );
b = SET_IN_RANGE( b + self->b_inc, 0, 255 );
*( offset + x + self->x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
}
}
/* ShapeArray --------------------------------------------------------------- */
Shape** ShapeArray_new( int n )
{
Shape **p_new = (Shape**) malloc( n * sizeof * p_new );
int i;
for( i = 0; i < n; i++ )
p_new[i] = Shape_new();
return p_new;
}
void ShapeArray_update( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
{
int d = shps[i]->r * 2;
Shape_update( shps[i] );
if( shps[i]->x + d < 0
|| shps[i]->x - d >= SCR_W
|| shps[i]->y + d < 0
|| shps[i]->y - d >= SCR_H )
{
Shape_delete( &shps[i] );
shps[i] = Shape_new();
}
}
}
void ShapeArray_display( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_display( shps[i] );
}
void ShapeArray_delete( Shape ***shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_delete( &( *shps )[i] );
free( *shps ), *shps = NULL;
}
Uint32 time_left( Uint32 *nxtTime )
{
Uint32 now = SDL_GetTicks();
return *nxtTime <= now ? 0 : *nxtTime - now;
}
void smooth( void )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
for( y = 0; y < s->h; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = 0; x < s->w; x++ )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( DEC_R + r, 0, 255 );
g = SET_IN_RANGE( DEC_G + g, 0, 255 );
b = SET_IN_RANGE( DEC_B + b, 0, 255 );
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
int main ( int argc, char* argv[] )
{
SDL_Surface *screen = NULL;
Uint32 startTime, nextTime;
Uint32 currentFrame = 0;
Shape **shapes;
srand( time( NULL ) );
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
exit( EXIT_FAILURE );
screen = SDL_SetVideoMode( SCR_W, SCR_H, 32, SDL_SWSURFACE );
if( screen == NULL )
exit( EXIT_FAILURE );
shapes = ShapeArray_new( NB_SHAPE );
SDL_FillRect( screen, NULL, 0 );
startTime = 0;
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while( !SDL_QuitRequested() )
{
ShapeArray_update( shapes, NB_SHAPE );
smooth();
ShapeArray_display( shapes, NB_SHAPE );
SDL_Delay( time_left( &nextTime ) );
SDL_Flip( screen );
nextTime += TICK_INTERVAL;
currentFrame++;
}
printf( "%.2f fps\n", currentFrame * 1000.0 / ( SDL_GetTicks() - startTime ) );
ShapeArray_delete( &shapes, NB_SHAPE );
SDL_Quit();
( void )argc;
( void )argv;
return 0;
}
Par contre si tu dois caster malloc, c'est que tu compiles en c++.
C'est pour ça que j'ai mis self et non this, pour que tu n'ai pas trop de boulot pour compiler.
Et encore une fois merci pour l'idée.
Citation : AstroB
Si déja tu passes le nextTime en paramètre, limite pas besoin d'un pointeur
C'est toute l'astuce. C'est équivalent au static.
edit: non, tu as raison le pointeur est inutile.
Pour l'alloc dynamique effectivement aucun rapport avec le précalculé, c'est juste que je gère mieux comme ça.
Merci encore pour ton code!
edit: comme quoi il y a de quoi s'amuser à tout niveau avec ce genre de choses.
Bon, si ça intéresse qq, on peut faire des trucs visuellement très sympa sans faire tous les hacks des qq codes dessus.
Il faut essayer.
@alienore: Si jamais tu as le temps ce serait sympa, et certainement très intéressant.
De rien pour l'idée, ça m'est venu aussi grâce aux idées de chacun...
Pour l'histoire du pointeur, je demande si c'est n'est pas un poil plus rapide dans le sens où il n'y a pas besoin de recopier la valeur de la variable dans une variable temporaire, mais d'aller pointer directement à l'adresse donnée... je ne sais pas...
En fait, c'est bien ce qui me semblait, mais le pré-calcul n'est utile que pour les cercles, en carré, il n'y en a pas besoin...
En fait, même avec les cercles, sans pré-calcule sa passerai aussi, c'est surtout qu'il y avait un "problème" dans mon algo', il était mal optimisé, je bouclais sur tout l'écran pour chaque carré, alors qu'il suffisait, comme tu le fait, de boucler sur la zone de l'écran où le carré est... C'est ce que j'ai fais une ma version corrigée:
EDIT: Ma version corrigée marche mieux, mais est toujours plus lente que la tienne, mais je ne vois pas pourquoi... si jamais tu trouve, ça m'intéresse! Car j'ai viré le pré-calcul (dans la struct data) dans ta version (car elle ne servais pas dans les carrés) et j'ai corrigé mon algo, donc là cela devrait être globalement équivalent, mais non, c'est toujours plus lent!
D'où les 2 versions (avec allocation dynamique et sans, i.e. ma version d'origine, corrigée et modifiée):
#include <SDL/SDL.h>
#include <time.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 40
#define NB_SHAPE 50
#define DEC_R -1
#define DEC_G -1
#define DEC_B -1
#define SHAPE_R (SCR_H/6)
#define SHAPE_COLOR_INC 3
#define SHAPE_POS_INC 3
#define SQUARE(a)((a) * (a))
#define MAX(a, b)((a) > (b) ? (a) : (b))
#define MIN(a, b)((a) < (b) ? (a) : (b))
#define RANDOM(a) ((a) * rand() / (RAND_MAX + 1.0))
#define SET_IN_RANGE(value, min, max)(MIN( MAX( value, min ), max ))
/* Shape -------------------------------------------------------------------- */
typedef struct struct_shape {
int x, y;
int r;
int r_inc, g_inc, b_inc;
int x_inc, y_inc;
} Shape;
Shape* Shape_new( void )
{
Shape *p_new = (Shape*) malloc( sizeof * p_new );
int vertical;
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new" );
exit( EXIT_FAILURE );
}
p_new->r = RANDOM( SHAPE_R );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new data" );
exit( EXIT_FAILURE );
}
/* Coordonnées */
p_new->x = RANDOM( SCR_W );
p_new->y = RANDOM( SCR_H );
/* Incrément pour les composantes RGB */
p_new->r_inc = RANDOM( SHAPE_COLOR_INC );
p_new->g_inc = RANDOM( SHAPE_COLOR_INC );
p_new->b_inc = RANDOM( SHAPE_COLOR_INC );
/* Vitesse en x et y */
vertical = RANDOM(2);
if(vertical)
do
{
p_new->x_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
p_new->y_inc = 0;
} while(!p_new->x_inc);
else
do
{
p_new->x_inc = 0;
p_new->y_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
} while(!p_new->y_inc);
return p_new;
}
void Shape_delete( Shape **self )
{
free( *self ), *self = NULL;
}
void Shape_update( Shape *self )
{
self->x += self->x_inc;
self->y += self->y_inc;
}
void Shape_display( Shape *self )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
int d = self->r * 2;
for( y = 0; y < d && self->y + y < s->h; y++ )
{
if( self->y + y >= 0 )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + ( self->y + y ) * s->pitch );
for( x = 0; x < d && self->x + x < s->w; x++ )
{
if( x + self->x >= 0)
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x + self->x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( r + self->r_inc, 0, 255 );
g = SET_IN_RANGE( g + self->g_inc, 0, 255 );
b = SET_IN_RANGE( b + self->b_inc, 0, 255 );
*( offset + x + self->x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
}
}
/* ShapeArray --------------------------------------------------------------- */
Shape** ShapeArray_new( int n )
{
Shape **p_new = (Shape**) malloc( n * sizeof * p_new );
int i;
for( i = 0; i < n; i++ )
p_new[i] = Shape_new();
return p_new;
}
void ShapeArray_update( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
{
int d = shps[i]->r * 2;
Shape_update( shps[i] );
if( shps[i]->x + d < 0
|| shps[i]->x - d >= SCR_W
|| shps[i]->y + d < 0
|| shps[i]->y - d >= SCR_H )
{
Shape_delete( &shps[i] );
shps[i] = Shape_new();
}
}
}
void ShapeArray_display( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_display( shps[i] );
}
void ShapeArray_delete( Shape ***shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_delete( &( *shps )[i] );
free( *shps ), *shps = NULL;
}
Uint32 time_left( Uint32 *nxtTime )
{
Uint32 now = SDL_GetTicks();
return *nxtTime <= now ? 0 : *nxtTime - now;
}
void smooth( void )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
for( y = 0; y < s->h; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = 0; x < s->w; x++ )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( DEC_R + r, 0, 255 );
g = SET_IN_RANGE( DEC_G + g, 0, 255 );
b = SET_IN_RANGE( DEC_B + b, 0, 255 );
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
int main ( int argc, char* argv[] )
{
SDL_Surface *screen = NULL;
Uint32 startTime, nextTime;
Uint32 currentFrame = 0;
Shape **shapes;
srand( time( NULL ) );
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
exit( EXIT_FAILURE );
screen = SDL_SetVideoMode( SCR_W, SCR_H, 32, SDL_SWSURFACE );
if( screen == NULL )
exit( EXIT_FAILURE );
shapes = ShapeArray_new( NB_SHAPE );
SDL_FillRect( screen, NULL, 0 );
startTime = 0;
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while( !SDL_QuitRequested() )
{
ShapeArray_update( shapes, NB_SHAPE );
smooth();
ShapeArray_display( shapes, NB_SHAPE );
SDL_Delay( time_left( &nextTime ) );
SDL_Flip( screen );
nextTime += TICK_INTERVAL;
currentFrame++;
}
printf( "%.2f fps\n", currentFrame * 1000.0 / ( SDL_GetTicks() - startTime ) );
ShapeArray_delete( &shapes, NB_SHAPE );
SDL_Quit();
( void )argc;
( void )argv;
return 0;
}
#include <SDL/SDL.h>
#include <math.h>
#include <time.h>
#include <float.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 40
#define NB_SHAPE 50
#define INIT_R 0
#define INIT_G 0
#define INIT_B 0
#define DEC_R -1
#define DEC_G -1
#define DEC_B -1
#define SHAPE_R SCR_H/6
#define SHAPE_COLOR_INC 3
#define SHAPE_POS_INC 3
typedef struct struct_shape{
int x;
int y;
int r;
int r_inc;
int g_inc;
int b_inc;
int x_inc;
int y_inc;
} shape;
Uint32 time_left()
{
static Uint32 nextTime = SDL_GetTicks();
Uint32 now = SDL_GetTicks();
nextTime += TICK_INTERVAL;
return nextTime <= now ? 0 : nextTime - now;
}
int setInRange(int value, int min, int max)
{
return fmin(fmax(value, min), max);
}
int isAtDistance(int x, int y, int x1, int y1, int distance)
{
return (pow(x-x1, 2)+pow(y-y1, 2) < pow(distance, 2));
}
void setPixel(int x, int y, Uint32 color, SDL_Surface *map)
{
if(x>0 && y>0 && x<map->w && y<map->h)
*((Uint32*)(map->pixels) + x + y * map->w) = color;
}
void getPixelColor(int x, int y, SDL_Surface *map, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
{
if(x>0 && y>0 && x<map->w && y<map->h)
SDL_GetRGBA(*((Uint32 *)map->pixels + x + y * map->w),map->format,r,g,b,a);
}
void applyPlasma(SDL_Surface *s, Sint16 x, Sint16 y, int r_inc, int g_inc, int b_inc)
{
Uint8 r, g, b, a;
getPixelColor(x, y, s, &r, &g, &b, &a);
Uint32 color = SDL_MapRGBA(s->format, setInRange(r+r_inc, 0, 255), setInRange(g+g_inc, 0, 255), setInRange(b+b_inc, 0, 255), 255);
setPixel(x, y, color, s);
}
void initPlasma(SDL_Surface *s)
{
int x, y;
Uint32 color = SDL_MapRGBA(s->format, INIT_R, INIT_G, INIT_B, 255);
for (y = 0; y < s->h; ++y)
for (x = 0; x < s->w; ++x)
setPixel(x, y, color, s);
}
void setPlasma(SDL_Surface *s)
{
Sint16 x, y, n;
static shape shapes[NB_SHAPE];
static int first_launch = 1;
int vertical;
if(first_launch)
{
first_launch = 0;
for(n = 0; n < NB_SHAPE; n++)
{
shapes[n].x = rand()%SCR_W;
shapes[n].y = rand()%SCR_H;
shapes[n].r = rand()%SHAPE_R;
shapes[n].r_inc = rand()%SHAPE_COLOR_INC;
shapes[n].g_inc = rand()%SHAPE_COLOR_INC;
shapes[n].b_inc = rand()%SHAPE_COLOR_INC;
vertical = rand()%2;
if(vertical)
do
{
shapes[n].x_inc = rand()%(SHAPE_POS_INC*2) - SHAPE_POS_INC;
shapes[n].y_inc = 0;
} while(!shapes[n].x_inc);
else
do
{
shapes[n].x_inc = 0;
shapes[n].y_inc = rand()%(SHAPE_POS_INC*2) - SHAPE_POS_INC;
} while(!shapes[n].y_inc);
}
}
for(n = 0; n < NB_SHAPE; n++)
{
shapes[n].x += shapes[n].x_inc;
shapes[n].y += shapes[n].y_inc;
if(shapes[n].x-shapes[n].r<0 || shapes[n].x>SCR_W || shapes[n].y-shapes[n].r<0 || shapes[n].y>SCR_H)
{
shapes[n].x = rand()%SCR_W;
shapes[n].y = rand()%SCR_H;
shapes[n].r = rand()%SHAPE_R;
shapes[n].r_inc = rand()%SHAPE_COLOR_INC;
shapes[n].g_inc = rand()%SHAPE_COLOR_INC;
shapes[n].b_inc = rand()%SHAPE_COLOR_INC;
vertical = rand()%2;
if(vertical)
do
{
shapes[n].x_inc = rand()%(SHAPE_POS_INC*2) - SHAPE_POS_INC;
shapes[n].y_inc = 0;
} while(!shapes[n].x_inc);
else
do
{
shapes[n].x_inc = 0;
shapes[n].y_inc = rand()%(SHAPE_POS_INC*2) - SHAPE_POS_INC;
} while(!shapes[n].y_inc);
}
}
for(n = 0; n < NB_SHAPE; n++)
for(y = shapes[n].y; y < shapes[n].y + shapes[n].r*2; y++)
if(y<s->h)
for( x = shapes[n].x; x < shapes[n].x + shapes[n].r*2; x++)
if(x<s->w)
applyPlasma(s, x, y, shapes[n].r_inc, shapes[n].g_inc, shapes[n].b_inc);
for(y = 0; y < s->h; ++y)
for(x = 0; x < s->w; ++x)
applyPlasma(s, x, y, DEC_R, DEC_G, DEC_B);
}
int main (int argc, char* argv[])
{
SDL_bool done = SDL_FALSE;
SDL_Surface *screen = NULL;
srand(time(NULL));
if(SDL_Init(SDL_INIT_VIDEO)==-1) exit(EXIT_FAILURE);
screen = SDL_SetVideoMode(SCR_W, SCR_H, 32, SDL_HWSURFACE | SDL_HWPALETTE);
initPlasma(screen);
while(!done)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
done = SDL_TRUE;
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE)
done = SDL_TRUE;
break;
}
}
setPlasma(screen);
SDL_Delay(time_left());
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
EDIT:
En bonus, une fonction pour faire un flou (gaussien? pas vraiment car la distribution est linéaire...), fonction à lancer dans la boucle du main après avoir fait ShapeArray_display()
Attention, ça fait chauffer le CPU!
void blur(void)
{
SDL_Surface *s = SDL_GetVideoSurface();
SDL_Surface *s_backup = SDL_CreateRGBSurface(SDL_HWSURFACE, s->w, s->h, 32, 0, 0, 0, 0); ;
SDL_Rect position;
int x, y, i, j;
position.x = 0;
position.y = 0;
SDL_BlitSurface(s, NULL, s_backup, &position);
for( y = BLUR_WIDTH; y < s->h-BLUR_WIDTH; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = BLUR_WIDTH; x < s->w-BLUR_WIDTH; x++ )
{
Uint32 r, g, b;
Uint8 r_temp, g_temp, b_temp;
r = 0;
g = 0;
b = 0;
for(i = -BLUR_WIDTH; i <= BLUR_WIDTH; i++)
for(j = -BLUR_WIDTH; j <= BLUR_WIDTH; j++)
{
getPixelColor(x + i, y + j, s_backup, &r_temp, &g_temp, &b_temp);
r += r_temp;
g += g_temp;
b += b_temp;
}
r /= SQUARE(BLUR_WIDTH*2+1);
g /= SQUARE(BLUR_WIDTH*2+1);
b /= SQUARE(BLUR_WIDTH*2+1);
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
En jetant un oeil rapidement, je dirais que c'est juste le nombre d'appel de fonction qui diffère lors de l'affichage.
Pour chaque pixel tu appelel les fonctions getPixelColor et setPixel, alors que j'ai tout mis en dur dans la double boucle.
Dans le même genre je ne calcule l'adresse du début de la ligne qu'à chaque ligne, tandis que tu le calcules plusieurs fois(2), pour chaque pixel.
Tu retrouves ces problèmes lorsque tu atténues chaque pixel également.
L'écart est ici, je pense.
Une autre solution pour atténuer, serait de créer une surface noire avec un alpha de 1 et de blitter cette surface sur l'écran.
Le blittage avec alpha 1 j'y avais pensé aussi, c'est p-e plus efficace (car fait à partir d'une fonction codé dans la SDL...)
Effectivement ,cela doit être le nombre d'appel...
T'a testé le blur (qui rame), pour le coup, sa commence vraiment à ressembler à du plasma (avec un blur width plus important, ça le fait vraiment!) Avec les cercles, plutôt qu'avec les carrés, cela doit être encore mieux!
Sinon j'ai testé, les 2 versions, et en modifiant les tailles max des carrés ou cercles, la vitesse de décrémént de chaque composante, oui on obtient quelque chose qui ressemble à un plasma.
En fait, un plasma, ce serait plutôt l'addition de plusieurs surfaces occupant tout l'écrna.
j'avais zappé.
Citation : AstroB
2/ sizeof(*p_new->data) est équivalent ) sizeof *p_new->data si j'ai bien compris, j'aurais après un 2e truc!
Le blur c'est la fonction blur (flou) que j'ai ajoutée en haut (dans l'édit) voila un code complet:
#include <SDL/SDL.h>
#include <time.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 40
#define NB_SHAPE 50
#define DEC_R -1
#define DEC_G -1
#define DEC_B -1
#define SHAPE_R (SCR_H/6)
#define SHAPE_COLOR_INC 3
#define SHAPE_POS_INC 3
#define BLUR_WIDTH 1
#define SQUARE(a)((a) * (a))
#define MAX(a, b)((a) > (b) ? (a) : (b))
#define MIN(a, b)((a) < (b) ? (a) : (b))
#define RANDOM(a) ((a) * rand() / (RAND_MAX + 1.0))
#define SET_IN_RANGE(value, min, max)(MIN( MAX( value, min ), max ))
/* Shape -------------------------------------------------------------------- */
typedef struct struct_shape {
int x, y;
int r;
int r_inc, g_inc, b_inc;
int x_inc, y_inc;
} Shape;
Shape* Shape_new( void )
{
Shape *p_new = (Shape*) malloc( sizeof * p_new );
int vertical;
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new" );
exit( EXIT_FAILURE );
}
p_new->r = RANDOM( SHAPE_R );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new data" );
exit( EXIT_FAILURE );
}
/* Coordonnées */
p_new->x = RANDOM( SCR_W );
p_new->y = RANDOM( SCR_H );
/* Incrément pour les composantes RGB */
p_new->r_inc = RANDOM( SHAPE_COLOR_INC );
p_new->g_inc = RANDOM( SHAPE_COLOR_INC );
p_new->b_inc = RANDOM( SHAPE_COLOR_INC );
/* Vitesse en x et y */
vertical = RANDOM(2);
if(vertical)
do
{
p_new->x_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
p_new->y_inc = 0;
} while(!p_new->x_inc);
else
do
{
p_new->x_inc = 0;
p_new->y_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
} while(!p_new->y_inc);
return p_new;
}
void Shape_delete( Shape **self )
{
free( *self ), *self = NULL;
}
void Shape_update( Shape *self )
{
self->x += self->x_inc;
self->y += self->y_inc;
}
void Shape_display( Shape *self )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
int d = self->r * 2;
for( y = 0; y < d && self->y + y < s->h; y++ )
{
if( self->y + y >= 0 )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + ( self->y + y ) * s->pitch );
for( x = 0; x < d && self->x + x < s->w; x++ )
{
if( x + self->x >= 0)
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x + self->x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( r + self->r_inc, 0, 255 );
g = SET_IN_RANGE( g + self->g_inc, 0, 255 );
b = SET_IN_RANGE( b + self->b_inc, 0, 255 );
*( offset + x + self->x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
}
}
/* ShapeArray --------------------------------------------------------------- */
Shape** ShapeArray_new( int n )
{
Shape **p_new = (Shape**) malloc( n * sizeof * p_new );
int i;
for( i = 0; i < n; i++ )
p_new[i] = Shape_new();
return p_new;
}
void ShapeArray_update( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
{
int d = shps[i]->r * 2;
Shape_update( shps[i] );
if( shps[i]->x + d < 0
|| shps[i]->x - d >= SCR_W
|| shps[i]->y + d < 0
|| shps[i]->y - d >= SCR_H )
{
Shape_delete( &shps[i] );
shps[i] = Shape_new();
}
}
}
void ShapeArray_display( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_display( shps[i] );
}
void ShapeArray_delete( Shape ***shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_delete( &( *shps )[i] );
free( *shps ), *shps = NULL;
}
Uint32 time_left( Uint32 *nxtTime )
{
Uint32 now = SDL_GetTicks();
return *nxtTime <= now ? 0 : *nxtTime - now;
}
void getPixelColor(int x, int y, SDL_Surface *map, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
{
if(x>0 && y>0 && x<map->w && y<map->h)
SDL_GetRGBA(*((Uint32 *)map->pixels + x + y * map->w),map->format,r,g,b,a);
}
void smooth( void )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
for( y = 0; y < s->h; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = 0; x < s->w; x++ )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( DEC_R + r, 0, 255 );
g = SET_IN_RANGE( DEC_G + g, 0, 255 );
b = SET_IN_RANGE( DEC_B + b, 0, 255 );
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
void blur(void)
{
SDL_Surface *s = SDL_GetVideoSurface();
SDL_Surface *s_backup = SDL_CreateRGBSurface(SDL_HWSURFACE, s->w, s->h, 32, 0, 0, 0, 0); ;
SDL_Rect position;
int x, y, i, j;
position.x = 0;
position.y = 0;
SDL_BlitSurface(s, NULL, s_backup, &position);
for( y = BLUR_WIDTH; y < s->h-BLUR_WIDTH; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = BLUR_WIDTH; x < s->w-BLUR_WIDTH; x++ )
{
Uint32 r, g, b;
Uint8 r_temp, g_temp, b_temp;
r = 0;
g = 0;
b = 0;
for(i = -BLUR_WIDTH; i <= BLUR_WIDTH; i++)
for(j = -BLUR_WIDTH; j <= BLUR_WIDTH; j++)
{
getPixelColor(x + i, y + j, s_backup, &r_temp, &g_temp, &b_temp);
r += r_temp;
g += g_temp;
b += b_temp;
}
r /= SQUARE(BLUR_WIDTH*2+1);
g /= SQUARE(BLUR_WIDTH*2+1);
b /= SQUARE(BLUR_WIDTH*2+1);
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
int main ( int argc, char* argv[] )
{
SDL_Surface *screen = NULL;
Uint32 startTime, nextTime;
Uint32 currentFrame = 0;
Shape **shapes;
srand( time( NULL ) );
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
exit( EXIT_FAILURE );
screen = SDL_SetVideoMode( SCR_W, SCR_H, 32, SDL_SWSURFACE );
if( screen == NULL )
exit( EXIT_FAILURE );
shapes = ShapeArray_new( NB_SHAPE );
SDL_FillRect( screen, NULL, 0 );
startTime = 0;
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while( !SDL_QuitRequested() )
{
ShapeArray_update( shapes, NB_SHAPE );
smooth();
ShapeArray_display( shapes, NB_SHAPE );
blur();
SDL_Delay( time_left( &nextTime ) );
SDL_Flip( screen );
nextTime += TICK_INTERVAL;
currentFrame++;
}
printf( "%.2f fps\n", currentFrame * 1000.0 / ( SDL_GetTicks() - startTime ) );
ShapeArray_delete( &shapes, NB_SHAPE );
SDL_Quit();
( void )argc;
( void )argv;
return 0;
}
Je m'attaque à ça demain, mais cette histoire de décrément/incrémente était une "mauvaise idée"...
1/ Il ne faut plus faire de décrément (comme sa, sa va plus vite)
2/ Il faut juste blitter des cercles qui avancent et plus aucun incrément de la couleur de fond => dc sans trainée, juste des cercles pleine couleur, comme sa c'est ultra rapide à blitter
3/ Et l'ingrédient magique: faire un gros flou, i.e. mettre BLUR_WIDTH à une grosse valeur...
... et là, cela devrait vraiment ressembler à un plasma (car le flou "ressemble" à l'équation de diffusion de la chaleur)
Si tu veux valider ce principe, tu peux déja tester avec le code ci-dessus en mettant un gros flou et un gros incrément de couleur, mais sa risque de ramer, à cause du décrément et des formes qui incrémentent la couleur...). Je te met le code (je suis pas chez moi, dc non testé, mais sa devrait marcher):
#include <SDL/SDL.h>
#include <time.h>
#define SCR_W 640
#define SCR_H 480
#define TICK_INTERVAL 40
#define NB_SHAPE 50
#define DEC_R 0
#define DEC_G 0
#define DEC_B 0
#define SHAPE_R (SCR_H/6)
#define SHAPE_COLOR_INC 225
#define SHAPE_POS_INC 3
#define BLUR_WIDTH 20
#define SQUARE(a)((a) * (a))
#define MAX(a, b)((a) > (b) ? (a) : (b))
#define MIN(a, b)((a) < (b) ? (a) : (b))
#define RANDOM(a) ((a) * rand() / (RAND_MAX + 1.0))
#define SET_IN_RANGE(value, min, max)(MIN( MAX( value, min ), max ))
/* Shape -------------------------------------------------------------------- */
typedef struct struct_shape {
int x, y;
int r;
int r_inc, g_inc, b_inc;
int x_inc, y_inc;
} Shape;
Shape* Shape_new( void )
{
Shape *p_new = (Shape*) malloc( sizeof * p_new );
int vertical;
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new" );
exit( EXIT_FAILURE );
}
p_new->r = RANDOM( SHAPE_R );
if( p_new == NULL )
{
fprintf( stderr, "Error : Shape_new data" );
exit( EXIT_FAILURE );
}
/* Coordonnées */
p_new->x = RANDOM( SCR_W );
p_new->y = RANDOM( SCR_H );
/* Incrément pour les composantes RGB */
p_new->r_inc = RANDOM( SHAPE_COLOR_INC );
p_new->g_inc = RANDOM( SHAPE_COLOR_INC );
p_new->b_inc = RANDOM( SHAPE_COLOR_INC );
/* Vitesse en x et y */
vertical = RANDOM(2);
if(vertical)
do
{
p_new->x_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
p_new->y_inc = 0;
} while(!p_new->x_inc);
else
do
{
p_new->x_inc = 0;
p_new->y_inc = RANDOM( SHAPE_POS_INC * 2 ) - SHAPE_POS_INC;
} while(!p_new->y_inc);
return p_new;
}
void Shape_delete( Shape **self )
{
free( *self ), *self = NULL;
}
void Shape_update( Shape *self )
{
self->x += self->x_inc;
self->y += self->y_inc;
}
void Shape_display( Shape *self )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
int d = self->r * 2;
for( y = 0; y < d && self->y + y < s->h; y++ )
{
if( self->y + y >= 0 )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + ( self->y + y ) * s->pitch );
for( x = 0; x < d && self->x + x < s->w; x++ )
{
if( x + self->x >= 0)
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x + self->x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( r + self->r_inc, 0, 255 );
g = SET_IN_RANGE( g + self->g_inc, 0, 255 );
b = SET_IN_RANGE( b + self->b_inc, 0, 255 );
*( offset + x + self->x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
}
}
/* ShapeArray --------------------------------------------------------------- */
Shape** ShapeArray_new( int n )
{
Shape **p_new = (Shape**) malloc( n * sizeof * p_new );
int i;
for( i = 0; i < n; i++ )
p_new[i] = Shape_new();
return p_new;
}
void ShapeArray_update( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
{
int d = shps[i]->r * 2;
Shape_update( shps[i] );
if( shps[i]->x + d < 0
|| shps[i]->x - d >= SCR_W
|| shps[i]->y + d < 0
|| shps[i]->y - d >= SCR_H )
{
Shape_delete( &shps[i] );
shps[i] = Shape_new();
}
}
}
void ShapeArray_display( Shape **shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_display( shps[i] );
}
void ShapeArray_delete( Shape ***shps, int n )
{
int i;
for( i = 0; i < n; i++ )
Shape_delete( &( *shps )[i] );
free( *shps ), *shps = NULL;
}
Uint32 time_left( Uint32 *nxtTime )
{
Uint32 now = SDL_GetTicks();
return *nxtTime <= now ? 0 : *nxtTime - now;
}
void getPixelColor(int x, int y, SDL_Surface *map, Uint8 *r, Uint8 *g, Uint8 *b)
{
if(x>0 && y>0 && x<map->w && y<map->h)
SDL_GetRGB(*((Uint32 *)map->pixels + x + y * map->w),map->format,r,g,b);
}
void smooth( void )
{
SDL_Surface *s = SDL_GetVideoSurface();
int x, y;
for( y = 0; y < s->h; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = 0; x < s->w; x++ )
{
Uint8 r, g, b;
SDL_GetRGB( *( offset + x ), s->format, &r, &g, &b );
r = SET_IN_RANGE( DEC_R + r, 0, 255 );
g = SET_IN_RANGE( DEC_G + g, 0, 255 );
b = SET_IN_RANGE( DEC_B + b, 0, 255 );
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
void blur(void)
{
SDL_Surface *s = SDL_GetVideoSurface();
SDL_Surface *s_backup = SDL_CreateRGBSurface(SDL_HWSURFACE, s->w, s->h, 32, 0, 0, 0, 0); ;
SDL_Rect position;
int x, y, i, j;
position.x = 0;
position.y = 0;
SDL_BlitSurface(s, NULL, s_backup, &position);
for( y = BLUR_WIDTH; y < s->h-BLUR_WIDTH; y++ )
{
Uint32 *offset = ( Uint32 * )( ( Uint8 * )s->pixels + y * s->pitch ) ;
for ( x = BLUR_WIDTH; x < s->w-BLUR_WIDTH; x++ )
{
Uint32 r, g, b;
Uint8 r_temp, g_temp, b_temp;
r = 0;
g = 0;
b = 0;
for(i = -BLUR_WIDTH; i <= BLUR_WIDTH; i++)
for(j = -BLUR_WIDTH; j <= BLUR_WIDTH; j++)
{
getPixelColor(x + i, y + j, s_backup, &r_temp, &g_temp, &b_temp);
r += r_temp;
g += g_temp;
b += b_temp;
}
r /= SQUARE(BLUR_WIDTH*2+1);
g /= SQUARE(BLUR_WIDTH*2+1);
b /= SQUARE(BLUR_WIDTH*2+1);
*( offset + x ) = ( r << 16 ) + ( g << 8 ) + ( b );
}
}
}
int main ( int argc, char* argv[] )
{
SDL_Surface *screen = NULL;
Uint32 startTime, nextTime;
Uint32 currentFrame = 0;
Shape **shapes;
srand( time( NULL ) );
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
exit( EXIT_FAILURE );
screen = SDL_SetVideoMode( SCR_W, SCR_H, 32, SDL_SWSURFACE );
if( screen == NULL )
exit( EXIT_FAILURE );
shapes = ShapeArray_new( NB_SHAPE );
SDL_FillRect( screen, NULL, 0 );
startTime = 0;
nextTime = SDL_GetTicks() + TICK_INTERVAL;
while( !SDL_QuitRequested() )
{
ShapeArray_update( shapes, NB_SHAPE );
smooth();
ShapeArray_display( shapes, NB_SHAPE );
blur();
SDL_Delay( time_left( &nextTime ) );
SDL_Flip( screen );
nextTime += TICK_INTERVAL;
currentFrame++;
}
printf( "%.2f fps\n", currentFrame * 1000.0 / ( SDL_GetTicks() - startTime ) );
ShapeArray_delete( &shapes, NB_SHAPE );
SDL_Quit();
( void )argc;
( void )argv;
return 0;
}
Le "problème", c'est que je suis plus à l'aise en C++ pour ce genre de code or ici, c'est du C. Par ailleurs, la SFML est plus simple à utiliser en C++ qu'en C.
Mon premier essai aléatoire ressemble plus à une télévision qui ne capte pas qu'à du plasma :
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.