Bonjour !!
À vous petits curieux qui me lisez, je tiens à vous dire que ceci est pour moi un rappel de mes galères sur Vscode ainsi que l'apprentissage des bases d'OpenGL et la Win32 api. Cette clarification faite, nous pouvons commencer.
j'ai commencé par me renseigner sur quel IDE pouvais accueillir le développement de mes projets et mes test C++. Je lis et écoute diverses personnes parler de leur IDE et je finis par me dire "tien VScode est beaucoup utiliser semble t'il". Vscode n'est pas livré avec un compilateur, il faut donc ajouter. Je pars à la recherche de l'émulateur idéal !!!! Et beaucoup parlent d'un certain Clang fessant partis d'une suite du nom de LLVM. Je décide donc de le tester ... Aile il y a un bug dessus et qui m'empêche d'ouvrir un terminal externe. Et celui-ci est connu depuis 2020 !!! Ce bug a 3 ans !!! Ce bug ne sera pas résolu de ci tôt... Bon pour utiliser clang de la meilleure façon, il faut 3 fichiers que voici :
un fichier build.bat :
```batch @echo off if not exist "./bin" mkdir "./bin" if not exist "./bin/debug" mkdir "./bin/debug" if not exist "./bin/release" mkdir "./bin/release" clang --version clang++ -std=c++20 -Wall -Wextra -pedantic -g main.cpp -o /bin/debug/test.exe -lgdi32 -lopengl32 -luser32 clang++ -std=c++20 -Wall -Wextra -pedantic main.cpp -o /bin/release/test.exe -lgdi32 -lopengl32 -luser32 //pause @echo on ```
(-lgdi32 -lopengl32 pour OpenGL et -luser32 pour Win32)
Puis un fichier tasks.json dans un dossier .vscode :
```json { "version": "2.0.0", "tasks": [ { "label": "Build", "type": "shell", "windows": { "command": "Start-Process -FilePath \"build.bat\" -NoNewWindow 2>&1" }, "group": { "kind": "build", "isDefault": true } } ] } ```
Et un fichier launch.json dans un dossier .vscode
```json { "version": "0.2.0", "configurations": [ { "name": "Windows Launch(lldb)", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/test.exe", "args": [], "cwd": "${workspaceFolder}", "preLaunchTask": "Build", //"console": "externalTerminal" } ] } ```
Oui, je laisse l'option pour que la console se lance en externe en commentaire, j'ai espoir. Mais bon s'il a moyen de compiler, on pourrait se dire que ce n'est pas grave et se passer de la console externe... Il y a un autre problème ... Et celui-ci bien plus grave.
j'ai compilé plusieurs mêmes fichiers avec GCC et Clang. j'ai donc pu comparer le temps de compilation ainsi que le poids en octet des deux versions de ces mêmes applications. Clang est connu pour être plus rapide... Pourtant je n'ai vu aucune différence ... Par contre, je passe d'une application entre 50 et 59 ko avec GCC a une application de 600 a 1 000 ko. Et ces applications étaient très simples. Je me suis demandé en voyant ça combien supportait les disquettes de mon enfance ... 1,44 Mo... Soit 2 applications faites avec Clang... Ça ne fait pas beaucoup ... Donc va pour GCC. Et ce coup si je prévois le cas où je ferais du Linux
./build.bat
```batch @echo off if not exist "./bin" mkdir "./bin" if not exist "./bin/debug" mkdir "./bin/debug" if not exist "./bin/release" mkdir "./bin/release" g++ --version g++ -g -Wall -o ./bin/debug/test.exe ./main.cpp -lgdi32 -lopengl32 g++ -Wall -o ./bin/release/test.exe ./main.cpp -lgdi32 -lopengl32 //pause @echo on ```
( -lgdi32 -lopengl32 pour la suite avec OpenGL)
./.vscode/tasks.json
```json { "version": "2.0.0", "tasks": [ { "label": "Build", "type": "shell", "windows": { "command": "Start-Process -FilePath \"build.bat\" -NoNewWindow 2>&1" }, "linux": { "command": "./build.sh", }, "group": { "kind": "build", "isDefault": true } } ] } ```
./.vscode/launch.json
```json { "version": "0.2.0", "configurations": [ { "name": "Linux build & Launch(gcc)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/release/test", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "environment": [], "externalConsole": true, "preLaunchTask": "Build", }, { "name": "Linux Launch(gcc)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/release/test", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "environment": [], "externalConsole": true, }, { "name": "Windows build & Launch(gcc)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/debug/test.exe", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "environment": [], "externalConsole": true, "preLaunchTask": "Build", }, { "name": "Windows Launch(gcc)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/release/test.exe", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "environment": [], "externalConsole": true, } ] } ```
Bon, on va enfin vraiment coder.
Pour commencer, on pourrait commencer par une fenêtre non ? pour cela Windows propose une fonction d'entrée particulier mais pas les autres OS alors on va s'en passé donc tout commence par :
```c++ int main() { return 0; } ```
Un petit hello world ?
```c++ #include <iostream> int main() { std::cout << "Hello World! "<<" \n"; system("pause"); return 0; } ```
Voilà ça dit hello world dans la console, mais c'est un peu nul une console ? Pour cela, il nous faut le HINSTANCE de notre application pour cela, il nous faut utiliser cette fonction ::
```c++ HINSTANCE hInstance = GetModuleHandle(NULL); ```
Ne pas oublier de rajouter le petit include :
```c++ #include <windows.h> ```
Jusque-là rien de bien compliqué maintenant, il va nous falloir créer le style de la fenêtre (il parle de winclass dans l'api Win32) pour ce faire, je vais avoir besoin de donne de données textuelles qui change de format suivant si je suis en Unicode ou pas et donc je vais unifier cela.
```c++ void StrFreeA(char * s) { delete[] s; } void StrFreeW(wchar_t * s) { delete[] s; } //Surcharge C++, plus simple. inline void StrFree( char * s) { return StrFreeA(s); } inline void StrFree(wchar_t * s) { return StrFreeW(s); } //Fonctions de conversion wchar_t * char_to_wchar(char const *inString) { size_t const cchLenA = strlen(inString); size_t const cchLenW = mbstowcs(NULL, inString, cchLenA+1); wchar_t * outString = new wchar_t[cchLenW+1]; mbstowcs(outString, inString, cchLenA+1); return outString; } char * wchar_to_char(wchar_t const *inString) { size_t const cchLenW = wcslen(inString); size_t const cchLenA = wcstombs(NULL, inString, cchLenW+1); char * outString = new char[cchLenA+1]; wcstombs(outString, inString, cchLenW+1); return outString; } #ifdef UNICODE #define TXT_Win(t) char_to_wchar(t) #else #define TXT_Win(t) t #endif ```
Voilà cela unifie un peu tout cela ensuite créons la winClass, c'est ce qui donne un peu le style de la fenêtre :
```c++ WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); //taille de la class wc.style = 0; //pas de style parent wc.lpfnWndProc = WndProc; //fonction de message de la fenêtre a définir wc.cbClsExtra = 0; //pas de taille extra pour la fenêtre wc.cbWndExtra = 0; //pas de taille extra pour la class wc.hInstance = hInstance; //le HINSTANCE que nous avons récupérer wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique wc.hCursor = LoadCursor(NULL, IDC_ARROW); //pas de curseur spécifique wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); //pas de font de fenêtre wc.lpszMenuName = NULL; //pas de menu wc.lpszClassName = TXT_Win("CLASS_NAME"); //le nom de la class c'est CLASS_NAME wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique versions petite RegisterClassEx(&wc); // penser en enregistre la class ```
Mais qu'est que cette fonction WndProc ? Une simple fonction qui gère des message envoyer à la fenêtre comme celle-ci :
```c++ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: //si la fenetre est créer break; case WM_CLOSE: //si on appuye sur la croix DestroyWindow(hwnd); //détruit la fenetre break; case WM_DESTROY: //évènement quand la fenêtre est détruite PostQuitMessage(0); //message pour quiter l'application break; default: return DefWindowProc(hwnd, msg, wParam, lParam);//procedure par default } return 0; } ```
Bien maintenant, nous pouvons ouvrir une fenêtre en utilisant cette winClass :
```c++ HWND hwnd; //identifiant de la fenetre hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, //La fenêtre a une bordure avec un bord enfoncé. TXT_Win("CLASS_NAME"), //le nom de la winclass que nous avons choisi TXT_Win("The title window"), //le titre de la fenetre sera : "The title window" WS_OVERLAPPEDWINDOW, //une fenetre classic de windows CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,//position par défaut taille 800x600 NULL, //pas de parent NULL, //pas de menu hInstance, // le fameux HINSTANCE NULL); //user pointer ```
Et là, rien ne s'affiche !! Normal, il faut dire de montrer la fenêtre.
```c++ ShowWindow(hwnd, SW_SHOW); //on montre la fenêtre UpdateWindow(hwnd); //première mise a jour de la fenêtre ```
Bon, la fenêtre s'affiche, mais elle reste figée.
C'est normal, les événements de la fenêtre ne sont pas lus :
```c++ while(GetMessage(&Msg, NULL, 0, 0) > 0)//récupère le message ou attend le prochain { TranslateMessage(&Msg); //traduit le message DispatchMessage(&Msg); //transfere le message a la fonction de fenetre(WndProc) } ```
Bien, nous avons une fenêtre qui répond normalement. Que faire de plus ? Déjà un récap ?
```c++ #include <iostream> #include <windows.h> void StrFreeA(char * s) { delete[] s; } void StrFreeW(wchar_t * s) { delete[] s; } //Surcharge C++, plus simple. inline void StrFree( char * s) { return StrFreeA(s); } inline void StrFree(wchar_t * s) { return StrFreeW(s); } //Fonctions de conversion wchar_t * char_to_wchar(char const *inString) { size_t const cchLenA = strlen(inString); size_t const cchLenW = mbstowcs(NULL, inString, cchLenA+1); wchar_t * outString = new wchar_t[cchLenW+1]; mbstowcs(outString, inString, cchLenA+1); return outString; } char * wchar_to_char(wchar_t const *inString) { size_t const cchLenW = wcslen(inString); size_t const cchLenA = wcstombs(NULL, inString, cchLenW+1); char * outString = new char[cchLenA+1]; wcstombs(outString, inString, cchLenW+1); return outString; } #ifdef UNICODE #define TXT_Win(t) char_to_wchar(t) #else #define TXT_Win(t) t #endif LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: //si la fenetre est créer break; case WM_CLOSE: //si on appuye sur la croix DestroyWindow(hwnd); //détruit la fenetre break; case WM_DESTROY: //évènement quand la fenêtre est détruite PostQuitMessage(0); //message pour quiter l'application break; default: return DefWindowProc(hwnd, msg, wParam, lParam);//procedure par default } return 0; } int main() { HINSTANCE hInstance = GetModuleHandle(NULL); WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); //taille de la class wc.style = 0; //pas de style parent wc.lpfnWndProc = WndProc; //fonction de message de la fenêtre a définir wc.cbClsExtra = 0; //pas de taille extra pour la fenêtre wc.cbWndExtra = 0; //pas de taille extra pour la class wc.hInstance = hInstance; //le HINSTANCE que nous avons récupérer wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique wc.hCursor = LoadCursor(NULL, IDC_ARROW); //pas de curseur spécifique wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); //pas de font de fenêtre wc.lpszMenuName = NULL; //pas de menu wc.lpszClassName = TXT_Win("CLASS_NAME"); //le nom de la class c'est CLASS_NAME wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique versions petite RegisterClassEx(&wc); // penser en enregistre la class HWND hwnd; //identifiant de la fenetre hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, //La fenêtre a une bordure avec un bord enfoncé. TXT_Win("CLASS_NAME"), //le nom de la winclass que nous avons choisi TXT_Win("The title window"), //le titre de la fenetre sera : "The title window" WS_OVERLAPPEDWINDOW, //une fenetre classic de windows CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,//position par défaut taille 800x600 NULL, //pas de parent NULL, //pas de menu hInstance, // le fameux HINSTANCE NULL); //user pointer ShowWindow(hwnd, SW_SHOW); //on montre la fenêtre UpdateWindow(hwnd); //première mise a jour de la fenêtre while(GetMessage(&Msg, NULL, 0, 0) > 0)//récupère le message ou attend le prochain { TranslateMessage(&Msg); //traduit le message DispatchMessage(&Msg); //transfere le message a la fonction de fenetre(WndProc) } return 0; } ```
Maintenant, la chose intéressante serait d'afficher quelque chose dans cette fenêtre : pour cela je test OpenGL et... problème, partout, on me parle de glu, glaux ou glew... j'en veux pas !!!!
Déjà ajouter un include
```c++ #include <gl/gl.h> ```
Bon après de dures recherches, je découvre qu'il faut commencer par créer un contexte de rendu. Et on commence par récupérer le contexte de la zone client... En gros, un identifiant de zone a dessiné qui est utiliser pour l'api graphique GDI de Windows.
```c++ HDC gldc = GetDC(hwnd); //utiliser pour connaitre la zone de dessin ```
Super, maintenant, nous devons définir le format de pixel utilisé pour OpenGL
```c++ PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // taille du PIXELFORMATDESCRIPTOR 1, // versiom PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags //PFD_DRAW_TO_WINDOW = peut dessiner la fenetre //PFD_SUPPORT_OPENGL = supporte OpenGL //PFD_DOUBLEBUFFER = dessine dans une mémoire avant d'envoyer a la fenêtre PFD_TYPE_RGBA, // utilise le rouge vert bleu et transparence 32, // bits du framebuffer. 0, 0, //plan et décalage rouge 0, 0, //plan et décalage vert 0, 0, //plan et décalage bleu 0, 0, //plan et décalage de transparence 0, //plan total accumulation buffer 0, 0, 0, 0, //plan r,g,b,a de accumulation buffer 24, // nombre de bits du depthbuffer 8, // nombre de bits du stencilbuffer 0, // nombre de Aux buffers du framebuffer. PFD_MAIN_PLANE, // ceci est la couche pricipal 0, // reserved 0, 0, 0 // couche ignorer }; int PixelFormat; PixelFormat = ChoosePixelFormat(gldc, &pfd); //trouve un pixel format qui correspond SetPixelFormat(gldc,PixelFormat, &pfd); //sélection le pixel format ```
Maintenant, il nous faut la fonction spécifique de Windows pour obtenir le contexte.
```c++ HGLRC gl_context = wglCreateContext(gldc);//créer le context wglMakeCurrent(gldc, gl_context); //utilise ce context ```
Voilà, je peux maintenant jouer avec OpenGL !!!! On test ?
```c++ while(GetMessage(&Msg, NULL, 0, 0) > 0)//récupère le message ou attend le prochain { TranslateMessage(&Msg); DispatchMessage(&Msg); //nettoye l'écran avec un noire immaculer glClearColor(0f, 0f, 0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //couleur de dessin blanche glColor3f(1.0f, 1.0f, 1.0f); //dessine un triangle glBegin(GL_TRIANGLES); glVertex3f(-0.25f, -0.25f, 0.0f); // V0 glVertex3f( 0.0f, 0.25f, 0.0f); // V1 glVertex3f( 0.25f, -0.25f, 0.0f); // V2 glEnd(); SwapBuffers(gldc); //mise a jour du dessin } ```
Bon deux problème OpenGL dessine que quand des event arrive à la fenêtre. On peut donc changer ça dans la boucle.
```c++ while (true) { while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))//récupère le message ou attend le prochain { TranslateMessage(&Msg); DispatchMessage(&Msg); } if(Msg.message == WM_QUIT) break; //nettoye l'écran avec un noire immaculer glClearColor(0f, 0f, 0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //couleur de dessin blanche glColor3f(1.0f, 1.0f, 1.0f); //dessine un triangle glBegin(GL_TRIANGLES); glVertex3f(-0.25f, -0.25f, 0.0f); // V0 glVertex3f( 0.0f, 0.25f, 0.0f); // V1 glVertex3f( 0.25f, -0.25f, 0.0f); // V2 glEnd(); SwapBuffers(gldc); //mise a jour du dessin } ```
Maintenant, rajoutons de la couleur pour cela, je vais adapter des fonction que j'ai utilisé dans : https://dimesto.itch.io/circleloop
```c++ typedef struct RGB { float r, g, b; } ; typedef struct HSV { float h, s, v; } ; RGB hsl_to_rgb( HSV hsv) { RGB rgb = {}; if(hsv.h > 360) hsv.h -= 360.0 * ((int)(hsv.h / 360)); if(hsv.h < 0) hsv.h += 360.0 * ((int)(hsv.h / 360)); float v = hsv.v; int t1 = (int)(hsv.h/60.0f) % 6; float f = hsv.h/60.0f - t1; float l = hsv.v * (1-hsv.s); float m = hsv.v * (1-f*hsv.s); float n = hsv.v * (1-(1-f)*hsv.s); float r,g,b; switch (t1) { case 0: r = v; g = n; b=l; break; case 1: r = m; g = v; b=l; break; case 2: r = l; g = v; b=n; break; case 3: r = l; g = m; b=v; break; case 4: r = n; g = l; b=v; break; case 5: r = v; g = l; b=m; break; default: break; } rgb.r = r; rgb.g = g; rgb.b = b; return rgb; } HSV rgb_to_hsv(RGB rgb) { HSV hsv = {}; float max = 0.0f; float min = 0.0f; int maxI = 0; if(rgb.r > max) { max = rgb.r; maxI = 1; } if(rgb.g > max) { max = rgb.g; maxI = 2; } if(rgb.b > max) { max = rgb.b; maxI = 3; } if(rgb.r < min)min = rgb.r; if(rgb.g < min)min = rgb.g; if(rgb.b < min)min = rgb.b; hsv.v = max; if(max == 0) hsv.s = 0; else hsv.s = 1-(min/max); if (max == min)hsv.h = 0; else if(maxI== 1) hsv.h = (360 + 60 * (rgb.g - rgb.b)/(max-min)); else if(maxI== 2) hsv.h = (120 + 60 * (rgb.b - rgb.r)/(max-min)); else if(maxI== 3) hsv.h = (240 + 60 * (rgb.r - rgb.g)/(max-min)); hsv.h -= 360.0 * ((int)(hsv.h / 360)); return hsv; } ```
Et donc récap ....
``` c++ #include <iostream> #include <windows.h> #include <gl/gl.h> void StrFreeA(char * s) { delete[] s; } void StrFreeW(wchar_t * s) { delete[] s; } //Surcharge C++, plus simple. inline void StrFree( char * s) { return StrFreeA(s); } inline void StrFree(wchar_t * s) { return StrFreeW(s); } //Fonctions de conversion wchar_t * char_to_wchar(char const *inString) { size_t const cchLenA = strlen(inString); size_t const cchLenW = mbstowcs(NULL, inString, cchLenA+1); wchar_t * outString = new wchar_t[cchLenW+1]; mbstowcs(outString, inString, cchLenA+1); return outString; } char * wchar_to_char(wchar_t const *inString) { size_t const cchLenW = wcslen(inString); size_t const cchLenA = wcstombs(NULL, inString, cchLenW+1); char * outString = new char[cchLenA+1]; wcstombs(outString, inString, cchLenW+1); return outString; } #ifdef UNICODE #define TXT_Win(t) char_to_wchar(t) #else #define TXT_Win(t) t #endif LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: //si la fenetre est créer break; case WM_CLOSE: //si on appuye sur la croix DestroyWindow(hwnd); //détruit la fenetre break; case WM_DESTROY: //évènement quand la fenêtre est détruite PostQuitMessage(0); //message pour quiter l'application break; default: return DefWindowProc(hwnd, msg, wParam, lParam);//procedure par default } return 0; } typedef struct RGB { float r, g, b; } ; typedef struct HSV { float h, s, v; } ; RGB hsl_to_rgb( HSV hsv) { RGB rgb = {}; if(hsv.h > 360) hsv.h -= 360.0 * ((int)(hsv.h / 360)); if(hsv.h < 0) hsv.h += 360.0 * ((int)(hsv.h / 360)); float v = hsv.v; int t1 = (int)(hsv.h/60.0f) % 6; float f = hsv.h/60.0f - t1; float l = hsv.v * (1-hsv.s); float m = hsv.v * (1-f*hsv.s); float n = hsv.v * (1-(1-f)*hsv.s); float r,g,b; switch (t1) { case 0: r = v; g = n; b=l; break; case 1: r = m; g = v; b=l; break; case 2: r = l; g = v; b=n; break; case 3: r = l; g = m; b=v; break; case 4: r = n; g = l; b=v; break; case 5: r = v; g = l; b=m; break; default: break; } rgb.r = r; rgb.g = g; rgb.b = b; return rgb; } HSV rgb_to_hsv(RGB rgb) { HSV hsv = {}; float max = 0.0f; float min = 0.0f; int maxI = 0; if(rgb.r > max) { max = rgb.r; maxI = 1; } if(rgb.g > max) { max = rgb.g; maxI = 2; } if(rgb.b > max) { max = rgb.b; maxI = 3; } if(rgb.r < min)min = rgb.r; if(rgb.g < min)min = rgb.g; if(rgb.b < min)min = rgb.b; hsv.v = max; if(max == 0) hsv.s = 0; else hsv.s = 1-(min/max); if (max == min)hsv.h = 0; else if(maxI== 1) hsv.h = (360 + 60 * (rgb.g - rgb.b)/(max-min)); else if(maxI== 2) hsv.h = (120 + 60 * (rgb.b - rgb.r)/(max-min)); else if(maxI== 3) hsv.h = (240 + 60 * (rgb.r - rgb.g)/(max-min)); hsv.h -= 360.0 * ((int)(hsv.h / 360)); return hsv; } int main() { HINSTANCE hInstance = GetModuleHandle(NULL); WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); //taille de la class wc.style = 0; //pas de style parent wc.lpfnWndProc = WndProc; //fonction de message de la fenêtre a définir wc.cbClsExtra = 0; //pas de taille extra pour la fenêtre wc.cbWndExtra = 0; //pas de taille extra pour la class wc.hInstance = hInstance; //le HINSTANCE que nous avons récupérer wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique wc.hCursor = LoadCursor(NULL, IDC_ARROW); //pas de curseur spécifique wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); //pas de font de fenêtre wc.lpszMenuName = NULL; //pas de menu wc.lpszClassName = TXT_Win("CLASS_NAME"); //le nom de la class c'est CLASS_NAME wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);//pas d'icone spécifique versions petite RegisterClassEx(&wc); // penser en enregistre la class HWND hwnd; //identifiant de la fenetre hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, //La fenêtre a une bordure avec un bord enfoncé. TXT_Win("CLASS_NAME"), //le nom de la winclass que nous avons choisi TXT_Win("The title window"), //le titre de la fenetre sera : "The title window" WS_OVERLAPPEDWINDOW, //une fenetre classic de windows CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,//position par défaut taille 800x600 NULL, //pas de parent NULL, //pas de menu hInstance, // le fameux HINSTANCE NULL); //user pointer ShowWindow(hwnd, SW_SHOW); //on montre la fenêtre UpdateWindow(hwnd); //première mise a jour de la fenêtre HDC gldc = GetDC(hwnd); //utiliser pour connaitre la zone de dessin PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // taille du PIXELFORMATDESCRIPTOR 1, // versiom PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags //PFD_DRAW_TO_WINDOW = peut dessiner la fenetre //PFD_SUPPORT_OPENGL = supporte OpenGL //PFD_DOUBLEBUFFER = dessine dans une mémoire avant d'envoyer a la fenêtre PFD_TYPE_RGBA, // utilise le rouge vert bleu et transparence 32, // bits du framebuffer. 0, 0, //plan et décalage rouge 0, 0, //plan et décalage vert 0, 0, //plan et décalage bleu 0, 0, //plan et décalage de transparence 0, //plan total accumulation buffer 0, 0, 0, 0, //plan r,g,b,a de accumulation buffer 24, // nombre de bits du depthbuffer 8, // nombre de bits du stencilbuffer 0, // nombre de Aux buffers du framebuffer. PFD_MAIN_PLANE, // ceci est la couche pricipal 0, // reserved 0, 0, 0 // couche ignorer }; int PixelFormat; PixelFormat = ChoosePixelFormat(gldc, &pfd); //trouve un pixel format qui correspond SetPixelFormat(gldc,PixelFormat, &pfd); //sélection le pixel format HGLRC gl_context = wglCreateContext(gldc);//créer le context wglMakeCurrent(gldc, gl_context); //utilise ce context RGB color ={}; color.r = 1.0; color.g = 0.0; color.b = 0.0; while(true) { while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))//récupère le message ou attend le prochain { TranslateMessage(&Msg); //traduit le message DispatchMessage(&Msg); //transfere le message a la fonction de fenetre(WndProc) } if(Msg.message == WM_QUIT) break; HSV hcolor =rgb_to_hsv(color); hcolor.h +=0.01f; color = hsl_to_rgb(hcolor); glClearColor(color.r, color.g, color.b, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0f - color.r, 1.0f - color.g, 1.0f - color.b); glBegin(GL_TRIANGLES); glVertex3f(-0.25f, -0.25f, 0.0f); // V0 glVertex3f( 0.0f, 0.25f, 0.0f); // V1 glVertex3f( 0.25f, -0.25f, 0.0f); // V2 glEnd(); SwapBuffers(gldc);//mise a jour du dessin } return 0; } ```
Did you like this post? Tell us
Leave a comment
Log in with your itch.io account to leave a comment.
C'est le fameux triangle, mais pas n'importe comment mossieu ! C'est un triangle en HSV ! Et ça, ça, c'est la classe.
Merci, ça permet de mieux voir si le programme freeze, ça aide avec des api plus compliqué.