Étant donné que OpenGL.pas de Delphi est la version 1.0 et que ce qui est actuellement utilisé est au moins la version 1.1, et que la méthode de simulation logicielle pure de Windows est également la version 1.1, vous devez donc importer vous-même certaines fonctions nécessaires. Certaines unités gratuites open source sont également disponibles, comme OpenGL12.pas de Mike Lischke. Bien sûr, l'écrire vous-même peut rendre la conception plus concise et vous n'avez pas besoin de trouver des erreurs dans un code énorme, trop avancé et complet.
Introduisez d’abord les unités nécessaires Windows, Messages, OpenGL
Pour ajouter quelques extensions nécessaires.
const
//GL_EXT_bgra
GL_BGR_EXT = 80E0 $ ;
GL_BGRA_EXT = 80E1 $ ;
// décalage du polygone
GL_POLYGON_OFFSET_UNITS = 2A00 $ ;
GL_POLYGON_OFFSET_POINT = 2A01 $ ;
GL_POLYGON_OFFSET_LINE = 2A02 $ ;
GL_POLYGON_OFFSET_FILL = 8 037 $ ;
GL_POLYGON_OFFSET_FACTOR = 8 038 $ ;
PROcédure glBindTexture (cible : GLEnum ; texture : GLuint ); opengl32 externe ;
procédure glDeleteTextures(n : GLsizei ; textures : PGluint);
procédure glGenTextures(n : GLsizei ; textures : PGluint); stdcall externe opengl32 ;
fonction glIsTexture(texture : GLuint) : GLboolean ; stdcall externe ;
procédure glPolygonOffset (facteur, unités : GLfloat); stdcall externe opengl32 ;
// Cette instruction est utilisée pour corriger un bug dans OpenGL.pas
fonction gluBuild2DMipmaps (cible : GLEnum ; composants, largeur, hauteur : GLint ; format, type : GLEnum ; Données : Pointeur) : GLint stdcall externe ;
L'interface a désormais été mise à niveau vers la version 1.1. Si d'autres extensions sont nécessaires, elles peuvent être ajoutées de la même manière.
Ensuite, vous devez créer le contexte de dessin OpenGL RC, pour lequel vous avez besoin du contexte de périphérique DC de la fenêtre GDI. La propriété TForm.Handle ou d'autres propriétés Handle de TWinControl sont DC. Vous pouvez utiliser la fonction suivante pour créer RC à partir de DC, et la valeur de retour est le handle de RC. Vous pouvez ensuite dessiner en utilisant OpenGL. Peut généralement être utilisé dans l'événement OnCreate du formulaire. Les options de cette fonction signifient le tampon de profondeur, le tampon de modèle, le tampon d'accumulation et génèrent la valeur du canal Alpha.
taper
TRCOptions = ensemble de (roDepth, roStencil, roAccum, roAlpha) ;
fonction CreateRC(dc : HDC ; opt : TRCOptions) : HGLRC ;
var
PFDescriptor : TPixelFormatDescriptor ;
Format de pixels : entier ;
commencer
FillChar(PFDescriptor, SizeOf(PFDescriptor), 0);
avec PFDescriptor faire
commencer
nTaille := SizeOf(PFDescriptor);
nVersion := 1;
dwFlags := PFD_SUPPORT_OPENGL ou PFD_DRAW_TO_WINDOW ou PFD_DOUBLEBUFFER ;
iPixelType := PFD_TYPE_RGBA ;
cColorBits := GetDeviceCaps(DC, BITSPIXEL) * GetDeviceCaps(DC, PLANS);
si roDepth en opt alors cDepthBits := 24 ;
si roStencil est en option alors cStencilBits := 8 ;
si roAccum en option alors cAccumBits := 64 ;
iLayerType := PFD_MAIN_PLANE;
fin;
PixelFormat := ChoisirPixelFormat(DC, @PFDescriptor);
Assert (PixelFormat <> 0);
Assert(SetPixelFormat(DC, PixelFormat, @PFDescriptor));
Résultat := wglCreateContext(DC);
Assert (Résultat <> 0);
wglMakeCurrent(dc, Résultat);
fin;
Dessinez dans l'événement OnPaint du formulaire. N'oubliez pas qu'une fois le dessin terminé, vous devez utiliser SwapBuffers (dc : HDC) pour échanger le tampon de dessin et le tampon d'affichage afin que l'image soit affichée. N'oubliez pas non plus d'appeler glViewport(0, 0, ClientWidth, ClientHeight); dans l'événement OnResize du formulaire afin que RC et DC puissent être synchronisés.
Détruisez RC lors de l'événement OnDestroy du formulaire.
procédure DestroyRC(rc:HGLRC);
commencer
si rc = 0 alors Quittez ;
wglMakeCurrent(0, 0);
wglDeleteContext(rc);
fin;
À ce stade, le cadre d’un programme OpenGL a à peu près pris forme. Mais il reste encore des problèmes à résoudre.
Tout d’abord, empêchez Windows d’effacer l’arrière-plan et d’affecter la vitesse. Ajouter des fonctions membres au formulaire
privé
procédure WMEraseBkgnd(var Message : TWmEraseBkgnd); message WM_ERASEBKGND ;
procédure TGLWindow.WMEraseBkgnd(var Message : TWmEraseBkgnd);
commencer
Message.Résultat := 1;
fin;
Deuxièmement, pour être plus en sécurité. Ajoutez les fonctions membres suivantes.
protégé
procédure CreateParams (var Params : TCreateParams );
procédure TGLWindow.CreateParams(var Params: TCreateParams);
commencer
hérité;
avec les paramètres faire
commencer
Style := Style ou WS_CLIPCHILDREN ou WS_CLIPSIBLINGS ;
WindowClass.Style := CS_VREDRAW ou CS_HREDRAW ou CS_OWNDC ;
fin;
fin;
D'accord, maintenant vous pouvez oublier ces choses gênantes et écrire votre magnifique affichage 3D :)
Je dois dire quelques mots, ne créez pas plusieurs RC dans un seul thread, car cela affecterait sérieusement les performances. Certaines démonstrations personnelles de contrôles de fenêtre OpenGL placent plusieurs contrôles sur un formulaire, ce qui n'est en fait pas une bonne idée. Plusieurs vues doivent être affichées avec une seule fenêtre OpenGL. De plus, n’accédez pas aux fonctions OpenGL entre les threads.
De plus, lorsque Windows installe automatiquement le pilote de la carte graphique, il n'installera pas l'accélération matérielle OpenGL. Vous devez installer vous-même le pilote du fabricant de la carte graphique !
De plus, une fonction d'affichage plein écran gratuite est fournie :)
function FullScreen(win : TWinControl ; largeur, hauteur, profondeur de bits : entier) : booléen ;
var mode d'affichage : DEVMODE ;
commencer
FillChar (mode d'affichage, taille de (mode d'affichage), 0);
avec le mode d'affichage, faites
commencer
dmSize := sizeof(mode d'affichage);
dmPelsWidth:= largeur ;
dmPelsHeight := hauteur;
dmBitsPerPel := profondeur de bits ;
dmFields := DM_BITSPERPEL ou DM_PELSWIDTH ou DM_PELSHEIGHT ;
fin;
si ChangeDisplaySettings (displaymode, CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL
puis commence
ShowWindow(win.Handle, WS_MAXIMIZE);
résultat := vrai;
fin
sinon résultat := faux;
fin;
procédure RestoreDisplay(win: TWinControl);
commencer
ChangeDisplaySettings(PDEVMODE(0)^, 0);
ShowWindow(win.Handle, SW_RESTORE);
fin;