Original Post
Here's my code:
It displays a 2D Ortho output on top of a 3D output.
I'm trying to get Picking working...
I've tried everything and i can't get it reliably working...
Here is the code:
/* Base Code for a Windows Application */
#pragma comment(lib,"d3d8.lib")
#pragma comment(lib,"d3dx8.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"dxerr8.lib")
#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"winmm.lib")
#include <windows.h>
#include <d3d8.h>
#include <dinput.h>
#include <stdio.h>
#include "cfont.h"
#include "cmouse.h"
#include "gui_window.h"
#include "parray.h"
// Globals
// Structures
struct D3DVERTEX
{
D3DXVECTOR3 p;
D3DXVECTOR3 n;
FLOAT tu, tv;
};
struct INTERSECTION
{
DWORD dwFace; // mesh face that was intersected
FLOAT fBary1, fBary2; // barycentric coords of intersection
FLOAT fDist; // distance from ray origin to intersection
FLOAT tu, tv; // texture coords of intersection
};
// A structure for our custom vertex type
struct CUSTOMVERTEX
{
FLOAT x, y, z; // The transformed position for the vertex
DWORD color; // The vertex color
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
IDirect3D8 *D3D; // Pointer to Direct3D
IDirect3DDevice8 *D3DDevice; // Pointer to the Direct3D device
LPDIRECTINPUT8 DInput; // Pointer to DirectInput Device
LPDIRECTINPUTDEVICE8 DInputKeyB; // Pointer to Keyboard
int g_iX = 1024;
int g_iY = 768;
LPDIRECT3DVERTEXBUFFER8 g_pVB = NULL; // Buffer to hold vertices
FontEngine Font;
CMouse DIMouse;
gui_main GUI;
// Global Windows Stuff
HANDLE g_hMouseEvent = NULL;
HRESULT result;
HWND hWnd;
static TCHAR szAppName[] = TEXT("D3DApp");
bool done=false;
bool g_bActive=true;
// Function Definitions
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool D3DInit();
void D3DCleanup();
void D3DRender();
HRESULT InitVB();
bool DIInit();
bool DIInitKeyB();
bool DIInitMouse();
HRESULT DIPick2D();
HRESULT DIPick3D();
IntersectTriangle( const D3DXVECTOR3& orig,
const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0;
D3DXVECTOR3 edge2 = v2 - v0;
// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 );
// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec );
D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0;
}
else
{
tvec = v0 - orig;
det = -det;
}
if( det < 0.0001f )
return FALSE;
// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
if( *u < 0.0f || *u > det )
return FALSE;
// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );
// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;
// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Cannot Register Window Class"), szAppName, MB_ICONERROR);
return 0;
};
hWnd = CreateWindow (szAppName,
TEXT("Broken Glass GUI Test"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
g_iX,
g_iY,
NULL,
NULL,
wndclass.hInstance,
NULL);
if(!D3DInit())
{
MessageBox(NULL, TEXT("Direct3D Init Error"), szAppName, MB_ICONERROR);
return 0;
};
DIInit();
InitVB();
Font.Initialize((HFONT)GetStockObject(SYSTEM_FONT),D3DCOLOR_XRGB(255,255,0));
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else // If There Are No Messages
{
// Draw The Scene.
if (D3DDevice) D3DRender();
GUI.RenderGUI();
DIMouse.Refresh();
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;
switch(msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, ▭);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
D3DCleanup();
return 0;
case WM_ACTIVATE:
if( WA_INACTIVE == wParam )
g_bActive = FALSE;
else
g_bActive = TRUE;
// Set exclusive mode access to the mouse based on active state
DIMouse.SetAcquire();
return 0;
};
return DefWindowProc(hWnd, msg, wParam, lParam);
}
bool D3DInit()
{
D3D=Direct3DCreate8(D3D_SDK_VERSION); // Create Direct3D
if (D3D==NULL) // Check if it succeeded, if it didn't, return failure
{
MessageBox(NULL, TEXT("D3DInit - Direct3D Object Creation Error"), szAppName, MB_ICONERROR);
return false;
}
D3DDISPLAYMODE d3ddm;
if( FAILED( D3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
MessageBox(NULL, TEXT("D3DInit - Error Getting Adapter Display Mode"), szAppName, MB_ICONERROR);
return false;
};
D3DPRESENT_PARAMETERS d3dpp;
memset(&d3dpp, 0, sizeof(D3DPRESENT_PARAMETERS)); // We need to fill it with 0's first
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format; // The color format
// Create the device
result=D3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &D3DDevice );
if (FAILED(result)) // If it failed, return failure
{
MessageBox(NULL, TEXT("D3DInit CreateDevice Error"), szAppName, MB_ICONERROR);
return false;
}
// Turn off culling, so we see the front and back of the triangle
D3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Turn off D3D lighting, since we are providing our own vertex colors
D3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
return true;
};
VOID SetupMatrices()
{
// For our world matrix, we will just rotate the object about the y-axis.
D3DXMATRIX matWorld;
D3DXMATRIX matView;
D3DXMATRIX matProj;
D3DXMATRIX matIdentity;
D3DXMatrixIdentity(&matIdentity);
D3DXMatrixRotationY( &matWorld, timeGetTime()/300.0f );
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 0.0f, -5.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
D3DDevice->SetTransform( D3DTS_VIEW, &matView );
D3DDevice->SetTransform( D3DTS_PROJECTION, &matProj );
D3DDevice->SetTransform( D3DTS_WORLD, &matIdentity );
}
VOID SetupMatrices2D()
{
D3DXMATRIX matOrtho;
D3DXMATRIX matIdentity;
D3DXMATRIX matView;
D3DXMATRIX matTrans;
D3DXMATRIX matScale;
D3DXMATRIX matWorld;
//Setup the orthogonal projection matrix and the default world/view matrix
D3DXMatrixOrthoLH(&matOrtho, 100.0f, 100.0f, 0.0f, 1.0f);
D3DXMatrixIdentity(&matIdentity);
D3DXMatrixScaling(&matScale, 10.0f, 10.0f, 1.0f);
D3DXMatrixTranslation(&matTrans, -30.0f, 0.0f, 0.0f);
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 0.0f,-5.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
D3DXMatrixMultiply(&matWorld, &matScale, &matTrans);
// D3DDevice->SetTransform(D3DTS_PROJECTION, &matOrtho);
// D3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
// D3DDevice->SetTransform(D3DTS_VIEW, &matIdentity);
D3DDevice->SetTransform(D3DTS_PROJECTION, &matOrtho);
D3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
D3DDevice->SetTransform(D3DTS_VIEW, &matIdentity);
//Make sure that the z-buffer and lighting are disabled
D3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
}
void D3DCleanup()
{
if( D3DDevice != NULL)
D3DDevice->Release();
if( D3D != NULL)
D3D->Release();
};
void DICleanup()
{
if (DInput)
{
if (DInputKeyB)
{
// Always unacquire device before calling Release().
DInputKeyB->Unacquire();
DInputKeyB->Release();
DInputKeyB = NULL;
}
DInput->Release();
DInput = NULL;
}
};
bool DIInit()
{
DIInitKeyB();
DIInitMouse();
return true;
};
bool DIInitMouse()
{
#ifdef _WIN64
HINSTANCE hInstance = (HINSTANCE) GetWindowLongPtr( hWnd, GWLP_HINSTANCE );
#else
HINSTANCE hInstance = (HINSTANCE) GetWindowLong( hWnd, GWL_HINSTANCE );
#endif
LPDIRECTINPUT di = NULL;
// Create DInput Object
if (FAILED(DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&di, NULL))) {
MessageBox(NULL, TEXT("DInput CreateDevice Error"), szAppName, MB_ICONERROR);
return false;
};
// Init Mouse Object
if(FAILED(DIMouse.Init(di))) {
MessageBox(NULL, TEXT("Mouse Initialization Error"), szAppName, MB_ICONERROR);
return false;
};
return S_OK;
};
bool DIInitKeyB()
{
HRESULT hr;
#ifdef _WIN64
HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hWnd, GWLP_HINSTANCE );
#else
HINSTANCE hInst = (HINSTANCE) GetWindowLong( hWnd, GWL_HINSTANCE );
#endif
hr = DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DInput, NULL);
if FAILED(hr)
{
MessageBox(NULL, TEXT("Cannot create DirectInput Device"), szAppName, MB_ICONERROR);
return false;
// DirectInput not available; take appropriate action
}
hr = DInput->CreateDevice(GUID_SysKeyboard, &DInputKeyB, NULL);
if FAILED(hr) {
DICleanup();
MessageBox(NULL, TEXT("Cannot create DirectInput Keyboard"), szAppName, MB_ICONERROR);
return FALSE;
}
hr = DInputKeyB->SetDataFormat(&c_dfDIKeyboard);
if FAILED(hr) {
DICleanup();
MessageBox(NULL, TEXT("Cannot set Keyboard Data Format"), szAppName, MB_ICONERROR);
return FALSE;
}
// Set the cooperative level
hr = DInputKeyB->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
if FAILED(hr) {
DICleanup();
MessageBox(NULL, TEXT("Cannot set Keyboard Behaviour"), szAppName, MB_ICONERROR);
return FALSE;
}
if (DInputKeyB) DInputKeyB->Acquire();
return true;
};
HRESULT InitVB()
{
// Initialize three vertices for rendering a triangle
CUSTOMVERTEX g_Vertices[] =
{
{ -0.5f, -0.5f, 0.0f, 0xffff0000, },
{ 0.5f, 0.5f, 0.0f, 0xff00ff00, },
{ 0.5f, -0.5f, 0.0f, 0xff0000ff, },
{ -0.5f, -0.5f, 0.0f, 0xffff0000, },
{ -0.5f, 0.5f, 0.0f, 0xff0000ff, },
{ 0.5f, 0.5f, 0.0f, 0xff00ff00, }
};
// Create the vertex buffer.
if( FAILED( D3DDevice->CreateVertexBuffer( 6*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB ) ) )
{
return E_FAIL;
}
// Fill the vertex buffer.
VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof(g_Vertices), (BYTE**)&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
g_pVB->Unlock();
return S_OK;
}
void D3DRender()
{
// Set up the cursor
POINT ptCursor;
GetCursorPos( &ptCursor );
ScreenToClient( hWnd, &ptCursor );
D3DDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0L );
// Clear the backbuffer and the zbuffer
D3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
// Begin the scene
D3DDevice->BeginScene();
// Do Spinning Plane
SetupMatrices();
D3DDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
D3DDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
D3DDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
DIPick3D();
// Do 2D Static Plane
SetupMatrices2D();
D3DDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
D3DDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
D3DDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
// DIPick2D();
// Draw Text
TCHAR szText[50] = "Press F1 for Stats";
CPoint P;
P = DIMouse.GetAbsPosition();
sprintf(szText, "Position : %d, %d", P.x, P.y );
Font.OutputText(szText,10,10);
if(DIMouse.GetButton(0)) { Font.OutputText("Button 1 down!", 10, 25); };
if(DIMouse.GetButton(1)) { Font.OutputText("Button 2 down!", 10, 40); };
if(DIMouse.GetButton(2)) { Font.OutputText("Button 3 down!", 10, 55); };
D3DDevice->EndScene();
// Present the backbuffer contents to the display
D3DDevice->Present( NULL, NULL, NULL, NULL );
};
HRESULT DIPick2D()
{
return S_OK;
};
HRESULT DIPick3D()
{
if(!DIMouse.GetButton(0)) return E_FAIL;
HRESULT hr;
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
DWORD m_dwNumIntersections = 0L;
// Get the pick ray from the mouse position
D3DXMATRIX matProj;
D3DDevice->GetTransform( D3DTS_PROJECTION, &matProj );
POINT ptCursor;
GetCursorPos( &ptCursor );
ScreenToClient(hWnd, &ptCursor );
// Compute the vector of the pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / g_iX ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / g_iY ) - 1 ) / matProj._22;
v.z = 1.0f;
// Get the inverse view matrix
D3DXMATRIX matView, m;
D3DDevice->GetTransform( D3DTS_VIEW, &matView );
D3DXMatrixInverse( &m, NULL, &matView );
// Transform the screen space pick ray into 3D space
vPickRayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
vPickRayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
vPickRayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;
// Get the picked triangle
LPDIRECT3DVERTEXBUFFER8 pVB;
D3DVERTEX* pVertices;
pVB = g_pVB;
pVB->Lock( 0,0,(BYTE**)&pVertices, 0 );
// Not using D3DX
DWORD dwNumFaces = 2;
FLOAT fBary1, fBary2;
FLOAT fDist;
INTERSECTION m_IntersectionArray[16];
for( DWORD i=0; i<dwNumFaces; i++ )
{
D3DXVECTOR3 v0 = pVertices[3*i+0].p;
D3DXVECTOR3 v1 = pVertices[3*i+1].p;
D3DXVECTOR3 v2 = pVertices[3*i+2].p;
// Check if the pick ray passes through this point
if( IntersectTriangle( vPickRayOrig, vPickRayDir, v0, v1, v2,
&fDist, &fBary1, &fBary2 ) )
{
m_dwNumIntersections = 0;
m_IntersectionArray[m_dwNumIntersections].dwFace = i;
m_IntersectionArray[m_dwNumIntersections].fBary1 = fBary1;
m_IntersectionArray[m_dwNumIntersections].fBary2 = fBary2;
m_IntersectionArray[m_dwNumIntersections].fDist = fDist;
m_dwNumIntersections++;
if( m_dwNumIntersections == 16 )
break;
}
}
if(m_dwNumIntersections > 0) MessageBox(NULL, TEXT("Intersection Found"), TEXT("Intersection Found"), MB_OK);
pVB->Unlock();
pVB->Release();
return S_OK;
};
It works with the bottom left triangle (3D) but not the top right (3D) - don't worry about the 2D implementation - I can do that...
Please please please tell me what the hell I'm doing wrong!
Synex
Code Monkey
[edited by - Synex on January 4, 2004 4:45:41 AM]