Tutoriels Direct3D 10 : DXUT

| Msdn | Romain Perruchon (Traducteur, relecteur) | Cyril Doillon (relecteur) |

Traduction d'un article original de la Library MSDN US

- Titre : Tutoriels Direct3D 10 : DXUT

- Auteurs : Msdn, Romain Perruchon (Traducteur, relecteur), Cyril Doillon (relecteur)

- Parution : 3 mai 2009

- Mise à jour : 3 mai 2009

- Licence : Cet article est une traduction d'un article original de Microsoft en anglais. Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Microsoft. Lire l'article original Ici.

Sommaire

- II. Tutoriels sur DXUT

- II-8. Tutoriel 8 : Introduction à DXUT

- II-8-a. résumé

- II-8-b. source

- II-8-c. DXUT

- II-8-d. Mettre en place les fonctions de Callback

- II-8-e. Débogage avec DXUTTrace

- II-8-f. Gestion et initialisation de Device

- II-8-f-1. Callback IsD3D10DeviceAcceptable

- II-8-f-2. Callback ModifyDeviceSettings

- II-8-f-3. Callback OnD3D10CreateDevice

- II-8-f-4. Callback OnD3D10DestroyDevice

- II-8-g. Affichage

- II-8-g-1. Callback OnFrameMove

- II-8-g-2. Callback OnD3D10FrameRender

- II-8-h. Traitement des messages

- II-8-h-1. Callback MsgProc

- II-8-h-2. Callback KeyboardProc

- II-8-i. Conclusion

- II-9. Tutoriel 9 : Meshes avec DXUT

- II-9-a. Résumé

- II-9-b. Source

- II-9-c. Maillage

- II-9-c-1. Création du maillage

- II-9-c-2. Rendu du maillage

- II-9-c-3. Destruction du maillage

- II-10. Tutoriel 10 : Aller plus loin avec DXUT

- II-10-a. Résumé

- II-10-b. Source

- II-10-c. Caméra DXUT

- II-10-d. Boîtes de dialogue de DXUT

- II-10-d-1. Déclarations

- II-10-d-2. Initialisation des boîtes de dialogue

- II-10-e. Initialisation du Gestionnaire de Ressources

- II-10-e-1.

- II-10-e-2. Actualisation du Traitement de Message

- II-10-f. Boîte de Dialogue 3D Settings

- II-10-g. Rendu de Texte

- II-10-g-1. Initialisation

- II-10-g-2. Rendu

II - Tutoriels sur DXUT

II-8 - Tutoriel 8 : Introduction à DXUT

II-8-a - résumé

Ce tutoriel présente DXUT. DXUT est une couche bâtie sur Direct3D pour aider à rendre les échantillons, les prototypes, les outils et les jeux professionnels plus robustes et faciles à bâtir. Il simplifie les interfaces de programmation Windows et Direct3D, sur la base d'un usage typique.

Le résultat de ce tutoriel est un exemple qui ressemble comme celui du précédent tutoriel. Toutefois, il est implémenté différemment.

II-8-b - source

(SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial08

II-8-c - DXUT

DXUT fournit un processus simplifié de création de fenêtre, de création (ou sélection) d'un appareil Direct3D et de traitement de messages Windows. Cela vous permet de passer moins de temps à vous demander comment effectuer ces tâches standard.

DXUT pour Direct3D 10 est aussi hautement modulaire. Le composant fondamental de DXUT contient la création de fenêtre standard, la création de device et les fonctions de gestion. Les composants en option de DXUT incluent des fonctions comme la manipulation de caméra, un système GUI et un traitement de maillage. Ce tutoriel explique les composants fondamentaux de DXUT. Les composants en option seront expliqués dans des tutoriels ultérieurs. Les caractéristiques présentées dans ce tutoriel incluent la création de device, la boucle principale et l'entrée simple au clavier.

DXUT expose une large gamme de fonctions de rappel que l'utilisateur peut utiliser. Les fonctions de rappel sont appelées par le DXUT à des points logiques pendant l'exécution d'un programme. Vous pouvez insérer un code personnalisé dans les fonctions de rappel pour construire l'application, tandis que DXUT gère les exigences d'implémentation de fenêtre et de device.

DXUT supporte des applications qui contiennent des voies de code Direct3D 9 et/ou Direct3D 10. Cela permet à DXUT de prendre le meilleur chemin de code pour le système sous lequel tourne l'application. Toutefois, ce tutoriel ne se concentre que sur le rendu Direct3D 10. Pour un exemple d'application duale Direct3D 9 et Direct3D 10 bâtie sur DXUT, voyez l'échantillon BasicHLSL10 dans le SDK DirectX.

II-8-d - Mettre en place les fonctions de Callback

Modifier la fonction WinMain d'une application est la première étape. Dans les précédents tutoriels, WinMain invoquait la fonction d'initialisation puis entrait la boucle de message. Dans l'environnement cadre DXUT, WinMain se comporte de façon similaire.

D'abord, les fonctions de rappel sont configurées par l'application. Ce sont les fonctions que DXUT appelle pendant des évènements spécifiques quand l'application tourne. Les évènements notables incluent la création de device, la création de swap chain, l'entrée au clavier, le déplacement et le rendu de trame.

// Fonctions de rappel Direct3D10
DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable );
DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice );
DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizedSwapChain );
DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain );
DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice );
DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender );

DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );

Ensuite, l'application configure tout réglage supplémentaire de DXUT, comme dans l'exemple suivant :

// Affiche le curseur et le clippe quand on est en plein écran
DXUTSetCursorSettings( true, true );

Finalement, les fonctions d'initialisation sont appelées. La différence entre ce tutoriel et les didacticiels de base, c'est que vous ne devez traiter que du code spécifique de l'application pendant l'initialisation. C'est dû au fait que la création de device et de fenêtre est traitée par DXUT. On peut insérer du code spécifique de l'application pendant chaque fonction de rappel associée. DXUT invoque ces fonctions à mesure de la progression du processus d'initialisation.

// Initialise DXUT et créer la fenêtre Win32 désirée et le device
// Direct3D pour l'application. Appeler chacune de ces fonctions est
// facultatif, mais elles vous permettent de régler des options qui
// contrôlent le comportement de l'environnement cadre.
DXUTInit( true, true ); // Analyse la ligne de commande, traite les
// raccourcis clavier par défaut et affiche les msgboxes
DXUTCreateWindow( L"Tutorial8" );
DXUTCreateDevice( true, 640, 480 );

II-8-e - Débogage avec DXUTTrace

DXUTTrace est une macro-commande que l'on peut appeler pour créer un débogage de l'application. Elle fonctionne largement comme les fonctions de débogage standard, mais elle autorise un nombre variable d'arguments. Par exemple :

DXUTTRACE( L"Hit points left: %d\n", nHitPoints );

Dans ce tutoriel, elle est placée à côté de l'entrée de fonction pour rapporter l'état de l'application. Par exemple, au début de OnD3D10ResizedSwapChain(), le débogueur rapporte "SwapChain Reset called".

DXUTTRACE( L"SwapChain Reset called\n" );

II-8-f - Gestion et initialisation de Device

DXUT fournit diverses méthodes de création et de configuration de la fenêtre et du device Direct3D. Les méthodes utilisées dans ce tutoriel sont énumérées ci-dessous. Elles suffisent à complexifier modérément l'application Direct3D.

La procédure du tutoriel précédent dans InitDevice() et CleanupDevice() a été convenablement gérée la scindant entre les fonctions suivantes :

- • IsD3D10DeviceAcceptable Callback

- • ModifyDeviceSettings Callback

- • OnD3D10CreateDevice Callback

- • OnD3D10DestroyDevice Callback

Parce que toutes les ressources ne sont pas créées en même temps, on peut minimiser la perte de temps en réduisant le nombre d'appels répétés. On atteint ce résultat en ne recréant que les ressources qui dépendent du contexte. Par soucis de simplicité, les tutoriels précédents recréaient tout quand l'écran était redimensionné.

II-8-f-1 - Callback IsD3D10DeviceAcceptable

Cette fonction est invoquée pour chaque combinaison de réglages de device valide que l'on trouve dans le système. Elle permet à l'application d'accepter ou de rejeter chaque combinaison. Par exemple, l'application peut rejeter tous les devices REF ou rejeter des combinaisons de réglages plein écran.

Dans ce tutoriel, tous les devices sont acceptables, parce qu'on n'a besoin d'aucune fonctionnalité avancée.

II-8-f-2 - Callback ModifyDeviceSettings

Cette fonction de rappel permet à l'application de modifier tout réglage de device immédiatement avant que DXUT crée le device. Dans ce tutoriel, il n'y a rien qu'il faille faire dans le rappel, parce qu'on n'a besoin d'aucune fonctionnalité avancée.

II-8-f-3 - Callback OnD3D10CreateDevice

Cette fonction est appelée après la création du device Direct3D10. Après la création du device, une application peut utiliser ce rappel pour allouer des ressources, régler des mémoires tampons, gérer d'autres tâches nécessaires.

Dans ce tutoriel, l'essentiel de la fonction InitDevice() du tutoriel 7 est copié dans la fonction de rappel. Le code pour la création de device et de swap chain est omis, parce que ces fonctions sont gérées par DXUT. OnD3D10CreateDevice crée l'effet, les mémoires tampons vertex/index, les textures et les matrices de transformation. Le code a été copié à partir du tutoriel 7 avec des altérations minimales.

II-8-f-4 - Callback OnD3D10DestroyDevice

Cette fonction de rappel est appelée immédiatement avant que ID3D10Device soit mise à jour par DXUT. Ce rappel est utilisé pour mettre à jour les ressources qui étaient utilisées par le device.

Dans ce tutoriel, OnD3D10DestroyDevice met à jour les ressources crées par la fonction OnD3D10CreateDevice. Ces ressources incluent les mémoires tampon vertex/index, la mise en page, les textures et les effets. Le code est copié à partir de la fonction CleanupDevice(), mais il a été modifié pour utiliser la macro SAFE_RELEASE.

II-8-g - Affichage

Pour l'affichage, DXUT fournit deux fonctions de rappel pour initialiser le rendu de votre application. La première, OnFrameMove, est appelée avant que chaque trame soit rendue. Elle accélère le temps dans l'application. La seconde, OnD3D10FrameRender, fournit le rendu pour DXUT.

Ces deux fonctions divisent le travail de la fonction Render() en deux étapes logiques. OnFrameMove actualise toutes les matrices pour animation. OnD3D10FrameRender contient les appels de rendu.

II-8-g-1 - Callback OnFrameMove

Cette fonction est appelée avant le rendu d'une trame. Elle sert à traiter l'état du monde. Toutefois, sa fréquence d'actualisation dépend de la vitesse du système. Sur des systèmes relativement rapides, elle est appelée plus d'une fois par seconde. Cela signifie que tout code d'actualisation d'état doit être régulé en fonction du temps. Sinon, elle fonctionnera différemment sur un système lent par rapport à un système rapide.

Chaque fois que la fonction est appelée dans le tutoriel, le monde est actualisé une fois et la couleur du maillage est ajustée. Ce code est copié directement à partir de la fonction Render() du tutoriel 7. Notez que les appels de rendu ne sont pas inclus.

II-8-g-2 - Callback OnD3D10FrameRender

Cette fonction est appelée chaque fois qu'une trame est redessinée. Dans cette fonction, des effets sont appliqués, des ressources sont associées et le dessin de la scène est appelé.

Dans ce tutoriel, cette fonction contient les appels pour effacer le back buffer et le stencil buffer, pour initialiser les matrices et dessiner les cubes.

II-8-h - Traitement des messages

Le traitement des messages est une propriété intrinsèque de toutes les applications de fenêtre. DXUT expose ces messages pour les applications avancées.

II-8-h-1 - Callback MsgProc

DXUT invoque cette fonction quand des messages de fenêtre sont reçus. La fonction permet à l'application de traiter les messages comme il semble adéquat.

Dans ce tutoriel, aucun message additionnel n'est traité.

II-8-h-2 - Callback KeyboardProc

Cette fonction de rappel est invoqué par DXUT quand une touche est appuyée. On peut l'utiliser comme une simple fonction pour traiter des commandes au clavier.

La fonction de rappel KeyboardProc n'est pas utilisée dans ce tutoriel, parce qu'aucune interaction au clavier n'est nécessaire. Toutefois, il existe un cas pour F1 que vous pouvez expérimenter. Essayez d'insérer du code pour déclencher la rotation des cubes.

II-8-i - Conclusion

Les fonctions couvertes par ce tutoriel vous permettent de démarrer un projet sous DXUT. Les tutoriel 9 et 10 couvrent des caractéristiques plus avancées de DXUT.

Pour lancer un nouveau projet avec DXUT, vous pouvez utiliser le Sample Browser pour copier et renommer tout projet dans le SDK DirectX. EmptyProject est un bon point de départ vierge pour des applications DXUT, ou vous pouvez choisir un autre échantillon.

II-9 - Tutoriel 9 : Meshes avec DXUT

II-9-a - Résumé

Ce tutoriel présente l'utilisation de maillages pour importer du source art. Il illustre les maillages en utilisant DXUT. Toutefois, on peut aussi utiliser les maillages sans DXUT.

Dans le tutoriel, vous remplacez un cube au centre de la fenêtre par un modèle importé d'un fichier. Le modèle contient déjà une texture avec des coordonnées.

II-9-b - Source

(SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial09

II-9-c - Maillage

Enumérer chaque vertex dans le code source est une méthode fastidieuse et brutale pour définir le source art. Au lieu de cela, il existe des méthodes pour importer des modèles déjà constitués dans votre application.

Un maillage est une collection de données de vertex prédéfinies qui incluent souvent des informations supplémentaires comme des vecteurs normaux, des couleurs, des matières et des coordonnées de texture. Aussi longtemps que l'on connaît le format du fichier de maillage, on peut l'importer et le rendre.

Les maillages servent à maintenir le source art séparément du code d'application, afin qu'il puisse être réutilisé. Par conséquent, les maillages sont conservés dans des fichiers séparés. Ils sont rarement générés dans une application proprement dite. Au lieu de cela, ils sont créés dans des logiciels de création 3D. Le cube qui a été généré dans les tutoriels précédents peut être sauvegardé dans un fichier séparé puis rechargé. Toutefois, importer peut être beaucoup plus efficace, en particulier si le maillage augmente en complexité. Un des plus grands avantages est la capacité d'importer les coordonnées de texture, afin qu'elles correspondent parfaitement. Elles peuvent être facilement spécifiées dans les applications de création.

DXUT traite les maillages en utilisant la classe CDXUTMesh10 qui est une classe enveloppante pour la classe D3DX Mesh. Cette classe inclut des fonctions pour importer, rendre et détruire un maillage. Le format de fichier que l'on utilise pour importer est le fichier .X. Il existe de nombreux convertisseurs disponibles gratuitement qui convertissent d'autres formats de modèles en format .X.

II-9-c-1 - Création du maillage

Pour importer le modèle, on commence par créer un objet CDXUTMesh10. Dans le cas présent, on l'appelle g_Mesh, mais en général, il vaut mieux que le nom de l'objet et le nom du source art correspondent pour s'associer plus facilement.

CDXUTMesh10 g_Mesh;

Ensuite, on appelle la fonction Create pour lire le fichier X et le stocker dans l'objet. La fonction Create nécessite que l'on passe dans le D3D10Device, le nom du fichier X qui contient le maillage, la mise en page et le nombre d'éléments dans la mise en page. Il existe aussi un paramètre facultatif appelé optimize qui appelle des fonctions D3DX pour ordonner les faces et vertex d'un maillage donné. Cela peut améliorer les performances de rendu.

Dans ce cas, on importe un fichier appelé "tiny.x". Le format des vertex qui définissent ce maillage contient des coordonnées des vertex, des normes et des coordonnées de texture. On doit spécifier la mise en page d'entrée comme indiqué dans l'exemple suivant :

// Définir la mise en page d'entrée
const D3D10_INPUT_ELEMENT_DESC layout[] =
{
{ L"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ L"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ L"TEXCOORD0", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
};

Après définition de la mise en page, on appelle la fonction Create pour importer le modèle. Le dernier paramètre est le nombre d'éléments dans le format de vertex. Parce qu'on a des coordonnées, des normes et des coordonnées de texture, on spécifie 3.

// Charger le maillage
V_RETURN( g_Mesh.Create( pd3dDevice, L"tiny.x", (D3D10_INPUT_ELEMENT_DESC*)layout, 3 ) );

S'il n'y a pas d'erreur, g_Mesh contient désormais le tampon vertex et index pour notre maillage nouvellement importé, ainsi que les textures et matériaux. Ensuite, on commence le rendu.

II-9-c-2 - Rendu du maillage

Dans les précédents tutoriels, parce qu'on avait un contrôle explicite du tampon vertex et des tampons index, on devait les régler convenablement avant chaque trame. Toutefois, avec un maillage, ces éléments sont soustraits. Par conséquent, on n'a à fournir que la technique d'effets qu'il faut utiliser pour rendre le maillage, et ça fait tout le travail.

La différence par rapport au tutoriel précédent est qu'on a éliminé la portion de OnD3DFrameRender où la fonction commençait à rendre le cube. Elle est remplacée par l'appel de rendu du maillage. Il est toujours une bonne pratique de régler la bonne mise en page en entrée avant que tout rendu de maillage. Cela garantit que la mise en page du maillage correspondra à l'input assembler.

//
// Configure la mise en page de vertex
//
pd3dDevice->IASetInputLayout( g_pVertexLayout );

Le rendu effectif se fait en appelant la fonction Render dans la classe CDXUTMesh10. Après que les tampons de la technique aient été correctement associés, on peut en faire le rendu. Pour assurer le rendu, on transfert le D3D10Device, l'Effet et la Technique contenue dans cet effet.

//
// Rendu du maillage
//
g_Mesh.Render( pd3dDevice, g_pEffect, g_pTechnique );

Si la matrice du monde est convenablement réglée pour le modèle, on peut voir à présent que le cube dans l'exemple précédent est remplacé par ce maillage plus compliqué. Notez que le maillage est beaucoup plus gros que le cube. Essayez d'appliquer une échelle à la matrice du monde pour que le maillage convienne au mieux à l'écran.

II-9-c-3 - Destruction du maillage

Comme tous les objets, l'objet CDXUTMesh10 dit être détruit après utilisation. On le fait en appelant la fonction Destroy.

g_Mesh.Destroy();

II-10 - Tutoriel 10 : Aller plus loin avec DXUT

II-10-a - Résumé

Ce tutoriel couvre les concepts avancés de DXUT. La plupart des fonctionnalités montrées dans ce tutoriel sont facultatives. Toutefois, elles peuvent servir à améliorer votre application à moindre coût. DXUT fournit un simple système GUI à base de sprites et une boîte de dialogue de réglage de device. De plus, il fournit quelques types de classes de caméra.

Dans ce tutoriel, vous créez un GUI pleinement fonctionnel pour modifier les réglages en utilisant le device et la scène. Il y aura des boutons, des barres de défilement et du texte pour démontrer ces capacités.

II-10-b - Source

(SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial10

II-10-c - Caméra DXUT

La classe CModelViewerCamera dans DXUT est fournie pour simplifier la gestion des transformations de vue et de projection. Elle fournit aussi des fonctionnalités GUI.

CModelViewerCamera g_Camera;

La première fonction que fournit la caméra est la création des matrices de vue et de projection. Avec la caméra, vous n'avez pas à vous soucier de ces matrices. Au lieu de cela, spécifiez l'emplacement de l'observateur, la vue elle-même et la taille de la fenêtre. Ensuite, passez ces paramètres à l'objet caméra, ce qui crée les matrices derrière la scène.

L'exemple suivant règle la portion de vue de la caméra. Cela inclut l'emplacement et la vue.

// Initialise la caméra
D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f );
D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f );
g_Camera.SetViewParams( &Eye, &At );

Ensuite, spécifiez la portion de projection de la caméra. On a besoin de fournir l'angle de vue, le rapport hauteur/longueur et les plans de coupe avant et arrière de la pyramide tronquée de visualisation. Ce sont les mêmes informations dont on avait besoin dans les tutoriels précédents. Toutefois, dans ce tutoriel, on n'a pas besoin de se soucier de créer les matrices elles-mêmes.

// Initialisation des paramètres de projection de la caméra
float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 5000.0f );
g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );

La caméra crée aussi des masques pour le feedback simple de la souris. Ici, on spécifie trois boutons de souris pour l'utilisation des opérations à la souris qui sont fournies - rotation du modèle, zoom et rotation de la caméra. Essayez de compiler le projet et de jouer avec chaque bouton pour comprendre ce que fait chaque opération.

g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );

Lorsque les boutons sont configurés, la caméra surveilles les entrées à la souris et agit en conséquence. Pour réagir aux entrées de l'utilisateur, ajoutez une fonction de surveillance à la fonction de rappel MsgProc. C'est la fonction vers laquelle DXUT dirige les messages.

// Transmet tous les messages de fenêtre restants à la caméra pour qu'elle puisse réagir aux entrées d'utilisateur
g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );

Finalement, après que toutes les données nécessaires aient été entrées dans la caméra, on extrait les matrices effectives pour les transformations. On saisit la matrice de projection et la matrice de vue ensemble avec les fonctions associées. L'objet caméra est responsable du calcul des matrices elles-mêmes.

g_pProjectionVariable->SetMatrix( (float*)g_Camera.GetProjMatrix() );
g_pViewVariable->SetMatrix( (float*)g_Camera.GetViewMatrix() );

II-10-d - Boîtes de dialogue de DXUT

L'interaction avec l'utilisateur peut être réalisée grâce à la classe CDXUTDialog. Elle contient des commandes dans une boîte de dialogue qui accepte les entrées d'utilisateur et les transmet à l'application à traiter. D'abord, on instancie la classe de boîte de dialogue. Ensuite, on peut ajouter des commandes individuelles.

II-10-d-1 - Déclarations

Dans ce tutoriel, deux boîtes de dialogue sont ajoutées. L'une s'appelle g_HUD, et contient le même code que les exemples Direct3D 10. L'autre s'appelle g_SampleUI et illustre des fonctions qui sont spécifiques à ce tutoriel. La seconde boîte de dialogue sert à contrôler le caractère "bouffi" du modèle. Elle règle une variable qui est transmise aux shaders.

CDXUTDialog g_HUD;      // gère la 3D UI
CDXUTDialog g_SampleUI; // boîte de dialogue pour les commandes spécifiques de l'exemple

Les boîtes de dialogue sont contrôlées par une classe appelée CDXUTDialogResourceManager. Elle transfère les messages et gère des ressources qui sont partagées par les boîtes de dialogue.

CDXUTDialogResourceManager g_DialogResourceManager; // gestionnaire des ressources partagées par les boîtes de dialogue

Finalement, une nouvelle fonction de rappel est associée aux évènements qui sont traités par le GUI. Cette fonction sert à gérer l'interaction entre les commandes.

void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );

II-10-d-2 - Initialisation des boîtes de dialogue

Parce que davantage d'usages ont été introduits et doivent être initialisés, ce tutoriel reporte l'initialisation de ces modules vers une fonction séparée appelée InitApp().

Les commandes pour chaque boîte de dialogue sont initialisées dans cette fonction. Chaque boîte de dialogue appelle sa fonction Init et passe au gestionnaire de ressources pour spécifier où les commandes doivent être placées. Elle règle aussi la fonction de rappel pour traiter les réponses GUI. Dans ce cas, la fonction de rappel associée est OnGUIEvent.

g_HUD.Init( &g_DialogResourceManager );
g_SampleUI.Init( &g_DialogResourceManager );
g_HUD.SetCallback( OnGUIEvent );
g_SampleUI.SetCallback( OnGUIEvent );

Après que chaque boîte de dialogue ait été initialisée, elle peut insérer les commandes à utiliser. HUD ajoute trois boutons à la fonctionnalité de base : touche plein écran, touche rendu de référence (logiciel), et modifier le device.

Pour ajouter un bouton, spécifiez l'identifiant IDC à utiliser, une chaîne à afficher, les coordonnées, la largeur et la longueur, et facultativement un raccourci clavier à associer au bouton.

Notez que les coordonnées sont relatives à l'ancre de la boîte de dialogue.

int iY = 10;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );

De façon similaire, pour l'interface utilisateur de l'exemple, trois commandes sont ajoutées - un texte statique, une barre de défilement et une case à cocher.

Les paramètres du texte statique sont l'identifiant IDC, la chaîne, les coordonnées, la largeur et la hauteur.

Les paramètres de la barre de défilement sont l'identifiant IDC, les coordonnées, la largeur et la hauteur, puis les valeurs min et max de la barre de défilement, enfin la variable où stocker le résultat.

Les paramètres de la case à cocher sont l'identifiant IDC, une étiquette de chaîne, les coordonnées, la largeur et la hauteur, et la variable booléenne où stocker le résultat.

iY = 10;
WCHAR sz[100];
iY += 24;
StringCchPrintf( sz, 100, L"Puffiness: %0.2f", g_fModelPuffiness );
g_SampleUI.AddStatic( IDC_PUFF_STATIC, sz, 35, iY += 24, 125, 22 );
g_SampleUI.AddSlider( IDC_PUFF_SCALE, 50, iY += 24, 100, 22, 0, 2000, (int)(g_fModelPuffiness*100.0f) );

iY += 24;
g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Toggle Spinning", 35, iY += 24, 125, 22, g_bSpinning );

Lorsque les boîtes de dialogue ont été initialisées, il faut les placer à l'écran. Cela se fait en appelant OnD3D10ResizedSwapChain, parce que les coordonnées d'écran peuvent changer chaque fois que la swap chain est recréée - par exemple si l'on redimensionne la fenêtre.

g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
g_HUD.SetSize( 170, 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-300 );
g_SampleUI.SetSize( 170, 300 );

Finalement, les boîtes de dialogue doivent être identifiées dans la fonction OnD3D10FrameRender. Cela permet qu'elles soient dessinées afin que l'utilisateur puisse effectivement les voir.

//
// Rendu de l'interface utilisateur
//
g_HUD.OnRender( fElapsedTime );
g_SampleUI.OnRender( fElapsedTime );

II-10-e - Initialisation du Gestionnaire de Ressources

Le gestionnaire de ressources doit être initialisé à chaque rappel associé à une initialisation et une destruction. Ceci parce que le GUI doit être recréé chaque fois qu'un device est créé ou qu'une swap chain est recréée. La classe CDXUTDialogResourceManager contient des fonctions qui correspondent à chaque rappel. Chaque fonction a le même nom que son rappel correspondant. Tout ce qu'on doit faire, c'est insérer le code pour appeler chacun d'entre eux aux bons endroits.

V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) );
V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );
g_DialogResourceManager.OnD3D10ReleasingSwapChain();
g_DialogResourceManager.OnD3D10DestroyDevice();

II-10-e-1 -

Après que tout ait été initialisé, on peut écrire du code pour traiter les interactions GUI. Pendant l'initialisation des boîtes de dialogue, on règle la fonction de rappel sur OnGUIEvent. On peut maintenant créer la fonction OnGUIEvent qui surveille les évènements liés au GUI puis les traite (le GUI est invoqué par l'environnement cadre).

OnGUIEvent est une fonction simple qui contient une instruction de cas pour chaque identifiant IDC détecté quand les boîtes de dialogue ont été créées. Chaque instruction de cas contient le code de gestion d'évènement, en présumant que l'utilisateur interagisse avec la commande. Le code ici est très similaire au code Win32 qui gère les commandes.

Les commandes liées aux fonctions d'appel HUD sont incorporées dans DXUT. Il existe une fonction DXUT pour alterner entre les modes plein écran et fenêtré, pour activer et désactiver le moteur de rendu du logiciel de référence et pour modifier les réglages du device.

La boîte de dialogue SampleUI contient un code personnalisé pour manipuler les variables associées à la barre de défilement. Elle collecte la valeur, actualise le texte associé et transfère la valeur au shader.

void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{

switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
case IDC_TOGGLEREF:        DXUTToggleREF(); break;
case IDC_CHANGEDEVICE:     g_D3DSettingsDlg.SetActive( !g_D3DSettingsDlg.IsActive() ); break;

case IDC_TOGGLESPIN:
{
g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked();
break;
}

case IDC_PUFF_SCALE:
{
g_fModelPuffiness = (float) (g_SampleUI.GetSlider( IDC_PUFF_SCALE )->GetValue() * 0.01f);

WCHAR sz[100];
StringCchPrintf( sz, 100, L"Puffiness: %0.2f", g_fModelPuffiness );
g_SampleUI.GetStatic( IDC_PUFF_STATIC )->SetText( sz );

g_pPuffiness->SetFloat( g_fModelPuffiness );
break;
}
}

}

II-10-e-2 - Actualisation du Traitement de Message

A présent, nous avons des messages de boîte de dialogue et des interactions d'utilisateur. Les messages qui sont transmis à l'application doivent être traités par les boîtes de dialogue. Le code correspondant est traité dans la fonction de rappel MsgProc qui est fournie par DXUT. Dans les tutoriels précédents, cette section est vide parce qu'il n'y a pas de message à traiter. A présent, on doit s'assurer que les messages destinés au gestionnaire de ressources et aux boîtes de dialogue sont convenablement acheminés.

Aucun code de traitement de message spécial n'est requis. On se contente d'appeler les MsgProcs pour chaque boîte de dialogue pour s'assurer que le message est traité. On le fait en appelant la fonction MsgProc qui correspond à chaque classe. Notez que la fonction fournit un registre pour notifier à l'environnement cadre qu'aucun autre traitement du message n'est nécessaire, et donc que l'environnement cadre peut se fermer.

LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext )
{
// Toujours permettre aux appels du gestionnaire de ressources de boîte de dialogue de gérer les messages globaux
// ainsi l'état GUI sera actualisé correctement
*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;

if( g_D3DSettingsDlg.IsActive() )
{
g_D3DSettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0;
}

// Permettez aux boîtes de dialogue de traiter le message en premier
*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;

if( uMsg == WM_CHAR && wParam == '1' )
DXUTToggleFullScreen();

return 0;
}

II-10-f - Boîte de Dialogue 3D Settings

Il existe une boîte de dialogue spéciale incorporée qui contrôle les réglages du device Direct3D. Cette boîte de dialogue est fournie par DXUT sous le nom CD3DSettingsDlg. Elle fonctionne comme une boîte de dialogue personnalisée, mais elle fournit toutes les options dont les utilisateurs ont besoin pour modifier les réglages.

CD3DSettingsDlg         g_D3DSettingsDlg;       // Boîte de dialogue de réglage du device

L'initialisation ressemble beaucoup à celle d'autres boîtes de dialogue. Il suffit d'appeler la fonction Init. Toutefois, chaque fois que Direct3D modifie sa swap chain ou son device, la boîte de dialogue aussi doit être actualisée. Par conséquent, il faut un appel convenablement nommé dans OnD3D10CreateDevice et OnD3D10ResizedSwapChain. De même, les modifications aux objets détruits doivent aussi être notifiées. Par conséquent, on a besoin des appels appropriés dans OnD3D10DestroyDevice.

g_D3DSettingsDlg.Init( &g_DialogResourceManager );

V_RETURN( g_D3DSettingsDlg.OnD3D10CreateDevice( pd3dDevice ) );
V_RETURN( g_D3DSettingsDlg.OnD3D10ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );

g_D3DSettingsDlg.OnD3D10DestroyDevice();

Pour ce qui est du rendu, pour faire alterner l'état d'apparence de la boîte de dialogue, on utilise un registre appelé IsActive(). Si ce registre est réglé sur false, le panneau n'est pas rendu. L'alternance d'affichage du panneau est gérée par la boîte de dialogue HUD. Le IDC_CHANGEDEVICE qui est associé au HUD contrôle ce registre.

if( g_D3DSettingsDlg.IsActive() )
{
g_D3DSettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0;
}

Lorsque les étapes d'initialisation sont terminées, vous pouvez inclure la boîte de dialogue dans votre application. Essayez de compiler le tutoriel et d'interagir avec le panneau Change Settings pour voir ses effets. La reconstruction du device Direct3D ou de la swap chain est faite en interne par DXUT.

II-10-g - Rendu de Texte

Une application n'est pas très intéressante si l'utilisateur n'a aucune idée de ce qu'il doit faire. DXUT inclut une classe utilitaire pour dessiner du texte 2D à l'écran, pour le retour d'action de l'utilisateur. Cette classe, CDXUTD3D10TextHelper, vous permet de tracer des lignes de texte n'importe où à l'écran en utilisant de simples entrées de chaînes. D'abord, on instancie la classe. Puisque le rendu de texte peut être isolé de la plupart des procédures d'initialisation, on garde l'essentiel du code dans RenderText10.

CDXUTD3D10TextHelper txtHelper( g_pFont, g_pSprite, 15 );

II-10-g-1 - Initialisation

Le premier paramètre transmis est la fonte à tracer. Cette fonte est du type ID3DXFont qui est fourni par D3DX. Pour initialiser la fonte, appelez D3DX10CreateFont et transférez le device, la hauteur, la largeur, la nuance, les niveaux mipmap (généralement 1), l'italique, le jeu de caractères, la précision, la qualité, la chasse et la famille, le nom de la fonte et le pointeur de l'objet. Seuls les quatre premiers et les deux derniers éléments de cette liste sont vraiment importants.

V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L"Arial", &g_pFont ) );

Le deuxième paramètre exige que l'on initialise une classe ID3DXSprite. Pour le faire, on appelle D3DX10CreateSprite. Les seules choses que la fonction exige comme paramètres sont le device, le nombre maximum de sprites dessinés sur une trame et le pointeur de l'objet.

// Initialise le sprite
V_RETURN( D3DX10CreateSprite( pd3dDevice, MAX_SPRITES, &g_pSprite ) );

Comme pour tout autre objet, la fonte et le sprite doivent être détruits après que l'on en ait fini avec eux. On peut le faire en utilisant la macro SAFE_RELEASE.

SAFE_RELEASE( g_pFont );
SAFE_RELEASE( g_pSprite );

II-10-g-2 - Rendu

Le texte dans cet exemple inclut des statistiques sur le rendu. Il y a aussi une section d'aide qui explique comment manipuler le modèle en utilisant la souris.

Les appels de rendu doivent être faits dans OnD3D10FrameRender. Ici, on appelle RenderText10 dans le cadre de l'appel de rendu de trame.

La première section est toujours rendue la première. Le premier appel à rendu de texte est Begin(). Cela notifie à l'appareil de commencer à envoyer du texte à l'écran. Ensuite, on règle la position du curseur et la couleur du texte. A présent, on peut tracer.

La sortie de la chaîne de texte s'effectue en appelant DrawTextLine. La transmission de la chaîne et la sortie qui correspond à la chaîne sont assurées à la position en cours. Le curseur est incrémenté pendant l'écriture du texte. Par exemple, si la chaîne contient "\n", le curseur est automatiquement déplacé à la ligne suivante.

// Statistiques de sortie
txtHelper.Begin();
txtHelper.SetInsertionPos( 2, 0 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats() );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );

Il existe une autre méthode pour assurer la sortie de texte, qui est similaire à printf. Formatez la chaîne en utilisant des caractères spéciaux puis insérez des variables dans la chaîne. Utilisez DrawFormattedTextLine à cette fin.

txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
txtHelper.DrawFormattedTextLine( L"fTime: %0.1f  sin(fTime): %0.4f", fTime, sin(fTime) );

Puisque le texte d'aide est tracé de la même manière, on n'a pas besoin de passer en revue son code.

Vous pouvez repositionnez le pointeur à tout moment en appelant SetInsertionPos.

Quand vous êtes satisfait de la sortie de texte, appelez End() pour en notifier le device.