/*
..:: Plugin Visuel Basique Pour Winamp en OpenGL ::..
Code Réalisé Par BeLZeL (fini le 30 juillet 2002)
Sous Microsoft Visual C++ 5.0
Site : http://headlines.fr.st
Mail : belzel@free.fr
Le Plugin dessine un Cube arc-en-ciel qui tourne en arrière-plan. Devant, deux
lignes représentent les ondes du canal gauche et droit de la musique. Le Plugin
affiche aussi le nombre d'images par seconde dans le titre de la fenêtre. J'espère
que ce petit code d'exemple (qui peut être assez dur à comprendre pour les
débutants) pourra vous permettre de faire le meilleur plugin visuel du monde
pour Winamp ;)
Pour le Plugin, je suis parti du plugin visuel de base, fourni par Winamp :
- http://ftp.winamp.com/winamp/nsdn/vis_minisdk.zip
Je l'ai fusionné avec un programme OpenGL fait pour Win32. Informations et
tutoriaux en français sur l'excellent site d'Antoche :
- http://antoche.alrj.org/prog/opengl/OpenGLII/OpenGLII.htm
- http://antoche.alrj.org/prog/opengl/OpenGLII/OpenGLIIbis.htm
Project / Settings
- Links : OpenGL32.lib GLu32.lib GLaux.lib kernel32.lib user32.lib gdi32.lib
- Output Filename : c:/répertoire/de/winamp/plugins/vis_test.dll
Fichiers :
- svis.c : fichiers source modifié
- vis.h : header non modifié (mais modifiable :), fourni par Winamp.
Notes : Le projet doit être compilable sous Dev-C++ mais j'ai eu trop de problèmes
de compilations bizarres. Parfois, il fallait redémarrer le logiciel pour
qu'il compile la DLL.
*/
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <windows.h> // on est bien sous Windows, je vous le confirme
#include <gl/glut.h> // on travaille aussi avec OpenGL
#include <stdio.h> // nécessaire juste pour "sprintf"
#include <math.h> // pour les cos et autres sin
#include <time.h> // pour le calcul du nombre d'images par seconde
#include "vis.h" // notre petit header préféré
//------------------------------------------------------------------------------
// Fonctions & Procédures
//------------------------------------------------------------------------------
// WINAMP
winampVisModule *getModule(int which); // quel module ?
void ConfigMod(struct winampVisModule *this_mod); // quelle config ?
int InitMod(struct winampVisModule *this_mod); // classe et fenêtre
int RenderMod(struct winampVisModule *this_mod); // le rendu
void QuitMod(struct winampVisModule *this_mod); // la fin
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// OpenGL
void SetupPixelFormat(HDC hDC); // Format Des Pixels
void Reshape(int width, int height); // Redimensionnement
void InitGL(); // Initialisation d'OpenGL
// Autres
bool AnimateNextFrame(int desiredFrameRate);
void BuildFont(LPSTR nom, int hauteur);
void CreateRenderTexture(UINT textureArray[], int size, int channels, int type, int textureID);
void DrawMB(struct winampVisModule *this_mod);
void DrawNMB(struct winampVisModule *this_mod);
void glPrint(const char *fmt, ...);
void RenderMotionBlur(int textureID);
//------------------------------------------------------------------------------
// Variables & Constantes
//------------------------------------------------------------------------------
// couleur arc-en-ciel
#define COLOR_ARC_EN_CIEL glColor3f(1.0f*float(cos(arc_en_ciel/20.0f)),1.0f*float(sin(arc_en_ciel/25.0f)),1.0f-0.5f*float(cos(arc_en_ciel/17.0f)));
float arc_en_ciel = 0.0f;
// pour les FPS
double frame=0;
// pour la rotation du cube
#define PI 3.1415926535897932384626433832795f // PI pour les angles
double a = 0;
// pour l'écriture
#define FONT_HEIGHT 24
UINT base; // Base Display List For The Font Set
float cnt1; // 1st Counter Used To Move Text & For Coloring
float cnt2; // 2nd Counter Used To Move Text & For Coloring
// pour la fenêtre
HWND hMainWnd; // Handle (numéro) de la fenêtre
char szAppName[] = "BeLZeLVis"; // Nom de notre classe
int ORIGINX=50; // origine en X
int ORIGINY=50; // origine en Y
int WIDTH=800; // largeur de la fenêtre
int HEIGHT=600; // hauteur de la fenêtre
HDC DC; // Device Context
HGLRC RC; // Rendering Context
// pour le motion blur
UINT g_Texture[2];
int g_Viewport = 0;
int g_BlurRate = 50;
int n=0;
// constantes et variables WINAMP
#define WM_WA_IPC WM_USER
#define IPC_GETOUTPUTTIME 105 // position et durée d'une musique
#define IPC_GETLISTPOS 125 // position dans la playlist
#define IPC_GETPLAYLISTTITLE 212 // titre de la musique
int Winamp_Pos; // position
int Winamp_Max; // durée
int Winamp_Num; // numéro
char Winamp_Titre[255]; // titre
char *Winamp_Titre2; // titre tampon (tmp)
int load=0;
// pour Winamp (Nom du Plugin et Nom du Module)
winampVisHeader hdr = { VIS_HDRVER, "Le Cube A BeLZeL", getModule };
winampVisModule mod1 = { "Cube",
NULL, // hwndParent
NULL, // hDllInstance
2, // sRate
2, // nCh
25, // latencyMS
25, // delayMS
2, // spectrumNch
2, // waveformNch
{ 0, }, // spectrumData
{ 0, }, // waveformData
ConfigMod,
InitMod,
RenderMod,
QuitMod };
//------------------------------------------------------------------------------
// DLL
//------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
__declspec( dllexport ) winampVisHeader *winampVisGetHeader() { return &hdr; }
#ifdef __cplusplus
}
#endif
//------------------------------------------------------------------------------
// Peut-on afficher la frame suivante ? Et on calcule/affiche le nombre de FPS
//------------------------------------------------------------------------------
bool AnimateNextFrame(int desiredFrameRate)
{
static float lastTime = 0.0f; // dernier temps récupéré
char title[255]; // titre de la fenêtre
float float_fps=0; // nombre de FPS
float currentTime = GetTickCount() * 0.001f; // temps actuel en ms
float elapsedTime = currentTime - lastTime; // temps écoulé
// on vérifie si on peut animer la prochaine frame (1 seconde / FPS)
if( elapsedTime > (1.0f / desiredFrameRate) )
{
float_fps = (float)frame/(float)(currentTime-lastTime); // calcul des FPS
frame = 0;
lastTime = currentTime;
sprintf(title,"Le Cube A BeLZeL - %4.2f FPS", float_fps);
SetWindowText(hMainWnd, title);
return true;
}
return false; // on anime pas encore
}
//------------------------------------------------------------------------------
// Création de la Police de Caractères
//------------------------------------------------------------------------------
void BuildFont(LPSTR nom, int hauteur) // Build Our Bitmap Font
{
HFONT font; // Windows Font ID
HFONT oldfont; // Used For Good House Keeping
base = glGenLists(96); // Storage For 96 Characters
font = CreateFont( hauteur, // Height Of Font
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
FW_BOLD, // Font Weight
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
ANSI_CHARSET, // Character Set Identifier
OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
nom ); // Font Name
oldfont = (HFONT)SelectObject(DC, font); // Selects The Font We Want
wglUseFontBitmaps(DC, 32, 96, base); // Builds 96 Characters Starting At Character 32
SelectObject(DC, oldfont); // Selects The Font We Want
DeleteObject(font); // Delete The Font
}
//------------------------------------------------------------------------------
// ConfigMod : que ce passe-t-il quand on appuie sur le bouton "config" de Winamp
//------------------------------------------------------------------------------
void ConfigMod(struct winampVisModule *this_mod)
{
MessageBox(this_mod->hwndParent,"Un tit Cube qui tourne en OpenGL.\n"
"Exemple Basique d'un Plugin visuel pour Winamp.\n\n"
" Par BeLZeL © 29/07/2k2",
"Le Cube A BeLZeL (30/07/2k2)",MB_OK);
}
//------------------------------------------------------------------------------
// Crée une texture vide
//------------------------------------------------------------------------------
void CreateRenderTexture(UINT textureArray[], int size, int channels, int type, int textureID)
{
unsigned int *pTexture = NULL; // crée un pointeur
// Alloue de la mémoire et initialise la mémoire
pTexture = new unsigned int [size * size * channels];
memset(pTexture, 0, size * size * channels * sizeof(unsigned int));
// Enregistre la texture dans OpenGL
glGenTextures(1, &textureArray[textureID]);
glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);
glTexImage2D(GL_TEXTURE_2D, 0, channels, size, size, 0, type, GL_UNSIGNED_INT, pTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
// Since we stored the texture space with OpenGL, we can delete the image data
delete [] pTexture;
}
//------------------------------------------------------------------------------
// DrawMB : Dessine ce qui est nécessaire, avec Motion Blur
//------------------------------------------------------------------------------
void DrawMB(struct winampVisModule *this_mod)
{
int x, y;
float bass=0, aigu=0;
glDisable(GL_TEXTURE_2D);
glEnable(GL_COLOR);
// CALCUL DES BASSES
for (y=0;y<this_mod->nCh;y++) // il n'y a que 2 canaux ("y" va de 0 à 1)
for (x=0;x<20;x++) // il y a 576 données par canaux
bass += this_mod->spectrumData[y][x];
bass /= (float)(1000*y); // moyenne
if (bass < 0.05) bass = 0.05;
// CALCUL DES AIGUES
for (y=0;y<this_mod->nCh;y++) // il n'y a que 2 canaux ("y" va de 0 à 1)
for (x=100;x<150;x++) // il y a 576 données par canaux
aigu += this_mod->spectrumData[y][x];
aigu /= (float)(5*y); // moyenne
a+=aigu + 2; // ajout
glTranslated(-5*cos(a/(float)(45*PI)),-4*sin(a/(float)(45*PI)),10);
glRotated(a, 1, 2, 3);
// LE CUBE
glBegin(GL_LINE_STRIP);
//glBegin(GL_LINES);
//glBegin(GL_QUADS);
// derrière
glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
// devant
glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
glColor3f(1,0,1); glVertex3f(bass,bass,bass);
glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
// gauche
glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
// droite
glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
glColor3f(1,0,1); glVertex3f(bass,bass,bass);
// haut
glColor3f(0,0,0); glVertex3f(-bass,bass,-bass);
glColor3f(1,0,0); glVertex3f(bass,bass,-bass);
glColor3f(1,0,1); glVertex3f(bass,bass,bass);
glColor3f(0,0,1); glVertex3f(-bass,bass,bass);
// bas
glColor3f(0,1,0); glVertex3f(-bass,-bass,-bass);
glColor3f(1,1,0); glVertex3f(bass,-bass,-bass);
glColor3f(1,1,1); glVertex3f(bass,-bass,bass);
glColor3f(0,1,1); glVertex3f(-bass,-bass,bass);
glEnd();
// PASSAGE EN ORTHO 2D
glMatrixMode(GL_PROJECTION); // On se met en PROJECTION 2D
glLoadIdentity(); // On initialise la matrice
glOrtho(0,WIDTH,0,HEIGHT,0,0.1); // Fait un écran Ortho, 0-0 en bas à gauche
glMatrixMode(GL_MODELVIEW); // On se met en MODELVIEW 3D
glLoadIdentity(); // On initialise
COLOR_ARC_EN_CIEL;
// LES LIGNES (composées de points)
glBegin(GL_POINTS);
for (x=0;x<576;x++) // il y a 576 données par canaux
for (y=0;y<this_mod->nCh;y++) // il n'y a que 2 canaux ("y" va de 0 à 1)
glVertex3f(x*WIDTH/(float)576,(HEIGHT*0.001*(this_mod->waveformData[y][x]^128) + (0.5*y*HEIGHT) + HEIGHT*0.1),0);
glEnd();
// LES BARRES
glBegin(GL_LINES);
for (y=0; y<this_mod->nCh;y++)
{
for (x=0;x<100;x++)
{
if (y == 0) bass = this_mod->spectrumData[y][x];
else bass = -(this_mod->spectrumData[y][x]);
glColor3d(0,0,0); glVertex3f(x*WIDTH/(float)100, 0+(HEIGHT*y), 0);
glColor4f(x/(float)100, fabs(bass)/(float)100, this_mod->nCh*0.5, 0.6);
glVertex3f(x*WIDTH/(float)100, 0.5*bass+(HEIGHT*y),0);
}
}
glEnd();
// LE CERCLE
glBegin(GL_POINTS);
for (y=0;y<this_mod->nCh;y+=2) // il n'y a que 2 canaux ("y" va de 0 à 1)
for (x=0;x<576;x++) // il y a 576 données par canaux
{
glColor3f(1.0f*float(cos(cnt2)),1.0f*float(sin(cnt1)),1.0f-0.5f*float(cos(cnt1+cnt2)));
glVertex3f(0.5*((this_mod->waveformData[y][x]^128)+20)*sin(x*360/(float)576)+WIDTH*0.5,
0.5*((this_mod->waveformData[y][x]^128)+20)*cos(x*360/(float)576)+HEIGHT*0.5,
0);
}
glEnd();
glDisable(GL_COLOR);
glEnable(GL_TEXTURE_2D);
glColor3d(1,1,1);
}
//------------------------------------------------------------------------------
// DrawNMB : Dessine ce qui est nécessaire, sans Motion Blur
//------------------------------------------------------------------------------
void DrawNMB(struct winampVisModule *this_mod)
{
glEnable(GL_COLOR);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
// TITRE DE LA CHANSON
glColor4f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)), 0.8);
glRasterPos2f(20,20);
glPrint("%s", Winamp_Titre);
cnt1+=0.051f; // Increase The First Counter
cnt2+=0.005f; // Increase The First Counter
// BARRE DE PROGRESSION
glColor4f(0.2,0.6,0.9,0.5);
glBegin(GL_QUADS);
glVertex2d( 0, 0 );
glVertex2d( 0.001*Winamp_Pos*WIDTH/(float)Winamp_Max, 0 );
glVertex2d( 0.001*Winamp_Pos*WIDTH/(float)Winamp_Max, 15 );
glVertex2d( 0, 15 );
glEnd();
glDisable(GL_COLOR);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3d(1,1,1);
}
//------------------------------------------------------------------------------
// GetModule : quel module est choisi depuis Winamp
//------------------------------------------------------------------------------
winampVisModule *getModule(int which)
{
switch (which)
{
case 0: return &mod1;
default:return NULL;
}
}
//------------------------------------------------------------------------------
// InitMod : Classes enregistrées, création de la fenêtre, etc ...
//------------------------------------------------------------------------------
int InitMod(struct winampVisModule *this_mod)
{
// Notre Classe
WNDCLASS wc;
memset(&wc,0,sizeof(wc));
wc.lpfnWndProc = WndProc; // our window procedure
wc.hInstance = this_mod->hDllInstance; // hInstance of DLL
wc.lpszClassName = szAppName; // our window class name
if (!RegisterClass(&wc))
{
MessageBox(this_mod->hwndParent,"Erreur lors de l'enregistrement de la classe de la fenêtre","Attention !",MB_OK);
return 1;
}
// Notre fenêtre
hMainWnd = CreateWindowEx( WS_EX_TOOLWINDOW|WS_EX_APPWINDOW, // these exstyles put a nice small frame,
// but also a button in the taskbar
szAppName, // our window class name
this_mod->description, // use description for a window title
WS_VISIBLE|WS_SYSMENU, // make the window visible with a close button
ORIGINX,ORIGINY, // screen position (read from config)
WIDTH,HEIGHT, // width & height of window (need to adjust client area later)
this_mod->hwndParent, // parent window (winamp main window)
NULL, // no menu
this_mod->hDllInstance, // hInstance of DLL
0); // no window creation data
if (!hMainWnd)
{
MessageBox(this_mod->hwndParent,"Erreur lors de la création de la fenêtre","Attention !",MB_OK);
return 1;
}
return 0;
}
//------------------------------------------------------------------------------
// Affichage d'un texte à l'écran
//------------------------------------------------------------------------------
void glPrint(const char *fmt, ...)
{
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) return; // If There's No Text Do Nothing
va_start(ap, fmt); // Parses The String For Variables
vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits
glListBase(base - 32); // Sets The Base Character to 32
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
glPopAttrib(); // Pops The Display List Bits
}
//------------------------------------------------------------------------------
// Initialisation d'OpenGL
//------------------------------------------------------------------------------
void InitGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Arrière Plan Noir
glClearDepth(1.0f); // Configuration de la profondeur du buffer
Reshape(WIDTH, HEIGHT);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST); // Test sur la profondeur (évite des bugs)
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Smooth Shading Activé, il doit lisser les formes (?)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glPointSize(2); // taille des points en pixels
glLineWidth(6);
CreateRenderTexture(g_Texture, 512, 3, GL_RGB, 0);
BuildFont("Courier New", FONT_HEIGHT);
glEnable(GL_COLOR);
while ((pow(2,n) <= WIDTH) && (pow(2,n) <= HEIGHT)) n++;
g_Viewport = pow(2,n-1);
}
//------------------------------------------------------------------------------
// QuitMod : heu ... lorsqu'on quitte
//------------------------------------------------------------------------------
void QuitMod(struct winampVisModule *this_mod)
{
glDeleteLists(base, 96);
DeleteObject(DC);
DestroyWindow(hMainWnd); // delete our window
UnregisterClass(szAppName,this_mod->hDllInstance); // unregister window class
}
//------------------------------------------------------------------------------
// RenderMod : Notre rendu de la fenêtre
//------------------------------------------------------------------------------
int RenderMod(struct winampVisModule *this_mod)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
Reshape(WIDTH, HEIGHT);
arc_en_ciel++; // Pour la couleur arc-en-ciel
frame++;
gluLookAt(0,0,-10,0,0,0,0,1,0);
Winamp_Pos = SendMessage(this_mod->hwndParent,WM_WA_IPC,0,IPC_GETOUTPUTTIME);
// load = 0 -> lancement du plugin / chargement demandé -> passage à 2
// load = 1 -> nouvelle musique / chargement demandé -> passage à 3
// load = 2 -> attente d'une nouvelle musique / pas de chargement
// load = 3 -> passage à 2
if (load == 3) load = 2;
if ((Winamp_Pos < 1000) && (load != 3)) load = 1;
if (load <= 1)
{
load+=2;
Winamp_Max = SendMessage(this_mod->hwndParent,WM_WA_IPC,1,IPC_GETOUTPUTTIME);
Winamp_Num = SendMessage(this_mod->hwndParent,WM_WA_IPC,0,IPC_GETLISTPOS);
Winamp_Titre2 = (char *)SendMessage(this_mod->hwndParent,WM_WA_IPC,Winamp_Num,IPC_GETPLAYLISTTITLE);
strcpy(Winamp_Titre, Winamp_Titre2);
}
if( AnimateNextFrame(g_BlurRate) )
{
glViewport(0, 0, g_Viewport, g_Viewport);
RenderMotionBlur(0);
DrawMB(this_mod);
glBindTexture(GL_TEXTURE_2D,g_Texture[0]);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, g_Viewport, g_Viewport, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, WIDTH, HEIGHT);
}
RenderMotionBlur(0);
DrawNMB(this_mod);
SwapBuffers(DC);
return 0;
}
//------------------------------------------------------------------------------
// Rendu du Motion Blur
//------------------------------------------------------------------------------
void RenderMotionBlur(int textureID)
{
int add=-10;
glPushMatrix();
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, g_Texture[textureID]);
glColor4f(1, 1, 1, 0.95f);
// OrthoMode
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho( 0, WIDTH, HEIGHT, 0, 0, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f); glVertex2f(-add, -add);
glTexCoord2f(0.0f, 0.0f); glVertex2f(-add, HEIGHT+add);
glTexCoord2f(1.0f, 0.0f); glVertex2f(WIDTH+add, HEIGHT+add);
glTexCoord2f(1.0f, 1.0f); glVertex2f(WIDTH+add, -add);
glEnd();
// PerspectiveMode
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glPopMatrix();
}
//------------------------------------------------------------------------------
// Redimensionnement de la fenêtre
//------------------------------------------------------------------------------
void Reshape(int width, int height)
{
if (height==0) height=1;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,(float)width/(float)height,0.5f,500);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
//------------------------------------------------------------------------------
// Format Des Pixels
//------------------------------------------------------------------------------
void SetupPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // taille du descripteur de format
1, // version
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, // Propriétés
PFD_TYPE_RGBA, // Mode de couleurs
16, // Bits de couleur
0, 0, 0, 0, 0, 0, // Paramètres des couleurs
0,0, // Paramètres alpha
0,0, 0, 0, 0, // Paramètres du buffer d'accumulation
32, // Bits de profondeur
0, // Bits du buffer stencil
0, // Nombre de buffers auxiliaires
0, // ignoré (obsolète)
0, // réservé
0, // ignoré (obsolète)
0, // Couleur de transparence
0 }; // Ignoré (obsolète)
int pixelFormat = ChoosePixelFormat(hDC, &pfd);
// Vérifie si un PixelFormat existe et s'il peut l'appliquer
if ((!pixelFormat) || (!SetPixelFormat(hDC, pixelFormat, &pfd)))
{
MessageBox ( WindowFromDC(hDC), "Mode graphique non supporté.", "Problème - 1", MB_ICONERROR | MB_OK );
exit(1);
}
}
//------------------------------------------------------------------------------
// WndProc : Interception des messages virtuels
//------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
DC=GetDC(hwnd);
SetupPixelFormat(DC);
RC = wglCreateContext(DC);
if (!RC) SendMessage(hwnd,WM_CLOSE,0,0);
wglMakeCurrent(DC, RC);
InitGL();
return 0;
case WM_DESTROY:
wglMakeCurrent(NULL, NULL);
if (RC) wglDeleteContext(RC);
ReleaseDC(hwnd,DC);
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
/*
case VK_SPACE:
g_Viewport=pow(2,n);
n++;
return 0;*/
}
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
//------------------------------------------------------------------------------
// Fin Du Programme (ouf !)
//------------------------------------------------------------------------------