Direct3D demo in delphi - dx3tst2

(c) Luc J.M. Cluitmans, February 1997
    email: L.J.M.Cluitmans@ele.tue.nl


DISCLAIMER:
  I provide this source in the hope that it is useful to you. I am
  not responsible for whatever nasty things may happen when you try to
  use this code.
  
  
WHAT'S THIS?
  Dx3tst2 is a small test program that I wrote to demonstrate that it is
  possible to program Direct3D's retained mode from Delphi 2. It can
  load Direct3D model files (*.x), display them and rotate them. 
  
WHAT DO YOU NEED TO KNOW?
  I assume that you have a basic understanding of DirectX and Direct3D
  Retained mode. If you don't, install Microsoft's DirectX3 SDK first
  (download it from microsoft's WWW site) and start reading the
  documentation that comes with it.

WHAT ARE THOSE FILES?
  The 'compnent' subdirectory contains two files: dxtools.pas and
  d3drmwnd.pas. The latter file is a component that you should install
  before trying to load the Dx3tst2.dpr project (Sorry, no icon yet).
  This component will contain the (sub)window containing the 3D image.
  It contains most of the nasty Direct3DRM programming code for this
  demo application. The DXtools file contains some functions for
  making errorchecking easier and COM object releasing safer. (The 
  d3drmwnd unit uses dxtools, so put those two files in the same
  directory).
  
  The program sources itself consist of dx3tst2.dpr, unit1.pas (main
  screen) and unit2.pas (help screen). The *.x files are some sample
  Direct3D data files. By default, the demo program tries to load
  'mything.x' (a simple octahedron). You can use The demo program's 'Open
  Mesh' menu item to load most data files, including those that come
  with the DirectX SDK. If the *.x file contains a frame use
  'Open frame' instead.
  
HOW TO COMPILE IT
  In order to compile the project, you must have the latest version of
  Blake Stone's Delphi port of the DirectX3 headers somewhere on your
  delphi library search path (get them fromhttp://www.dkw.com/bstone).
  Put them for instance in the same directory as you put dxtools.pas and
  d3drmwnd.pas. If you get errors when running the the program (I got a
  system lockup once) try disabling the delphi (integrated) debugging
  features.
  
RUNNING THE PROGRAM
  Well, toy around a bit and hope that you have enough RAM to prevent
  heavy swapping (Direct3D is a RAM eater). When you click on the 3D
  window you set the keyboard focus to it (indicated by the red border).
  The following keys are recognized:
  
    T, R: move camera forward and backward
    cursor keys: move camera up, down, right, left
    Space: reset camera position and object orientation
    
  Note: Delphi does a good job in trying to prevent the programmer to
  use cursor keys :-). I had to add several nasty things in both the
  component (trapping CM_WANTSPECIALKEY) and the key handler events
  (capturing the mouse on KeyDown to prevent the KeyUp from being
  lost...) to get it working.
  
USING THE COMPONENT
  When you want to use the d3drmwnd component in your own programs you
  need to add the following two things:
  
    1) Most of the drawing in Direct3D is not performed when handling a
       WM_PAINT event, but when your application is idle (that's why
       your CPU usage goes to 100% when running the demo: It uses all
       spare CPU time). In the FormCreate handler of the form you put
       the d3drmwnd component on you should add something like:

          Application.OnIdle := D3DRMWnd1.IdleProc;

       to allow the D3DRMWnd to trap idle time.
          
    2) Direct3D wants to know when your form is activated and when it is
       deactivated (to allow palette handling). You should add a message
       handler to handle WM_ACTIVATE messages sent to your form:
       
       In your form declaration (e.g. the 'protected' part):
         
         procedure WMActivate(var Msg: TMessage); message WM_ACTIVATE;
         
       (note that I use TMessage instead of TWMActivate)
       And in your form's implementation:
       
         procedure TForm1.WMActivate(var Msg: TMessage);
         begin
           inherited;
           D3DRMWnd1.ActivateCallback(Msg);
         end;
  
  Most Direct3D related initialization is not performed in the
  component's Create method but isperformed *after* reading the
  properties in the component's 'Loaded' method. If you derive a
  component from D3DrmWnd, do not use DirectX calls in the constructor.
  
THE TOOLKIT
  The dxtools.pas file contains three utility functions that you will
  use heavily in Direct3DRM programming:
  
  To release a COM object (you did read the DirectX documentation, did
  you?) call COMRelease(IUnknown(<object>)). This releases the object
  and sets it to nil.
  
  Most DirectX calls return an errorcode if something goes wrong. Wrapping
  the call in a 'DXCheck' call translates this error code to a 'EDirectX'
  exception.
   Example:
    DXCheck(FSubScene.Load(Pointer(fnm), nil, D3DRMLOAD_FROMFILE,
            nil, nil));
  
  If you want to perform some error handling before raising the
  exception you can alternatively use a combination of 'COMFailed' and
  'DXCheck'. An example that is equivalent to the previous one:
  
    var r: HRESULT
    ...
    if COMFailed(r, FSubScene.Load(Pointer(fnm), nil, D3DRMLOAD_FROMFILE,
            nil, nil)) then
    begin
      {you can add some clean-up code here}
      DXCheck(r);
    end;

BUGS
  Once loading a frame fails, it is possible that nothing will load
  correctly anymore . You have to close the program and start it again.

  
FINAL REMARKS
  I hope this code can get you started using Direct3D retained mode from
  delphi. Good luck...
  
  
  
  Luc Cluitmans  (L.J.M.Cluitmans@ele.tue.nl)

  

  










