GAM670/DPS905 -- Weekly Schedule 20121

Week 1 - Jan 8

This Week

• Assignment Discussion
• Suggested Enhancements
• Review of the Base Code
• Definition of a Framework
• Modularity through stable interfaces
• Re-usability through generic components
• Extensibility through hook methods
• Inversion of control - determines which application methods to invoke in response to external events
• Framework Architecture
• Modelling Layer
• API Translation Layer
• Notable Features of the Base Code
• camera, sound, and light are also derived from the Frame class
• textures attach at the object level
• texture connection is uncoupled from drawing of the graphics primitives
• reference frames are relative
• very simple collision detection

To Do

2. create a team page that includes the semester number 20121
• describe the game that you intend to develop
• list the topics of interest to your team in developing its game
• list the other topics of interest

Week 2 - Jan 16

This Week

• Relative Reference Frames
• Recursive calls
Vector Frame::position()
Matrix Frame::rotation()
Matrix Frame::world()
• Detaching from and attaching to a parent frame
Frame::attachTo()
• Geometry
• Plane
normal + constant - examples
equation of a plane: dot(n, x) + D = 0
positive side of a plane dot(n, x) + D > 0
• Collision Detection
types of colliders
spheres
planes
axis-aligned bounding boxes
oriented bounding boxes

To Do

• Research the feature that you are going to add and prepare a plan of action
• Prepare a team page for your team so that repos can be ordered

Week 3 - Jan 23

This Week

• Collision Detection (cont'd)
Shape
Shape : Frame
Shape::setRadius(float x, float y, float z);
Shape::setPlane(Vector n, float d);
Shape::setAxisAligned(Vector min, Vector max);
• Comprehensive Camerawork
order of rotation matters
Euler angles
3-2-1 angles
gimbal lock
StephenSeefeld.net
complex numbers
solution of cubic equations 16th century
two-dimensional representation
matrix representation
quaternions
extension of complex numbers
four-dimensional representation
matrix representation
geometric algebra (more abstract)
Dorst's site
Hitzer's site
• Visibility Determination
• test a point for presence within a set of planes
normal calculations - general rotation matrix - vector and angle
• ViewFrustum
parameter - view * projection
6 planes
near and far planes
left and right planes
top and bottom planes
coding
constructor
ViewFrustum::contains()
• Finite Size of Objects
Expansion of the View Frustum
• Index Buffers
amount of storage needed for vertex data
duplication of vertex data
indexing
indexed primitives

Week 4 - Jan 30

This Week

• Meshes
What is a mesh?
vertex list -> vertex buffer
index list -> index buffer
attribute list -> subset to which primitives belong
pyramid sample
Stock Objects
Sphere
slices and partitions
Cylinder
Torus
Utah Teapot
APIGraphic.h and .cpp code
Custom Mesh
Create a Mesh
APIGraphic.h code
```template <class T = Vertex, class I = Index>
class APICustomMesh : public iAPIGraphic, public APIBase {

unsigned   nSubsets;    // number of subsets
unsigned   nPrimitives; // number of primitives
unsigned*  attribute;   // points to mesh's attribute list
I*         index;       // points to mesh's array of indices
unsigned   iIndex;      // number of indices currently saved
unsigned   nIndices;    // number of indices in the mesh
T*         vertex;      // points to mesh's array of vertices
unsigned   iVertex;     // number of vertices currently saved
unsigned   nVertices;   // number of vertices in the mesh
LPD3DXMESH apiMesh;     // set of vertices, indices

protected:
virtual ~APICustomMesh();
void setup();

public:
APICustomMesh(unsigned*, int, int, int, int);
APICustomMesh(const APICustomMesh& v);
APICustomMesh& operator=(const APICustomMesh& v);
APICustomMesh* clone() const { return new APICustomMesh(*this); }
void     draw(unsigned);
void     suspend();
void     release()           { suspend(); }
void     Delete() const      { delete this; }
};```
• APIGraphic.cpp - APIGraphic
```template <class T, class I>
APICustomMesh<T, I>::APICustomMesh(unsigned* a, int np, int ni, int nv, int ns)
: nSubsets(ns), nPrimitives(np), nIndices(ni), nVertices(nv), iIndex(0),
iVertex(0) {

attribute = new unsigned[nPrimitives];
for (unsigned i = 0; i < nPrimitives; i++)
attribute[i] = a[i];

index   = new I[nIndices];
vertex  = new T[nVertices];

apiMesh = nullptr;
}```
```template <class T, class I>
unsigned APICustomMesh<T, I>::add(const T& v) {

unsigned i = iVertex;

if (vertex && iVertex < nVertices)
vertex[iVertex++] = v;

return i;
}```
```template <class T, class I>

if (index && iIndex < nIndices)
index[iIndex++] = v;
}```
• APIGraphic.cpp - setup()
```template <class T, class I>
void APICustomMesh<T, I>::setup() {

T *pv;
I *pi;
DWORD *pa;
nIndices  = iIndex;
nVertices = iVertex;

// create an empty mesh and lock its buffers
if (FAILED(D3DXCreateMesh(nPrimitives, nVertices, 0,
APIVertexDeclaration<T>::format(), d3dd, &apiMesh))) {
error(L"APIMesh::14 Couldn\'t create the empty mesh");
apiMesh = nullptr;
}
else if (FAILED(apiMesh->LockVertexBuffer(0, (void**)&pv))) {
error(L"APIMesh::15 Couldn\'t lock vertex buffer");
release();
}
else if (FAILED(apiMesh->LockIndexBuffer(0, (void**)&pi))) {
error(L"APIMesh::16 Couldn\'t lock index buffer");
release();
}
else if (FAILED(apiMesh->LockAttributeBuffer(0, &pa))) {
error(L"APIMesh::17 Couldn\'t lock attribute buffer");
release();
}
else {
// populate the newly created Vertex Buffer
for (unsigned i = 0; i < nVertices; i++)
vertex[i].populate((void**)&pv);
apiMesh->UnlockVertexBuffer();
// populate the newly created Index Buffer
for (unsigned i = 0; i < nIndices; i++)
pi[i] = index[i];
apiMesh->UnlockIndexBuffer();
// Populate the newly created Attribute Buffer
for (unsigned i = 0; i < nPrimitives; i++)
pa[i] = attribute[i];
apiMesh->UnlockAttributeBuffer();
}
}```
• APIGraphic.cpp - DrawSubset()
```template <class T, class I>
void APICustomMesh<T, I>::draw(unsigned iSubset) {

// if mesh doesn't exist, set it up first
if (!apiMesh) setup();

if (apiMesh)
apiMesh->DrawSubset(iSubset);
}```
• DrawIndexedPrimitive parameters
APIGraphic.cpp - suspend()
```template <class T, class I>
void APICustomMesh<T, I>::suspend() {

// release the interface to the mesh
if (apiMesh) {
apiMesh->Release();
apiMesh = nullptr;
}
}```
• APIGraphic.cpp - ~APIGraphic
```template <class T, class I>
APICustomMesh<T, I>::~APICustomMesh() {

release();
if (attribute)
delete [] attribute;
if (index)
delete [] index;
if (vertex)
delete [] vertex;
}```
• X File
Create Mesh from File
• SkyBox
definition of a skybox
attachment to camera
inverted coordinates
skybox textures
Graphic.cpp code
more complicated forms - skydome
• Billboards
definition, purpose of a billboard
```void Billboard::render(unsigned) {

Vector h, u, r, p = position();
Camera* camera = *(Camera**)(Camera::getCurrent());
Vector cameraPosition = camera->position();
Vector cameraUp       = ::normal(camera->orientation('y'));
switch (type) {
// ... see below
}
Matrix rot(r.x, r.y, r.z, 0,
u.x, u.y, u.z, 0,
h.x, h.y, h.z, 0,
0,   0,   0, 1);
orient(rot);

Object::render(0);
}```
• types of billboards
screen-aligned - useful for annotation text, lens flares
normal is opposite to camera heading
up is camera->up
```        case SCREEN:
u = cameraUp;      // up is fixed
r = cross(u, h);
break;```
• axial - useful for cylindrical symmetry - trees (textured object does not face straight on)
up is fixed
normal faces the viewer as much as possible
```        case AXIAL:
h = ::normal(position() - cameraPosition); // heading is open to change
u = Vector(0, 1, 0); // up axis is fixed
r = cross(u, h);
h = cross(u, r);
break;```
• view_plane - no distortion - useful for
normal is fixed (opposite to camera heading)
up is open to change
```        case VIEW_PLANE:
u = Vector(0, 1, 0); // up is open to change
r = cross(u, h);
u = cross(h, r);
break;```
• viewpoint - simulates distortion due to perspective projection - useful for clouds
normal is fixed (difference between viewpoint position and camera heading)
up is open to change
```        case VIEWPOINT:
h = ::normal(position() - cameraPosition); // heading is fixed
u = Vector(0, 1, 0); // up is open to change
r = cross(u, h);
u = cross(h, r);
break;```
• Object.h and Object.cpp code
• Texture Filtering
mip maps
multum in parvo
texture creation
APITexture::SetSamplerState()
```    // mipmap filtering
if (flags & TEX_MIPMAP)
d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
else
d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE);```
• DirectX Errors
DirectX Utilities - Lookup Tool
APIDisplay::restore() example
```bool APIDisplay::restore() {

bool rc = false;

if (d3dd) {
HRESULT hr;
hr = d3dd->TestCooperativeLevel();
if (hr == D3DERR_DEVICENOTRESET)
// reset the APIDisplay device
rc = d3dd->Reset(&d3dpp) == D3D_OK;
else if (hr == S_OK)
rc = true;
}
if (rc) {
// reacquire sprite manager references to video memory
if (manager)
manager->OnResetDevice();
}

// complete the restoration
if (rc) {
setupLighting();
setupBlending();
}

return rc;
}```

Week 5 - Feb 6

This Week

```template <class T = Vertex>
class APIVertexDeclaration {

static D3DVERTEXELEMENT9 fmt[MAXD3DDECLLENGTH + 1];
static unsigned vertexSize;

public:
static D3DVERTEXELEMENT9* format() { return fmt; }
static unsigned size()             { return vertexSize; }
};```
```template <>
D3DVERTEXELEMENT9 APIVertexDeclaration<Vertex>::fmt[MAXD3DDECLLENGTH + 1]
= {
{ 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},
D3DDECL_END()};

template<>
unsigned APIVertexDeclaration<Vertex>::vertexSize = 32;```
```template <>
D3DVERTEXELEMENT9 APIVertexDeclaration<LitVertex>::fmt[MAXD3DDECLLENGTH + 1]
= {
{ 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()};

template <>
unsigned APIVertexDeclaration<LitVertex>::vertexSize = 16;```
D3DVERTEXELEMENT9 struct

Week 6 - Feb 13

This Week

• Host
APIPlatformSettings.h - Vertex Shader Identification - select between fixed function and programmable pipelines here
```// shader file data
APIBase.h - pointers into the shader - APIBase is the base class for the graphics API classes
```    static IDirect3DVertexShader9* vertexShader; // vertex shader
static ID3DXConstantTable*     uniformVS;    // for vertex shader```
APIBase.cpp - initialize the shader pointers
```IDirect3DVertexShader9* APIBase::vertexShader   = nullptr; // vertex shader
ID3DXConstantTable*     APIBase::uniformVS      = nullptr; // for vertex shader```
APIDisplay.h - keeps track of the current projection matrix
`    Matrix   projection;       // projection transformation`
APIDisplay.cpp - setup() - checks the shader version
```    // points to compiled shader code
LPD3DXBUFFER compiledCodeVS = nullptr;

// check for minimum vertex shader version required
error(L"APIDisplay::09 Device does not support vertex shader 2_0");```

```    // compile the vertex shader source code
&compiledCodeVS, NULL, &uniformVS))) {
release();
error(L"APIDisplay::13 Unable to compile vertex shader");
}
// create the vertex shader object
compiledCodeVS->Release();
release();
error(L"APIDisplay::14 Unable to create vertex shader object");
}
else {
compiledCodeVS->Release();```

`        d3dd->SetVertexShader(vertexShader);`
APIDisplay.cpp - setProjection() - stores the projection matrix
`    this->projection = *((Matrix*)projection);`
APIDisplay.cpp - beginDrawFrame() - copies the view matrix and the camera heading to constant memory
```    Matrix& v = *((Matrix*)view);
Matrix viewProjection = v * projection;
uniformVS->SetMatrix(d3dd, "viewProjection",
(D3DXMATRIX*)&viewProjection);
// Required for specular lighting calculations
```        Colour colour(red, green, blue);
uniformVS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4);
uniformVS->SetInt(d3dd, "noLights", 4);```
APIDisplay.cpp - set() - copies the lighting state to constant memory
`                uniformVS->SetBool(d3dd, "lighting", b);`
APIDisplay.cpp - setWorld() - copies the world matrix to constant memory
`        uniformVS->SetMatrix(d3dd, "world", (D3DXMATRIX*)world);`
APIDisplay.cpp - setReflectivity() - copies the reflectivity to constant memory
```        uniformVS->SetFloatArray(d3dd, "material.ambient",  (FLOAT*)&r.ambient, 4);
uniformVS->SetFloatArray(d3dd, "material.diffuse",  (FLOAT*)&r.diffuse, 4);
uniformVS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&r.specular, 4);
uniformVS->SetFloat     (d3dd, "material.power",    (FLOAT)r.power);```
APIDisplay.cpp - release() - releases constant memory and the vertex shader
```    // release the shader COM objects
if (uniformVS) {
uniformVS->Release();
uniformVS = nullptr;
}
}```
APILight.cpp - setup() - copies the light properties to constant memory
```        // Populate the vertex shader constant table
//
// Light descriptors within the vertex shader
char typ[] = "light[0].type";
char amb[] = "light[0].ambient";
char dif[] = "light[0].diffuse";
char spe[] = "light[0].specular";
char pos[] = "light[0].position";
char dir[] = "light[0].direction";
char spt[] = "light[0].spot";
char att[] = "light[0].attenuation";
char ran[] = "light[0].range";
//
// Reset index in light descriptor
typ[6] = index + '0';
amb[6] = index + '0';
dif[6] = index + '0';
spe[6] = index + '0';
pos[6] = index + '0';
dir[6] = index + '0';
spt[6] = index + '0';
att[6] = index + '0';
ran[6] = index + '0';
// Populate the vertex shader constant table
Vector attenuation(attenuation0, attenuation1, attenuation2);
Vector spot(cosf(phi/2), cosf(theta/2), falloff);
Vector zero;
uniformVS->SetInt(d3dd, typ, type);
uniformVS->SetFloatArray(d3dd, amb, (FLOAT*)&ambient, 4);
uniformVS->SetFloatArray(d3dd, dif, (FLOAT*)&diffuse, 4);
uniformVS->SetFloatArray(d3dd, spe, (FLOAT*)&specular, 4);
uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&zero, 3);
uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&zero, 3);
uniformVS->SetFloatArray(d3dd, att, (FLOAT*)&attenuation, 3);
uniformVS->SetFloatArray(d3dd, spt, (FLOAT*)&spot, 3);
uniformVS->SetFloat(d3dd, ran, range);
rc = true;```
APILight.cpp - turnOn() - repositions the light and turns it on
```        char constantLightOn[] = "lightOn[0]";
constantLightOn[8] = index + '0';
char pos[] = "light[0].position";
char dir[] = "light[0].direction";
pos[6] = index + '0';
dir[6] = index + '0';
uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
uniformVS->SetBool(d3dd, constantLightOn, true);```
APILight.cpp - update() - repositions the light
```        char constantLightOn[] = "lightOn[0]";
constantLightOn[8] = index + '0';
char pos[] = "light[0].position";
char dir[] = "light[0].direction";
pos[6] = index + '0';
dir[6] = index + '0';
uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
uniformVS->SetBool(d3dd, constantLightOn, true);```
APILight.cpp - turnOff() - turns off the light
```        char constantLightOn[] = "lightOn[0]";
constantLightOn[8] = index + '0';
uniformVS->SetBool(d3dd, constantLightOn, false);```
APIGraphic.h - class APIXMesh - processes an X file mesh
```    D3DXCOLOR*          ambient;
D3DXCOLOR*          diffuse;
D3DXCOLOR*          specular;
FLOAT*              power;```
APIGraphic.cpp - APIXMesh() - constructor
```    ambient  = nullptr;
diffuse  = nullptr;
specular = nullptr;
power    = nullptr;```
APIGraphic.cpp - APIXMesh() - copy constructor
```    ambient  = nullptr;
diffuse  = nullptr;
specular = nullptr;
power    = nullptr;```
APIGraphic.cpp - operator=() = assignment operator
```        if (ambient)
delete [] ambient;
if (diffuse)
delete [] diffuse;
if (specular)
delete [] specular;
if (power)
delete [] power;
ambient  = new D3DXCOLOR[src.nSubsets];
diffuse  = new D3DXCOLOR[src.nSubsets];
specular = new D3DXCOLOR[src.nSubsets];
power    = new FLOAT[src.nSubsets];```
```        for (unsigned i = 0; i < nSubsets; i++) {
ambient[i]  = src.ambient[i];
diffuse[i]  = src.diffuse[i];
specular[i] = src.specular[i];
power[i]    = src.power[i];
}```
APIGraphic.cpp - setup() -
```        ambient  = new D3DXCOLOR[nSubsets];
diffuse  = new D3DXCOLOR[nSubsets];
specular = new D3DXCOLOR[nSubsets];
power    = new FLOAT[nSubsets];```
```            ambient[i].r = matl[i].MatD3D.Diffuse.r * 0.7f;
ambient[i].g = matl[i].MatD3D.Diffuse.g * 0.7f;
ambient[i].b = matl[i].MatD3D.Diffuse.b * 0.7f;
ambient[i].a = matl[i].MatD3D.Diffuse.a;
diffuse[i]   = matl[i].MatD3D.Diffuse; // reflected from lights
specular[i]  = matl[i].MatD3D.Specular;       // shine from lights
power[i]     = matl[i].MatD3D.Power; // 0 if it shouldn't be shiny```
APIGraphic.cpp - draw()
```            uniformVS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&ambient[i], 4);
uniformVS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&diffuse[i], 4);
uniformVS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&specular[i], 4);
uniformVS->SetFloat(d3dd, "material.power", (FLOAT)power[i]);```
APIGraphic.cpp - suspend()
```    if (ambient)
delete [] ambient;
if (diffuse)
delete [] diffuse;
if (specular)
delete [] specular;
if (power)
delete [] power;```
• Device
```#define MLIGHTS 4
#define POINT_LIGHT       0
#define SPOT_LIGHT        1
#define DIRECTIONAL_LIGHT 2

// Types
//
// Light holds the data for a single light in world space
//
struct Light {
int    type;        // POINT_LIGHT, SPOT_LIGHT, DIRECTIONAL_LIGHT
float4 ambient;
float4 diffuse;
float4 specular;
float3 direction;   // in world space
float3 position;    // in world space
float3 attenuation; // .xyz for 1.0f/ (.x + .y * d + .z * d * d)
float3 spot;        // .x = cos(phi/2), .y = cos(theta/2), .z = falloff
float  range;       // where attenuation becomes 0
};

// Material holds the reflectivity properties of the material
//
struct Material {
float4 ambient;
float4 diffuse;
float4 specular;
float  power;
};

// RawVertex holds the untransformed data for a single vertex
//
struct RawVertex {

float3 position : POSITION;  // position in local space
float3 normal   : NORMAL;    // normal in local space
float2 texCoord : TEXCOORD;  // texture coordinates
};

// TransformedVertex holds the transformed data for a single vertex
//
struct TransformedVertex {

float4 position  : POSITION;   // position in homogeneous clip space
float4 colour    : COLOR;      // colour of the lit vertex
float2 texCoord0 : TEXCOORD0;  // texture coordinates - stage 0
float2 texCoord1 : TEXCOORD1;  // texture coordinates - stage 1
};

// Uniform Data (constant for a stream of vertices)
//
// Lighting
float4   ambient;          // global ambient light - always on
Light    light[MLIGHTS];   // static lights
bool     lightOn[MLIGHTS]; // switches for static lights
Material material;         // material reflectivity
// Geometry
float4x4 viewProjection;   // view * projection transformation
float4x4 world;            // world transformation
// Lit Vertex
bool     litVertex;        // omit lighting calculations - already lit```
```// vertexShader receives a raw vertex and returns the transformed vertex
//

TransformedVertex transformed;
float4            worldPosition;  // world position of the vertex
float3            worldNormal;    // vertex normal in world space

// Transform the vertex to homogeneous clip coordinates
//
// A more efficient algorithm would accept the world*view*projection
// tranformation as one uniform matrix and avoid the 2-stage product
// This will require a bit of restructuring of the application code.
//
worldPosition = mul(float4(raw.position, 1.0), world); // local to world
transformed.position = mul(worldPosition, viewProjection); //... to clip

// not working
if (litVertex) {
transformed.colour.r = raw.normal.r;
transformed.colour.g = raw.normal.g;
transformed.colour.b = raw.normal.b;
transformed.colour.a = 1.0f;
}
else {

// Transform the vertex normal to world space. Only the rotation-scaling
// part of the world transformation is used. Since the world
// transformation may contain scaling, the result of this multiplication
// needs to be normalized.
//
worldNormal = mul(raw.normal, (float3x3)world);
worldNormal = normalize(worldNormal);

// Determine the colour of the vertex from each light in turn
//
// Use the cosine of the angle between the worldNormal and the direction
// of the light to determine the amount of reflected light. The cosine
// is given by the dot product, if both vectors have been normalized. If
// the cosine is less than 0, the angle is greater than 90 degrees and
// no light is reflected.  Use saturate() to implement this condition.
//
// A more efficient algorithm would supply the light direction already
// converted to the local space of the vertex (by using the inverse of
// the world transformation).
//

float  diffuseFactor, reflectFactor, distance;
float  attenuationFactor, spotFactor, rho;
float3 ambientLight  = ambient.xyz;
float3 diffuseLight  = (float3)0;
float3 specularLight = (float3)0;

for (int i = 0; i < MLIGHTS; i++) {
if (lightOn[i]) {
lightDirection = - normalize((light[i].type == POINT_LIGHT)?
float3(worldPosition.x, worldPosition.y, worldPosition.z) -
light[i].position : light[i].direction);
diffuseFactor = saturate(dot(worldNormal, lightDirection));
reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
worldNormal - lightDirection), camera));
attenuationFactor = 1.0f;
spotFactor = 1.0f;

if (light[i].type == POINT_LIGHT ||
light[i].type == SPOT_LIGHT) {
// detail calcs for attenuationFactor and spotFactor
distance = length((float3)worldPosition - light[i].position);
if (distance < light[i].range) {
attenuationFactor = light[i].attenuation.x +
light[i].attenuation.y * distance +
light[i].attenuation.z * distance * distance;
attenuationFactor = 1.0f / attenuationFactor;
if (light[i].type == SPOT_LIGHT) {
rho = saturate(dot(normalize(light[i].position -
float3(worldPosition.x, worldPosition.y,
worldPosition.z)),
normalize(-light[i].direction)));
if (rho <= light[i].spot.x)
spotFactor = 0.0f;
else if (rho <= light[i].spot.y)
spotFactor = pow(
abs((rho - light[i].spot.x)/
(light[i].spot.y - light[i].spot.x)),
light[i].spot.z);
}
}
else
attenuationFactor = 0.0f;
}

// accumulate ambient, diffuse, and specular elements of light
//
ambientLight += attenuationFactor * spotFactor *
light[i].ambient.xyz;
diffuseLight += attenuationFactor * spotFactor * diffuseFactor *
light[i].diffuse.xyz;
specularLight += attenuationFactor * spotFactor *
light[i].specular.xyz * pow(reflectFactor, material.power);
}
}

// apply material reflectivity to each accumulated element of light
// to obtain the colour of the lit vertex
//
transformed.colour.xyz =
saturate(material.ambient.xyz * ambientLight) +
saturate(material.diffuse.xyz * diffuseLight) +
saturate(material.specular.xyz * specularLight);

// pass the diffuse alpha along as the alpha component
//
transformed.colour.w = material.diffuse.w;
}

// pass the texture coordinates along unaltered
//
transformed.texCoord0 = raw.texCoord;
transformed.texCoord1 = raw.texCoord;

return transformed;
}```

• Host
APIPlatformSettings.h
```#define FRAGMENT_SHADER_FILE        L"fragmentShader.hlsl"
APIBase.h
```    // Fragment Shader Support
static ID3DXConstantTable*    uniformFS;      // for fragment shader```
APIBase.cpp
```IDirect3DPixelShader9*  APIBase::fragmentShader = nullptr; // fragment shader
ID3DXConstantTable*     APIBase::uniformFS      = nullptr; // for fragment shader```
APIDisplay.cpp - setup()
```    LPD3DXBUFFER compiledCodeFS = nullptr;

// checks for minimum pixel shader version required
error(L"Display::10 Device does not support pixel shader 3_0");```
```    // compile the fragment shader source code
&compiledCodeFS, NULL, &uniformFS))) {
release();
error(L"APIDisplay::15 Unable to compile the fragment shader code");
}
// create the pixel shader object
compiledCodeFS->Release();
release();
error(L"APIDisplay::16 Unable to create fragment shader object");
}
else {
compiledCodeFS->Release();```
`        d3dd->SetPixelShader(fragmentShader);`
APIDisplay.cpp - beginDrawFrame()
```        Colour colour(red, green, blue);
uniformFS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4);
uniformFS->SetInt(d3dd, "noLights", 4);```
ID3DXConstantTable::SetFloatArray()
ID3DXConstantTable::SetInt()
APIDisplay.cpp - set()
`                uniformFS->SetBool(d3dd, "lighting", b);`
ID3DXConstantTable::SetBool()
APIDisplay.cpp - setReflectivity()
```        uniformFS->SetFloatArray(d3dd, "material.ambient",  (FLOAT*)&r.ambient, 4);
uniformFS->SetFloatArray(d3dd, "material.diffuse",  (FLOAT*)&r.diffuse, 4);
uniformFS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&r.specular, 4);
uniformFS->SetFloat     (d3dd, "material.power",    (FLOAT)r.power);```
APIDisplay.cpp - release()
```    }
if (uniformFS) {
uniformFS->Release();
uniformFS = nullptr;
}
}```
APIGraphic.cpp - APIXMesh::draw()
```            uniformFS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&ambient[i], 4);
uniformFS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&diffuse[i], 4);
uniformFS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&specular[i], 4);
uniformFS->SetFloat(d3dd, "material.power", (FLOAT)power[i]);```
ID3DXConstantTable::SetFloat()
APILight.cpp - setup()
```        uniformFS->SetInt(d3dd, typ, type);
uniformFS->SetFloatArray(d3dd, amb, (FLOAT*)&ambient, 4);
uniformFS->SetFloatArray(d3dd, dif, (FLOAT*)&diffuse, 4);
uniformFS->SetFloatArray(d3dd, spe, (FLOAT*)&specular, 4);
uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&zero, 3);
uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&zero, 3);
uniformFS->SetFloatArray(d3dd, att, (FLOAT*)&attenuation, 3);
uniformFS->SetFloatArray(d3dd, spt, (FLOAT*)&spot, 3);
uniformFS->SetFloat(d3dd, ran, range);```
APILight.cpp - turnOn()
```        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
uniformFS->SetBool(d3dd, constantLightOn, true);```
```        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
uniformFS->SetBool(d3dd, constantLightOn, true);```
APILight.cpp - update()
```        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
uniformFS->SetBool(d3dd, constantLightOn, true);```
APILight.cpp - turnOff()
`        uniformFS->SetBool(d3dd, constantLightOn, false);`
APITexture.cpp - attach()
```        char str[] = "texOn";
uniformFS->SetBool(d3dd, str, true);```
APITexture.cpp - detach()
```        char str[] = "texOn";
uniformFS->SetBool(d3dd, str, false);```
• Device
```// Types
//
// RawVertex holds the original data for a vertex in the stream
//
struct RawVertex {

float3 position : POSITION;  // position in local space
float3 normal   : NORMAL;    // normal in local space
float2 texCoord : TEXCOORD0;  // texture coordinates
};

// TransformedVertex holds the transformed data for the vertex
//
struct TransformedVertex {

float4 position : POSITION;   // position in homogeneous clip space
float2 texCoord : TEXCOORD;   // texture coordinates
float3 worldPos : TEXCOORD1;  // position in world space
float3 worldNor : TEXCOORD2;  // lighting normal in world space
float3 toViewer : TEXCOORD3;  // direction to viewer in world space
};

// Uniform Data (constant for the stream of vertices)
//
// Geometry
float4x4 viewProjection;   // view * projection transformation
float4x4 world;            // world transformation
float3   viewPoint;        // camera viewpoint for specular calcs
// Lit Vertex
bool     litVertex;        // omit lighting calculations - already lit```
```// vertexShader receives a raw data for a vertex and transforms that data
//

TransformedVertex transformed;    // result returned by this function
float4            worldPosition;  // world position of the vertex
float3            worldNormal;    // vertex normal in world space

// Transform the vertex to homogeneous clip coordinates
//
// A more efficient algorithm would accept the world*view*projection
// tranformation as one uniform matrix and avoid the 2-stage product
// This will require a bit of restructuring of the application code.
//
worldPosition = mul(float4(raw.position, 1.0), world); // local to world
transformed.position = mul(worldPosition, viewProjection); //... to clip
transformed.worldPos = worldPosition.xyz;

// Transform the vertex normal to world space. Only the rotation-scaling
// part of the world transformation is used. Since the world
// transformation may contain scaling, the result of this multiplication
// needs to be normalized.
//
worldNormal = mul(raw.normal, (float3x3)world);
worldNormal = normalize(worldNormal);
transformed.worldNor = worldNormal;

// Determine the direction from the camera's viewpoint to this vertex for
// subsequent lighting calculations
//
transformed.toViewer = normalize(viewPoint - worldPosition.xyz);

// pass the texture coordinates along unaltered
//
transformed.texCoord = raw.texCoord;

return transformed;
}```
```#define MLIGHTS 4
#define MTEXTURES 2
#define POINT_LIGHT       0
#define SPOT_LIGHT        1
#define DIRECTIONAL_LIGHT 2

// Types
//
// Light holds the data for a single static light in world space
//
struct Light {
int    type;        // POINT_LIGHT, SPOT_LIGHT, DIRECTIONAL_LIGHT
float4 ambient;
float4 diffuse;
float4 specular;
float3 direction;   // in world space
float3 position;    // in world space
float3 attenuation; // .xyz for 1.0f/ (.x + .y * d + .z * d * d)
float3 spot;        // .x = cos(phi/2), .y = cos(theta/2), .z = falloff
float  range;       // where attenuation becomes 0
};

// Material holds the reflectivity properties of the material
//
struct Material {
float4 ambient;
float4 diffuse;
float4 specular;
float  power;
};

// RawPixel holds the data for a single fragment of the stream
//
struct RawPixel {
float2 texcoord : TEXCOORD0;  // texture coordinate at this fragment
float3 position : TEXCOORD1;  // fragment position in world space
float3 normal   : TEXCOORD2;  // lighting normal in world space
float3 toViewer : TEXCOORD3;  // direction to viewer in world space
};

// Uniform Data (constant for a stream of fragments)
//
float4 ambient;           // global ambient light - always on
int    noLights;          // no of active lights
Light  light[MLIGHTS];    // static lights
bool   lightOn[MLIGHTS];  // light switch
Material material;        // material reflectivity
bool   lighting;          // lighting calculations on?

bool    texOn; // texture switch
sampler2D tex; // set by the application```
```// The fragment shader receives raw fragment data and returns a pixel colour
//
float4 fragmentShader(RawPixel raw) : COLOR {

float4 colour;          // result returned by this function
float3 normal;          // normal to the fragment
float3 toViewer;        // from fragment to the camera
float3 toLightSource;   // from fragment to current light source

// lighting contribution accumulators
float3 ambientLight  = ambient.xyz;
float3 diffuseLight  = (float3)0;
float3 specularLight = (float3)0;
// lighting calculation factors
float  diffuseFactor, reflectFactor, distance;
float  attenuationFactor, spotFactor, rho;

// normalize the fragment data
normal   = normalize(raw.normal);
toViewer = normalize(raw.toViewer);

// perform calculations for each light in turn
for (int i = 0; i < noLights && i < MLIGHTS; i++) {
if (lightOn[i]) {
float diffuseFactor, reflectFactor, factor;
// diffuse and reflection factors
toLightSource = normalize((light[i].type == POINT_LIGHT)?
light[i].position - raw.position : - light[i].direction);
diffuseFactor = saturate(dot(normal, toLightSource));
reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
normal - toLightSource), toViewer));

attenuationFactor = 1.0f;
spotFactor = 1.0f;

if (light[i].type == POINT_LIGHT ||
light[i].type == SPOT_LIGHT) {
// detail calcs for attenuationFactor and spotFactor
distance = length(raw.position - light[i].position);
if (distance < light[i].range) {
attenuationFactor = light[i].attenuation.x +
light[i].attenuation.y * distance +
light[i].attenuation.z * distance * distance;
attenuationFactor = 1.0f / attenuationFactor;
if (light[i].type == SPOT_LIGHT) {
rho = saturate(dot(normalize(light[i].position -
float3(raw.position.x, raw.position.y,
raw.position.z)),
normalize(-light[i].direction)));
if (rho <= light[i].spot.x)
spotFactor = 0.0f;
else if (rho <= light[i].spot.y)
spotFactor = pow(abs(
(rho - light[i].spot.x)/
(light[i].spot.y - light[i].spot.x)),
light[i].spot.z);
}
}
else
attenuationFactor = 0.0f;
}

// accumulate ambient, diffuse, and specular elements of light
//
ambientLight += attenuationFactor * spotFactor *
light[i].ambient.xyz;
diffuseLight += attenuationFactor * spotFactor * diffuseFactor *
light[i].diffuse.xyz;
specularLight += attenuationFactor * spotFactor *
light[i].specular.xyz * pow(reflectFactor, material.power);
}

// apply material reflectivity to each accumulated element of light
// to obtain the colour of the lit fragment
//
colour.xyz =
saturate(material.ambient.xyz * ambientLight) +
saturate(material.diffuse.xyz * diffuseLight) +
saturate(material.specular.xyz * specularLight);
colour.w = material.diffuse.w;
}

// apply texture
//
if (texOn)
colour *= tex2D(tex, raw.texcoord);

return colour;
}```

To Do

• reorganize framework code so that vertex shader receives product of world, view, and projection matrices
• store viewProjection matrix as an instance variable in APIDisplay
• pre-multiply viewProjection by world to obtain composite matrix to pass to vertex shader
• add composite matrix to the constant table in the vertex shader
• reorganize framework code to minimize duplication of heading normalization
• perform normalization of heading in APIDisplay::beginDrawFrame()

Week 7 - Feb 20

This Week

• Effects Framework
• techniques
passes
• Source Code
APIBase.h
`    static ID3DXEffect*           effect;         // points to effects framework`
APIBase.cpp
`ID3DXEffect*            APIBase::effect         = nullptr; // effects framework`
APIDisplay.h
```    // Effects Framework handles
D3DXHANDLE   viewProjection;   // view * projection
D3DXHANDLE   viewPoint;        // camera viewpoint
D3DXHANDLE   ambient;          // global ambient color
D3DXHANDLE   ambientHandle;    // current ambient reflectivity
D3DXHANDLE   diffuseHandle;    // current diffuse reflectivity
D3DXHANDLE   specularHandle;   // current specular reflectivity
D3DXHANDLE   powerHandle;      // current shininess coefficient
D3DXHANDLE   worldHandle;      // current world transformation```
```    void beginEffect(const char*, unsigned&);
void beginPass(unsigned);
void endPass();
void endEffect();```
APIDisplay.cpp - APIDisplay()
```    viewProjection = nullptr;
viewPoint      = nullptr;
ambient        = nullptr;
ambientHandle  = nullptr;
diffuseHandle  = nullptr;
specularHandle = nullptr;
powerHandle    = nullptr;
worldHandle    = nullptr;```
APIDisplay.cpp - setup()
`    LPD3DXBUFFER errorBuffer = NULL;`
```    // create the effects framework
else if (FAILED(D3DXCreateEffectFromFile(d3dd, EFFECT_FILE, 0,
0, D3DXSHADER_DEBUG, 0, &effect, &errorBuffer))) {
release();
error(L"APIDisplay::17 Unable to create the effects framework");
}```
D3DXCreateEffectFromFile()
```        if (errorBuffer) errorBuffer->Release();
viewProjection = effect->GetParameterByName(0, "viewProjection");
viewPoint      = effect->GetParameterByName(0, "viewPoint");
ambient        = effect->GetParameterByName(0, "ambient");
worldHandle    = effect->GetParameterByName(0, "world");
ambientHandle  = effect->GetParameterByName(0, "material.ambient");
diffuseHandle  = effect->GetParameterByName(0, "material.diffuse");
specularHandle = effect->GetParameterByName(0, "material.specular");
powerHandle    = effect->GetParameterByName(0, "material.power");```
GetParameterByName()
APIDisplay.cpp - beginDrawFrame()
```    Matrix& v = *((Matrix*)view);
Matrix viewprojection = v * projection;
effect->SetMatrix(viewProjection, (D3DXMATRIX*)&viewprojection);
SetMatrix()
SetVector()
```        Colour colour(red, green, blue);
effect->SetVector(ambient, (D3DXVECTOR4*)&colour);```
APIDisplay.cpp - beginEffect()
```void APIDisplay::beginEffect(const char* technique, unsigned& nPasses) {

D3DXHANDLE techniqueHandle = effect->GetTechniqueByName(technique);
effect->SetTechnique(techniqueHandle);
effect->Begin(&nPasses, 0);
}```
GetTechniqueByName()
SetTechnique()
Begin()
APIDisplay.cpp - beginPass()
```void APIDisplay::beginPass(unsigned i) {

effect->BeginPass(i);
}```
BeginPass()
APIDisplay.cpp - endPass()
```void APIDisplay::endPass() {

effect->EndPass();
}```
EndPass()
APIDisplay.cpp - endEffect()
```void APIDisplay::endEffect() {

effect->End();
}```
End()
APIDisplay.cpp - setWorld()
`        effect->SetMatrix(worldHandle, (D3DXMATRIX*)world);`
APIDisplay.cpp - setReflectivity()
```        effect->SetVector(ambientHandle,  (D3DXVECTOR4*)&r.ambient);
effect->SetVector(diffuseHandle,  (D3DXVECTOR4*)&r.diffuse);
effect->SetVector(specularHandle, (D3DXVECTOR4*)&r.specular);
effect->SetFloat(powerHandle,     r.power);
effect->CommitChanges();```
CommitChanges()
APIDisplay.cpp - release()
```    if (effect) {
effect->Release();
effect = NULL;
}```
effects.fx - Constant Memory
```#define MLIGHTS 4
#define POINT_LIGHT       0
#define SPOT_LIGHT        1
#define DIRECTIONAL_LIGHT 2

// Types
//
// Light holds the data for a single static light in world space
//
struct Light {
int    type;        // POINT_LIGHT, SPOT_LIGHT, DIRECTIONAL_LIGHT
float3 ambient;
float3 diffuse;
float3 specular;
float3 direction;   // in world space
float3 position;    // in world space
float3 attenuation; // .xyz for 1.0f/ (.x + .y * d + .z * d * d)
float3 spot;        // .x = cos(phi/2), .y = cos(theta/2), .z = falloff
float  range;       // where attenuation becomes 0
};

// Material holds the reflectivity properties of the material
//
struct Material {
float4 ambient;
float4 diffuse;
float4 specular;
float  power;
};

// RawPixel holds the data for a single fragment of the stream
//
struct RawPixel {
float2 texcoord : TEXCOORD0;  // texture coordinate at this fragment
float3 position : TEXCOORD1;  // fragment position in world space
float3 normal   : TEXCOORD2;  // lighting normal in world space
float3 toViewer : TEXCOORD3;  // direction to viewer in world space
};

// Uniform Data (constant for a stream of fragments)
//
float4 ambient;           // global ambient light - always on
int    noLights;          // no of static lights
Light  light[MLIGHTS];    // static lights
bool   lightOn[MLIGHTS];  // light switch
Material material;        // material reflectivity

bool    texOn; // texture switch
sampler2D tex; // set by the application

// Types
//
// RawVertex holds the original data for a vertex in the stream
//
struct RawVertex {

float3 position : POSITION;  // position in local space
float3 normal   : NORMAL;    // normal in local space
float2 texCoord : TEXCOORD0;  // texture coordinates
};

// TransformedVertex holds the transformed data for the vertex
//
struct TransformedVertex {

float4 position : POSITION;   // position in homogeneous clip space
float2 texCoord : TEXCOORD;   // texture coordinates
float3 worldPos : TEXCOORD1;  // position in world space
float3 worldNor : TEXCOORD2;  // lighting normal in world space
float3 toViewer : TEXCOORD3;  // direction to viewer in world space
};

// Uniform Data (constant for the stream of vertices)
//
// Geometry
float4x4 viewProjection;   // view * projection transformation
float4x4 world;            // world transformation
float4   viewPoint;        // camera viewpoint for specular calcs
// Geometry
// Lit Vertex
bool     litVertex;        // omit lighting calculations - already lit```
```// vertexShader receives a raw data for a vertex and transforms that data
//

TransformedVertex transformed;    // result returned by this function
float4            worldPosition;  // world position of the vertex
float3            worldNormal;    // vertex normal in world space

// Transform the vertex to homogeneous clip coordinates
//
// A more efficient algorithm would accept the world*view*projection
// tranformation as one uniform matrix and avoid the 2-stage product
// This will require a bit of restructuring of the application code.
//
worldPosition = mul(float4(raw.position, 1.0), world); // local to world
transformed.position = mul(worldPosition, viewProjection); //... to clip
transformed.worldPos = worldPosition.xyz;

// Transform the vertex normal to world space. Only the rotation-scaling
// part of the world transformation is used. Since the world
// transformation may contain scaling, the result of this multiplication
// needs to be normalized.
//
worldNormal = mul(raw.normal, (float3x3)world);
worldNormal = normalize(worldNormal);
transformed.worldNor = worldNormal;

// Determine the direction from the camera's viewpoint to this vertex for
// subsequent lighting calculations
//
transformed.toViewer = normalize(viewPoint - worldPosition.xyz);

// pass the texture coordinates along unaltered
//
transformed.texCoord = raw.texCoord;

return transformed;
}```
```// The fragment shader receives raw fragment data and returns a pixel colour
//
float4 fragmentShader(RawPixel raw) : COLOR {

float4 colour;          // result returned by this function
float3 normal;          // normal to the fragment
float3 toViewer;        // from fragment to the camera
float3 toLightSource;   // from fragment to current light source

// lighting contribution accumulators
float3 ambientLight  = ambient.xyz;
float3 diffuseLight  = (float3)0;
float3 specularLight = (float3)0;
// lighting calculation factors
float  diffuseFactor, reflectFactor, distance;
float  attenuationFactor, spotFactor, rho;

// normalize the fragment data
normal   = normalize(raw.normal);
toViewer = normalize(raw.toViewer);

// perform calculations for each light in turn
for (int i = 0; i < noLights && i < MLIGHTS; i++) {
if (lightOn[i]) {
float diffuseFactor, reflectFactor, factor;
// diffuse and reflection factors
toLightSource = normalize((light[i].type == POINT_LIGHT)?
light[i].position - raw.position : - light[i].direction);
diffuseFactor = saturate(dot(normal, toLightSource));
reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
normal - toLightSource), toViewer));

attenuationFactor = 1.0f;
spotFactor = 1.0f;

if (light[i].type == POINT_LIGHT ||
light[i].type == SPOT_LIGHT) {
// detail calcs for attenuationFactor and spotFactor
distance = length(raw.position - light[i].position);
if (distance < light[i].range) {
attenuationFactor = light[i].attenuation.x +
light[i].attenuation.y * distance +
light[i].attenuation.z * distance * distance;
attenuationFactor = 1.0f / attenuationFactor;
if (light[i].type == SPOT_LIGHT) {
rho = saturate(dot(normalize(light[i].position -
float3(raw.position.x, raw.position.y,
raw.position.z)),
normalize(-light[i].direction)));
if (rho <= light[i].spot.x)
spotFactor = 0.0f;
else if (rho <= light[i].spot.y)
spotFactor = pow(abs(
(rho - light[i].spot.x)/
(light[i].spot.y - light[i].spot.x)),
light[i].spot.z);
}
}
else
attenuationFactor = 0.0f;
}

// accumulate ambient, diffuse, and specular elements of light
//
ambientLight += attenuationFactor * spotFactor *
light[i].ambient.xyz;
diffuseLight += attenuationFactor * spotFactor * diffuseFactor *
light[i].diffuse.xyz;
specularLight += attenuationFactor * spotFactor *
light[i].specular.xyz * pow(reflectFactor, material.power);
}
}

// apply material reflectivity to each accumulated element of light
// to obtain the colour of the lit fragment
//
colour.xyz =
saturate(material.ambient.xyz * ambientLight) +
saturate(material.diffuse.xyz * diffuseLight) +
saturate(material.specular.xyz * specularLight);
colour.w = material.diffuse.w;

// apply texture
//
if (texOn)
colour *= tex2D(tex, raw.texcoord);

return colour;
}```
effects.fx - technique opaque
```technique opaque {

pass {
}
}```
effects.fx - technique translucent
```technique translucent {

pass {
}
}```

Week 8 - Mar 4

This Week

• Frank Luna's notes for DirectX10 (page 306)
Environment Maps(Seneca ELibraray)
• Design.cpp
Design::initialize() - create the skybox object
```// initialize initializes the general display design coordinator, creates the
// primitive sets, textures, objects, lights, sounds, cameras, and text items
//
void Design::initialize() {

// ...

// create textures
iTexture* sunset   = CreateCubeTexture(L"Islands.dds");

// ...

iObject* skybox = CreateSkybox();
skybox->rotatex(-1.5708f);
skybox->attach(sunset);
setSkybox(skybox);

// ...
}```
• Coordinator.cpp
Coordinator::render() - using different techniques for different objects
```void Coordinator::render() {

if (now - lastReset <= unitsPerSec)
framecount++;
else {
// recalculate the frame rate
fps        = framecount * unitsPerSec / (now - lastReset);
framecount = 0;
lastReset  = now;
if (timerText) {
wchar_t str[MAX_DESC + 1];
sprintf(str, fps, L" fps");
timerText->set(str);
}
}
// update the user input devices
userInput->update();
Coordinator::update();
// update the model
update();
// update the audio
audio->setVolume(volume);
audio->setFrequencyRatio(frequency);
audio->update(Camera::getView());

// start rendering
display->beginDrawFrame(Camera::getView());
display->setAmbientLight(ambient.r, ambient.g, ambient.b);
unsigned nPasses;
// render all of the opaque unlit objects
display->beginEffect("opaque", nPasses);
for (unsigned i = 0; i < nPasses; i++) {
display->beginPass(i);
render(OPAQUE_OBJECT);
display->endPass();
}
display->endEffect();
// render all of the translucent unlit objects
display->beginEffect("translucent", nPasses);
for (unsigned i = 0; i < nPasses; i++) {
display->beginPass(i);
render(TRANSLUCENT_OBJECT);
display->endPass();
}
display->endEffect();
// render all of the lit objects
display->beginEffect("litObjects", nPasses);
for (unsigned i = 0; i < nPasses; i++) {
display->beginPass(i);
render(LIT_OBJECT);
display->endPass();
}
display->endEffect();
//  render the skybox
display->beginEffect("skybox", nPasses);
if (background && !skybox) {
Rectf fullScreen(0, 0, 1, 1);
display->beginDrawHUD(0);
background->render(fullScreen, true);
display->endDrawHUD();
}
else if (skybox) {
for (unsigned i = 0; i < nPasses; i++) {
display->beginPass(i);
render(SKYBOX);
display->endPass();
}
}
display->endEffect();
display->set(ALPHA_BLEND, false);
display->beginDrawHUD(HUD_ALPHA);
render(ALL_HUDS);
display->endDrawHUD();
display->endDrawFrame();
render(ALL_SOUNDS);
}```
Coordinator::render(iObject*) - render a single object one subset at a time
```void Coordinator::render(iObject* object) {

display->setWorld(&object->world());
unsigned nSubsets = object->noSubsets();
for (unsigned i = 0; i < nSubsets; i++) {
iTexture* texture = object->getTexture(i);
if (texture) texture->attach();
display->setReflectivity(object->getReflectivity(i));
object->render(i);
if (texture) texture->detach();
}
}```
• Skybox class
iObject interface - CreateSkybox declaration
```class iObject : public Shape, public Base {
public:
// initialization
virtual void        attach(iTexture* t)                  = 0;
virtual void        attach(iTexture** t)                 = 0;
// execution
virtual unsigned    noSubsets() const                    = 0;
virtual void        render(unsigned)                     = 0;
virtual void        setTextureFilter(unsigned)           = 0;
virtual iTexture*   getTexture(unsigned) const           = 0;
virtual const void* getReflectivity(unsigned) const      = 0;
virtual bool        belongsTo(Category category) const   = 0;
};

iObject* CreateObject(iGraphic*, const Reflectivity* = nullptr, unsigned = 1u);
iObject* CreateBillboard(BillboardType, iGraphic*,
const Reflectivity* = nullptr);
iObject* CreateSkybox();

iObject* Clone(const iObject*);```
Skybox class - derived from Object
```//-------------------------------- Skybox -------------------------------------
//
// A Skybox is an inverted Object that translates with the viewpoint
//
class Skybox : public Object {

public:
Skybox();
void render(unsigned);
};```
CreateSkybox
```iObject* CreateSkybox() {

return new Skybox();
}```
Skybox::Skybox - SKYBOX category, 2 x 2 x 2 cube
```Skybox::Skybox() : Object(SKYBOX, CreateIBox(-1, -1, -1 * MODEL_Z_AXIS, 1, 1,
1 * MODEL_Z_AXIS)) {
}```
Skybox::render(unsigned) - move skybox centroid to current camera position
```void Skybox::render(unsigned) {

Camera* camera = *(Camera**)(Camera::getCurrent());
Vector disp = camera->position() - position();
translate(disp.x, disp.y, disp.z);

Object::render(0);
}```
• Texture class
iTexture interface - CreateCubeTexture declaration
```class iTexture : public Base {
public:
virtual void attach() const                                        = 0;
virtual void setFilter(unsigned) const                             = 0;
virtual void detach()                                              = 0;
virtual void render(const Rectf&, bool = false)                    = 0;
};

iTexture* CreateTexture(const wchar_t* file, unsigned filter = 0);
iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter = 0);

iTexture* Clone(const iTexture*);```
Texture class - add the cube parameter to constructor
```class Texture : public iTexture {

iAPITexture* apiTexture;   // points to the api texture

Texture(const Texture&);
virtual ~Texture();

public:
Texture(const wchar_t* file, unsigned filter = 0, bool cube = false);
Texture& operator=(const Texture&);
void* clone() const { return new Texture(*this); }
// execution
void attach() const;
void setFilter(unsigned) const;
void detach();
void render(const Rectf&, bool);
// termination
void suspend();
void release();
};```
CreateCubeTexture - call constructor with true flag for cube
```iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter) {

return new Texture(file, filter, true);
}```
Texture::Texture() - create APICubeTexture()
```Texture::Texture(const wchar_t* file, unsigned filter, bool cube) {

wchar_t* fileWithPath = nullptr;
if (file) {
// add the directory to create the relative filename
int len = strlen(file) + strlen(TEXTURE_DIRECTORY) + 1;
fileWithPath = new wchar_t[len + 1];
::nameWithDir(fileWithPath, TEXTURE_DIRECTORY, file, len);
}

// apiTexture on the graphics device
if (cube)
apiTexture = CreateAPICubeTexture(fileWithPath);
else
apiTexture = CreateAPITexture(fileWithPath, filter);

if (fileWithPath) delete [] fileWithPath;
}```
iAPITexture interface - add CreateAPICubeTexture declaration
```class iAPITexture {
public:
virtual iAPITexture* clone() const                                = 0;
// execution
virtual void attach()                                             = 0;
virtual void setFilter(unsigned flags)                            = 0;
virtual void detach()                                             = 0;
virtual void render(const Rectf&, unsigned char, bool = false)    = 0;
// termination
virtual void suspend()                                            = 0;
virtual void release()                                            = 0;
virtual void Delete() const                                       = 0;
};

iAPITexture* CreateAPITexture(const wchar_t* file, unsigned filter);
iAPITexture* CreateAPICubeTexture(const wchar_t* file);```
• APITexture.h
APICubeTexture class definition
```class APICubeTexture : public iAPITexture, public APIBase {

wchar_t*               file;   // points to file with texture image
unsigned               filter; // default texture filtering flags

IDirect3DCubeTexture9* tex;    // interface to texture COM object

virtual ~APICubeTexture();

void setup();

public:
APICubeTexture(const wchar_t* file);
APICubeTexture(const APICubeTexture&);
iAPITexture& operator=(const APICubeTexture&);
iAPITexture* clone() const { return new APICubeTexture(*this); }
// execution
void   attach();
void   setFilter(unsigned filter) {}
void   detach();
void   render(const Rectf&, unsigned char, bool) {}
// suspension
void   suspend();
// termination
void   release();
void   Delete() const { delete this; }
};```
IDirect3DCubeTexture9 interface
APICubeTexture class implementation
```//-------------------------------- APICubeTexture -----------------------------
//
// The APICubeTexture class implements a texture at the API level
//
iAPITexture* CreateAPICubeTexture(const wchar_t* file) {

return new APICubeTexture(file);
}

// constructor initializes the texture identifier
//
APICubeTexture::APICubeTexture(const wchar_t* file) {

if (file) {
int len = strlen(file);
this->file = new wchar_t[len + 1];
strcpy(this->file, file, len);
}
else
this->file = nullptr;

tex = nullptr;
}

APICubeTexture::APICubeTexture(const APICubeTexture& src) {

file  = nullptr;
tex   = nullptr;
*this = src;
}

iAPITexture& APICubeTexture::operator=(const APICubeTexture& src) {

if (this != &src) {
if (file)
delete [] file;
if (src.file) {
int len = strlen(src.file);
file = new wchar_t[len + 1];
strcpy(file, src.file, len);
}
else
file = nullptr;
suspend();
tex = nullptr;
}

return *this;
}

// setup creates the api texture from the texture file
//
void APICubeTexture::setup() {

// create a texture COM object from the texture file
//
HRESULT hr;
if (file && FAILED(hr = D3DXCreateCubeTextureFromFileEx(d3dd, file,
0, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT,
D3DX_DEFAULT, 0, nullptr, nullptr, &tex))) {
error(L"APICubeTexture::11 Failed to create texture COM object from file");
tex = nullptr;
}
}

// attach attaches the api texture to sampling stage i
//
void APICubeTexture::attach() {

if (!tex) setup();

if (tex)
d3dd->SetTexture(0, tex);
}

// detach detaches the api texture from sampling stage 0
//
void APICubeTexture::detach() {

if (tex)
d3dd->SetTexture(0, nullptr);
}

// suspend releases the api texture
//
void APICubeTexture::suspend() {

// release the Interface to the texture COM object
if (tex) {
tex->Release();
tex = nullptr;
}
}

// releases suspends the api texture
//
void APICubeTexture::release() {

suspend();
}

// destructor releases the api texture
//
APICubeTexture::~APICubeTexture() {

release();
}```
D3DXCreateCubeTextureFromFileEx
• effects.fx
```//-------------------------------- Skybox -------------------------------------
//
struct FS_Skybox {
float4 pos : POSITION;
float3 tex : TEXCOORD0;
};```
```FS_Skybox skyboxVertexShader(float3 pos : POSITION) {
FS_Skybox output = (FS_Skybox) 0;
output.pos = mul(float4(pos, 0), world);            // Note the 0, this so the skybox rotates, but without perspective
output.pos = mul(output.pos, viewProjection).xyww;  // The z coordinate is replaced by w, so that the point is projected onto the far clipping plane.
output.tex = pos.xzy;
return output;
}```
skybox sampler state
```texture skyBox;
samplerCUBE skySampler = sampler_state {
texture = <skyBox>;
MagFilter = LINEAR;
Minfilter = LINEAR;
Mipfilter = LINEAR;
};```
```float4 skyboxFragmentShader(FS_Skybox input) : COLOR0 {
return texCUBE(skySampler, input.tex);
}```
skybox technique
```technique skybox {

pass {
AlphaBlendEnable = false;
ZENABLE = true;
ZWRITEENABLE = false;    // By not storing the skybox's z-buffer value, it enables objects behind the skybox to be drawn, giving a realist look (e.g. a airplane in the distance)
CullMode = None;