Friday, March 13, 2009

Collision




This was also fun to work on. It would change from truth to false if that line hit the white area. We used to change the picture of it to look like something else. The code for this is below.

/*
Demo Name: Plane/Line Collisions
Author: Allen Sherrod
Chapter: Ch 9
*/

#include
#include
#include
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#define WINDOW_CLASS "UGPDX"
#define WINDOW_NAME "Plane/Line Collision Detection"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
// Function Prototypes...
bool InitializeD3D(HWND hWnd, bool fullscreen);
bool InitializeObjects();
void RenderScene();
void Shutdown();

// Direct3D object and device.
LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice = NULL;
// Matrices.
D3DXMATRIX g_projection;
D3DXMATRIX g_worldMatrix;
D3DXMATRIX g_ViewMatrix;

// DirectX font object.
LPD3DXFONT g_Font = NULL;

// Vertex buffers to hold the geometry.
LPDIRECT3DVERTEXBUFFER9 g_squareBuffer = NULL;
LPDIRECT3DVERTEXBUFFER9 g_lineBuffer = NULL;
// A structure for our custom vertex type
struct stD3DVertex
{
float x, y, z;
unsigned long color;
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_VERTEX (D3DFVF_XYZ D3DFVF_DIFFUSE)

#define UGP_FRONT 0
#define UGP_BACK 1
#define UGP_ON_PLANE 2
class CPlane
{
public:
CPlane() { a = b = c = d = 0; }
void NormalizeVec(stD3DVertex &v)
{
// Normalize normal.
float lenght = (float)sqrt((v.x * v.x +
v.y * v.y +
v.z * v.z));
if(lenght == 0.0f) lenght = 1.0f;
v.x /= lenght;
v.y /= lenght;
v.z /= lenght;
}
void CreatePlaneFromTri(stD3DVertex &v1, stD3DVertex &v2,
stD3DVertex &v3)
{
// Get triangle normal.
stD3DVertex normal, e1, e2;
// Get edge 1.
e1.x = v3.x - v1.x;
e1.y = v3.y - v1.y;
e1.z = v3.z - v1.z;
NormalizeVec(e1);
// Get edge 2.
e2.x = v2.x - v1.x;
e2.y = v2.y - v1.y;
e2.z = v2.z - v1.z;
NormalizeVec(e2);
// Get cross product of the edges.
normal.x = ((e1.y * e2.z) - (e1.z * e2.y));
normal.y = ((e1.z * e2.x) - (e1.x * e2.z));
normal.z = ((e1.x * e2.y) - (e1.y * e2.x));
NormalizeVec(normal);
// Save normal and calculate d.
a = normal.x;
b = normal.y;
c = normal.z;
d = - (a * v1.x + b * v1.y + c * v1.z);
}
int ClassifyPoint(float x, float y, float z)
{
float distance = a * x + b * y + c * z + d;
if(distance > 0.001) return UGP_FRONT;
if(distance < -0.001) return UGP_BACK;
return UGP_ON_PLANE;
}
float a, b, c, d;
};
CPlane g_plane;

// Start and end Z positions and amounts to move each point.
float g_lineStartZPos = -1;
float g_lineEndZPos = 1;
float g_lineZMoveAmt = 0;
float g_lineZDir = -0.02f;
// True if collision occurred, false if not.
bool g_collision = false;

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_KEYUP:
if(wParam == VK_ESCAPE) PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
WINDOW_CLASS, NULL };
RegisterClassEx(&wc);
// Create the application's window
HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
GetDesktopWindow(), NULL, wc.hInstance, NULL);
// Initialize Direct3D
if(InitializeD3D(hWnd, false))
{
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Enter the message loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
RenderScene();
}
}
// Release any and all resources.
Shutdown();
// Unregister our window.
UnregisterClass(WINDOW_CLASS, wc.hInstance);
return 0;
}

bool InitializeD3D(HWND hWnd, bool fullscreen)
{
D3DDISPLAYMODE displayMode;
// Create the D3D object.
g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
if(g_D3D == NULL) return false;
// Get the desktop display mode.
if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
return false;
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
if(fullscreen)
{
d3dpp.Windowed = FALSE;
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
}
else
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = displayMode.Format;
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

// Create the D3DDevice
if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING D3DCREATE_PUREDEVICE,
&d3dpp, &g_D3DDevice))) return false;
// Initialize any objects we will be displaying.
if(!InitializeObjects()) return false;
return true;
}

bool InitializeObjects()
{
// Create the font.
if(FAILED(D3DXCreateFont(g_D3DDevice, 18, 0, 0, 1, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH FF_DONTCARE, "Arial",
&g_Font))) return false;

// Create our objects.
stD3DVertex squareData[] =
{
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255)},
{0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255)},
{0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255)},
{0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255)},
{-0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255)},
{-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255)}
};
stD3DVertex lineData[] =
{
{0, 0, g_lineStartZPos, D3DCOLOR_XRGB(0,255,0)},
{0, 0, g_lineEndZPos, D3DCOLOR_XRGB(0,255,0)},
};

// Get plane from the object. Only need one triangle since
// it is a even square (plane will be the same for both tris).
g_plane.CreatePlaneFromTri(squareData[0], squareData[1], squareData[2]);

// Create square vertex buffer.
if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(squareData), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_squareBuffer, NULL))) return false;
void *ptr;
// Fill the vertex buffer.
if(FAILED(g_squareBuffer->Lock(0, sizeof(squareData),
(void**)&ptr, 0))) return false;
memcpy(ptr, squareData, sizeof(squareData));
g_squareBuffer->Unlock();

// Create line vertex buffer.
if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(lineData), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_lineBuffer, NULL))) return false;
// Fill the vertex buffer.
if(FAILED(g_lineBuffer->Lock(0, sizeof(lineData),
(void**)&ptr, 0))) return false;
memcpy(ptr, lineData, sizeof(lineData));
g_lineBuffer->Unlock();

// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_D3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

// Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, D3DX_PI / 4,
WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

// Define camera information.
D3DXVECTOR3 cameraPos(5.0f, 0.0f, -5.0f);
D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);
// Build view matrix.
D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
&lookAtPos, &upDir);
return true;
}

void RenderScene()
{
// RECT used to position the font and a string.
RECT fontPos = {0, 125, WINDOW_WIDTH, WINDOW_HEIGHT};
char str[64] = {0};

// Move line. If position limit is hit, switch directions.
g_lineZMoveAmt += g_lineZDir;
if(g_lineZMoveAmt > 2) g_lineZDir *= -1;
if(g_lineZMoveAmt < -2) g_lineZDir *= -1;

// Test which side of the plane both points are.
int result1 = g_plane.ClassifyPoint(0, 0, g_lineStartZPos + g_lineZMoveAmt);
int result2 = g_plane.ClassifyPoint(0, 0, g_lineEndZPos + g_lineZMoveAmt);
// Test for collision. True if points are on different ends.
g_collision = (result1 != result2);
// Create string.
if(g_collision) sprintf(str, "Collision: TRUE");
else sprintf(str, "Collision: FALSE");

// Clear the backbuffer.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();
// Display if collision occurred.
g_Font->DrawText(NULL, str, -1, &fontPos, DT_CENTER,
D3DCOLOR_XRGB(255,255,255));

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

// Draw line.
g_D3DDevice->SetStreamSource(0, g_lineBuffer,
0, sizeof(stD3DVertex));
D3DXMatrixTranslation(&g_worldMatrix, 0, 0, g_lineZMoveAmt);
g_D3DDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix);
g_D3DDevice->SetFVF(D3DFVF_VERTEX);
g_D3DDevice->DrawPrimitive(D3DPT_LINELIST, 0, 1);

// Draw square.
g_D3DDevice->SetStreamSource(0, g_squareBuffer,
0, sizeof(stD3DVertex));
D3DXMatrixIdentity(&g_worldMatrix);
g_D3DDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix);
g_D3DDevice->SetFVF(D3DFVF_VERTEX);
g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

// End the scene. Stop rendering.
g_D3DDevice->EndScene();
// Display the scene.
g_D3DDevice->Present(NULL, NULL, NULL, NULL);
}

void Shutdown()
{
if(g_D3DDevice != NULL) g_D3DDevice->Release();
g_D3DDevice = NULL;
if(g_D3D != NULL) g_D3D->Release();
g_D3D = NULL;
if(g_squareBuffer != NULL) g_squareBuffer->Release();
g_squareBuffer = NULL;
if(g_lineBuffer != NULL) g_lineBuffer->Release();
g_lineBuffer = NULL;
if(g_Font != NULL) g_Font->Release();
g_Font = NULL;
}

No comments:

Post a Comment