Wherefore art thou Arius?   no comments

Posted at 2:42 pm in Uncategorized

I’ve had a few issues over the last couple weeks. Most notably I got drunk, stumbled into my open case( seriously folks, if your PC case isn’t open and lying on the floor even during operation then you just don’t have the minerals for this game we call geek ), passed out in a drunken stuper and woke up in agony with blood everywhere. Anyway, in the pounding painful process of putting my foot into my case and destroying my foot I also, more devastantingly destroyed my motherboard and video card( the foot destroying culprit ). Anyway, that’s where I am, limbo, PCless. I’m writing this on my old mans PC right now. The reason for this post is because, rather oddly tbh, I’ve had several emails - by which I mean about 50, asking me where I’ve vanished too. It’s nice to feel popular, but also annoying. I’ve started deleting those emails as spam because for every response I give I seem to get another 2 in return. So I’m hoping this post here will stem the tide somewhat.

To be honest, I don’t know who about 40 of the emails are from. I apologise, it’s nice that you care enough to email, but it’s unusual for me. I keep my social activities online rather limited, because I feel most intermahweb users are…. well, y’know. Anyway, I can only assume most of the influx is from this site - as I tend to recognise emails from Truevision3D users. Not really any major commenting going on here though.

Anyway, that’s why things have been slow. Also to answer some of the questions about epiphany. Yes, development is still going on, although erraticaly. I have it on flash memory, when the oppertunity arises to use a PC I do so and add little more code. As for the stuff I was doing for Zepa, I was unable to contact them properly due to the difference in time zones and my internet usage being constrained. Anyway, I did tell people in the TV3D IRC channel, so I can only assume at this point that word has gotten back to Michael. If not and he’s reading this, my apologies, I hope to be back up and running fully in early January. If you haven’t found a replacement by then I shall continue working etc.

Well, hope that clears things up. STOP EMAILING ME lol. It’s bad enough with the oodles of spam I’m wracking up not being able to clear it for days on end. Thanks for the “you haven’t died, have you?”, it’s sweet, but I’m cool. I’ll be back soon :).

Written by admin on October 23rd, 2008

Direct3D10 and epiphany   no comments

Posted at 4:26 am in Direct3D10, epiphany

Been a little while since I’ve posted. Not for any reason other than I’m lazy. Anyway, inbetween my Zepa works I decided to take a look at Direct3D10. My card is a pretty crappy mid-level 8500GT, but I intend to get a HD 4870 in the next week or so. That’s right, I have no qualms about switching from NV to ATI and vice versa - fanboyism in this area is for 12 year old school girls called “Candy”. So I figured I’d give D3D10 a whirl and see what’s up in anticipation of this new card. This of course meant going back to Vista( spit, spit, cough, cough ). I’m not overly anti-vista like a lot of people, but my preference is always on more resource light alternatives. Anyway, as a compromise I went with Server 2008 - because I could and I have always felt 2008 is more viable a system than Vista.

Anyway, as first impressions go, it seems the one thing I will remember Vista for once it shuffles off this virtual coil is the slaughter and murder of what seems to be an exceptionally good 3D API. D3D10 is such a welcome change from D3D9. D3D9 was really good, but D3D10 just feels cleaner and more fluid - especially now that MS have rid us of that old fashioned FFP. As an avid HLSL programmer I feel as though Microsoft sat down and said “What can we do to Direct3D to put a big smile on Geoff’s face?”. An for once, that smile was not induced by a big bottle of single malt Irish and a 20-deck of Embassy filts. So yea, happy chappy right here right now.

At the start it was a little tough, there are so few good D3D10 resources online on account of it being VistaCore only. The only real “tutorials” I could find outside of the SDK where a few sites with 2 or 3 articles and one site with quite a few but in Italian( and despite my Sicilian ancestry I can’t speak or read a word ). But I kept on going anyway. I decided the best way to learn given this situation would be to start writing a small-scale mini-engine. This way, I have a clear idea of what I’m doing and I can pound the MSDN like a nymphomaniac pounds a whore after 6 months of clean living at an ineffectual rehabilitation clinic. So far, this tactic is working.

I named this mini-framework epiphany and set to work. Pretty soon I had my base engine and timer classes written. The engine initialised in windowed or fullscreen and had a tacky watermark rendering in the bottom right. Next up, geometry. Now, one of the few pet peeves I have with D3D10 so far is that Microsoft seem to have completely removed support for their X format. Unless you use DXUT( seems to be like glut ) and well, to be honest, I have and had absolutely no interest in using that. So what, Microsoft X is awful? you might think. You may be right, that’s an opinion and it’s based on purpose as far as I am concerned. I wouldn’t use X for a serious project but it’s pretty handy to have a single function call to load geometry in for testing purposes. Anyways, I started thinking about ways to get around this without using DXUT. The solution I figured was to load the X file in D3D9 and convert it over to a D3D10 mesh. I’m not the most experianced when it comes to D3D, so I decided to search around online. I wasn’t hopeful about finding a solution given the complete lack of websites around but at the same time it seemed like a common problem to me. Fortunately, I found the solution in a gamedev.net journal here. It is actually less complex than I was expecting and I had it working in no time. Now, it’s slow, but for testing purposes that bothers me not. Later on I intend to load data in from FBX/DAE and save it to a custom fast-loading format.

Now, one of the stumbling blocks I can see for newbies in D3D10 is that in order to render anything you must use a shader. This isn’t really an issue if you already know and love HLSL, but it does make the process slightly more daunting for the average wannabe 3D developer. D3D10 of course introduces SM4 and I was more than eager to start tinkering around. After a few trial and error attempts, there are a few changes about the place it seems, I got a simple IN->OUT shader written and a nice little cube rendering. Next on the list was lighting, I decided to go for a normal mapping shader with some subcolour( ala NVIDIA’s lambskin ). This is up and working great, all so simple too. Here is my current decleration as it stands right now.


D3D10_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"BITANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0}
};

Pretty cool compared to the more fixed D3D way of doing things:


D3DVERTEXELEMENT9 decl[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
{0, 48, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
D3DDECL_END()
};

Next on the list was subset, or group, support. I got that in last night. I currently have the following classes:

  • epiphanyEngine
  • epiphanyStatic ( static geom )
  • epiphanyInput
  • epiphanyUtility

The next little bits of media are all chronologically in order of development.

Written by admin on October 4th, 2008

GeoUpdate   no comments

Posted at 5:24 pm in Articles

Ok, yay, I have some directional shadow mapping in. I am used to doing point light shadow mapping and I had heard that, unlike most things where directional is easiest, shadow mapping was different and it was harder. Fortunately I managed to get this simple stuff up very quickly. It supports alpha via clipping - clip is ofc relatively slow but meh. The scene is a composite. In the following video, the top-left buffer is the scene with just the shadows and the buffer next too it is the scene geometry without shadows. These two are then composited together for the final image. Anyway, here is a video.

Written by admin on September 16th, 2008

Geo Test Bed   no comments

Posted at 9:08 pm in Articles

Here is the some total of my work for Zepa so far. It’s not really much, just me getting things sorted in my head.

Currently has:

  • Colour Specmapping.
  • Normalmapping.
  • Depth gathering.
  • Per-Pixel Lit Instancing.

Not much yet really, but the underlying code has a lot of skeleton work in it for when I add the shadow mapping, SSAO and HDRR work.

Here are some screens. Click for the 1280×1024 shots.

Before PPL Instancing.

Before PPL Instancing.

Full Specular.

Full Specular.

Specular map only. No Diffuse, No Bump.

Specular map only. No Diffuse, No Bump.

Colour Specular Map.

Colour Specular Map.

Final.

Final.

PPL Instances Wire.

PPL Instances Wire.

PPL Instances.

PPL Instances.

Colour Spec:

PPL Grass:

Written by admin on September 8th, 2008

Sparkle Sparkle.   no comments

Posted at 8:24 pm in Uncategorized

Michael Shearon, one of the clever chaps over at Zepa studios, has asked me to help out with some of his lighting pipeline. So that’s what I’m going to be doing for the foreseeable future. You can check out some of Zepas stuff here( http://www.zepadev.net/ ). Anyway, if you’re a user of their world API and/or their editor Geonardo, you’ll probably already know that the screen-space ambient occlusion is my work - with a modified blur shader. But here is what you can expect from me in terms of this project.

Directional Shadow Mapping( Probably CSM, haven’t decided yet ) - including shadow casting particles.

Parallax, Specular and Occlusion mapped geometry - this goes for static, animated and instanced geometry.

Texture Splatting and Normal Mapped landscape geometry - the splatting must be rewritten as the shadow mapping shader kills TV’s internal splatting.

High-Dynamic Range Rendering, with alpha blend support.

Screen-Space Ambient Occlusion, this is already in as I said, but it probably needs rewriting to tie it in with the HDRR.

Bump mapped refraction - for things like glass.

Written by admin on August 30th, 2008

XP->360   1 comment

Posted at 5:46 pm in Uncategorized

This isn’t really development related. I just thought it was curious and worth a mention. Anyway, I lent my 360 to my older brother a couple months ago and I got it back a couple days ago. Finally decided to hook it back up( it’s painful connecting HD to a flatscreen TV mounted on your wall when the idiot designers of said TV put the jacks on the back ). First thing I wanted to do was download the Civilization, Dark Sector and Ninja Gaiden 2 demos. Normally, I would simply bridge my LAN and WLAN and get instant inet access for my 360. However, since lending my 360 out I’ve downgraded to XP. I didn’t think anything of this and proceeded to select my LAN and WLAN connections and hit up on “bridge”. BOOM, instant loss of internet on my PC. So, I unbridged them, internet connection was restored and I started to google. Most people seemed to simply be enabling ICS on their WLAN connections. Doing this however also killed my internet connection. After about 3 hours I managed to clock the problem. ICS under XP( I assume Vista also, I don’t know as I bridge under Vista ) uses the IP range 192.168.0.1 - this is not something that can be changed( grats MS ) and of course this is also the range that most out-of-the-box wireless routers use. The solution is to change the default range on ones router - rather than a simple edit box in the connections properties( this was too hard for MS for some unknown reason ).

Anyway, another pointless post, but worth noting if you don’t want to spend 50 quid on a wireless adapter for your 360 and you’re having issues like this.

Written by admin on August 20th, 2008

Mesh -> Landscape   no comments

Posted at 2:55 am in Articles

I was talking with likedonuts this morning on IRC. He was curious about whether or not it would be possible to use a CTVMesh as a landscape. This of course has the obvious flaws - loss of LOD, texture splatting and culling-by-chunk. We decided the best idea would be to translate vertices over from a mesh on to the landscape geometry. I’ve been bored all day wallowing in my weekend hangover. So I have written some code. This is entirely messy and in some cases just flat out stupid. But here is what I came up with.

Firstly, I wasn’t going to worry about generics so much. So the mesh must be the same size as the landscape, reside in the same position and have enough verts to fill the scape. So, taking a mesh I built up in maya( then ran a smooth over it ):

[click image for larger 1280x1024]

Maya based mesh.

Maya based mesh.


///<summary>
//    Take each vertex in a mesh and apply it to the terrain.
///</summary>
void Land::GenerateTerrainFromMesh(CTVMesh *m_Mesh)
{
int iCount;
float fX, fY, fZ;
float fNx, fNy, fNz;
float fTu1, fTv1, fTu2, fTv2;
float fLVX, fLVZ;
int iColour;

fLVX = 0;
fLVZ = 0;

iCount = m_Mesh->GetVertexCount();

for(int i = 0; i < iCount; i++)
{
m_Mesh->GetVertex(i, &amp;fX, &amp;fY, &amp;fZ, &amp;fNx, &amp;fNy, &amp;fNz, &amp;fTu1, &amp;fTv1, &amp;fTu2, &amp;fTv2, &amp;iColour);
Land::m_Terrain->SetHeight(fX, fZ, fY, true, false, false);
}
Land::m_Terrain->FlushHeightChanges(true, true);
Land::m_Terrain->ComputeNormals(true);
}

This results in the following terrain inside Truevision3D.

Landscape with mesh verts.

Landscape with mesh verts.

As you can see in the larger image, this translation of vertices is rather unsmooth. So I wrote a very dirty, hacky smoothing function. NOTE: I am not proud of this code :).


///<summary>
//    Average out the verts, making it smoother.
///</summary>
void Land::SmoothTerrain(HWND Handle, cCONST_TV_LANDSCAPE_PRECISION Precision)
{
float p1, p2, p3, p4, p5, p6, p7, p8;
float Avg;
float X, Z;
int Gap;
int TotalRow;

X        = -512;
Z        = -512;
Gap      = Precision;
TotalRow = (256 / Gap) * 4; //4 is the chunk amount.

while(TRUE)
{
for(int i = 0; i <= TotalRow; i++)
{
SetWindowText(Handle, "Smoothing... Please Wait");
p1 = Land::m_Terrain->GetHeight(X + Gap, Z);
p2 = Land::m_Terrain->GetHeight(X - Gap, Z);
p3 = Land::m_Terrain->GetHeight(X, Z + Gap);
p4 = Land::m_Terrain->GetHeight(X, Z - Gap);

p5 = Land::m_Terrain->GetHeight(X + (Gap * 2), Z);
p6 = Land::m_Terrain->GetHeight(X - (Gap * 2), Z);
p7 = Land::m_Terrain->GetHeight(X, Z + (Gap * 2));
p8 = Land::m_Terrain->GetHeight(X, Z - (Gap * 2));

Avg = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8) / 8;

Land::m_Terrain->SetHeight(X, Z, Avg, true, false, false);

X += Gap;
}

if(Z > 512) break;
Z += Gap;
X = -512;
}

Land::m_Terrain->FlushHeightChanges(true, true);
Land::m_Terrain->ComputeNormals(true);
SetWindowText(Handle, "Mesh2Scape");
}

I ran this smoothing function twice for the final result.

Before smoothing.

Before Smoothing.

After Smoothing(2x).

After Smoothing(2x).

Finished Result.

Finished Result.

Anyway, kind of pointless and also a bit useless. But meh. ;)

Written by admin on August 18th, 2008

Tutorial #02: A textured cube.   no comments

Posted at 5:30 pm in Articles

So we have a spinning cube, but it has no texture. This process is exceptionally simple in Truevision3D and requires just 6 additional lines of code. We add the following to our declarations.


//Startup.
CTVMesh           *m_Cube;
CTVTextureFactory *m_Tex;    //This is for basic texturing functionality.
CTVCamera         *m_Cam;    //This is a camera.
CTVScene          *m_Scene;  //This is used for instantiating resource types - Geometry, Render Targets, Shaders and so on.
CTVEngine         *m_Engine; //This is the main engine class. It's all we require for a blank screen.

int   IDDiffuse;             //This is an ID for our texture. You can use strings also but strings are slower.
float fTime;                 //This is our tick value.

We add TV3D’s texture factory class and also a simple int, which is our texture ID. Then in our SetupScene() function we load the texture and apply it to the cube.


//Setup TV.
void SetupScene(HWND Handle)
{
//Instantiate. NOTE: We do NOT instantiate geometry in this way.
m_Tex     = new CTVTextureFactory;
m_Cam     = new CTVCamera;
m_Scene   = new CTVScene;
m_Engine  = new CTVEngine;

//Now, lets initialize the engine. It's important to understand that this must be done before any other TV class is used - with the exception of CTVDeviceInfo.
m_Engine->SetDebugFile("debug.txt");      //We want TV to dump a debug file, this is very useful, Sylvain is good at catching common mistakes and informing you that you've made them in this files log.
m_Engine->Init3DWindowed(Handle, true);   //We want to initialize on our windows handle and we have hardware transform and lighting.
//m_Engine->Init3DFullscreen(800, 600, 32, true, false, cTV_DEPTHBUFFER_BESTBUFFER, 1, Handle);

//Load a texture in to our integer ID.
IDDiffuse = m_Tex->LoadTexture("..\\common\\tv3dlogo_d.dds", "diffuse texture", -1, -1, cTV_COLORKEY_NO, true);

//Now we instantiate our cube.
m_Cube    = m_Scene->CreateMeshBuilder("cube");
m_Cube->CreateBox(5, 5, 5, false);
m_Cube->SetTexture(IDDiffuse, -1);        //Set our texture ID on to the cube.

m_Cam->SetPosition(0, 0, -20);            //We move the camera back by 20 on Z because the cube is at 0, 0, 0. So we move it back so we can see the cube.
}

That’s it, job done. :)

Written by admin on August 14th, 2008

Tutorial #01: A spinning cube.   no comments

Posted at 6:38 pm in Articles

Right, so we’ve got a blank screen on the go. Let us add some geometry to the scene. This is very easy to do in Truevision3D. We’re going to use the blank screen code that we covered in tutorial 01 and add a few lines. So, along with the engine declaration that we made before, we add the following.


//Startup.
CTVMesh   *m_Cube;
CTVCamera *m_Cam;    //This is a camera.
CTVScene  *m_Scene;  //This is used for instantiating resource types - Geometry, Render Targets, Shaders and so on.
CTVEngine *m_Engine; //This is the main engine class. It's all we require for a blank screen.

float fTime;         //This is our tick value.

We’ve added three new engine classes and a float variable. The float variable is going to be used to ensure that the cube spins/rotates at the same speed regardless of FPS. This is a rather important thing to learn, afterall, if somebody runs your game or application on a super computer you don’t want the movement of objects to be 300x faster than it is on your system. The next thing we want to do is instantiate our new classes, create a cube and position the camera. So we add the following to our SetupScene() function.


//Setup TV.
void SetupScene(HWND Handle)
{
//Instantiate. NOTE: We do NOT instantiate geometry in this way.
m_Cam    = new CTVCamera;
m_Scene  = new CTVScene;
m_Engine = new CTVEngine;

//Now, lets initialize the engine. It's important to understand that this must be done before any other TV class is used - with the exception of CTVDeviceInfo.
m_Engine->SetDebugFile("debug.txt");      //We want TV to dump a debug file, this is very useful, Sylvain is good at catching common mistakes and informing you that you've made them in this files log.
m_Engine->Init3DWindowed(Handle, true);   //We want to initialize on our windows handle and we have hardware transform and lighting.
//m_Engine->Init3DFullscreen(800, 600, 32, true, false, cTV_DEPTHBUFFER_BESTBUFFER, 1, Handle);

//Now we instantiate our cube.
m_Cube   = m_Scene->CreateMeshBuilder("cube");
m_Cube->CreateBox(5, 5, 5, false);

m_Cam->SetPosition(0, 0, -20);            //We move the camera back by 20 on Z because the cube is at 0, 0, 0. So we move it back so we can see the cube.
}

A few new lines here, the obvious instantiation of the new classes and the rigging of our cube. As you can see we’re using the CreateBox() function, we will cover loading geometry later. You’ll notice that I did not instantiate the cube via “new” here. In Truevision3D most geometrical types are instantiated using the CTVScene class - the same is true of shaders, render targets and landscapes. After the box creation we move the camera back by 20 units because the cube, by default, is at position 0, 0, 0 and we want the camera pointing at it - not on it.

A new function, this will be used in the following samples to do any scene updating tasks that we require.


void UpdateScene()
{
//Rotate the cube by an amount scaled by our fTime tick variable.
m_Cube->RotateX(0.0003f * fTime, true);
m_Cube->RotateY(0.003f * fTime, true);
m_Cube->RotateZ(0.00003f * fTime, true);
}

We rotate the cube on each axis by a set amount, however, notice how use the fTime variable here to scale the amount. The fTime variable is the amount of time, in milliseconds, that it took to render the last frame. We fill the variable each frame using the function CTVEngine->AccurateTimeElapsed(). As seen in our render loop here:


//Entry point.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Firstly lets create a window.
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&amp;wc, sizeof(WNDCLASSEX));

wc.cbSize        = sizeof(WNDCLASSEX);
wc.style         = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc   = (WNDPROC)WindowProc;
wc.hInstance     = hInstance;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass1";

RegisterClassEx(&amp;wc);

int Cx = GetSystemMetrics(SM_CXSCREEN);
int Cy = GetSystemMetrics(SM_CYSCREEN);

hWnd = CreateWindowEx(NULL, "WindowClass1", "Spinning Cube", WS_CAPTION, (Cx / 2) - (800 / 2), (Cy / 2) - (600 / 2), 800, 600, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);

//Setup our scene, we send it a handle to our window.
SetupScene(hWnd);

//Now we create a game loop.
MSG msg;

while(TRUE)
{
//Fill our tick value with the time it took to render the last frame.
fTime = m_Engine->AccurateTimeElapsed();

//Render a frame.
m_Engine->Clear(false);
m_Cube->Render(); //Render the cube.
m_Engine->RenderToScreen();

//Update the scene.
UpdateScene();

//Now we process the message queue.
if(PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))
{
//If the user closes the window, we break the game loop.
if(msg.message == WM_QUIT) break;
TranslateMessage(&amp;msg);
DispatchMessage(&amp;msg);
}
}

//If the game loop was broken, we clean up.
m_Engine->ReleaseAll();
delete(m_Engine);

return msg.wParam;
}

As you can see, we fill the tick value, render the frame and then call our UpdateScene() function.

Written by admin on August 13th, 2008

Tutorial #00: Creating a blank screen.   no comments

Posted at 1:10 am in Articles

Ok, first post.

We’re going to create a blank screen using Truevision3D. This will form the basis of the rest of these tutorials. These tutorials assume the reader is a C++ programmer, however, the downloadable samples at the end of each article come in a plethora of languages. C++/C#/VB.NET and VB6 - with Delphi ports coming soon. I’m also going to assume that you know how to reference a library and rig paths.

Our program starts, as most, with headers. We include the following.


#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>

//TV header files. You don't need to include them all of course, but for the purposes of this I am going too.
#include <CTVActor.h>
#include <CTVAI.h>
#include <CTVAtmosphere.h>
#include <CTVCamera.h>
#include <CTVCameraFactory.h>
#include <CTVCollisionResult.h>
#include <CTVDeviceInfo.h>
#include <CTVShader.h>
#include <CTVTextureFactory.h>
#include <CTVViewport.h>
#include <tv_types.h>
#include <HelperFunctions.h>
#include <CTVScreen2DText.h>
#include <CTVScreen2DImmediate.h>
#include <CTVScene.h>
#include <CTVRenderSurface.h>
#include <CTVPhysics.h>
#include <CTVPath.h>
#include <CTVParticleSystem.h>
#include <CTVPackage.h>
#include <CTVNode.h>
#include <CTVMiniMesh.h>
#include <CTVMesh.h>
#include <CTVMathLibrary.h>
#include <CTVMaterialFactory.h>
#include <CTVLightEngine.h>
#include <CTVLandscape.h>
//#include <CTVInternalObjects.h>       INSTALL DIRECTX 9 SDK IN ORDER TO USE THE ENGINES INTERNAL DX OBJECTS.
#include <CTVInputEngine.h>
#include <CTVGraphicEffect.h>
#include <CTVGlobals.h>
#include <CTVGameControllers.h>
#include <CTVGameController.h>
#include <CTVEngine.h>

These are all of Truevision3D’s headers. Once we have all these we can start with the actual code.


//Startup.
CTVEngine *m_Engine; //This is the main engine class. It's all we require for a blank screen.

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

We’ve declared an instance of CTVEngine. The engine can be initialized on HWND/Handle, be it a window/form or a picturebox. Because this is C++ we must create a window, hence the callback, but for other languages one can just use the form provided. We’re going to create a small function now to setup the scene.


//Setup TV.
void SetupScene(HWND Handle)
{
//Instantiate.
m_Engine = new CTVEngine;

//Now, lets initialize the engine. It's important to understand that this must be done before any other TV class is used - with the exception of CTVDeviceInfo.
m_Engine->SetDebugFile("debug.txt");      //We want TV to dump a debug file, this is very useful, Sylvain is good at catching common mistakes and informing you that you've made them in this files log.
m_Engine->Init3DWindowed(Handle, true);   //We want to initialize on our windows handle and we have hardware transform and lighting.

//m_Engine->Init3DFullscreen(800, 600, 32, true, false, cTV_DEPTHBUFFER_BESTBUFFER, 1, Handle);
}

The comments there are pretty self explanatory. In the applications entry point, we have three things going on. Firstly, we create our window using WinAPI. Secondly, we create our game loop and process the windows messages. Lastly we clean up the engine if the loop is broken.


//Entry point.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Firstly lets create a window.
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&amp;wc, sizeof(WNDCLASSEX));

wc.cbSize        = sizeof(WNDCLASSEX);
wc.style         = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc   = (WNDPROC)WindowProc;
wc.hInstance     = hInstance;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass1";

RegisterClassEx(&amp;wc);

int Cx = GetSystemMetrics(SM_CXSCREEN);
int Cy = GetSystemMetrics(SM_CYSCREEN);

hWnd = CreateWindowEx(NULL, "WindowClass1", "Blank Screen", WS_CAPTION, (Cx / 2) - (800 / 2), (Cy / 2) - (600 / 2), 800, 600, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);

//Setup our scene, we send it a handle to our window.
SetupScene(hWnd);

//Now we create a game loop.
MSG msg;

while(TRUE)
{
//Render a frame.
m_Engine->Clear(false);
//Stuff is usually rendered here.
m_Engine->RenderToScreen();

//Now we process the message queue.
if(PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))
{
//If the user closes the window, we break the game loop.
if(msg.message == WM_QUIT) break;
TranslateMessage(&amp;msg);
DispatchMessage(&amp;msg);
}
}

//If the game loop was broken, we clean up.
m_Engine->ReleaseAll();
delete(m_Engine);

return msg.wParam;
}

You can see that if the window receives a quit message, the game loop breaks and the engine is released cleanly. As for the message loop, most RAD languages have simple functions for this, I beleive in VB6/.NET it is DoEvents() and under Delphi one should use Application.ProcessMessages;. The final part of the program is a standard callback.


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}

Written by admin on August 13th, 2008