Chapitre 2 : Le
DirectDraw |
. |
a) Notion de surface |
Une surface est un objet dans lequel
on peut dessiner. Jusque là, rien de bien compliqué. Il existe
deux types de surfaces : les surfaces primaires "Primary Surface"
et les surfaces secondaires "Seconday Surface". |
Les surfaces primaires correspondent
à l'écran. C'est à dire que tout ce qui y sera dessiné sera
directement affiché à l'écran physique. On peut comparer cette
surface avec un pointeur dont l'adresse correspond à A000:0000
en mode 13h sous Dos. |
A l'inverse, les surfaces secondaires
sont des surfaces qui se trouvent "ailleurs", soit dans la
RAM, soit dans la mémoire vidéo dans une autre page d'écran.
|
Une surface est dite complexe (Complex
Surface) si elle se décompose en plusieurs sous-surfaces,
appelées BackBuffer Surface. On pourra passer d'une sous-surface
à une autre en disant "au suivant". Quand on est passé par
la dernière sous-surface, on repasse à la première. |
Un exemple pour bien saisir le principe
et l'utilité : |
Nous créons une surface
primaire complexe constituée de deux sous-surface. Seulement
une de ces deux sous-surface est affichée à l'écran, pendant
que nous pouvons dessiner sur la seconde. A un moment, on
passe à la suivante, ce qui a pour conséquence de littéralement
inverse les deux surfaces, permettant ainsi un page flip en
douceur. |
On peut imposer à DirectDraw de placer
une surface en mémoire RAM plutôt qu'en mémoire vidéo. Cela
sert en général quand il faut pouvoir à la fois LIRE et ECRIRE
sur l'écran (pour un effet feu par exemple), car en général
une seule de ces deux opérations est possible à la fois. |
En général, il y a trois façons d'utiliser
les surfaces : |
- On utilise la mémoire vidéo, on
déclare une surface primaire complexe composée de deux sous-surfaces
et on utilise l'écran avec un page flip classique. |
- On utilise la mémoire vidéo, on
déclare une surface primaire simple, et on passe son temps
à y copier le contenu d'un buffer depuis la mémoire de l'application
où l'image aura été dessinée (C'est en général comme cela
que ça se passait avec le mode 13h sous Dos) |
- On utilise RAM, on y déclare une
surface primaire complexe composée de deux sous-surfaces,
on trace dans la seconde sous-surface tandis que la demande
de flip ("au suivant") provoque en réalité la COPIE de cette
seconde sous-surface vers l'écran, symbolisé par la première
sous-surface. |
On ne dessine jamais directement sur
l'écran quand il est en RAM, on passe toujours par la sous-surface
non affichée, car sinon cela est bien trop lent. A chaque
octet envoyé dans la RAM, DirectDraw doit effectuer l'opération
similaire vers l'écran, je vous laisse imaginer le faste de
ce genres d'opérations. |
Voyons à présent les avantages de
chacune de ces méthodes : |
- Le page flipping : marche assez
bien pour les routines 3D où l'écran est de toutes façons
totalement effacé d'une image à une autre. On prend la sous-surface
non affichée, on efface tout son contenu, on y trace l'image
suivante, on flipe et on boucle. |
- La mémoire vidéo avec buffer en
RAM : pratique pour les effets où il faut utiliser l'image
précédente pour générer l'image suivante, ou s'il faut pouvoir
lire le contenu de l'écran au fur et à mesure de son traçage
(On en aura besoin ici pour les MetaBalls). Il y a cependant
un problème ennuyant : puisque notre buffer se trouve chez
nous, DirectDraw n'en a pas connaissance et on ne pourra pas
se servir des primitives Windows pour y tracer quoi que ce
soit. |
- La sous-surface en RAM : quand on
y réfléchit, cela revient exactement à ce que l'on fait dans
le point précédant, à la différence que cette fois, DirectDraw
connaît le buffer en ram vu que c'est lui qui l'a créé. Cela
fait que nous pourrons y utiliser les primitives Windows,
et c'est cette solution que nous adopterons pour notre programme.
|
. |
ATTENTION : il faut bien se souvenir
qu'avec cette troisème méthode, DirectDraw COPIE entièrement
le buffer vers l'écran, même si pratiquement rien n'a changé.
Ca peut être un gaspillage incroyable, et cela devient invivable
avec des résolutions de l'ordre de 800x600 en 32bits. Mais
pour notre effet qui sera en 640x480 en 8bit, cela fait parfaitement
l'affaire. (Et puis, on peut toujours espérer que DirectDraw
trouvera un support Hardware pour la copie, ce que l'on ne
peut pas envisager si c'est nous qui faisons directement la
copie). |
. |
b) Un peu de pratique |
Parce que bon, c'est un peu vague
tout cela... On est toujours incapables d'afficher un pixel
à l'écran... |
Primo et avant toutes choses, il va
vous falloir les headers du DirectX que vous pouvez aller
charger à l'adresse suivante : |
|
Normalement il vous suffit de déziper
les fichiers dans le répertoire Lib de Delphi et le problème
est réglé. |
Vous devez utiliser l'unité DDraw.
|
Donc il vous faut d'abord un OBJET
DIRECTX. Ben waip, nos amis de chez Microsoft ont décidé qu'on
se la jouerait à la POO, donc tant pis, c'est comme ça que
ça marche. Créons une variable de type IDirectDraw. Il va
nous falloir également une surface pour l'affichage, une surface
complexe qui plus est, accompagnée d'une BackBuffer Surface.
|
Au moment de créer les surfaces, il
faudra passer en paramètre à une des fonctions de DirectX
une structure contenant les instructions qu'on lui donne.
Cette structure sera de type TDDSURFACEDESC et nous créons
donc également une variable de ce type. |
Enfin, il nous faudra une palette
des couleurs comme pour tout mode qui se respecte. Nos couleurs
devront être stockées dans un tableau de 256 éléments de type
PaletteEntry. Il faudra également un objet palette en lui-même,
de type IDirectDrawPalette. PaletteEntry se trouve dans l'Unit
Windows il faudra donc l'utiliser aussi. |
Ca a l'air beaucoup d'un coup, mais
rassurez-vous, après c'est tout :) |
Tout cela nous donne ceci : |
. |
Var (..) |
lpDD:IDirectdraw; |
Surface,Buffer:IDirectDrawSurface; |
ddSD:TDDSURFACEDESC; |
Palette:array[0..255] of PaletteEntry;
|
ddPalette:IDirectDrawPalette; |
. |
Bien, alors la première chose, c'est
de créer cet objet de type IDirectDraw : très simple, nous
appelons une des Api du DirectX : |
If DirectDrawCreate(Nil,lpDD,Nil)<>DD_OK
Then Exit; |
. |
Suite à cet appel, lpDD contient un
objet de type IDirectDraw. C'est à partir de lui que nous
allons créer nos surfaces. Mais avant cela, pensons à lui
expliquer ce que nous attendons de lui : nous voulons tout
l'écran pour nous, en fullscreen, tout en autorisant les appels
Ctrl+Alt+Del on ne sait jamais si ça plante : |
If lpDD.SetCooperativeLevel(MyForm.Handle,DDSCL_EXCLUSIVE
OR DDSCL_FULLSCREEN OR DDSCL_ALLOWMODEX OR DDSCL_ALLOWREBOOT)<>DD_OK
Then Exit; |
. |
Remarquez qu'il doit connaître le
handle de notre fenêtre. Ha bon... |
Ensuite donnons-lui notre résolution
: |
If lpDD.SetDisplayMode(640,480,8)<>DD_OK
Then Exit; |
. |
Bien, c'est déjà une bonne chose,
il nous faut à présent créer nos surfaces : pour cela nous
allons une nouvelle fois appeler une méthode lpDD, mais il
nous faudra lui donner une structure. C'est notre fameuse
structure TDDSURFACEDESC. |
. |
Nous commençons par tout mettre à
zéro, par prudence : |
Fillchar(ddSD,SizeOf(ddSD),0);
|
. |
Ensuite, expliquons ce qu'on veut
comme surface. Tout d'abord il lui faut la taille de la structure,
pour vérifier que tout va bien : |
ddSD.dwSize:=SizeOf(ddSD); |
. |
Ensuite, nous devons lui dire quels
sont les champs de la structure qu'il doit effectivement prendre
en compte. Nous lui expliquons qu'il faudra qu'il regarde
le contenu des caractéristiques ainsi que le nombre des sous-buffers.
ddSD.dwflags:=ddSD_caps or |
ddSD_backbuffercount; |
. |
Et puisqu'on lui a dit qu'il fallait
qu'il regarde les caractéristiques, il s'agit de les entrer
: une surface primaire en ram, de type complexe qui supporte
le flip. |
ddSD.ddscaps.dwcaps:=ddscaps_primarysurface
or ddscaps_systemmemory or ddscaps_complex or ddscaps_flip;
|
. |
Et puis également pour le nombre de
sous-buffers de cette surface complexe : ATTENTION : même
si ici nous avons une surface composée de deux sous-buffers,
nous devons lui dire "1", car il y a "une surface en plus
que celle de base". |
ddSD.dwbackbuffercount:=1; |
. |
Nous pouvons donc créer la surface
: |
If lpDD.CreateSurface(ddSD,Surface,Nil)<>DD_OK
Then Exit; |
. |
A partir de cet endroit, Surface contient
un objet de type IDirectDrawSurface. A ce moment, il nous
semble interessant d'avoir également un pointeur vers la buffer
secondaire, car ce que nous donne l'objet Surface, c'est en
fait le pointeur vers la première surface, celle qui est affichée
à l'écran, et c'est justement l'autre qui nous interesse :
|
ddSD.ddscaps.dwCaps:=DDSCAPS_BACKBUFFER; |
If Surface.GetAttachedSurface(ddSD.ddscaps,Buffer)<>DD_OK
Then Exit; |
. |
A partir d'ici, Buffer contient un
objet de type IDirectDrawSurface, mais cette surface représente
la surface non affichée. |
Bon, il est temps de songer à notre
palette des couleurs, remplissons notre tableau de couleurs,
on va se taper un beau dégradé de gris : |
. |
For I:=0 To 255 Do Begin |
Palette[I].peRed:=I; |
Palette[I].peGreen:=I; |
Palette[I].peBlue:=I; |
End; |
If lpDD.CreatePalette(DDPCAPS_8BIT,@Palette,ddPalette,Nil)<>DD_OK
Then Exit; |
Surface.SetPalette(ddPalette); |
. |
Et enfin, un truc qu'on oublie toujours
: marquer le curseur de la souris : |
ShowCursor(False); |
. |
Pfou... |
Ben c'est fini, l'écran est en 640x480x8
et nous avons tout contrôle dessus. Avant d'y afficher quoi
que ce soit, pensons déjà à la désinitialisation : |
lpDD.RestoreDisplayMode; |
ShowCursor(True); |
ddPalette:=nil; |
Buffer:=nil; |
Surface:=nil; |
lpDD:=nil; |
. |
Dans l'état actuel de notre progression,
notre programme se présente comme suit : |
program Effect; |
. |
uses |
Forms,Windows,DDraw; |
. |
var |
IsTerminated:Boolean; |
MyForm:TForm; |
lpDD:IDirectdraw; |
Surface,Buffer:IDirectDrawSurface; |
ddSD:TDDSURFACEDESC; |
Palette:array[0..255] of PaletteEntry; |
ddPalette:IDirectDrawPalette; |
I:Integer; |
. |
Procedure Key(Sender: TObject; Var
Key: Char); |
Begin |
IsTerminated:=True; |
End; |
. |
begin |
IsTerminated:=False; |
MyForm:=TForm.Create(Nil); |
MyForm.BorderStyle:=bsNone; |
@MyForm.OnKeyPress:=@Key; |
MyForm.Show |
. |
If DirectDrawCreate(Nil,lpDD,Nil)<>DD_OK
Then Exit; |
If lpDD.SetCooperativeLevel(MyForm.Handle,DDSCL_EXCLUSIVE
OR DDSCL_FULLSCREEN OR DDSCL_ALLOWMODEX OR DDSCL_ALLOWREBOOT)<>DD_OK
Then Exit; |
If lpDD.SetDisplayMode(640,480,8)<>DD_OK
Then Exit; |
Fillchar(ddSD,SizeOf(ddSD),0); |
ddSD.dwSize:=SizeOf(ddSD); |
ddSD.dwflags:=ddSD_caps or ddSD_backbuffercount; |
ddSD.ddscaps.dwcaps:=ddscaps_primarysurface
or ddscaps_systemmemory or ddscaps_complex or ddscaps_flip;
|
ddSD.dwbackbuffercount:=1; If lpDD.CreateSurface(ddSD,Surface,Nil)<>DD_OK
Then Exit; |
ddSD.ddscaps.dwCaps:=DDSCAPS_BACKBUFFER; |
If Surface.GetAttachedSurface(ddSD.ddscaps,Buffer)<>DD_OK
Then Exit; |
For I:=0 To 255 Do Begin |
Palette[I].peRed:=I; |
Palette[I].peGreen:=I; |
Palette[I].peBlue:=I; |
End; |
If lpDD.CreatePalette(DDPCAPS_8BIT,@Palette,ddPalette,Nil)<>DD_OK
Then Exit; |
Surface.SetPalette(ddPalette); |
ShowCursor(False); |
MyForm.WindowState:=wsMaximized;
|
. |
Repeat |
Application.ProcessMessages; |
Until IsTerminated; |
MyForm.Hide; |
lpDD.RestoreDisplayMode; |
ShowCursor(True); |
ddPalette:=nil; |
Buffer:=nil; |
Surface:=nil; |
lpDD:=nil; |
MyForm.Release; |
end. |
. |
Il ne fait rien de plus que de changer
la résolution, d'attendre une touche et revenir sous Windows.
|
. |
c) Le premier dessin |
Bien, nous avons des surfaces et tout
le tralala dont on a besoin pour dessiner : il ne nous reste
plus qu'à dessiner vraiment à l'écran. |
Nous allons écrire une nouvelle procédure
que l'on appelera à chaque tour de boucle, appelons là Show.
Dans cette procédure, il faudra demander un pointeur vers
notre surface secondaire, dessiner dans ce pointeur, libérer
le pointeur et demander le "flipping" afin que s'opère la
copie de notre image vers l'écran. |
Pour demander ce pointeur, il faut
utiliser la méthode Lock sur l'objet Buffer. Nous devons lui
passer un pointeur vers une structure de type tddsurfacedesc
qu'il remplira alors des informations qui nous seront utiles.
Une fois que nous aurons terminé notre image, il nous faudra
libérer le pointeur en appelant UnLock. Cela est impératif,
on ne peut pas locker une bonne fois pour toute la surface,
il faut la libérer à chaque tour de boucle. Cela se présente
comme ceci : |
Procedure Show; |
Var SurfaceDesc:TDDSurfaceDesc; |
Begin |
SurfaceDesc.dwSize:=SizeOf(SurfaceDesc);
|
If Buffer.Lock(Nil,SurfaceDesc,0,0)<>DD_OK
Then Begin |
IsTerminated:=True; |
Exit; |
End; |
(...) |
Buffer.UnLock(SurfaceDesc.LPSurface); |
lpDD.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0); |
Surface.Flip(Nil,0); |
End; |
. |
Une fois l'appel Lock effectué, la
structure SurfaceDesc contient une multitude d'informations,
mais seulement deux champs vont réelement nous servir : SurfaceDesc.LPSurface
: il s'agit d'un pointeur vers la zone mémoire de la surface.
On y dessine comme on y dessinerait en mode 13H sous Dos.
|
SurfaceDesc.LPitch : contient une
valeur qui est le Pitch de l'écran. Cette valeur peut parraître
curieuse si l'on en connaît pas son origine. En mode 13H,
vous êtes bien sûr habitués à avoir une longueur de ligne
de 320pixels, et par conséquent une longueur équivalant à
320octets. Il semble à nouveau évident que si on était en
32bit, la longueur de cette même ligne serait de 320x4 octets.
Mais tout n'est pas si simple, car parfois la longueur de
la ligne en mémoire EST PLUS GRANDE que la longueur réelement
affichée, afin de garantir un alignement plus facile dans
la mémoire. Il n'est pas rare en effet dans les modes 640x480x8
d'avoir une longueur de ligne en mémoire de 1024 octets. La
coordonée d'un pixel se calcule alors selon la formule X+Y*Pitch
et non plus X+Y*640. |
Il y a bien sur neuf chances sur dix
que Pitch valle 640, mais on ne sait jamais... |
. |
Créons une nouvelle routine : DrawPixel.
Cette routine se présente comme ceci : |
Procedure DrawPixel(X,Y:Integer;C:Byte;Desc:TDDSurfaceDesc);
|
Type TScreen=Array Of Byte; |
Begin |
If (X>=0) And (X<=639) And (Y>=0)
And (Y<=479) Then Begin |
TScreen(Desc.LPSurface)[X+Y*Desc.LPitch]:=C;
|
End; |
End; |
. |
Ce qu'elle fait semble clair : elle
affiche le plus simplement du monde un pixel dans ce buffer.
Elle est loin d'être optimisée mais tel n'est pas encore le
but ici... |
. |
Ensuite nous pouvous créer par exemple
une routine DrawRectangle : |
Procedure DrawRectangle(X,Y,W,H:Integer;C:Byte;Desc:TDDSurfaceDesc);
|
Var I,J:Integer; |
Begin |
For J:=Y To Y+H-1 Do Begin |
For I:=X To X+W-1 Do Begin |
DrawPixel(I,J,C,Desc); |
End; |
End; |
End; |
. |
Bien sûr cette routine est d'une
lenteur appocalyptique mais on s'en fiche pour le moment...
|
Nous pouvons remplacer le (...) de
tout à l'heure dans Show par |
DrawRectangle(Random(640),Random(480),Random(50)+10,Random(50)+10,Random(256),SurfaceDesc);
|
. |
Normalement, si vous n'oubliez pas
d'appeler Show dans la routine principale avant d'appeler
Application.ProcessMessages, vous devriez voir apparaître
des rectangles à l'écran. |
Voici le programme à peine modifié
qui se contente d'afficher un rectangle se déplaçant à l'écran
pour montrer que l'on peut tout aussi bien des des choses
animées si l'on oublie pas d'effacer le buffer avant chaque
mise à jour : remarquez le FillChar. |
. |
Program Effect; |
. |
Uses |
Forms,Windows,DDraw; |
. |
Var |
IsTerminated:Boolean; |
MyForm:TForm; |
lpDD:IDirectdraw; |
Surface,Buffer:IDirectDrawSurface;
|
ddSD:TDDSURFACEDESC; |
Palette:array[0..255] of PaletteEntry;
|
ddPalette:IDirectDrawPalette; |
I:Integer; |
X,Y,Dx,Dy:Integer; |
. |
Procedure Key(Sender: TObject; Var
Key: Char); |
Begin |
IsTerminated:=True; |
End; |
. |
Procedure DrawPixel(X,Y:Integer;C:Byte;Desc:TDDSurfaceDesc);
|
Type TScreen=Array Of Byte; |
Begin |
If (X>=0) And (X<=639) And (Y>=0)
And (Y<=479) Then Begin |
TScreen(Desc.LPSurface)[X+Y*Desc.LPitch]:=C;
|
End; |
End; |
. |
Procedure DrawRectangle(X,Y,W,H:Integer;C:Byte;Desc:TDDSurfaceDesc);
|
Var I,J:Integer; |
Begin |
For J:=Y To Y+H-1 Do Begin |
For I:=X To X+W-1 Do Begin |
DrawPixel(I,J,C,Desc); |
End; |
End; |
End; |
. |
Procedure Show; |
Var |
SurfaceDesc:TDDSurfaceDesc; |
Begin |
SurfaceDesc.dwSize:=SizeOf(SurfaceDesc);
|
If Buffer.Lock(Nil,SurfaceDesc,0,0)<>DD_OK
Then Begin |
IsTerminated:=True; |
Exit; |
End; |
Inc(X,Dx);Inc(Y,Dy); |
If (X<0) Or (X>639-50) Then Begin
Dx:=-Dx;Inc(X,Dx);End; |
If (Y<0) Or (Y>479-50) Then Begin
Dy:=-Dy;Inc(Y,Dy);End; |
FillChar(SurfaceDesc.LPSurface^,480*SurfaceDesc.LPitch,0);
|
DrawRectangle(X,Y,50,50,255,SurfaceDesc);
|
Buffer.UnLock(SurfaceDesc.LPSurface); |
lpDD.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0); |
Surface.Flip(Nil,0); |
End; |
. |
Begin |
IsTerminated:=False; |
MyForm:=TForm.Create(Nil); |
MyForm.BorderStyle:=bsNone; |
@MyForm.OnKeyPress:=@Key; |
MyForm.Show; |
. |
If DirectDrawCreate(Nil,lpDD,Nil)<>DD_OK
Then Exit; |
If lpDD.SetCooperativeLevel(MyForm.Handle,DDSCL_EXCLUSIVE
OR DDSCL_FULLSCREEN OR DDSCL_ALLOWMODEX OR DDSCL_ALLOWREBOOT)<>DD_OK
Then Exit; |
If lpDD.SetDisplayMode(640,480,8)<>DD_OK
Then Exit; |
Fillchar(ddSD,SizeOf(ddSD),0); |
ddSD.dwSize:=SizeOf(ddSD); |
ddSD.dwflags:=ddSD_caps or ddSD_backbuffercount;
|
ddSD.ddscaps.dwcaps:=ddscaps_primarysurface
or ddscaps_systemmemory or ddscaps_complex or ddscaps_flip;
|
ddSD.dwbackbuffercount:=1; |
If lpDD.CreateSurface(ddSD,Surface,Nil)<>DD_OK
Then Exit; |
ddSD.ddscaps.dwCaps:=DDSCAPS_BACKBUFFER; |
If Surface.GetAttachedSurface(ddSD.ddscaps,Buffer)<>DD_OK
Then Exit; |
For I:=0 To 255 Do Begin |
Palette[I].peRed:=I; |
Palette[I].peGreen:=I; |
Palette[I].peBlue:=I; |
End; |
If lpDD.CreatePalette(DDPCAPS_8BIT,@Palette,ddPalette,Nil)<>DD_OK
Then Exit; |
Surface.SetPalette(ddPalette); |
ShowCursor(False); |
MyForm.WindowState:=wsMaximized;
|
. |
X:=0; |
Y:=0; |
Dx:=1; |
Dy:=1; |
. |
Repeat |
Show; |
Application.ProcessMessages; |
Until IsTerminated; |
MyForm.Hide; |
lpDD.RestoreDisplayMode; |
ShowCursor(True); |
ddPalette:=nil; |
Buffer:=nil; |
Surface:=nil; |
lpDD:=nil; |
MyForm.Release; |
End. |
. |
d) Approfondissements |
Evidement ici je n'ai pas pu entrer
dans les détails. Je ne me suis même pas pris la peine de
détailler les paramètres des diverses méthodes de DirectX
que j'ai utilisé. En général, le code ci-dessus suffira, mais
je vous conseille de charger le SDK de DirectX (il ne fait
que 8Mo après tout) depuis le link se trouvant normalement
quelque part sur le site de Keskivoufo pour pouvoir utiliser
à fond le DirectX. |
Il faut tout de même faire quelques
remarques : |
Quand on locke une surface, il se
peut que la réponse soit autre chose que DD_OK. Habituellement
ça sera DDERR_SURFACELOST, ce qui signifie que quelque chose
s'est passé entraînant le passage à l'avant plan d'autre chose
que notre fenêtre. Si une telle chose arrive, il faudra attendre
que notre fenêtre repasse à l'avant-plan et RECREER LES SURFACES
avant de pouvoir continuer. En général cela se produit quand
une application affiche un message ou bien quand vous appuiez
sur alt+tab. La politique utilisée par notre programme est
tout simplement de quitter quand une telle chose arrive. |
Un oeil attentif aura peut-être repéré
que j'ai déplacé MyForm.WindowState:=wsMaximized APRES avoir
créé les surfaces et changé le mode d'écran. Bien qu'il faut
que la fenêtre soit créée et visible pour correctement configurer
l'écran, le changement de résolution entraîne des comportements
anormaux en ce qui concerne l'état de maximisation de la fenêtre.
Pour être tout à fait précis : si la résolution est effectivement
changée (c'est à dire si elle est différente du bureau), la
fenêtre est automatique maximisée. Mais par contre, si la
résolution ne change pas, la fenêtre, même si elle était maximisée
AVANT l'appel, se retrouvera en mode normal! Ne me demandez
pas de vous expliquer pourquoi, je n'en sais rien. Afin d'éviter
toutes surprises, il vaut mieux maximiser la fenêtre après
avoir créé les surfaces. |
Il est bien entendu possible de changer
la palette des couleurs pendant l'exécution du programme,
je n'ai montré ici que la configuration statique de la palette.
Il faut utiliser la méthode SetEntries sur notre objet IDirectDrawPalette.
Vous aurez tous les détails dans les références de DirectDraw.
|
Comme son nom l'indique, lpDD.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0)
attends la fin du balayage vertical de l'écran. Cette ligne
n'est pas obligatoire, bien entendu. |
Evitez de trop faire les
marioles une fois que vous être en mode FullScreen : si votre
programme plante, vous aurez souvent un mal de chien à récupérer
la machine. Ici cela peut se faire grâce à l'autorisation
d'utiliser Ctrl+Alt+Del (AllowReboot) afin de killer l'application,
mais si vous oubliez (ou interdisez) de la donner, soyez prudents.
De même, évitez le pas à pas quand votre programme est en
full-screen. |