Busy not doing the dishes - by Noel Rice

By: Lino Tadros

Abstract: Noel demonstrates the ability of Delphi 8 in working with Managed DirectX 9.x with the same ease as C# and VB.NET under the .NET Framework.

Remember all the cool technology you were going to learn this year? Like all the things you haven’t been doing with DirectX 8.1? Well, you can still not do them with DirectX 9. In fact with Managed DirectX your code is more object oriented, cohesive and with fewer (although some) lines of code. Everything you weren’t using is still there, right where you never saw it before.
Now I’m always about to procrastinate and then I think, “Maybe I’ll procrastinate later…” So as long as we’re failing miserably at our goals, lets play hooky and see how a minimal DirectX graphics program compares in VB.NET, C#, Delphi 7 and Delphi 8.
Just setting up the environment for DirectX to clear the screen and prepare to render takes a couple of screens of code regardless of language. For instance, Delphi 7 is similar to C++ in its approach, uses COM interfaces and is unmanaged from a .NET perspective. This example shows a form with a blue background and performs housekeeping needed for further 3D drawing:
...
uses D3D9;
...
var
  Direct3D9: IDirect3D9;
  Direct3DDevice8: IDirect3DDevice9;

procedure TfrmMain.FormCreate(Sender: TObject);
var
  DisplayMode: TD3DDisplayMode;
  D3DPresent_Parameters: TD3DPresent_Parameters;
begin
  Direct3D9 := Direct3DCreate9(D3D_SDK_VERSION);
  Direct3D9.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, DisplayMode);

  FillChar(D3DPresent_Parameters, SizeOf(TD3DPresent_Parameters), 0);
  with D3DPresent_Parameters do
  begin
    Windowed := True;
    hDeviceWindow := Handle;
    SwapEffect := D3DSWAPEFFECT_DISCARD;
    BackBufferFormat := DisplayMode.Format;
  end;

  Direct3D9.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
    Handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DPresent_Parameters,
    Direct3DDevice8);
end;

procedure TfrmMain.FormPaint(Sender: TObject);
begin
  Direct3DDevice8.Clear(0, nil, D3DCLEAR_TARGET,
    D3DCOLOR_XRGB(0, 0, 255), 0, 0);

  Direct3DDevice8.BeginScene;
  // assemble your scene here on the back buffer
  Direct3DDevice8.EndScene;

  // swap your back buffer to the visible screen
  Direct3DDevice8.Present(nil, nil, 0, nil);
end;

procedure TfrmMain.FormResize(Sender: TObject);
begin
  FormPaint(Self);
end;

The same general paradigm here is echoed in C# and VB.NET examples shown later. Two interfaces perform the work: IDirect3D9 is used to create an IDirect3DDevice9 interface, and IDirect3DDevice9 communicates requests to the physical hardware display adapter on your machine. The point of the code in the form create is to set up a TD3DPresent_Parameters structure and feed it to the creation of the device interface. TD3DPresent_Parameters is used to communicate that we want the display in windowed (not full screen) mode, that the window handle in question is the form’s handle, and how to handle memory. Finally, TD3DPresent_Parameters needs some information about the primary display adapter so an earlier call to GetAdapterDisplayMode queries the primary display adapter for dimensions, refresh rate, and most importantly here the display mode; a constant describing the memory layout representing pixels (for example D3DFMT_X8R8G8B8 signifying a 32-bit RGB pixel format, where 8 bits are reserved for each color).
Once the device is created, the form’s OnPaint event handler draws or renders to the device. “Clear” wipes the surface with some red/green/blue combination color with values from 0..255 (set to blue here). “BeginScene” and “EndScene” bracket most of the rendering work performed in more involved applications, and finally “Present” makes the rendered scene visible on screen.
Note: the references in comments to the “back buffer” refer to a commonly used technique “screen swapping” where one area of memory is drawn to, and then at an interval optimum for the hardware, the assembled scene is made visible.
In order to do any of the above you need the DirectX9 SDK installed (navigate to http://msdn.Microsoft.com/directx and follow the prompts to download) and the Delphi wrapper units from the fine folks at Project Jedi who help make this kind of development possible: http://www.delphi-jedi.org/, click the Delphi Graphics link and follow the prompts.
Now let’s swing the Code-Cam around to see excerpts from a C# example that ships with the DirectX 9 SDK. You will need the .NET framework installed on your machine and a C# environment IDE such as C# Builder to experiment with the examples.


...
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
...
public bool InitializeGraphics()
{
	try
	{
	  // Now let's setup our D3D stuff
	  PresentParameters presentParams = 
            new PresentParameters();
	  presentParams.Windowed=true;
	  presentParams.SwapEffect = SwapEffect.Discard;
	  device = new Device(0, DeviceType.Hardware,
            this, CreateFlags.SoftwareVertexProcessing, 
            presentParams);
	  return true;
	}
	catch (DirectXException)
{ 
    return false; 
}
}
private void Render()
{
	if (device == null) 
		return;

	//Clear the backbuffer to a blue color 
	device.Clear(ClearFlags.Target, 
           System.Drawing.Color.Blue, 1.0f, 0);
	//Begin the scene
	device.BeginScene();
	
	// Rendering of scene objects can happen here

	//End the scene
	device.EndScene();
	device.Present();
}
...
The C# example is like revisiting your old home after 10 years, familiar yet strange and with a few improvements. More tasks are taken care of for us in the managed code. “Present Parameters” is an actual object, not a record structure, but is assigned values much the same way as the Delphi example. The device object is still created but without the need for an IDirect3D9 parallel. Likewise, the call to GetAdapterDisplayMode is gone. The Render method is almost identical except during the call to “Clear” where the color parameter (set to System.Drawing.Color.Blue) brings up a feature of DirectX 9 well worth having – tighter integration with .NET where common types, such as the system drawing color, can be used. Versions prior to 9 constantly needed little data massaging routines – here in .NET, everything speaks the same lingo.
The VB.NET example is almost identical to the C#, with VB flavoring:

Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D
...
Public Function InitializeGraphics() As Boolean
    Try
        ' Now let's setup our D3D stuff
        Dim presentParams As New PresentParameters()
        presentParams.Windowed = True
        presentParams.SwapEffect = SwapEffect.Discard
        device = New Device(0, DeviceType.Hardware, _
          Me, CreateFlags.SoftwareVertexProcessing, presentParams)
        Return True
    Catch e As DirectXException
        Return False
    End Try
End Function 'InitializeGraphics

Private Sub Render()
    If device Is Nothing Then
        Return
    End If
    'Clear the backbuffer to a blue color
    device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0F, 0)
    'Begin the scene
    device.BeginScene()

    ' Rendering of scene objects can happen here
    'End the scene
    device.EndScene()
    device.Present()
End Sub 'Render
...

You may be curious if Delphi 8 can play in this same ballpark with the big kids. Absolutely. The same code with relatively little massaging:


type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    FDevice: Device;
  public
    procedure InitializeGraphics;
  end;
...
procedure TForm1.InitializeGraphics;
var
  PresentParams: PresentParameters;
begin
  PresentParams := PresentParameters.Create;
  PresentParams.Windowed := True;
  PresentParams.SwapEffect := Microsoft.DirectX.Direct3D.SwapEffect.Discard;
  FDevice := Device.Create(0, DeviceType.Hardware, IntPtr(Self.WindowHandle),
    CreateFlags.SoftwareVertexProcessing, PresentParams);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeGraphics;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  if not Assigned(FDevice) then
    Exit;
  FDevice.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1, 0);
  FDevice.BeginScene;
  FDevice.EndScene;
  FDevice.Present;
end;

To get the above code to work in Delphi 8 you will need to add references to the DirectX assemblies used. In the Project Manager window, right click the “References” node and click “Add Reference”. In the .NET Assemblies tab of the dialog select Microsoft.DirectX and Microsoft.DirectX.Direct3D from the list, click the “Add Reference” button and finally click OK to close the dialog. If the System.Drawing.Dll isn’t in the references list, make sure to add that too; System.Drawing provides the pre-defined colors used in the example.

And while you’re busy not learning new technology this year, be sure to check out the new DirectX Sample Browser that ships with the DirectX 9 SDK for easy navigation of tutorials, examples and utilities. You may find such inspiration that you won’t learn anything that you didn’t expect not to learn next year. Yup.



Falafel Software is all about making the most of software development technology in order to complete the project on time and on budget with best possible user experience. Falafel Software offers a comprehensive suite of software development solutions ranging from strategy to design to implementation that businesses need in order to realize high returns on their investment.

 

Copyright ) 2003 Noel Rice, Falafel Software Inc.
ALL RIGHTS RESERVED. NO PART OF THIS DOCUMENT CAN BE COPIED IN ANY FORM WITHOUT THE EXPRESS, WRITTEN CONSENT OF THE AUTHOR.


Server Response from: ETNASC03