Accueil > > > BLUE FIRE (ANIMATION DE FLAMMES - EXEMPLE DIRECTDRAW PLEIN ECRAN)
BLUE FIRE (ANIMATION DE FLAMMES - EXEMPLE DIRECTDRAW PLEIN ECRAN)
Information sur la source
Description
Algorythme d'effet fraphique 2D de flammes, utilisant l'interface DirectDraw en plein ecran.
Source
- //Compilé avec Borland C++ Builder 4
-
- /*----------------------------------------------------------------------------*
- | |
- | Dessiner des Flammes, Unité principale (Feu.cpp) |
- | |
- | programmé par Blustuff |
- | |
- *----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------*
- | Includes |
- *----------------------------------------------------------------------------*/
-
- #include <windows.h>
- #include "affichage.cpp"
-
- //Uniquement pour Borland (Les lignes suivantes permette la liaision des librairies DirectDraw) :
- #include <condefs.h>
- USELIB("..\mssdk\lib\borland\dxguid.lib");
- USELIB("..\mssdk\lib\borland\ddraw.lib");
-
- /*----------------------------------------------------------------------------*
- | Variables Globales |
- *----------------------------------------------------------------------------*/
-
- bool FinDeProgramme = false;
-
-
- /*----------------------------------------------------------------------------*
- | Fonction WindowProc |
- *----------------------------------------------------------------------------*/
-
- #pragma argsused //La fonction suivante n'utilise pas tous ses parametres
- LRESULT CALLBACK WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
- {
- switch (uMsg)
- {
- case WM_KEYDOWN :
- if (wParam == VK_ESCAPE)
- FinDeProgramme = true; //Quitter le programme lors de l'appui sur escape
- break;
-
- default : return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
-
- return 0;
- }
-
-
- /*----------------------------------------------------------------------------*
- | Initialisation de la fenêtre |
- *----------------------------------------------------------------------------*/
-
- bool InitialisationFenetre(HINSTANCE hInstance, HWND* hWnd)
- {
- *hWnd = 0;
-
- WNDCLASS wc;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = (WNDPROC) WindowProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = sizeof(DWORD);
- wc.hInstance = hInstance;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "XmplHr17Class";
-
- if (!RegisterClass(&wc))
- return false;
-
- if (!(*hWnd = CreateWindow("XmplHr17Class", "Line Race", WS_VISIBLE|WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstance, NULL)))
- return false;
-
- ShowCursor(false); //Cacher le curseur de la souris
-
- return true;
- }
-
-
- /*----------------------------------------------------------------------------*
- | Fonction WinMain |
- *----------------------------------------------------------------------------*/
-
- #pragma argsused //La fonction suivante n'utilise pas tous ses parametres
- WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
- {
- HWND hWnd;
- MSG msg;
-
- if (!InitialisationFenetre(hInstance, &hWnd))
- return 0;
-
- if (!InitialiseAffichage(hWnd))
- FinDeProgramme = true;
-
- AfficherTexte(SurfaceTexte, "Blustuff Blue Fire", 0, 0, false, 0x00ff0000); //Afficher le texte sur la surface de texte
-
- while (!FinDeProgramme)
- {
- if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- else
- {
- DessinerFlammes(); //Dessiner les flammes
- RECT Destination = {0,0,200,50};
- SurfaceSecondaire->BltFast(40, 130, SurfaceTexte, &Destination, DDBLTFAST_SRCCOLORKEY);//Ecire le texte
- SurfacePrimaire->Flip(0,DDFLIP_DONOTWAIT); //Afficher la surface
- }
- }
-
- DesallocationAffichage();
- return 0;
- }
-
-
-
- /*----------------------------------------------------------------------------*
- | |
- | Dessiner des Flammes, Unité d'affichage V.1.0 (Affichage.cpp) |
- | |
- | programmé par Blustuff |
- | |
- *----------------------------------------------------------------------------*/
-
- /*
- Note du programmeur :
-
- - Ce programme utilise DirectDraw pour initialiser l'affichage, mais accede
- par ses propres fonctions a la mémore vidéo pour la modifier. La connaissance
- de DirectDraw n'est pas importante, la fonction DessinerFlamme et la seulle
- qui puisse etre interessante ici.
-
- - Ce programme n'est pas entièrement optimisé en rapidité. Cela pour diverse
- raison (j'ai la flemme), dont la lisibilité du code qui doit rester a peu près
- acceptable
-
- - Note lexicale : Une interface est une structure de base de DirectX, dont
- chaque autre élément,DirectDraw, DirectSound, DirectInput etc. hérite. Elle
- possède notament la fonction Release() qui permet de désallouer la mémoire qui
- lui était réservée.
- Une Surface est un emplacement en mémoire contenant des
- données susceptible d'etre affichée, a l'ecran ou sur une autre surface.
-
- - J'ai horreur des termes en anglais dans une programme, parce que j'aime bien
- rapeller que les francais ont réalisé les plus beaux programme jusqu'a
- maintenant. Si j'ai laissé des noms de variables en anglais, veuillez m'en
- excuser. (Celles de DX j'y suis pour rien)
-
- - Je n'ai pas tout inventé tout seul. J'ai repris cet algorythme de Franck
- Bauquier (defcon1@caramail.com) sur son site http://defcon1.free.fr/ . J'ai
- juste personalisé les flammes et adapté le programme pour DirectDraw
-
- - Les flammes sont bleues. Ca simplifie vraiment le programme. Si vous voulez
- faire des flammes avec autre chose, il faut revoir une bonne partie du code.
- Les flammes doivent etre traitées couleur par couleur. Si vous voulez faire des
- flammes violettes, vous devez traiter le rouge et le bleu séparement. Mon
- programme ne s'y adapte pas (Et puis j'aime bien le bleu).
-
-
- Pour me contacter :
-
- blustuff@wanadoo.fr
- http://perso.wanadoo.fr/blustuff/
-
- */
-
-
- /*----------------------------------------------------------------------------*
- | Fichier d'en tête |
- *----------------------------------------------------------------------------*/
-
- #include "affichage.h"
-
-
- /*----------------------------------------------------------------------------*
- | Initialisation |
- *----------------------------------------------------------------------------*/
-
- /*
- N'essayez pas trop de vous lancer dans la comprehension du code de
- l'initialisation graphique de DirectDraw si vous n'avez jamais programmé avec
- DirectX. J'appelle ici de nombreuse fonctions que je n'expliquerai pas
- */
-
- bool InitialiseAffichage(HWND hWnd)
- {
- DDSURFACEDESC2 ddsd;
- DDSCAPS2 ddscaps;
-
- //Creation de l'interface DirectDraw
- if (DirectDrawCreateEx(NULL, (void**)&InterfaceDirectDraw, IID_IDirectDraw7, NULL) != DD_OK)
- return false;
-
- //Selection du niveau cooperatif
- if (InterfaceDirectDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) != DD_OK)
- return false;
-
- //Choix du mode d'affichage
- if (InterfaceDirectDraw->SetDisplayMode(LargeurEcran, HauteurEcran, 32, 0, 0) != DD_OK)
- return false;
-
- //Creation des surfaces primaires et secondaires
- ZeroMemory(&ddsd, sizeof(ddsd));
- ZeroMemory(&ddscaps, sizeof(ddscaps));
- ddsd.dwSize = sizeof( ddsd );
- ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
- ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
- ddsd.dwBackBufferCount = 1;
- ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
-
- if (InterfaceDirectDraw->CreateSurface(&ddsd, &SurfacePrimaire, NULL) != DD_OK)
- return false;
-
- //Association du back Buffer
- if (SurfacePrimaire->GetAttachedSurface(&ddscaps, &SurfaceSecondaire) != DD_OK)
- return false;
-
- //Effacement des surfaces
- EffacerSurface(SurfacePrimaire);
- EffacerSurface(SurfaceSecondaire);
-
- //Création et effacement d'une surface réservée au texte
- ZeroMemory(&ddsd,sizeof(ddsd));
- ddsd.dwSize = sizeof(DDSURFACEDESC2);
- ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
- ddsd.dwWidth = 200;
- ddsd.dwHeight = 50;
-
- InterfaceDirectDraw->CreateSurface(&ddsd, &SurfaceTexte, NULL);
-
- DDCOLORKEY key;
- key.dwColorSpaceLowValue = 0x00000000;
- key.dwColorSpaceHighValue = 0x00000000;
- SurfaceTexte->SetColorKey(DDCKEY_SRCBLT, &key);
- EffacerSurface(SurfaceTexte);
-
-
- //Stockage dans un tableau des valeurs en octet pour le débur de chaque ligne de l'ecran
- SurfacePrimaire->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); //Obtention des propriétés de la surface
- SurfacePrimaire->Unlock(NULL);
-
- AlignY = (int*) malloc(ddsd.dwHeight * sizeof(int));
- for (unsigned int y = 0 ; y < ddsd.dwHeight ; y++)
- AlignY[y] = ddsd.lPitch * y / 4;
-
-
- //La fonction retourne true si l'initialisation réussit
-
- return true;
- }
-
-
- /*----------------------------------------------------------------------------*
- | Desallocation Affichage |
- *----------------------------------------------------------------------------*/
-
- /*
- Desallocation de l'affichage : Cette fonction libère l'espace alloué par
- DirectDraw. Il faut vérifier que ces interface aient été allouées d'où
- l'importance d'initialiser les pointeurs vers elle à NULL. Lorsque les
- interfaces sont initialisée, le pointeur prend donc leur adresse, et on sait
- donc que l'on peut les désallouer. Voici donc l'interet de verifier la
- non-nullité des pointeurs vers les interfaces avant d'appeler Release()
- */
-
- void DesallocationAffichage()
- {
- free(AlignY);
-
- if (SurfaceTexte)
- SurfaceTexte->Release();
- if (SurfaceSecondaire)
- SurfaceSecondaire->Release();
- if (SurfacePrimaire)
- SurfacePrimaire->Release();
- if (InterfaceDirectDraw)
- InterfaceDirectDraw->Release();
- }
-
-
- /*----------------------------------------------------------------------------*
- | Affichage de texte (Fonction GDI) |
- *----------------------------------------------------------------------------*/
-
- /*
- Cette fonction fait appel a une fonction GDI de Windows pour afficher du
- texte, cela grace a la compatibilité de DirectX, qui fournit un handle context
- (hdc) pour permetre a la fonction TextOut d'ecrire sur cette surface. Ici on ne
- voit pas très bien le fonctionement interne de l'affichage de texte. Il est en
- réalité plus compliqué puisque DirectX doit informer la fonction GDI de la
- taille de la surface, de son format de pixels, etc. Ca n'a ici aucune
- importance. Cette fonction est lente, mais l'affichage de texte ne recquiert pas
- une grande rapidité. J'ai donc préféré la simplicité a la rapidité. (J'espère
- que vous ne m'en voulez pas trop :) )
- */
-
-
- void AfficherTexte(LPDIRECTDRAWSURFACE7 Surface, char* Text, int X, int Y, bool Center, DWORD TextColor, DWORD BackColor)
- {
- if (InterfaceDirectDraw) //La fonction s'eecute que si l'affichage est initialisé
- {
- HDC hdc;
- if (Surface->GetDC(&hdc) == DD_OK) //Creer un contexte de dessin et bloquer la surface pour cet usage
- {
- if (Center)
- SetTextAlign(hdc, TA_CENTER); //Centrer le texte sur (x,y) si Center est spécifié
- else
- SetTextAlign(hdc, TA_LEFT | TA_TOP); //Sinon (x,y) corespond au coin haut droit du cadre de texte
-
- SetTextColor(hdc,TextColor); //Selection de la couleur du texte
- SetBkColor(hdc,BackColor); //Et du fond
- TextOut(hdc, X, Y, Text, strlen(Text)); //Ecrire le texte
- Surface->ReleaseDC(hdc); //Débloquer la surface pour qu'elle puisse etre réutilisée normalement
- }
- }
- }
-
-
- /*----------------------------------------------------------------------------*
- | Effacer une surface |
- *----------------------------------------------------------------------------*/
-
- /*
- Cette fonction efface une surface quatre octets par quatre octets. Elle est
- optimisée
- */
-
- void EffacerSurface(LPDIRECTDRAWSURFACE7 Surface)
- {
- if (InterfaceDirectDraw) //La fonction s'eecute que si l'affichage est initialisé
- {
- DDSURFACEDESC2 ddsd;
- ddsd.dwSize = sizeof(ddsd);
-
- if (Surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) //Bloquer la surface pour l'ecriture
- {
- register int* FinDeSurface = (int*)((char*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch); //Fin de la surface (lPitch est le nombre d'octets entre deux lignes)
- for (register int* x = (int*)ddsd.lpSurface ; x < FinDeSurface ; x++)
- *x = 0;
-
- Surface->Unlock(NULL); //Debloquer la surface pour usage posterieur
- }
- }
- }
-
-
- /*----------------------------------------------------------------------------*
- | Dessiner les Flammes |
- *----------------------------------------------------------------------------*/
-
- /*
- Voici la fonction interessante : Elle va dessiner les flammes. J'ai tout
- d'abord défini des macros pour obtenir la valeur d'un pixel et une pour changer
- la valeur d'un pixel. Elle sont optimisés pour le mode d'affichage en couleur
- 32 bits , mais ne vérifient jamais si le pixel est hors ecran, ce qui est
- dangereux si on controle mal son usage.
-
- Ensuite viens la fonction proprement dite. Elle suit l'algorythme suivant :
- On trace d'abord une ligne de pixels aléatoirement (appelée foyer). Dans cet
- exemple elle n'est pas réelement aléatoire. J'ai choisi de faire suivre aux
- couleurs une fonction sinusoidale irégulière. C'est a dire que l'angle
- n'évolue pas uniformenent. Cela donerait si on voulait tracer la courbe
- représentative de la fonction, des formes courbes mais sans direction apparente
- ni periode.
-
- L'étape suivante consiste a fiare partir les flammes du foyer. Ici j'ai
- choisit d'attribuer a chaque pixel la valeur moyenne des pixels inferieurs (bas
- gauche, bas milieu, bas droit). Cela permet d'avoir une continuité dans les
- flammes. J'ai mis un plus fort coeficient devant le pixel juste en dessous, de
- telle sorte que les flammes soient plus fines. J'ai ajouté a cette moyenne la
- couleur du pixel précédent a la même place. Cela donne encore une continuité
- mais cette fois-ci dans le temps.
-
- L'effet d'ondulation est effectué par un décalage (quie j'ai appelé z) de
- chaque ligne suivant la fonction sinus. Pour que L'ondulation ne soit pas
- régulière, j'ai décalé l'angle de départ de la fonction sinus a chaque affichage
- d'une valeur aléatoire (c).
-
- Il faut que la pointe des flammes soit plus faible. Avant l'affichage de
- chaque pixel, on décrémente donc sa valeur de 1. De cette manière le foyer est
- nécessairement le plus lumineux.
- Il y a bien sur d'autre algorythmes, et d'autre effet pour dessiner des
- flammes.
- */
-
-
- #define GetLastPixel(X, Y) (*((int*)ddsd1.lpSurface + AlignY[(Y)] + (X))) //Obtention de la couleur du pixel sur la Surface Primaire (Couleur précédente)
- #define GetCurrentPixel(X, Y) (*((int*)ddsd2.lpSurface + AlignY[(Y)] + (X))) //Obtention de la couleur du pixel sur la Surface Secondaire (Couleur courante)
- #define SetPixel(X, Y, Couleur) (*((int*)ddsd2.lpSurface + AlignY[(Y)] + (X)) = (int)(Couleur)) //Définition de la couleur d'un pixel sur la surface secondaire
-
- void DessinerFlammes()
- {
- if (InterfaceDirectDraw)
- {
- DDSURFACEDESC2 ddsd1, ddsd2;
- ddsd1.dwSize = ddsd2.dwSize = sizeof(DDSURFACEDESC2);
-
- //Blocage des surfaces pour pouvoir y dessiner
- if (SurfacePrimaire->Lock(NULL, &ddsd1, DDLOCK_WAIT, NULL) == DD_OK &&
- SurfaceSecondaire->Lock(NULL, &ddsd2, DDLOCK_WAIT, NULL) == DD_OK)
- {
- float c;
-
- //Tracé du foyer
- for (int x = 10 ; x < LargeurEcran-12 ; x++, c += (float(random(100)-50)/140)) //Changer 140 par une valeur plus grande pour avoir des flammes au foyer plus fin
- SetPixel(x, 180, (sin(c)+1)/2*(ddsd1.ddpfPixelFormat.dwBBitMask)); //ddsd1.ddpfPixelFormat.dwBBitMask est la couleur bleue. Par ailleur : 0 < sin(c)+1)/2 < 1
-
- c += random(100); //Décalage d'angle pour la fonction sinus
-
- for (register int y = 179 ; y > 60 ; y--) //Tracé du corps de la flamme
- {
- int z = sin((float)y/5+c)*2; //Décalage de chaque ligne pour l'ondulation
- for (register int x = 1 ; x < LargeurEcran-2 ; x++) //Tracé de la ligne de flamme
- {
- int NouvelleCouleur;
-
- //Calcul de la couleur moyenne
- if (NouvelleCouleur = (GetCurrentPixel(x-1+z, y+1) + GetCurrentPixel(x+z, y+1)*16 + GetCurrentPixel(x+1+z, y+1) + GetLastPixel(x,y)*2)/20)
- NouvelleCouleur--; //Attenuation de la flamme
- SetPixel(x, y, NouvelleCouleur); //Tracé du pixel
- }
- }
- }
-
- SurfacePrimaire->Unlock(NULL);
- SurfaceSecondaire->Unlock(NULL);
- }
- }
-
-
- //----------------------------------------------------------------------------
-
-
- /*----------------------------------------------------------------------------*
- | |
- | Dessiner des Flammes, Unité d'affichage V.1.0 (Affichage.h) |
- | |
- | programmé par Blustuff |
- | |
- *----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------*
- | Includes |
- *----------------------------------------------------------------------------*/
-
- #include <ddraw.h> //Pour l'interface IDirectDraw
- #include <stdlib.h> //Pour random()
- #include <math.h> //Pour sin()
-
-
- /*----------------------------------------------------------------------------*
- | Propriétés de l'Affichage |
- *----------------------------------------------------------------------------*/
-
- /*
- Les valeurs suivantes doivent corespondre a un mode d'ecran existant et supporté
- sinon l'initialisation ne fonctionera pas
- */
- #define LargeurEcran 320
- #define HauteurEcran 200
-
-
-
- /*----------------------------------------------------------------------------*
- | Variables Globales |
- *----------------------------------------------------------------------------*/
-
- LPDIRECTDRAW7 InterfaceDirectDraw = NULL;
- LPDIRECTDRAWSURFACE7 SurfacePrimaire = NULL; //Primary Buffer. En clair, interface représentant la mémore vidéo directement reliée à l'ecran
- LPDIRECTDRAWSURFACE7 SurfaceSecondaire = NULL; //Back Buffer. Surface sur laquelle on dessine avant de proceder au bliting (Je n'epliquerai pas le bliting ici)
- LPDIRECTDRAWSURFACE7 SurfaceTexte = NULL; //Surface pour afficher le texte
-
- int* AlignY; //Tableau de valeurs indiquant la taille en octet jusqu'a une ligne de l'ecran
-
-
- /*----------------------------------------------------------------------------*
- | Fonctions |
- *----------------------------------------------------------------------------*/
-
- bool InitialiseAffichage(HWND hWnd);
- void DesallocationAffichage();
- void AfficherTexte(LPDIRECTDRAWSURFACE7 Surface, char* Text, int X, int Y, bool Center = true, DWORD TextColor = 0x00ffffff, DWORD BackColor = 0x00000000);
- void EffacerSurface(LPDIRECTDRAWSURFACE7 Surface);
- void DessinerFlammes();
-
-
- //----------------------------------------------------------------------------
-
-
-
//Compilé avec Borland C++ Builder 4
/*----------------------------------------------------------------------------*
| |
| Dessiner des Flammes, Unité principale (Feu.cpp) |
| |
| programmé par Blustuff |
| |
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*
| Includes |
*----------------------------------------------------------------------------*/
#include <windows.h>
#include "affichage.cpp"
//Uniquement pour Borland (Les lignes suivantes permette la liaision des librairies DirectDraw) :
#include <condefs.h>
USELIB("..\mssdk\lib\borland\dxguid.lib");
USELIB("..\mssdk\lib\borland\ddraw.lib");
/*----------------------------------------------------------------------------*
| Variables Globales |
*----------------------------------------------------------------------------*/
bool FinDeProgramme = false;
/*----------------------------------------------------------------------------*
| Fonction WindowProc |
*----------------------------------------------------------------------------*/
#pragma argsused //La fonction suivante n'utilise pas tous ses parametres
LRESULT CALLBACK WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN :
if (wParam == VK_ESCAPE)
FinDeProgramme = true; //Quitter le programme lors de l'appui sur escape
break;
default : return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
/*----------------------------------------------------------------------------*
| Initialisation de la fenêtre |
*----------------------------------------------------------------------------*/
bool InitialisationFenetre(HINSTANCE hInstance, HWND* hWnd)
{
*hWnd = 0;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(DWORD);
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "XmplHr17Class";
if (!RegisterClass(&wc))
return false;
if (!(*hWnd = CreateWindow("XmplHr17Class", "Line Race", WS_VISIBLE|WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstance, NULL)))
return false;
ShowCursor(false); //Cacher le curseur de la souris
return true;
}
/*----------------------------------------------------------------------------*
| Fonction WinMain |
*----------------------------------------------------------------------------*/
#pragma argsused //La fonction suivante n'utilise pas tous ses parametres
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
HWND hWnd;
MSG msg;
if (!InitialisationFenetre(hInstance, &hWnd))
return 0;
if (!InitialiseAffichage(hWnd))
FinDeProgramme = true;
AfficherTexte(SurfaceTexte, "Blustuff Blue Fire", 0, 0, false, 0x00ff0000); //Afficher le texte sur la surface de texte
while (!FinDeProgramme)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
DessinerFlammes(); //Dessiner les flammes
RECT Destination = {0,0,200,50};
SurfaceSecondaire->BltFast(40, 130, SurfaceTexte, &Destination, DDBLTFAST_SRCCOLORKEY);//Ecire le texte
SurfacePrimaire->Flip(0,DDFLIP_DONOTWAIT); //Afficher la surface
}
}
DesallocationAffichage();
return 0;
}
/*----------------------------------------------------------------------------*
| |
| Dessiner des Flammes, Unité d'affichage V.1.0 (Affichage.cpp) |
| |
| programmé par Blustuff |
| |
*----------------------------------------------------------------------------*/
/*
Note du programmeur :
- Ce programme utilise DirectDraw pour initialiser l'affichage, mais accede
par ses propres fonctions a la mémore vidéo pour la modifier. La connaissance
de DirectDraw n'est pas importante, la fonction DessinerFlamme et la seulle
qui puisse etre interessante ici.
- Ce programme n'est pas entièrement optimisé en rapidité. Cela pour diverse
raison (j'ai la flemme), dont la lisibilité du code qui doit rester a peu près
acceptable
- Note lexicale : Une interface est une structure de base de DirectX, dont
chaque autre élément,DirectDraw, DirectSound, DirectInput etc. hérite. Elle
possède notament la fonction Release() qui permet de désallouer la mémoire qui
lui était réservée.
Une Surface est un emplacement en mémoire contenant des
données susceptible d'etre affichée, a l'ecran ou sur une autre surface.
- J'ai horreur des termes en anglais dans une programme, parce que j'aime bien
rapeller que les francais ont réalisé les plus beaux programme jusqu'a
maintenant. Si j'ai laissé des noms de variables en anglais, veuillez m'en
excuser. (Celles de DX j'y suis pour rien)
- Je n'ai pas tout inventé tout seul. J'ai repris cet algorythme de Franck
Bauquier (defcon1@caramail.com) sur son site http://defcon1.free.fr/ . J'ai
juste personalisé les flammes et adapté le programme pour DirectDraw
- Les flammes sont bleues. Ca simplifie vraiment le programme. Si vous voulez
faire des flammes avec autre chose, il faut revoir une bonne partie du code.
Les flammes doivent etre traitées couleur par couleur. Si vous voulez faire des
flammes violettes, vous devez traiter le rouge et le bleu séparement. Mon
programme ne s'y adapte pas (Et puis j'aime bien le bleu).
Pour me contacter :
blustuff@wanadoo.fr
http://perso.wanadoo.fr/blustuff/
*/
/*----------------------------------------------------------------------------*
| Fichier d'en tête |
*----------------------------------------------------------------------------*/
#include "affichage.h"
/*----------------------------------------------------------------------------*
| Initialisation |
*----------------------------------------------------------------------------*/
/*
N'essayez pas trop de vous lancer dans la comprehension du code de
l'initialisation graphique de DirectDraw si vous n'avez jamais programmé avec
DirectX. J'appelle ici de nombreuse fonctions que je n'expliquerai pas
*/
bool InitialiseAffichage(HWND hWnd)
{
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
//Creation de l'interface DirectDraw
if (DirectDrawCreateEx(NULL, (void**)&InterfaceDirectDraw, IID_IDirectDraw7, NULL) != DD_OK)
return false;
//Selection du niveau cooperatif
if (InterfaceDirectDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) != DD_OK)
return false;
//Choix du mode d'affichage
if (InterfaceDirectDraw->SetDisplayMode(LargeurEcran, HauteurEcran, 32, 0, 0) != DD_OK)
return false;
//Creation des surfaces primaires et secondaires
ZeroMemory(&ddsd, sizeof(ddsd));
ZeroMemory(&ddscaps, sizeof(ddscaps));
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
if (InterfaceDirectDraw->CreateSurface(&ddsd, &SurfacePrimaire, NULL) != DD_OK)
return false;
//Association du back Buffer
if (SurfacePrimaire->GetAttachedSurface(&ddscaps, &SurfaceSecondaire) != DD_OK)
return false;
//Effacement des surfaces
EffacerSurface(SurfacePrimaire);
EffacerSurface(SurfaceSecondaire);
//Création et effacement d'une surface réservée au texte
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = 200;
ddsd.dwHeight = 50;
InterfaceDirectDraw->CreateSurface(&ddsd, &SurfaceTexte, NULL);
DDCOLORKEY key;
key.dwColorSpaceLowValue = 0x00000000;
key.dwColorSpaceHighValue = 0x00000000;
SurfaceTexte->SetColorKey(DDCKEY_SRCBLT, &key);
EffacerSurface(SurfaceTexte);
//Stockage dans un tableau des valeurs en octet pour le débur de chaque ligne de l'ecran
SurfacePrimaire->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); //Obtention des propriétés de la surface
SurfacePrimaire->Unlock(NULL);
AlignY = (int*) malloc(ddsd.dwHeight * sizeof(int));
for (unsigned int y = 0 ; y < ddsd.dwHeight ; y++)
AlignY[y] = ddsd.lPitch * y / 4;
//La fonction retourne true si l'initialisation réussit
return true;
}
/*----------------------------------------------------------------------------*
| Desallocation Affichage |
*----------------------------------------------------------------------------*/
/*
Desallocation de l'affichage : Cette fonction libère l'espace alloué par
DirectDraw. Il faut vérifier que ces interface aient été allouées d'où
l'importance d'initialiser les pointeurs vers elle à NULL. Lorsque les
interfaces sont initialisée, le pointeur prend donc leur adresse, et on sait
donc que l'on peut les désallouer. Voici donc l'interet de verifier la
non-nullité des pointeurs vers les interfaces avant d'appeler Release()
*/
void DesallocationAffichage()
{
free(AlignY);
if (SurfaceTexte)
SurfaceTexte->Release();
if (SurfaceSecondaire)
SurfaceSecondaire->Release();
if (SurfacePrimaire)
SurfacePrimaire->Release();
if (InterfaceDirectDraw)
InterfaceDirectDraw->Release();
}
/*----------------------------------------------------------------------------*
| Affichage de texte (Fonction GDI) |
*----------------------------------------------------------------------------*/
/*
Cette fonction fait appel a une fonction GDI de Windows pour afficher du
texte, cela grace a la compatibilité de DirectX, qui fournit un handle context
(hdc) pour permetre a la fonction TextOut d'ecrire sur cette surface. Ici on ne
voit pas très bien le fonctionement interne de l'affichage de texte. Il est en
réalité plus compliqué puisque DirectX doit informer la fonction GDI de la
taille de la surface, de son format de pixels, etc. Ca n'a ici aucune
importance. Cette fonction est lente, mais l'affichage de texte ne recquiert pas
une grande rapidité. J'ai donc préféré la simplicité a la rapidité. (J'espère
que vous ne m'en voulez pas trop :) )
*/
void AfficherTexte(LPDIRECTDRAWSURFACE7 Surface, char* Text, int X, int Y, bool Center, DWORD TextColor, DWORD BackColor)
{
if (InterfaceDirectDraw) //La fonction s'eecute que si l'affichage est initialisé
{
HDC hdc;
if (Surface->GetDC(&hdc) == DD_OK) //Creer un contexte de dessin et bloquer la surface pour cet usage
{
if (Center)
SetTextAlign(hdc, TA_CENTER); //Centrer le texte sur (x,y) si Center est spécifié
else
SetTextAlign(hdc, TA_LEFT | TA_TOP); //Sinon (x,y) corespond au coin haut droit du cadre de texte
SetTextColor(hdc,TextColor); //Selection de la couleur du texte
SetBkColor(hdc,BackColor); //Et du fond
TextOut(hdc, X, Y, Text, strlen(Text)); //Ecrire le texte
Surface->ReleaseDC(hdc); //Débloquer la surface pour qu'elle puisse etre réutilisée normalement
}
}
}
/*----------------------------------------------------------------------------*
| Effacer une surface |
*----------------------------------------------------------------------------*/
/*
Cette fonction efface une surface quatre octets par quatre octets. Elle est
optimisée
*/
void EffacerSurface(LPDIRECTDRAWSURFACE7 Surface)
{
if (InterfaceDirectDraw) //La fonction s'eecute que si l'affichage est initialisé
{
DDSURFACEDESC2 ddsd;
ddsd.dwSize = sizeof(ddsd);
if (Surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) //Bloquer la surface pour l'ecriture
{
register int* FinDeSurface = (int*)((char*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch); //Fin de la surface (lPitch est le nombre d'octets entre deux lignes)
for (register int* x = (int*)ddsd.lpSurface ; x < FinDeSurface ; x++)
*x = 0;
Surface->Unlock(NULL); //Debloquer la surface pour usage posterieur
}
}
}
/*----------------------------------------------------------------------------*
| Dessiner les Flammes |
*----------------------------------------------------------------------------*/
/*
Voici la fonction interessante : Elle va dessiner les flammes. J'ai tout
d'abord défini des macros pour obtenir la valeur d'un pixel et une pour changer
la valeur d'un pixel. Elle sont optimisés pour le mode d'affichage en couleur
32 bits , mais ne vérifient jamais si le pixel est hors ecran, ce qui est
dangereux si on controle mal son usage.
Ensuite viens la fonction proprement dite. Elle suit l'algorythme suivant :
On trace d'abord une ligne de pixels aléatoirement (appelée foyer). Dans cet
exemple elle n'est pas réelement aléatoire. J'ai choisi de faire suivre aux
couleurs une fonction sinusoidale irégulière. C'est a dire que l'angle
n'évolue pas uniformenent. Cela donerait si on voulait tracer la courbe
représentative de la fonction, des formes courbes mais sans direction apparente
ni periode.
L'étape suivante consiste a fiare partir les flammes du foyer. Ici j'ai
choisit d'attribuer a chaque pixel la valeur moyenne des pixels inferieurs (bas
gauche, bas milieu, bas droit). Cela permet d'avoir une continuité dans les
flammes. J'ai mis un plus fort coeficient devant le pixel juste en dessous, de
telle sorte que les flammes soient plus fines. J'ai ajouté a cette moyenne la
couleur du pixel précédent a la même place. Cela donne encore une continuité
mais cette fois-ci dans le temps.
L'effet d'ondulation est effectué par un décalage (quie j'ai appelé z) de
chaque ligne suivant la fonction sinus. Pour que L'ondulation ne soit pas
régulière, j'ai décalé l'angle de départ de la fonction sinus a chaque affichage
d'une valeur aléatoire (c).
Il faut que la pointe des flammes soit plus faible. Avant l'affichage de
chaque pixel, on décrémente donc sa valeur de 1. De cette manière le foyer est
nécessairement le plus lumineux.
Il y a bien sur d'autre algorythmes, et d'autre effet pour dessiner des
flammes.
*/
#define GetLastPixel(X, Y) (*((int*)ddsd1.lpSurface + AlignY[(Y)] + (X))) //Obtention de la couleur du pixel sur la Surface Primaire (Couleur précédente)
#define GetCurrentPixel(X, Y) (*((int*)ddsd2.lpSurface + AlignY[(Y)] + (X))) //Obtention de la couleur du pixel sur la Surface Secondaire (Couleur courante)
#define SetPixel(X, Y, Couleur) (*((int*)ddsd2.lpSurface + AlignY[(Y)] + (X)) = (int)(Couleur)) //Définition de la couleur d'un pixel sur la surface secondaire
void DessinerFlammes()
{
if (InterfaceDirectDraw)
{
DDSURFACEDESC2 ddsd1, ddsd2;
ddsd1.dwSize = ddsd2.dwSize = sizeof(DDSURFACEDESC2);
//Blocage des surfaces pour pouvoir y dessiner
if (SurfacePrimaire->Lock(NULL, &ddsd1, DDLOCK_WAIT, NULL) == DD_OK &&
SurfaceSecondaire->Lock(NULL, &ddsd2, DDLOCK_WAIT, NULL) == DD_OK)
{
float c;
//Tracé du foyer
for (int x = 10 ; x < LargeurEcran-12 ; x++, c += (float(random(100)-50)/140)) //Changer 140 par une valeur plus grande pour avoir des flammes au foyer plus fin
SetPixel(x, 180, (sin(c)+1)/2*(ddsd1.ddpfPixelFormat.dwBBitMask)); //ddsd1.ddpfPixelFormat.dwBBitMask est la couleur bleue. Par ailleur : 0 < sin(c)+1)/2 < 1
c += random(100); //Décalage d'angle pour la fonction sinus
for (register int y = 179 ; y > 60 ; y--) //Tracé du corps de la flamme
{
int z = sin((float)y/5+c)*2; //Décalage de chaque ligne pour l'ondulation
for (register int x = 1 ; x < LargeurEcran-2 ; x++) //Tracé de la ligne de flamme
{
int NouvelleCouleur;
//Calcul de la couleur moyenne
if (NouvelleCouleur = (GetCurrentPixel(x-1+z, y+1) + GetCurrentPixel(x+z, y+1)*16 + GetCurrentPixel(x+1+z, y+1) + GetLastPixel(x,y)*2)/20)
NouvelleCouleur--; //Attenuation de la flamme
SetPixel(x, y, NouvelleCouleur); //Tracé du pixel
}
}
}
SurfacePrimaire->Unlock(NULL);
SurfaceSecondaire->Unlock(NULL);
}
}
//----------------------------------------------------------------------------
/*----------------------------------------------------------------------------*
| |
| Dessiner des Flammes, Unité d'affichage V.1.0 (Affichage.h) |
| |
| programmé par Blustuff |
| |
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*
| Includes |
*----------------------------------------------------------------------------*/
#include <ddraw.h> //Pour l'interface IDirectDraw
#include <stdlib.h> //Pour random()
#include <math.h> //Pour sin()
/*----------------------------------------------------------------------------*
| Propriétés de l'Affichage |
*----------------------------------------------------------------------------*/
/*
Les valeurs suivantes doivent corespondre a un mode d'ecran existant et supporté
sinon l'initialisation ne fonctionera pas
*/
#define LargeurEcran 320
#define HauteurEcran 200
/*----------------------------------------------------------------------------*
| Variables Globales |
*----------------------------------------------------------------------------*/
LPDIRECTDRAW7 InterfaceDirectDraw = NULL;
LPDIRECTDRAWSURFACE7 SurfacePrimaire = NULL; //Primary Buffer. En clair, interface représentant la mémore vidéo directement reliée à l'ecran
LPDIRECTDRAWSURFACE7 SurfaceSecondaire = NULL; //Back Buffer. Surface sur laquelle on dessine avant de proceder au bliting (Je n'epliquerai pas le bliting ici)
LPDIRECTDRAWSURFACE7 SurfaceTexte = NULL; //Surface pour afficher le texte
int* AlignY; //Tableau de valeurs indiquant la taille en octet jusqu'a une ligne de l'ecran
/*----------------------------------------------------------------------------*
| Fonctions |
*----------------------------------------------------------------------------*/
bool InitialiseAffichage(HWND hWnd);
void DesallocationAffichage();
void AfficherTexte(LPDIRECTDRAWSURFACE7 Surface, char* Text, int X, int Y, bool Center = true, DWORD TextColor = 0x00ffffff, DWORD BackColor = 0x00000000);
void EffacerSurface(LPDIRECTDRAWSURFACE7 Surface);
void DessinerFlammes();
//----------------------------------------------------------------------------
Conclusion
Peut ramer sur certains PC mais pas sur mon 200 MHz (Je suis ébloui devant certeines choses inexpliquables)
Sources de la même categorie
Commentaires et avis
|
Derniers Blogs
UNE JOLIE-HORLOGE ET PAS QU'UN PEU !UNE JOLIE-HORLOGE ET PAS QU'UN PEU ! par neodante
Pour les possesseurs d'iPhone, ça y est Bijin Tokei - qui se traduit littéralement en Français par " Jolie Horloge " - est arrivé et GRATUITEMENT s'il vous plaît ! Après la version Tokyo, Hokkaido, night club, racing, Gal, "pour les mademoiselles'", . voi...
Cliquez pour lire la suite de l'article par neodante TECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICESTECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICES par ROMELARD Fabrice
Animé par: Gaetan Bouveret et Julien Chomarat Business Connectivity Services (BCS) est dans SharePoint 2010 la version 2 de Business Data Catalog (BDC dans SharePoint 2007). Il s'agit de la solution permettant de visualiser des données provenan...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice [DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE[DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE par orion
Comme de nombreux geek, je suis un grand amateur de série TV et je rate régulièrement des épisodes de mes séries préférés. Une solution s'offre à vous avec ce merveilleux site : Tv Gorge - www.tvgorge.com Moteur de recherche à l'appui, vous pouvez ...
Cliquez pour lire la suite de l'article par orion TECHDAYS PARIS 2010 : LA BI DANS SHAREPOINT 2010TECHDAYS PARIS 2010 : LA BI DANS SHAREPOINT 2010 par ROMELARD Fabrice
Animé par: Vincent Bellet et Baptiste Giraudier La BI dans SharePoint 2010, Les nouveaux services d'application dans SP2010 et SQL Server Reporting services 2008 R2. La BI dans SharePoint est généralisée pour tous afin de permettre à tous les coll...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice
Forum
RE : WIN APIRE : WIN API par racpp
Cliquez pour lire la suite par racpp
Logiciels
DB-MAIN (9.1.0)DB-MAIN (9.1.0)DB-MAIN is a data-modeling and data-architecture tool. It is designed to help developers and anal... Cliquez pour télécharger DB-MAIN Xilisoft DPG Convertisseur (5.1.37.0120)XILISOFT DPG CONVERTISSEUR (5.1.37.0120)Xilisoft DPG Convertisseur offre aux fans de Nintendo DS une bonne solution leur permettant de dé... Cliquez pour télécharger Xilisoft DPG Convertisseur GraphicsGale (2.01.01)GRAPHICSGALE (2.01.01)GraphicsGale est un logiciel de PixelArt avec de nombreuse fonctionnalités permettant de réalisé ... Cliquez pour télécharger GraphicsGale Architecte 3D (Platinum 2010)ARCHITECTE 3D (PLATINUM 2010)Architecte 3D Platinium vous permet de concevoir facilement les plans votre future maison, de l'é... Cliquez pour télécharger Architecte 3D TeamViewer 5 (TeamViewer 5)TEAMVIEWER 5 (TEAMVIEWER 5)Dépanner un ami,expliquer une manipulation devient un jeu d'enfant.
Prise en main d'un autre ord... Cliquez pour télécharger TeamViewer 5
|