Bobby Anguelov's Blog

A day in the life of a wannabe game developer

Multiple High Resolution Timer Class for Windows – C++

Earlier i had posted a tutorial on doing high resolution timing on windows and i’d given a very basic class to act as a timer, now i found when doing my graphics work i often needed multiple timers and so i just extended my baby timer class a little to support multiple timers.

So you can create as many timers as you need on the fly (the controller class acts as a big timer vector) and also get a pointer back for each timer if you wish to create a easily readable shortcut ie.

HRTimer* animationTimer = timers[5];

hope you find it useful: MHRTimer.h

31 August 2008 Posted by Bobby | Programming, Windows, Windows Programming | , , , | 2 Comments

DirectX 10 Tutorial 1: Setting up the D3D10 device

Introduction

So if you read my review of Wendy Jones’ book, you know my feelings on the state of DX10 tutorials and books, I want to try and maybe help some people out with tutorials in getting started with DX10, I am by no means an expert and the tutorials will basically cover everything that I’ve learnt so far. They will not be rehashes of the SDK tutorials nor Wendy Jones’ book. I’m hoping to slowly build up a dxManager wrapper class that can be easily used for some basic D3D apps. So let’s get started with the most basic topic: setting up the D3D device for drawing.

Note: The DX10 SDK tutorials are excellent, they are a must read and my early tutorials will be a concatenation of the information found in them!

Win32

The entry point of most 3D tutorials is win32 and so I’m not going to rewrite all those tutorials. If you want an excellent win32 tutorial Google forger’s win32 tutorials, they are the best I’ve found. Basically a simple win32 window consists of two things: the window and the window processing function (acts as an event handler). Inside of the tutorial project I’ve attached you’ll see three functions that create a window: the winMain function, the initialize window function and the wndProc, the functions are very basic and so I’m not going to go into any more detail. There are plenty of tutorials available online if you want more detail on win32.

dxManager

Before I start with the directX initialization stuff, I just want to cover something: the dxManager class. Most tutorials you’ll find will have the directX variables as global with a few global functions in a single file to render a simple triangle. Even Wendy Jones does so in her book, but I’m not, simply because it’s a terrible practice, its messy, inextensible and just plain silly. I’m going to instead create a dxManager class to wrap all my directX functions and just neaten things up.

In later tutorials you’ll see the justification for this more clearly. Enough of me prattling on, let’s dig in.

3D basics

Okay let just cover some very basic concepts about 3D graphics, the graphics API (directX/openGL) is what you’ll use to draw your objects out to the screen. The API is basically a layer that sits between your graphics card and you, you tell the layer what to do and the layer then tells the card.

The card makes use of a pipeline structure to display objects, I’m not going to go into the justifications about this since Google is your friend. Basically there a few key stages (their names differ across APIs), below is a diagram of the stages in DX10 followed by a brief description (taken from the SDK docs):

  • Input-Assembler Stage - The input-assembler stage is responsible for supplying data (triangles, lines and points) to the pipeline.
  • Vertex-Shader Stage – The vertex-shader stage processes vertices, typically performing operations such as transformations, skinning, and lighting. A vertex shader always takes a single input vertex and produces a single output vertex.
  • Geometry-Shader Stage - The geometry-shader stage processes entire primitives. Its input is a full primitive (which is three vertices for a triangle, two vertices for a line, or a single vertex for a point). In addition, each primitive can also include the vertex data for any edge-adjacent primitives. This could include at most an additional three vertices for a triangle or an additional two vertices for a line. The Geometry Shader also supports limited geometry amplification and de-amplification. Given an input primitive, the Geometry Shader can discard the primitive, or emit one or more new primitives.
  • Stream-Output Stage – The stream-output stage is designed for streaming primitive data from the pipeline to memory on its way to the rasterizer. Data can be streamed out and/or passed into the rasterizer. Data streamed out to memory can be recirculated back into the pipeline as input data or read-back from the CPU.
  • Rasterizer Stage - The rasterizer is responsible for clipping primitives, preparing primitives for the pixel shader and determining how to invoke pixel shaders.
  • Pixel-Shader Stage – The pixel-shader stage receives interpolated data for a primitive and generates per-pixel data such as color.
  • Output-Merger Stage - The output-merger stage is responsible for combining various types of output data (pixel shader values, depth and stencil information) with the contents of the render target and depth/stencil buffers to generate the final pipeline result.

The aim of this tutorial is to set up the D3D device to be ready for later tutorials. We will set up the swap chain, the D3D device, the render target, the viewport and finally just set up a view and projection matrix for the future.

The SwapChain and the D3D device

This is what is written in the SDK regarding the swapchain: “An IDXGISwapChain interface implements one or more surfaces for storing rendered data before presenting it to an output.” What this basically means is that you will set up a few “frames” or “buffers” to which you will draw and then swap out when you’re finished drawing. This is how you enable double or triple buffering in DX10.

Once we’ve set up our swapchain we create a D3D device with that swapchain, pretty simple.

To achieve this we need to fill out a DXGI_SWAP_CHAIN_DESC structure and then call D3D10CreateDeviceAndSwapChain to create our swap chain and our D3D device. The function parameters are in the SDK docs and I’m not going to describe what each one does since I’m pretty sure you can read it yourself. You will need pointers to both a swap chain interface and a D3D device interface. Here’s the code to set up and create the swap chain and D3D device.


//Set up DX swap chain
//--------------------------------------------------------------

DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

//set buffer dimensions and format
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;;

//set refresh rate
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;

//sampling settings
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.SampleDesc.Count = 1;

//output window handle
swapChainDesc.OutputWindow = *hWnd;
swapChainDesc.Windowed = true;

//Create the D3D device
//--------------------------------------------------------------

if ( FAILED( D3D10CreateDeviceAndSwapChain(	NULL,
											D3D10_DRIVER_TYPE_HARDWARE,
											NULL,
											0,
											D3D10_SDK_VERSION,
											&swapChainDesc,
											&pSwapChain,
											&pD3DDevice ) ) ) return fatalError("D3D device creation failed");

The RenderTarget

The render target describes what the format of output of the output merger stage will be. This output format is the same the format of the swapchain buffers. So what we need to do is get all the details from the swapchain about its buffer format and use that to create a render target.

//Create render target view
//--------------------------------------------------------------

//try to get the back buffer
ID3D10Texture2D* pBackBuffer;

if ( FAILED( pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer) ) ) return fatalError("Could not get back buffer");

//try to create render target view
if ( FAILED( pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView) ) ) return fatalError("Could not create render target view");

//release the back buffer
pBackBuffer->Release();

//set the render target
pD3DDevice->OMSetRenderTargets(1, &pRenderTargetView, NULL);

Note: Something that should be mentioned here is the “Release” call, basically all resources are semi-managed, basically resources are only freed once nothing is using them, whenever a resource is used an internal counter is incremented (semaphore) , once something doesn’t need the resource any more the counter is decremented. Once this counter reaches 0, the resource is freed. Here we don’t need the pBackBuffer resource any longer so we release it, if nothing else is using it then the resource is freed.

The Viewport

The viewport converts vertex positions to render target positions; this is the key step in the rasterizer stage. Creating this structure is really simple, it basically takes the height and width of your window and the starting positions of the window (usually 0 and 0). The depth variables should be set to 0 and 1 for min and max respectively. Once you have multiple viewports this will change but don’t worry about that for now.

//create viewport structure
viewPort.Width = width;
viewPort.Height = height;
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;

//set the viewport
pD3DDevice->RSSetViewports(1, &viewPort);

The View and Projection Matrices

Okay now we’re nearly done, the last thing we need to set up is the view and projection matrices. The view matrix basically positions and orients the camera in the scene. The matrix usage and transformations will be covered in the next tutorial.

The projection matrix basically defines the range of the view from the camera. This is explained extremely well in the 4th tutorial in the SDK docs! I really suggest reading it. It can also apply perspective to the scene; this basically allows near objects to be large and far objects to be small. In our case we’re going to set up a basic perspective projection with a view angle of 45 degrees and a max depth of 100 units. The near depth must not be set to 0, I will explain why in a later tutorial regarding picking and unprojecting co-ordinates.

// Set up the view matrix
//--------------------------------------------------------------

D3DXVECTOR3 eye(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 view(0.0f, 0.0f, 1.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f));

D3DXMatrixLookAtLH( &viewMatrix, eye, view, up );

//Set up projection matrix
//--------------------------------------------------------------
D3DXMatrixPerspectiveFovLH(&projectionMatrix, (float)D3DX_PI * 0.5f, (float)width/height, 0.1f, 100.0f);

Rendering of the Scene

Okay so we’ve set up our D3D device, let just output something. Unfortuneatly in DX10 doing that isnt all that simple and there are several more stage we need to do before we can proceed. So for now lets just clear the screen and flip the buffers.


//clear scene
pD3DDevice->ClearRenderTargetView( pRenderTargetView, D3DXCOLOR(0,0,0,0) );

//SCENE RENDERING GOES HERE!!!

//flip buffers
pSwapChain->Present(0,0);

Conclusion

So that’s it for my first tutorial! I didn’t cover a lot of material but I’ve set up the base for the rest of the tutorials, and time-permitting I’ll put up several more in the coming weeks.

Source Code

Tutorial 1 VS2k8 project and Source Code: tutorial1.zip

31 August 2008 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, General, Graphics Programming, Programming | , , , | 19 Comments

Beginning DirectX 10 Game Programming By Wendy Jones – Review

A search of amazon.com in regards to directx10 books yields only three entries: wendy jones’ book, a book by peter walsh which by all account is just a basic update of his previous directx9 book and recently a new book by frank luna which also seems just like an update of a previous book.

I purchased Wendy Jones’ book: Beginning DirectX 10 Game Programming in january of this year and have only recently had the time to sit and go through it. In brief I wasnt very impressed. This book is nothing more than a rehash of the tutorials available in the DX10 sdk, and to make matters worse you would think that she’d make an effort to improve upon the tutorials, that there would perhaps be more depth and clarity,  unfortuneatly she doesn’t.

What she’s done is taken clear concise tutorials and made them overly long, convoluted and tedious. All the problems in regards to explanation and presentation that are present in the SDK tutorial are present in her book. For example in one tutorial, they just show the instantiation of an object but never specify the object type name, so you have to dig around a little bit to get it, in her book the exact same thing occurs for the exact same section.

The only unique section she has is a chapter dealing with sprites which is not covered in the sdk tutorials and that could have been the only redeeming feature of the book but even that is written badly. What should be a short simple chapter gets dragged out, that chapter is nearly the length of the entire 3d section of the book.

Moving onto the 3D chapters, apart from the generic 3D primer and the cut and paste sections from the tutorials, there is practically no in depth information about what makes directx 10 different from directx 9 or even openGL. Lets not even get started on the quality of code present in the tutorials, i dont understand why she even attempted to rewrite the tutorials, she may as well have included the sdk examples. She does created a “modelObject” structure but this is not exactly a major change.

Also this book is entitled “beginning directx10 game programming” but should rather have been called “rendering 2 cubes and a basic mesh in directx10″ as this is the depth in which the text goes into. I’m not sure what the target audience is but having less than a 100 pages of a 350 page book dedicated to 3D graphics is plain unacceptable. The rest of the chapters cover directinput, and xinput.

Her explanations in these 100 pages are unclear, and the only depth covered is an explanation of input parameters which any beginner can get from the sdk docs anyways, there is absolutely no explanation of what functions actually do, why they do them and give the reader a basic intro into the dx10 pipeline and API. Alot of important information is missing and i had to end up digging up myself, especially in regards to displaying multiple objects.

Let me try explain how bad the source code examples are: in the triangle example she calls an initTriangle function to initialize the triangle, this now goes and creates an input layout. Now for a beginner, they might assume that for every object you make you need to create an input layout, seeing as the modelObject structure has that as a member. When in reality you only need to create one input layout for a specific vertex type, and only swap it if you pass through different types of vertices. The same goes for effects and techniques. Also she never really mentions how you would handle multiple objects properly, especially with the lack of a fixed function pipeline.

The just for a low blow, in the example where she renders a 3d cube, the initialization function is called and wait for it: initTriangle… You can see a lot of effort went into this book. (sarcasm!)

I feel the author herself doesnt have a solid grasp of DX10 and has ended up just writing a book for the hell of it, her tutorials dont convey any level of understanding but rather just say: want a vertex run this function call.

UPDATE: I’m now sure the author has very little understanding of dx10, in her book she implies that you need to create a vertex buffer for every object you wish to draw! This is a bad practice especially in regards to perforamnce. The vertexbuffer is a block of memory which you fill prior with vertices prior to sending it to IA. You’ll have a list of vertices stored in an object container, and you would load up the vertex buffer with the vertices from the object and then draw it. Seeing as there is no way to change the size of the buffer once created nor is there a way to delete it, all you can do is update the data stored within the buffer. That is the reason the draw call takes the number of vertices and the offset as a parameters.

So why cant we just create a buffer for each object, imagine we have a scene with 1000 objects, each object has 1000 vertices, so now we have 1 000 000 vertices stored in memory, the swapping of vertex buffers is a slow operation and having to swap out the vertex buffer 100 times each frame has a major performance impact.

I’ve gone through her book thoroughly and then started to do a very basic b-spline demo in dx10 and quickly realised how much information i was missing, how badly things were explained and how she’d simply ripped off the sdk tutorials. I also ran into a major problem trying to organise and store my object never mind draw them, i’ve spent two weeks messing around until i finally ended up slapping together a very basic DX manager class with a polymorphic object container hierarchy.

My advice is avoid this book,  dont waste your money, rather download the dx10 sdk and go through their tutorials, you’ll find them more useful and better explained.

Oh and speaking of ripping off tutorials: there is this jackass ( http://www.kevindonde.com/ ) that is ripping off her tutorials and putting them up on the net as his own.

I’ve spent the better part of two weeks now digging in the SDK docs and browsing the web for solutions to my very basic problems and so forgive my frustration. I will hopefully write my own tutorials on directx 10 in the upcoming weeks and i do hope that they might actually be more useful than hers. I’ll also try and get hold of frank luna’s book and see if that is any better.

23 August 2008 Posted by Bobby | DirectX 10, Graphics Programming, Windows | , , , | 20 Comments