Bobby Anguelov's Blog

A day in the life of a wannabe game developer

My Home Setup

So my home machine is nearly complete, here are the specs:

  • e8500 at 4320mhz
  • Thermalright TRUE + Scythe S-flex fan
  • 4gb mushkin ascent DDR2 Ram at 960
  • 4 320GB hdds
  • DFI p35dk T2RS mobo
  • 8800gtx (currently in for RMA)
  • P182 chassis
  • 2 Samsung 226bw 22″ LCDs
  • func surface archetype + MSIE 3.0

here’s some photos of my nice and plain room:

20 September 2008 Posted by Bobby | General | | No Comments Yet

S.T.A.L.K.E.R Clear Sky – Review and Postmortem

Okay so i bought Stalker Clear Sky last week and have managed to find some time this weekend to play it, I’ve spent a good 20 hours in the game and decided to write a small review on the state of the game because it is the first game in ages that really grabbed me.

First things first, the QA of the game is shocking, 3 patches released within 2 weeks of launch, not to mention the fact that the game is unplayable prior to patch 1.5.0.4, i tried with 1.5.0.3 and the game would constantly crash to desktop or even blue screen of death’d my machine. To manage to BSOD my vista machine is an impressive feat, so amazing that i cant even imagine how they managed to pull it off. I’m sure with a few more patches all the crashes will be resolved. In its current 1.5.0.4 state the game is quite stable, still not 100% but its playable for several hours without incident.

Okay So the main reason why i’m writing this is simple, this game could have been amazing! it could have been the best game i’ve played since fallout, but it’s not. The fact that the potential is there is great but the game designers seemed to have fallen flat and ended up delivering a half finished masterpiece.

So what did they do right:

  • Gorgeous terrain and lighting: this is one thing they did right, the terrain, lighting and weather effects are just jaw dropping.
  • Day Night Cycles: Beautiful, watching the sunrise, the sunset, it really adds that touch of realism.
  • Level Design: The level design is great, and it works, not too large and not too small. Excellent usage of props to deliver the intended emotional feel
  • Great Weapon and bullet physics: love the fact that weapons have condition, effective ranges, bullet drop spread, etc. Having realistic weapon modelling adds to the tactical planning and assault elements, knowing that the enemies outrange you will make you think twice about a frontal assault.
  • Weapon Upgrades and repairing: Excellent system, this is that way other games should do it. Again adds to realism and resource management.
  • World Setting: love the theme and setting. Cant fault them.
  • Difficulty: I like being challenged by games and this is one game that challenges me, i like having to actually sit and think whether i want to enter a battle, whether using up my ammo and health packs is worth it.
  • Resources: Love all the items and the fact that they arent abundant and you have to work for them. I love having to manage my inventory
  • Damage Effects: love the elements of radiation and bleeding. Really adds to the pressure in a firefight.

The game has pulled me in and i cant stop playing, but they also did a lot wrong and in my opinion the game is lacking several key things that would make for a better game experience. So lets start with the wrong:

  • Terrible Character Models: the character models looks atrocious, the outfits and armor is plain ugly, it really ruins the game for me, its hard to play the game when the enemies look like seedy porn dealers in their overcoats, or a hobo with a shotgun. Even the military uniforms look terrible. The character modellers need to be shot, or even worse force to dress up like their models. You know the character models remind me of venom’s models, seeing as stalker is practically venom 2.0 this isnt surprising.
  • Cant rest/sleep: i dont want to spend half the game stumbling around in the dark with a flashlight that has a 3m range. Give me the option to rest in friendly encampments, or pay to sleep, etc. I dont know why the designers would put in day night cycles and food and so on just to have a character that doesnt rest! Putting in fatigue would have been a great addition to the realism of the game.
  • No Economy: All the merchants offer the same prices on items, this is plain stupid, i want merchants in my faction to offer better deals than merchants in other factions, i want there to be ways to earn discounts for merchants by doing quests for them. Same thing with technicians. It doesnt matter what you do or dont do prices stay the same.
  • Faction Warfare is a bit buggy: After retakening the same spot 4 times in a row spending a ton of ammo and health packs just to walk away and have it retaken instantly pisses me off. I would like to have spent my time clearing out a level for a faction for a reason, give me better prices at your mercahnts, maybe take over the area with your troops and make it easier for me to travel safely. The system was a great idea but poorly implemented.
  • No character development: the world is populated but you never really feel like you get to know any of the characters, they are barely even fleshed out. I still fondly remember imoen, minsc and sarevok from baldurs gate, i remember the sheriff of NCR and brothel madam of new reno from fallout 2, i remember tali from mass effect. In Stalker you never really acre or remember anyone, everyone is just a name and often a terrible name like “dave mutant” or “peter corpse”, what did they run of out slavic surnames? The game designers failed miserable here, they made the tools to create an amazing immersive game and just used it for a sub par shooter.
  • Pointless Quests: go collect my loot from tree x, or pole y or pipe z? You’re kidding me right? Or perhaps, go to location z and kill generic bad guys. Thats about the depth into which stalker goes. I want to do stuff because its gonna benefit me or i’m gonna see the change in the world from doing it. Running for 10 minutes to reach to a stash just to get 15 shotgun shells and a sausage from it really pisses me off. Again they could have put in alot of politics, hidden agendas, etc in the game. All the tools for them to do so are present.
  • Unused Geographical Areas: There are lots of areas that are just empty or have no purpose, for example in the swamps there is a recycling station, it would be nice to get there and talk to the guy in charge to find out that mutants have been plaguing them at night, so you go to sleep, wake up at night and go hunting to earn faction points and maybe some cash. Can you imagine how much more immersive the game would have been if those sort of things were present. Yes it would be more of an RPG, but all the tools for an excellant RPG are already there. This could have been a fallout 3 killer.
  • Enemies jsut respawning, after cleaning out an entire map of bandits, leaving and coming back just respawns them all. This is fucking annoying! At least have them SLOWLY filter back in over time, and what are the faction guys that have now taken over the map do? Nothing apart from die. Again, you work really hard and dont get rewarded at all.

Like i said earlier stalker is a great game but i’m dissapointed with clear sky, it brings practically nothing new to the table. Same locations, same buggy AI and gameplay, same pointless quests, same weapons and items. Whats new? Lighting effects, a great upgrade system and “faction warfare” which is also really buggy.

The game feels empty and shallow, it needs more depth, a richer storyline, sub storylines, character development, you need to make the player feel part of the world and that his action no matter how small matter, unfortuneatly as the game stands now, nothing you do matters. its just a plain boring FPS where you dont have to do anythign on the side, just follow the main storyline from level to level and you jsut play the game as an FPS. All the potential in the world just to fall flat.

I feel so strongly about how great this game could ahev been that i’m considering trying to find people to start a mod project and fix the issues present in the game and perhaps show the world what could have been even if only for a single area. I do realise that good developers and artists especially ones that are willing to work are hard to find and so its just a pipe dream for now.

15 September 2008 Posted by Bobby | Game Reviews, Gaming, General | , | 7 Comments

Status Update: Bobby Anguelov is busy…

So as you can see I’ve written two directx 10 tutorials, while they arent any where near as detailed as my neural network tutorials i still think they are a step in the right direction. If you read my review of “beginning directX game programming”, you can see that i’m not very happy with the current lack of directx 10 resources. I’m going to do my best over the next couple of months to write up any tutorials and put up any code snippets in the hope it might help someone else out there.

What else have i been doing? Well i’ve been busy working on my varsity assignments and work has been pretty busy lately, we’ve started overhauling and retro fitting our legacy CMS we use in the department. I’ve had to completely rewrite several systems, i’m again finding myself working overtime to meet self imposed deadlines. I dont have any fixed deadlines but i do my best to stick to dates i specified initially. Unfortuneatly in doing so i often dont have a lot of time to test my code, luckily there were only two silly bugs in the rewrite of 2 major systems and i got both of those fixed in a matter of minutes.

I’ve also been hitting the caffeine a bit hard lately and its screwed up my body clock a bit. My body seem to think bed time is around 3am and wake up time is 7am :( Working off of 4 hours sleep isnt so great.

In other news I’m really really excited! September through to november are going to be epic from a gaming perspective! So many titles are being released that i just cant wait for: stalker : clear sky, far cry 2, COD:World at war, GTA 4 PC, FALLOUT 3, civilization 4: colonization, red alert 3… Man oh man! i cant wait, i havent touched a game in months, mainly due to the fact that nothign good has been released for PC in ages. HAHA! i’m gonna be so broke tho, i just cant seem to be okay with pirating games anymore. Its nice to own originals, i feel like i’m supporting the developers.

So yeh, my plan for the next few weeks is to start on my Special Project regarding the Discrete pulse transform, i’ve also noticed a massive stack overflow bug in my implementation that i need to correct. I also want to complete and improve my FPT toolkit application. All this while i’m working on my DX 10 tutorials and varsity assignment not to mention work.

It gonna be a rough next few weeks…

2 September 2008 Posted by Bobby | General, Personal | | No Comments Yet

DirectX 10 Tutorial 2: Basic Primitive Rendering

Okay I managed to find sometime and wrote a very basic second tutorial that introduces the main concepts behind primitive rendering in DX10. This tutorial builds upon the base code of tutorial 1 so check that out if you haven’t already.

Also I need to mention that I’m not writing these tutorials for complete beginners, I expect you to at least have a very basic understanding of graphics programming and the terminology involved. I’m not going to go into a lot of detail regarding terms like culling, rasterizing, fragments etc.

One last aside before the tutorial, what makes DX10 different to DX and openGL 2.0 is the removal of the fixed function pipeline. Now what the hell does that all mean? Well in directx9 and openGL, they had default ways of handling vertices, colors, texture co-ordinates etc. You’d pass through a vertex and a color and it would know what to do. It also handled lighting and other effects. In DX10 these defaults were removed and the core API has been simplified and reduced, this allows you to have full control over each pipeline stage and removes any past limitation on number of light sources and so on, but it has a major downside, the complexity and difficulty has now increased.

If we take lighting for example, before a hobbyist could enable lighting with a few function calls and would get a satisfactory result now for the same effect, the hobbyist would have to write pixel and vertex shaders using the phong (or other) equations to manually calculate the effect of lighting.

Basic Rendering and first steps into HLSL

Okay enough of that, let’s dig in. To render something there are several steps we need to take:

  1. Generate the vertices
  2. Send the vertices to the pipeline
  3. Apply any transformations need to the vertices (vertex shader)
  4. Set the vertex color (pixel shader)

Seems pretty simple? If only. The first addition to the code is the loading of an HLSL (high level shader language) effect file; this file will define the vertex and pixel shaders we will be using. The contents of the effect file are:

matrix World;
matrix View;
matrix Projection;

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Color : COLOR0;
};

PS_INPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
{
	PS_INPUT psInput;

	Pos = mul( Pos, World );
	Pos = mul( Pos, View );

	psInput.Pos = mul( Pos, Projection );
	psInput.Color = Color;

    return psInput;
}

float4 PS( PS_INPUT psInput ) : SV_Target
{
    return psInput.Color;
}

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

Its pretty simple, the vertex shader applies the matrix transformation by multiplying the vertex by the world, view and projection matrices we’ve declared in the file, and then it sends the tansformed vertex to the pixel shader which simply returns the color to the rasterizer, which draws it out on our frame.

We also define a Render technique which specifies which pixel/vertex shader programs we need to run for it. The effect file can contain multiple pixel/vertex shaders functions and techniques. Each technique can also feature multiple passes.

Loading the HLSL Effect File

Now to load the effect file we do the following:

if ( FAILED( D3DX10CreateEffectFromFile(  	"basicEffect.fx",
											NULL,
											NULL,
											"fx_4_0",
											D3D10_SHADER_ENABLE_STRICTNESS,
											0,
											pD3DDevice
											NULL, NULL,
											&pBasicEffect,
											NULL, NULL  ) ) ) return fatalError("Could not load effect file!");

pBasicTechnique = pBasicEffect->GetTechniqueByName("Render");

//create matrix effect pointers
pViewMatrixEffectVariable = pBasicEffect->GetVariableByName( "View" )->AsMatrix();
pProjectionMatrixEffectVariable = pBasicEffect->GetVariableByName( "Projection" )->AsMatrix();
pWorldMatrixEffectVariable = pBasicEffect->GetVariableByName( "World" )->AsMatrix();

What the above code does is load the effect file and creates an effect from it, it compiles the effect file on load, so any syntax errors in the file will cause this step to fail, so catching the error here is extremely important!

Then we create a pointer to the “Render()” technique defined in the file. This technique is what we will use for rendering, it defines what the pixel and vertex shader will do for any vertices pumped into the pipeline.

The last steps are to set up pointers to the effect matrix variables we declared in the effect file so we can update them during runtime. HLSL variables aren’t limited to just matrices, and there are lots of things you can achieve using HLSL but I’ll leave that research up to you!

So now we’ve loaded the effect file which defines the vertex and pixel shader parts of the pipeline, so now let’s deal with the input assembly stage. We define a basic vertex struct as follows:

struct vertex
{
      D3DXVECTOR3 pos;
      D3DXVECTOR4 color;

      vertex( D3DXVECTOR3 p, D3DXVECTOR4 c ) : pos(p), color(c) {}
};

Now we need to tell DX10 and more specifically the technique how to handle this vertex type, this is done via an InputLayout. First thing we do is fill out an input element desc structure. This defines the format of the vertex. The parameters are present in the SDK docs, but the important one is the byte offset parameter, as you will notice for the second structure the offset is 12 since the first element consists of 3 4byte variables.

D3D10_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
};

The next step is getting the description of the pass and creating the input layout. Since each pass in a technique will take in the same input format, we just get the first pass in the technique and use that to create the input layout. Once the layout is created we set it as the active input layout. This is important since you may need to process multiple types of vertices and may need to swap input layouts as needed.

UINT numElements = 2;
D3D10_PASS_DESC PassDesc;
pBasicTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );

if ( FAILED( pD3DDevice->CreateInputLayout( layout,
											numElements,
											PassDesc.pIAInputSignature,
											PassDesc.IAInputSignatureSize,
											&pVertexLayout ) ) ) return fatalError("Could not create Input Layout!");

// Set the input layout
pD3DDevice->IASetInputLayout( pVertexLayout );

Vertex Buffers

Phew, nearly done with the initialization, the last major thing we need to do is create the vertex buffer. The vertex buffer is a buffer that stores vertices before pumping them through to the video card, think of it as a waiting line for a carnival ride, people queue up until the ride is ready and then they get on, while the ride is busy, more people will queue up and so on.

There are several ways to efficiently use the vertex buffers, one of which is using the map function with the D3D10_MAP_WRITE_DISCARD flag but that’s something I’ll get to later.

So let’s create the vertex buffer. As expected the first step is filling out a DESC structure, the important parameters are the usage parameter which specifics what type of buffer to create, we want to be able to update it during runtime so we make it a dynamic buffer, and the CPUaccessFlag which specifies the type of access the CPU is granted to the buffer, again since we wish to update it during runtime, we allow writing by the CPU.

Then we create the vertex buffer and set the Input Assembler to use it. The parameters and their descriptions are once again found in the SDK documentation.

//create vertex buffer (space for 100 vertices)
//---------------------------------------------

UINT numVertices = 100;

D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof( vertex ) * numVertices;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

if ( FAILED( pD3DDevice->CreateBuffer( &bd, NULL, &pVertexBuffer ) ) ) return fatalError("Could not create vertex buffer!");;

// Set vertex buffer
UINT stride = sizeof( vertex );
UINT offset = 0;
pD3DDevice->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );

Setting up the Rasterizer

In my example I render a spinning triangle, but by default DX10 enables backface culling, this results in my triangle being visible only half the time so I want to disable that, since culling occurs during the rasterizer stage I need to create a custom rasterizer state and set the pipeline to use that:

D3D10_RASTERIZER_DESC rasterizerState;
rasterizerState.CullMode = D3D10_CULL_NONE;
rasterizerState.FillMode = D3D10_FILL_SOLID;
rasterizerState.FrontCounterClockwise = true;
rasterizerState.DepthBias = false;
rasterizerState.DepthBiasClamp = 0;
rasterizerState.SlopeScaledDepthBias = 0;
rasterizerState.DepthClipEnable = true;
rasterizerState.ScissorEnable = false;
rasterizerState.MultisampleEnable = false;
rasterizerState.AntialiasedLineEnable = true;

ID3D10RasterizerState* pRS;
pD3DDevice->CreateRasterizerState( &rasterizerState, &pRS);
pD3DDevice->RSSetState(pRS);

NOTE: you may have noticed that all the d3d device function are preceded by a label for which stage of the pipeline they affect, pretty nice of the developers to do that :P

Okay wow, we’ve gone through a lot just to set up the pipeline to render, and we havent even rendered anything yet. Jeez! I’m sure you openGL kids are screaming murder at this point, and I agree it is a bit more effort but to be honest after working in DX10 for the last couple of weeks I cant even imagine going back to openGL, while openGL might require less code, its so much messier.

Meet the Matrices

Damn I got side tracked, onto the rendering, first step lets create a world matrix, this defines the position and orientation of the object in the world, at a later stage every object in our scene will have its own world matrix.

//create world matrix
static float r;
D3DXMATRIX w;
D3DXMatrixIdentity(&w);
D3DXMatrixRotationY(&w, r);
r += 0.001f;

then we update the effect variables, using the pointers we created earlier

//set effect matrices
pWorldMatrixEffectVariable->SetMatrix(w);
pViewMatrixEffectVariable->SetMatrix(viewMatrix);
pProjectionMatrixEffectVariable->SetMatrix(projectionMatrix);

Filling the Vertex Buffer

Now the meat and potatoes of the whole tutorial, updating the vertex buffer. The first we do is lock the buffer, this allows us to safely write to the buffer without worrying about having any vertices being sent down the pipeline while we’re busy updating.

This function returns a pointer to the block of memory storing the vertex data. I’ve used a “discard” flag, which simply means that any previous data in the buffer must get discarded, if the buffer was busy being used to feed vertices into the pipeline, the map call will return a pointer to a new empty block of memory and discard the previous block once its finished being used. There are various other flags that I’ll probably cover in later tutorials but for now lets leave it at that.

Using our return pointer we set three vertices. We then unlock the buffer.

//fill vertex buffer with vertices
UINT numVertices = 3;
vertex* v = NULL;

//lock vertex buffer for CPU use
pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**) &v );

v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1) );
v[1] = vertex( D3DXVECTOR3(0,1,0), D3DXVECTOR4(0,1,0,1) );
v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1) );

pVertexBuffer->Unmap();

Input Assembly

The next step is telling the Input Assembly what type of primitive we’re drawing using the set topology function.

// Set primitive topology
pD3DDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

Finally using our technique pointer we get a Description of it and then process all the passes present in the technique. For each pass, we send through the vertices present in the vertex buffer using the draw command specify the number of vertices to draw and the start index in the vertex buffer.

Drawing the scene (finally) ;)

DX10 can only have one active vertex buffer at a time so if you have multiple buffers remember to load the correct one before you do any draw calls. The fact that there is an offset hints that you can store multiple objects in a single buffer and then draw them all using mutiple consecutive draw calls.

//get technique desc
D3D10_TECHNIQUE_DESC techDesc;
pBasicTechnique->GetDesc( &techDesc );

for( UINT p = 0; p < techDesc.Passes; ++p )
{
      //apply technique
      pBasicTechnique->GetPassByIndex( p )->Apply( 0 );

      //draw
      pD3DDevice->Draw( numVertices, 0 );
}

So that’s it, we’ve reached the end of the second tutorial, we’ve covered a lot of ground and I apologize that I haven’t gone too in depth regarding the functions and their parameters but I don’t have the time right now for in depth tutorials and I feel that a little bit of research and self study would be more beneficial than me spoon feeding you in these tutorials.

Tutorial 2

I’m actually hoping that these tutorials may serve as just a reference for your own code or just give you ideas and insight for your own projects.

Source Code

The source code and VS2k8 project for the tutorial can be found here: tutorial2.zip

2 September 2008 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, Graphics Programming, HLSL, Programming | , , , , , , | 5 Comments