Création de surface

 

Maintenant que DirectDraw et l'écran sont initialisés, vous allez pouvoir créer la surface primaire et le back buffer. Vous aurez dès lors tout le minimum pour faire une animation.

Remarque:

Un "vrai" back buffer n'est possible (à ma connaissance) que dans le cas d'un mode plein écran. Pour le mode fenêtré, il faudra simuler un back buffer en passant par un écran offscreen !

Pour se créer une surface, il faut passer par une structure qui va contenir toutes les informations nécessaires pour décrire cette surface:

il y a

typedef struct _DDSURFACEDESC {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
union {
LONG lPitch;
DWORD dwLinearSize;
};
DWORD dwBackBufferCount;
union {
DWORD dwMipMapCount;
DWORD dwZBufferBitDepth;
DWORD dwRefreshRate;
};
DWORD dwAlphaBitDepth;
DWORD dwReserved;
LPVOID lpSurface;
DDCOLORKEY ddckCKDestOverlay;
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS ddsCaps;
} DDSURFACEDESC;

ou

typedef struct _DDSURFACEDESC2 {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
union
{
LONG lPitch;
DWORD dwLinearSize;
} DUMMYUNIONNAMEN(1);
DWORD dwBackBufferCount;
union
{
DWORD dwMipMapCount;
DWORD dwRefreshRate;
} DUMMYUNIONNAMEN(2);
DWORD dwAlphaBitDepth;
DWORD dwReserved;
LPVOID lpSurface;
union
{
DDCOLORKEY ddckCKDestOverlay;
DWORD dwEmptyFaceColor;
} DUMMYUNIONNAMEN(3);
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS2 ddsCaps;
DWORD dwTextureStage;
} DDSURFACEDESC2, FAR* LPDDSURFACEDESC2;

Avec:

ddckCKDestBlt, ddckCKDestOverlay, ddckCKSrcBlt, ddckCKSrcOverlay
Ces quatres champs utilisent une structure de type DDCOLORKEY pour définir une couleur qui sera utilisée lors des opérations du blitter ou lorsque deux surfaces se superposent

Par exemple dans le champ ddckCKSrcBlt, vous allez pouvoir définir la couleur noire comme étant la couleur transparente. Vous aurez ainsi un sprite qui pourra passer sur un fond d'écran.

La couleur noire n'est pas forcement un choix judicieux, en effet, il s'agit d'une couleur fréquement utilisée dans une image, de même que le blanc. On pourra à la place utiliser une couleur dont une de ses composantes primaires est saturée. Exemple le rouge à 255 et le vert et bleu à 0.


ddpfPixelFormat
Champ de type DDPIXELFORMAT qui permettra de décrire le format du pixel

ddsCaps
de type DDSCAPS ou DDSCAPS2 suivant la structure choisie, c'est ce qui va permettre de définir les caractéristiques de la surface. Par exemple surface primaire associé à une surface secondaire.

dwBackBufferCount: Ce champ indique le nombre de back buffer à associer à la surface primaire.

dw Flags On précise ce que l'on veut définir et donc les champs qui seront valides et utilisables dans DDSURFACEDESC2.

Image non trouvée !S'assurer que l'on a bien effacé les valeurs initialisées dans la structure DDSURFACEDESC2 et initialiser le membre dwSize de cette structure.

ZeroMemory (&ddsd, sizeof (ddsd)) et ddsd.dwSize = sizeof (DDSURFACEDESC2)


dwHeight and dwWidth Taille de la surface en pixel

je passse les autres champs pour le moment:

On utilisera ensuite la fonction CreateSurface pour créer la surface:

Suivant la structure:

STDMETHOD CreateSurface(
LPDDSURFACEDESC lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter
);

HRESULT CreateSurface(
LPDDSURFACEDESC2 lpDDSurfaceDesc2,
LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter
);

Avec lpDDSurfaceDesc ou lpDDSurfaceDesc2 qui est la description de la surface à créer,

lplpDDSurface qui est un pointeur sur la surface créée. C'est donc un champ en sortie.

Le troisième paramètre doit être à NULL.

Pas d'exemple de code dans ce chapitre, vous ne connaissez pour le moment que peu de choses pour pouvoir voir grand chose à l'écran, mais cela va venir...

Par contre, voici quelques fonctions qui peuvent être utiles:

Remarque: Il est possible d'avoir un double tamponnage, c'est à dire une primary surface et un back buffer. Sous directX, et si la mémoire de votre carte est suffisante, rien n'empêche de faire un triple ou quadruple, ... tamponnage. J'en reparle en vitesse dans le chapitre flipping.

Voici un exemple de création d'une surface primaire et d'un back buffer en définissant une couleur transparente (Pour Dx 7).

Dans le cas où on désire un affichage en mode plein écran:

memset (&ddsd, 0, sizeof (DDSURFACEDESC2)); //initialisation de la structure
ddsd.dwSize = sizeof( DDSURFACEDESC2 );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; //on veut un backbuffer avec la surface primaire
//la surface que l'on veut se créer est primaire, associée à un backbuffer, et chargée en mémoire vidéo
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX| DDSCAPS_VIDEOMEMORY ; // pour indiquer qu'il s'agit d'une surface complexe (composé de plusieurs surfaces) et qu'elles peuvent être permutées.
ddsd.dwBackBufferCount = 1; // nombre de buffers associés à la surface. Ici 1 seul suffira.

//Sélection du noir comme clé de couleur transparente
ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0;


lpDD->CreateSurface(&ddsd,&lpDDSPrimary,NULL);

 

Un exemple de création de back surface:

ZeroMemory(&ddscaps, sizeof(ddscaps)); //initialisation de la structure
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

Ici, vous n'utiliserez pas CreateSurface, mais GetAttachedSurface() pour associer un back surface avec la surface primaire.
lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);

 

Mais il faudra peut-être (sûrement) se créer des surfaces offscreens pour charger les sprites, l'image de fond, ...

memset (&ddsd, 0, sizeof (DDSURFACEDESC2)); //initialisation de la structure
ddsd.dwSize = sizeof( DDSURFACEDESC2 );
//description de la surface, et couleurs transparentes
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_CKSRCBLT;

//Sélection du noir comme clé de couleur transparente
ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0;


ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = ...;

ddsd.dwHeight = ...;
lpDD->CreateSurface( &ddsd, &lpDDsOffscreen, NULL );

Dans le cas d'un mode fenêtré:

Rappel : Ce cas est un peu particulier, il est en effet impossible de rattacher un backbuffer sur une surface en mode fenêtré, car plusieurs applications utilisent le même écran. Vous allez donc simuler tout cela en passant par une surface offscreen !

// Mode windows
//-- Creation de la primary surface
memset (&ddsd, 0, sizeof (DDSURFACEDESC2)); //initialisation de la structure
ddsd.dwSize = sizeof( DDSURFACEDESC2 );


// Le paramètre dwFlags indique à DirectDraw quel champ DDSURFACEDESC2
// contiendra les valeurs correctes
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

//Sélection du noir comme clé de couleur transparente
ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0;

lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );

// Creation d'un back buffer virtuel

ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
// Initialisation de la résolution X-Y d'une surface off-screen qui doit être identique à la surface primaire
ddsd.dwWidth = w;
ddsd.dwHeight = h;
// Initialisation surface en "offscreen" surface
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

lpDD->CreateSurface(&ddsd, &g_pDDSBack, NULL); // On va ainsi simuler un écran logique du mode full-screen

Remarque, il est possible de faire appel à la fonction suivante pour créer un backbuffer virtuel:


Fonction de Création de surface offscreen