Screensaver starfield (effet a la starwar) projection 2d de points 3d

Description

C'est un simple starfield (j'en avais vu aucun sur cppfrance :().
Je l'utilise comme exemple pour montrer la manière d'obtenir des coords 2d de la projection d'un point 3d sur un plan (comment afficher sur un écran 2d des points 3d).
J'utilise openGL juste pour la commodité car je déteste les fonctions GDI. Opengl peut faire la projection tout seul mais le prog aurait peu d'interêt.

On peut changer la couleur des étoiles (R, SHIFT R ,B, SHIFT B, G et SHIFT G)
Chaque étoile a sa propre vitesse et on peut changer la vitesse max avec V et SHIFT V.

J'ai changé la version en screensaver avec les moyens du bord, j'ai vu aucun srceensaver sur cppfrance et je ne sais pas en faire donc après deux trois bidouillages j'ai trouvé comment afficher le screensaver dans la fenêtre d'aperçu des propriétés d'affichage et j'ai fait une boite de dialogue de configuration ça marche !
Téléchargez le Zip pour avoir l'icône et le script de la BDD (visual c++)
La BDD de config c'est seulement 6 edit box n'acceptant que les chiffres et deux boutons (pour ceux qui veulent pas télécharger le zip)

Il y a encore deux trois problèmes au niveau du screensaver (voir en bas), si quelqu'un sait en faire un qu'il me contacte !

Source / Exemple :


/*-----------------------------------------------------------------------------------------------*
//
//                                       Etoile.h
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 25/06/2003 à 20:42:42
//
//Description      : Declarations
//
/*----------------------------------------------------------------------------------------------*/

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <stdlib.h>
#include <string.h>
#include "resource.h"

//Defines
#define TIMER	1		//id du timer
#define d		50
#define ZMAX	500		//Profondeur de creation des etoiles	

//Declarations de variables globales
extern int		Xscr,Yscr;
extern int		xmax,ymax;
extern BYTE		vitessemax;

//Declaration de la classe etoile
class Etoile
{
	int x;		//coords 3d de l'etoile
	int y;
	int z;
	char vitesse;		//vitesse de l'etoile

public :
	int x2d;		//coord de l'etoile sur l'ecran
	int y2d;
	BOOL Inc(void);		//fait avancer l'etoile et calcule x2d et y2d
	Etoile(void);
};

//Declarations des fonctions

void Draw(HDC,Etoile*,BYTE,BYTE,BYTE,WORD);			//fonction de dessin
void Reshape();										//Ajustement de la matrice
void SetupPixelFormat(HDC);							//Set le mode d'affichage
void GetParams(BYTE&,BYTE&,BYTE&,BYTE&,BYTE&,WORD&);//Obtient les parametres du screensaver	
BOOL SauverParams(BYTE,BYTE,BYTE,BYTE,BYTE,WORD);	//Sauve les parametres
void CheckRange(HWND,int,int,int);					//Verifie si la valeur d'une edit box est
													//comprise entre un minimun et un maximum
													//et si la valeur depasse elle la set
													//correctement
void Process(HINSTANCE,HWND = NULL);				//Creation de la fenetre d'affichage
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);	//Gestion des messages de la fentre d'aff	
VOID CALLBACK OnTimer(HWND,UINT,UINT,DWORD);		//Gestion du timer
void ProcessConfig(HINSTANCE);						//Creation de la BDD de configuration
BOOL CALLBACK ConfigProc(HWND,UINT,WPARAM,LPARAM);	//Gestion des message de la BDD de config

/*-----------------------------------------------------------------------------------------------*
//
//                                       Etoile.cpp
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 25/06/2003 à 20:42:01
//
//Description      : Definition des fonctions de la classe etoile
//
/*----------------------------------------------------------------------------------------------*/

#include "Etoile.h"

Etoile::Etoile()
{
	//initialisation des coords
	z = ZMAX;
	x = rand()%(2*xmax+1)-xmax;
	y = rand()%(2*ymax+1)-ymax;
	vitesse = rand()%vitessemax + 1;

	//Calcul de la projection 2d
	x2d = (x*d)/(d+z);
	y2d = (y*d)/(d+z);
}

BOOL Etoile::Inc()
{
	z -= vitesse;		//mise a jour de la coord z
	if(z>0)
	{
		x2d = (x*d)/(d+z);		//Projection2d
		y2d = (y*d)/(d+z);
	}

	if(x2d < -Xscr/2 || x2d >Xscr/2 || y2d < -Yscr/2 || y2d > Yscr/2 || z<=0)
	{					//si on est en dehors des limites on refait une autre etoile
		z = ZMAX;
		x = rand()%(2*xmax+1)-xmax;
		y = rand()%(2*ymax+1)-ymax;
		vitesse = rand()%vitessemax + 1;
		x2d = (x*d)/(d+z);
		y2d = (y*d)/(d+z);
		return FALSE;		//pour la gestion des lignes
	}
	return TRUE;
}

/*-----------------------------------------------------------------------------------------------*
//
//                                       Config.cpp
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 26/06/2003 à 22:10:49
//
//Description      : Regroupe les fonctions de traitement de la configuration
//
/*----------------------------------------------------------------------------------------------*/
#include "Etoile.h"

//------------------------------------------
//Cree la boite de dialogue de configuration
//------------------------------------------
void ProcessConfig(HINSTANCE hInstance)
{
	HWND hWndDlg;
	hWndDlg = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_CONFIG),NULL,&ConfigProc);
	ShowWindow(hWndDlg,SW_SHOW);
}

//------------------------------------------------------
//Fonction de gestion des messages de la boite de config
//------------------------------------------------------
BOOL CALLBACK ConfigProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	BYTE r =			255;
	BYTE g =			255;
	BYTE b =			255;
	BYTE period =		1;
	WORD NbrEtoiles =	3000;

	switch(msg)
	{
	case WM_INITDIALOG :
		GetParams(r,g,b,vitessemax,period,NbrEtoiles);//a la creation on Obtient les parametres
		SetDlgItemInt(hWnd,IDC_R,r,FALSE);		//et on set mes valeurs
		SetDlgItemInt(hWnd,IDC_G,g,FALSE);
		SetDlgItemInt(hWnd,IDC_B,b,FALSE);
		SetDlgItemInt(hWnd,IDC_VITESSEMAX,vitessemax,FALSE);
		SetDlgItemInt(hWnd,IDC_PERIOD,period,FALSE);
		SetDlgItemInt(hWnd,IDC_NBRETOILES,NbrEtoiles,FALSE);
		return FALSE;
	case WM_COMMAND :
		switch(LOWORD(wParam))
		{
		case IDC_ANNULER :
			PostQuitMessage(0);
			return TRUE;
		case IDC_SAVE :			//On sauve les parametres
			if (!SauverParams(GetDlgItemInt(hWnd,IDC_R,NULL,FALSE),
					 		  GetDlgItemInt(hWnd,IDC_G,NULL,FALSE),
							  GetDlgItemInt(hWnd,IDC_B,NULL,FALSE),
							  GetDlgItemInt(hWnd,IDC_VITESSEMAX,NULL,FALSE),
							  GetDlgItemInt(hWnd,IDC_PERIOD,NULL,FALSE),
							  GetDlgItemInt(hWnd,IDC_NBRETOILES,NULL,FALSE)))
							  MessageBox(hWnd,"Erreur impossible d'enregistrer les modifications",
							  "Erreur d'écriture",MB_OK | MB_ICONEXCLAMATION);
			PostQuitMessage(0);
			return TRUE;
		case IDC_R :
			if(HIWORD(wParam)== EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_R,0,255);		//si on perd le focus on verifie que la valeur
				return TRUE;						//soit bien correcte
			}
			break;
		case IDC_G :
			if(HIWORD(wParam) == EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_G,0,255);
				return TRUE;
			}
			break;
		case IDC_B :
			if(HIWORD(wParam) == EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_B,0,255);
				return TRUE;
			}
			break;
		case IDC_VITESSEMAX :
			if(HIWORD(wParam) == EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_VITESSEMAX,1,50);
					return TRUE;
			}
			break;
		case IDC_PERIOD :
			if(HIWORD(wParam) == EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_PERIOD,1,50);
					return TRUE;
			}
			break;
		case IDC_NBRETOILES :
			if(HIWORD(wParam) == EN_KILLFOCUS)
			{
				CheckRange(hWnd,IDC_NBRETOILES,1,50000);
					return TRUE;
			}
			break;
		}
		return FALSE;
	}
	return FALSE;
}

//-------------------------------------
//Obtient les params d'apres le fichier
//-------------------------------------
void GetParams(BYTE& r,BYTE& g,BYTE& b,BYTE& vitessemax,BYTE& period,WORD& NbrEtoiles)
{
	HANDLE	fichier;
	char	cheminfichier[_MAX_PATH];
	DWORD	dummy;			//pour le ReadFile
	char	buffer[7];		//buffer de fichier	

	GetWindowsDirectory(cheminfichier,_MAX_PATH);
	strcat(cheminfichier,"\\Starfield.conf");

	fichier = CreateFile(cheminfichier,		//on ouvre le fichier
						 GENERIC_READ,
						 FILE_SHARE_READ,
						 NULL,
						 OPEN_EXISTING,
						 FILE_ATTRIBUTE_NORMAL,
						 NULL);

	if(fichier != INVALID_HANDLE_VALUE)			//si le fichier existe on recupere les valeurs
	{
		ReadFile(fichier,buffer,7,&dummy,NULL);
		r = buffer[0];			//1er octet  = composante rouge
		g = buffer[1];			//2eme....................verte	
		b = buffer[2];			//3.......................bleue
		vitessemax = buffer[3];	//4 la vitesse max
		period = buffer[4];		//5 le temps entre chaque appel du timer
		NbrEtoiles = MAKEWORD(buffer[5],buffer[6]);	//le nbr d'etoile dans les 2 derniers
		CloseHandle(fichier);
	}
}

//------------------------------------------
//Sauve les params dans le fichier de config
//------------------------------------------
BOOL SauverParams(BYTE r,BYTE g,BYTE b,BYTE vitessemax,BYTE period,WORD NbrEtoiles)
{
	HANDLE	fichier;
	char	cheminfichier[_MAX_PATH];
	DWORD	dummy;

	GetWindowsDirectory(cheminfichier,_MAX_PATH);
	strcat(cheminfichier,"\\Starfield.conf");

	fichier = CreateFile(cheminfichier,		//on ouvre le fichier
						 GENERIC_WRITE,
						 FILE_SHARE_READ,
						 NULL,
						 CREATE_ALWAYS,
						 FILE_ATTRIBUTE_NORMAL,
						 NULL);

	if (fichier == INVALID_HANDLE_VALUE)		//s'il n'existe pas return FALSE
		return FALSE;
	WriteFile(fichier,&r,1,&dummy,NULL);		//sinon on ecrit les données
	WriteFile(fichier,&g,1,&dummy,NULL);
	WriteFile(fichier,&b,1,&dummy,NULL);
	WriteFile(fichier,&vitessemax,1,&dummy,NULL);
	WriteFile(fichier,&period,1,&dummy,NULL);
	WriteFile(fichier,&NbrEtoiles,2,&dummy,NULL);
	CloseHandle(fichier);
	return TRUE;
}

//----------------------------------------------------------------------------------------
//Verifie si la valeur dans l'edit box est entre minimum et maximum et la set correctement
//----------------------------------------------------------------------------------------
void CheckRange(HWND hWnd,int id,int minimum,int maximum)
{
	int temp = GetDlgItemInt(hWnd,id,NULL,FALSE);
	if(temp>maximum)
		SetDlgItemInt(hWnd,id,maximum,FALSE);
	if(temp<minimum)
		SetDlgItemInt(hWnd,id,minimum,FALSE);											
}

/*-----------------------------------------------------------------------------------------------*
//
//                                       StarFieldGL
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 25/06/2003 à 20:40:52
//
//Description      : Un simple starfield pour exposer la methode de projection 3d/2d
//
//Notes             :-Lire le lisezmoi pour avoir une explication de la methode de projection
//	            -Lire ScreenSaver.txt pour avoir des infos si le taitement de la ligne de
//	            commande
//	           -Pas de gestion du password et alt+tab et ctrl+alt+suppr ou touche win ne 
//	           sont pas désactivés
//                       -Ne pas oublier les libs opengl32.lib et glu32.lib	 
//
//
/*----------------------------------------------------------------------------------------------*/

#include "Etoile.h"

//Vars globales
int				Xscr,Yscr;
int				xmax,ymax;
BYTE			vitessemax	= 10;

//----------------
//Fonction WinMain
//----------------
int APIENTRY WINAPI WinMain(HINSTANCE hInstance,  
							HINSTANCE hPrevInstance,   
							LPSTR lpCmdLine,   
							int nCmdShow)
{
	MSG		msg;
	BOOL	Launch = FALSE;		//defini si l'on lance la boule de message

	if(strncmp(lpCmdLine,"/S",2) == 0 || strncmp(lpCmdLine,"/s",2) == 0)
	{
		Process(hInstance);			//si affiche en plein ecran demandé on affiche
		Launch = TRUE;
	}
	if(strncmp(lpCmdLine,"/c",2) == 0 || strcmp(lpCmdLine,"") == 0)
	{
		ProcessConfig(hInstance);		//Affichage de la boite de config
		Launch = TRUE;
	}

	if(strncmp(lpCmdLine,"/p",2) == 0)
	{
		Process(hInstance,(HWND)atoi(&lpCmdLine[3]));		//affichage en petit ecran
		Launch = TRUE;
	}
	
	if(!Launch)					//si la parametre n'est pas bon on quitte
		return 0;

	
	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

//---------------------------------------------------------------------------
//Fonction creant la fenetre d'affichage (si en plein ecran hParent == NULL)
//---------------------------------------------------------------------------
void Process(HINSTANCE hInstance,HWND hParent)
{
	WNDCLASS	wc;
	HWND		hWnd;
	RECT		rect;
	int			X,Y;				//taille de la fenetre
	DWORD		style;				//style de la fentre
	LPARAM		Windowed = FALSE;
	LPARAM		*lParam = NULL;		//Parametre passé a la fonction WinProc en cas de WM_CREATE	

	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	wc.hCursor = NULL;
	wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
	wc.hInstance = hInstance;
	wc.lpfnWndProc = &WinProc;
	wc.lpszClassName = "StarField Window";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&wc); 

	if (hParent != NULL)		//si on est en petit ecran
	{
		GetClientRect(hParent,&rect);
		X = rect.right;					//on chope les coords
		Y = rect.bottom;
		style = WS_CHILD;				//Fenetre fille
		Windowed = TRUE;				//on set le flag
		lParam = &Windowed;
	}
	else
	{
		X = GetSystemMetrics(SM_CXSCREEN);		//sinon est plein ecran
		Y = GetSystemMetrics(SM_CYSCREEN);
		style = WS_POPUP;
	}

	//on cree la fenetre
	hWnd = CreateWindow("StarField Window",
                        "StarFieldGL",
                         style,
                         0,0,
                         X,
                         Y,
                         hParent,
					     NULL,
                         hInstance,
                         lParam);

	ShowWindow(hWnd,SW_SHOW);		//on l'affiche
	if (hParent == NULL)
		ShowCursor(FALSE);				//on cache le curseur seulement si en plein ecran
}

//-------------------
//Set le pixel format
//-------------------
void SetupPixelFormat(HDC hdc)
{
	int pixelFormat;
    PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
		1,
        PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        32,
        0, 0, 0, 0, 0, 0,
        0, 0,	
        0, 0, 0, 0, 0,
        32,
        0,
        0,
        0,
        0,
        0,
        0,
        0
	};		//on affiche en 32bits avec double buffer

    pixelFormat = ChoosePixelFormat(hdc, &pfd);
    if (pixelFormat == 0)
	{
        MessageBox(NULL,"Mode graphique non supporté","Erreur",MB_OK);
        exit(1);
    }

    if (SetPixelFormat(hdc,pixelFormat,&pfd) != TRUE)
	{
		MessageBox(NULL,"Mode graphique non supporté","Erreur",MB_OK);
        exit(1);
    }
}

//--------------------------------
//Fonction de gestion des messages
//--------------------------------
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	HDC						hdc;
	PAINTSTRUCT				ps;
	static HGLRC			hrc;
	static BOOL				Windowed;			//specifie si on est en plein ecran
	static BYTE				r = 255;			//composante rouge de la couleur des etoiles
	static BYTE				g = 255;			//..........verte.............
	static BYTE				b = 255;			//..........bleue.............
	static WORD				NbrEtoiles = 3000;
	static Etoile*			etoile;				//le tableau d'etoiles

	switch(msg)
	{
	case WM_CREATE:
		BYTE period;
		RECT rect;
		CREATESTRUCT *createstruct;

		createstruct = (CREATESTRUCT*) lParam;				//on va chercher le parametre passé par
		Windowed = (BOOL) createstruct->lpCreateParams;		//CreateWindow		
		
		
		GetParams(r,g,b,vitessemax,period,NbrEtoiles);		//on obtient les parametres

		hdc=GetDC(hWnd);
		SetupPixelFormat(hdc);		//on set le mode graphique

		GetClientRect(hWnd,&rect);
		Xscr = rect.right;
		Yscr = rect.bottom;
		xmax = ((Xscr*(d+ZMAX))/(2*d));			//on calcule les coords max d'un point en fonction
		ymax = ((Yscr*(d+ZMAX))/(2*d));			//du zmax et des coords de l'ecran

		srand(GetTickCount());					//on initialise le rand

		etoile = new Etoile[NbrEtoiles];		//un beau tableau d'etoiles
		if(etoile == NULL)
		{
			PostQuitMessage(0);
			break;
		}

		hrc = wglCreateContext(hdc);		//On cree un rendering context
		if (!hrc)
			DestroyWindow(hWnd);
		wglMakeCurrent(hdc,hrc);

		SetTimer(hWnd,TIMER,period,(TIMERPROC) OnTimer);		//on initialise le timer
		break;
	case WM_DESTROY:
		wglMakeCurrent(NULL,NULL);		//on libere le RC
		if (hrc)
			wglDeleteContext(hrc);		//on le delete
		PostQuitMessage(0);
		break;
	case WM_QUIT :
		KillTimer(hWnd,TIMER);			//on delete le timer
		delete[] etoile;				//on libere la mem
		break;
	case WM_SIZE:
		RECT rectClient;					//on met a jour l'affichage
		GetClientRect(hWnd,&rectClient);
		Xscr = rectClient.right;
		Yscr = rectClient.bottom;
		xmax = ((Xscr*(d+ZMAX))/(2*d));
		ymax = ((Yscr*(d+ZMAX))/(2*d));
		Reshape();		
		break;
	case WM_KEYDOWN :
		if (!Windowed)
		{
			switch(wParam)
			{
			case VK_ESCAPE :
				DestroyWindow(hWnd);
				break;
			case 'R' :
				if(GetKeyState(VK_SHIFT) & 0x8000 )
				{
					if (r>0)
						r--;
				}
				else
				{
					if (r<255)
						r++;
				}
				break;
			case 'G' :
				if(GetKeyState(VK_SHIFT) & 0x8000 )
				{
					if (g>0)
						g--;
				}
				else
				{
					if (g<255)
						g++;
				}
				break;
			case 'B' :
				if(GetKeyState(VK_SHIFT) & 0x8000 )
				{
					if (b>0)
						b--;
				}
				else
				{
					if (b<255)
						b++;
				}
				break;
			case 'V' :
				if(GetKeyState(VK_SHIFT) & 0x8000 )
				{
					if (vitessemax>1)
						vitessemax--;
				}
				else
				{
					if (vitessemax<50)
						vitessemax++;
				}
				break;
			}
			break;
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd,&ps);
		Draw(hdc,etoile,r,g,b,NbrEtoiles);			//dessin des etoiles
		EndPaint(hWnd,&ps);
		break;
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN :
	case WM_MBUTTONUP :
		if (!Windowed)				//si on est en plein ecran et que l'on a un click on quitte
			PostQuitMessage(0);
		break;
	}

	return DefWindowProc(hWnd,msg,wParam,lParam);
}

//------------------
//Fonction de dessin
//------------------
void Draw(HDC hdc,Etoile *etoile,BYTE r,BYTE g,BYTE b,WORD MAX_ETOILES)
{
	int i;					//controle
	int xtemp,ytemp;		//en cas de depassement de l'etoile		
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		//on efface couleur noire
	glMatrixMode(GL_MODELVIEW);			//on travaille sur la matrice modelview
	glLoadIdentity();
	glColor3ub(r,g,b);				//on set la couleur

		
	glBegin(GL_LINES);
	for(i=0;i<MAX_ETOILES;i++)			//enfin on draw les lignes
	{
		xtemp = etoile[i].x2d;
		ytemp = etoile[i].y2d;
		glVertex2i(xtemp,ytemp);
		if (!etoile[i].Inc())
			glVertex2i(xtemp,ytemp);
		else
			glVertex2i(etoile[i].x2d,etoile[i].y2d);
	}
	glEnd();
	SwapBuffers(hdc);
}

//------------------------------------
//Fonction metttant a jour la matrice
//------------------------------------
void Reshape()
{
	glViewport(0,0,Xscr,Yscr);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(-Xscr/2,Xscr/2,-Yscr/2,Yscr/2);		//met a jour la matrice (centre de coord(0,0))
}													//pour la perspective

//-----------------
//Fonction de timer
//-----------------
VOID CALLBACK OnTimer(HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
	InvalidateRect(hWnd,NULL,FALSE);		//on redraw
}

Conclusion :


Le screensaver ne gère pas le password et ne quitte que si l'on appuie sur echap ou que l'on clique. J'ai préféré laisser la gestion de la couleur et de la vitesse se faire au clavier pendant l'exécution (bien qu'il y ait initialisation par le fichier de config)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

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

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

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

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