Créer une interface DirectDraw

 

Maintenant que la fenêtre existe, il faut créer un objet DirectDraw:

La fonction DirectDrawCreateEx() sert à obtenir un pointeur vers une interface IDirectDraw7 (pour Dx7).

HRESULT WINAPI DirectDrawCreateEx(
GUID FAR *lpGUID,
LPVOID *lplpDD,
REFIID iid,
IUnknown FAR *pUnkOuter
);


Avec lpGUID qui va permettre d'indiquer :

  • une utilisation des fonctions gaphiques matérielles avec DDCREATE_HARDWAREONLY de la carte.
  • DDCREATE_EMULATIONONLY Pour une émulation. L'émulation peut-être intéressante pour voir les performances de la machine, mais en principe, vous devriez passer NULL pour indiquer l'utilisation du driver par défaut.
  • NULL pour le pilote par défaut

lplpDD : adresse d'une variable destinée à recevoir un pointeur vers une interface IDirectDraw7, si la fonction n'échoue pas, ce sera de là que vous pourrez lancer les fonctions DDraw.

iid : Doit être positionné à IID_IDirectDraw7. Rien d'autre ne marche...

pUnkOuter : doit être à NULL.


Exemple :

DX5 : DirectDrawCreate(NULL,&lpDD,NULL); avec LPDIRECTDRAW lpDD; // A proscrire donc ...

DX7 : DirectDrawCreateEx(NULL,(void**)&lpDD,IID_IDirectDraw7,NULL); avec LPDIRECTDRAW7 lpDD;

Remarque: une autre solution pour initialiser Ddraw 7 serait de faire ceci, mais je ne l'ai jamais essayé:

ddrval = CoCreateInstance(&CLSID_DirectDraw,NULL, CLSCTX_ALL, &IID_IDirectDraw7, &lpdd);
if(!FAILED(ddrval))
ddrval = IDirectDraw7_Initialize(lpdd, NULL);

 

Par contre, je pense qu'il faudra aussi faire ceci avant de créer l'objet:

Ddraw utilise des services de type COM (Component Object Model). Il faut donc les initialiser:

if (FAILED(CoInitialize(NULL)))
{

Gestion de l'erreur...

}

De la même manière, ne pas oublier à la fin du programme de faire CoUninitialize();

Je ne sais pas ce que cela apporte de plus par rapport à la première méthode de création qui reste selon moi bien plus simple et doit faire à peu près la même chose...

Reste ensuite à indiquer ce que l'on veut faire de l'interface:
- Dériver l'accès direct vers la vidéo dans la fenêtre d'un application
- Ou au contraire donner à DirectDraw le contrôle total du matériel vidéo, permettant ainsi de changer de résolution, ...

Il faut définir le niveau de coopération entre les différentes applications et la votre:

C'est le rôle de SetCooperativeLevel:

flags de la fonction SetCooperativeLevel

Valeur Désignation
DDSCL_ALLOWMODEX Permet d'utiliser le Mode X. Ce flag doit être utilise avec DDSCL_EXCLUSIVE et DDSCL_FULLSCREEN.
DDSCL_ALLOWREBOOT Permet d'utiliser la combinaison ctrl+alt+del alors qu'on est en mode exclusif
DDSCL_EXCLUSIVE Demande un monde exclusif. Ce flag doit être utilise avec DDSCL_FULLSCREEN.
DDSCL_FULLSCREEN Indique que notre programme sera en plein écran. Ce flag doit être utilisé avec DDSCL_EXCLUSIVE.
DDSCL_NORMAL L'application sera une application Windows normale, il est donc évident qu'il ne faut pas l'utiliser avec DDSCL_ALLOWMODEX, DDSCL_EXCLUSIVE, ou DDSCL_FULLSCREEN
DDSCL_NOWINDOWCHANGES Indique que DirectDraw n'a pas la permission de minimiser ou de restaurer une application.

 

Après avoir créé votre fenêtre en mode Fullscreen, C'est ici que vous allez pouvoir passer réellement en mode plein écran ou non en le précisant à DirectDraw:

Il faut indiquer que l'application fonctionne en mode plein écran:

HRESULT hr;

hr = lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);

ou en mode fenêtré

hr = lpDD->SetCooperativeLevel(g_hWnd, DDSCL_NORMAL);

 

et changer la résolution uniquement si on veut un mode plein écran:

hr = lpDD->SetDisplayMode(ResolX, ResolY, numcolor);

A partir de DirectX 7, la commande prend 2 paramètres supplémentaires:

void SetDisplayMode(
int width,
int height,
int bitPerPixel,
int refreshRate,
bool standardVgaMode);

En entrée:

width: Largeur

height: hauteur

bitPerPixel: Nombre de bits par pixel

refreshRate qui est la fréquence désirée, vous pourrez passer NULL

standardVgaMode dans lequel vous passerez aussi NULL

Pour passer d'une résolution à une autre, il faut quand même vérifier que cette résolution soit disponible sur la machine !


Pour cela, ous disposez de la méthode suivante:

HRESULT EnumDisplayModes(
DWORD dwFlags,
LPDDSURFACEDESC lpDDSurfaceDesc,
LPVOID lpContext,
LPDDENUMMODESCALLBACK lpEnumCallback
);

En entrée:

dwFlags étant NULL

lpDDSurfaceDesc, pointe sur une structure DDSURFACEDESC qui permettra de vérifier qu'il y a encore d'autres modes. Si NULL, alors tous les modes sont énumérés.

lpContext Quelque chose que l'on veut passer à une procédure callback qui sera lancée à chaque énumération.

lpEnumCallback la procédure callback

Cette méthode exécutera donc le code suivant:

HRESULT WINAPI EnumModesCallback(
LPDDSURFACEDESC lpDDSurfaceDesc,
LPVOID lpContext
);

Avec lpDDSurfaceDesc qui contient une adresse sur une variable de type DDSURFACEDESC contenant les informations comme le mode, la fréquence.

lpContext, Valeur passée lors de l'énumération par EnumDisplayModes.

 

La fonction retourne DDENUMRET_OK pour permettre de continuer l'énumération. DDENUMRET_CANCEL pour la stopper

Exemple de code:

HRESULT enummodescallback(LPDDSURFACEDESC lpddsd, LPVOID lpContext)
{

lpddsd->dwWidth;

lpddsd->dwHeight;
lpddsd->UNION_MEMBER(2, dwRefreshRate));
adddisplaymode(lpddsd); // Fonction à créer dans laquelle vous allez ajouter ce nouveau mode dans votre liste

return DDENUMRET_OK;
}