mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-04 18:09:53 +03:00
1
This commit is contained in:
560
utils/scratchpad3dviewer/d3dapp.cpp
Normal file
560
utils/scratchpad3dviewer/d3dapp.cpp
Normal file
@@ -0,0 +1,560 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// TerrainBlend.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
|
||||
#define MAX_LOADSTRING 100
|
||||
|
||||
// Global Variables:
|
||||
HINSTANCE hInst; // current instance
|
||||
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
|
||||
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
|
||||
HWND g_hWnd;
|
||||
|
||||
// Foward declarations of functions included in this code module:
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||
BOOL InitInstance(HINSTANCE, int);
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
int g_nCapture = 0;
|
||||
bool g_bFocus = false;
|
||||
|
||||
int g_ScreenWidth, g_ScreenHeight;
|
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp;
|
||||
|
||||
|
||||
IDirect3D8 *g_pDirect3D;
|
||||
IDirect3DDevice8 *g_pDevice;
|
||||
|
||||
|
||||
POINT GetWindowCenter()
|
||||
{
|
||||
RECT rc;
|
||||
GetWindowRect(g_hWnd, &rc);
|
||||
POINT ret;
|
||||
ret.x = (rc.left + rc.right) / 2;
|
||||
ret.y = (rc.top + rc.bottom) / 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void CallAppRender( bool bInvalidRect )
|
||||
{
|
||||
static DWORD lastTime = 0;
|
||||
static POINT lastMousePos = {0xFFFF, 0xFFFF};
|
||||
|
||||
// Sample time and mouse position and tell the app to render.
|
||||
DWORD curTime = GetTickCount();
|
||||
float frametime = (curTime - lastTime) / 1000.0f;
|
||||
if( frametime > 0.1f )
|
||||
frametime = 0.1f;
|
||||
|
||||
lastTime = curTime;
|
||||
|
||||
// Get the cursor delta.
|
||||
POINT curMousePos;
|
||||
GetCursorPos(&curMousePos);
|
||||
|
||||
int deltaX, deltaY;
|
||||
|
||||
if( lastMousePos.x == 0xFFFF )
|
||||
{
|
||||
deltaX = deltaY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
deltaX = curMousePos.x - lastMousePos.x;
|
||||
deltaY = curMousePos.y - lastMousePos.y;
|
||||
}
|
||||
|
||||
// Recenter the cursor.
|
||||
if( g_nCapture )
|
||||
{
|
||||
lastMousePos = GetWindowCenter();
|
||||
SetCursorPos( lastMousePos.x, lastMousePos.y );
|
||||
}
|
||||
else
|
||||
{
|
||||
lastMousePos = curMousePos;
|
||||
}
|
||||
|
||||
AppRender( frametime, (float)deltaX, (float)deltaY, bInvalidRect );
|
||||
}
|
||||
|
||||
|
||||
SpewRetval_t D3DAppSpewFunc( SpewType_t spewType, char const *pMsg )
|
||||
{
|
||||
switch (spewType)
|
||||
{
|
||||
case SPEW_ERROR:
|
||||
MessageBox(NULL, pMsg, "FATAL ERROR", MB_OK);
|
||||
return SPEW_ABORT;
|
||||
|
||||
default:
|
||||
OutputDebugString(pMsg);
|
||||
#ifdef _DEBUG
|
||||
return spewType == SPEW_ASSERT ? SPEW_DEBUGGER : SPEW_CONTINUE;
|
||||
#else
|
||||
return SPEW_CONTINUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
CommandLine()->CreateCmdLine( Plat_GetCommandLine() );
|
||||
|
||||
// TODO: Place code here.
|
||||
SpewOutputFunc( D3DAppSpewFunc );
|
||||
MathLib_Init( true, true, true, 2.2f, 2.2f, 0.0f, 2.0f );
|
||||
MSG msg;
|
||||
HACCEL hAccelTable;
|
||||
|
||||
// Initialize global strings
|
||||
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
||||
strcpy( szWindowClass, "d3dapp" );
|
||||
MyRegisterClass(hInstance);
|
||||
|
||||
// Perform application initialization:
|
||||
if (!InitInstance (hInstance, nCmdShow))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TERRAINBLEND);
|
||||
|
||||
|
||||
InvalidateRect( g_hWnd, NULL, FALSE );
|
||||
|
||||
// Main message loop:
|
||||
while(1)
|
||||
{
|
||||
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if(msg.message == WM_QUIT)
|
||||
break;
|
||||
|
||||
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
if(msg.message == WM_QUIT)
|
||||
break;
|
||||
|
||||
CallAppRender( false );
|
||||
}
|
||||
|
||||
AppExit();
|
||||
|
||||
return msg.wParam;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: MyRegisterClass()
|
||||
//
|
||||
// PURPOSE: Registers the window class.
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
// This function and its usage is only necessary if you want this code
|
||||
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
|
||||
// function that was added to Windows 95. It is important to call this function
|
||||
// so that the application will get 'well formed' small icons associated
|
||||
// with it.
|
||||
//
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASSEX wcex;
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = (WNDPROC)WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TERRAINBLEND);
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||||
wcex.lpszMenuName = NULL;
|
||||
wcex.lpszClassName = szWindowClass;
|
||||
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
|
||||
|
||||
return RegisterClassEx(&wcex);
|
||||
}
|
||||
|
||||
|
||||
void ShutdownD3D()
|
||||
{
|
||||
if( g_pDevice )
|
||||
{
|
||||
g_pDevice->Release();
|
||||
g_pDevice = NULL;
|
||||
}
|
||||
|
||||
if( g_pDirect3D )
|
||||
{
|
||||
g_pDirect3D->Release();
|
||||
g_pDirect3D = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InitD3D()
|
||||
{
|
||||
ShutdownD3D();
|
||||
|
||||
|
||||
RECT rcClient;
|
||||
GetClientRect( g_hWnd, &rcClient );
|
||||
|
||||
g_ScreenWidth = rcClient.right - rcClient.left;
|
||||
g_ScreenHeight = rcClient.bottom - rcClient.top;
|
||||
|
||||
// Initialize D3D.
|
||||
g_pDirect3D = Direct3DCreate8( D3D_SDK_VERSION );
|
||||
|
||||
// Get the current desktop display mode, so we can set up a back
|
||||
// buffer of the same format
|
||||
D3DDISPLAYMODE d3ddm;
|
||||
g_pDirect3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );
|
||||
|
||||
|
||||
// Set up the structure used to create the D3DDevice
|
||||
ZeroMemory( &d3dpp, sizeof(d3dpp) );
|
||||
d3dpp.Windowed = TRUE;
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
d3dpp.BackBufferFormat = d3ddm.Format;
|
||||
d3dpp.EnableAutoDepthStencil = TRUE;
|
||||
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
|
||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||||
|
||||
HRESULT hr = g_pDirect3D->CreateDevice(
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
g_hWnd,
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
|
||||
&d3dpp,
|
||||
&g_pDevice);
|
||||
if( FAILED(hr) )
|
||||
{
|
||||
Sys_Error( "CreateDevice failed (%s)", DXGetErrorString8(hr) );
|
||||
}
|
||||
|
||||
g_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
|
||||
g_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
|
||||
}
|
||||
|
||||
void DoResize()
|
||||
{
|
||||
AppPreResize();
|
||||
InitD3D();
|
||||
AppPostResize();
|
||||
CallAppRender( true );
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: InitInstance(HANDLE, int)
|
||||
//
|
||||
// PURPOSE: Saves instance handle and creates main window
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
// In this function, we save the instance handle in a global variable and
|
||||
// create and display the main program window.
|
||||
//
|
||||
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
||||
{
|
||||
hInst = hInstance; // Store instance handle in our global variable
|
||||
|
||||
int x = Sys_FindArgInt( "-x", 0 );
|
||||
int y = Sys_FindArgInt( "-y", 0 );
|
||||
int w = Sys_FindArgInt( "-width", CW_USEDEFAULT );
|
||||
int h = Sys_FindArgInt( "-height", CW_USEDEFAULT );
|
||||
|
||||
DWORD dwFlags = WS_OVERLAPPEDWINDOW;
|
||||
|
||||
// Get the 'work area' so we don't overlap the taskbar on the top or left.
|
||||
RECT rcWorkArea;
|
||||
SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWorkArea, 0 );
|
||||
|
||||
// If they don't specify anything, maximize the window.
|
||||
if( x == 0 && y == 0 && w == CW_USEDEFAULT && h == CW_USEDEFAULT )
|
||||
{
|
||||
x = rcWorkArea.left;
|
||||
y = rcWorkArea.top;
|
||||
w = rcWorkArea.right - rcWorkArea.left;
|
||||
h = rcWorkArea.bottom - rcWorkArea.top;
|
||||
dwFlags |= WS_MAXIMIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += rcWorkArea.left;
|
||||
y += rcWorkArea.top;
|
||||
}
|
||||
|
||||
|
||||
g_hWnd = CreateWindow(
|
||||
szWindowClass,
|
||||
szTitle,
|
||||
dwFlags, // window style
|
||||
x, // x
|
||||
y, // y
|
||||
w, // width
|
||||
h, // height
|
||||
NULL,
|
||||
NULL,
|
||||
hInstance,
|
||||
NULL);
|
||||
|
||||
if (!g_hWnd)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ShowWindow(g_hWnd, nCmdShow);
|
||||
UpdateWindow(g_hWnd);
|
||||
|
||||
|
||||
InitD3D();
|
||||
AppInit();
|
||||
|
||||
// Reinitialize D3D. For some reason, D3D point primitives are way too large
|
||||
// unless we do this.
|
||||
DoResize();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
|
||||
//
|
||||
// PURPOSE: Processes messages for the main window.
|
||||
//
|
||||
// WM_COMMAND - process the application menu
|
||||
// WM_PAINT - Paint the main window
|
||||
// WM_DESTROY - post a quit message and return
|
||||
//
|
||||
//
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint( hWnd, &ps );
|
||||
EndPaint( hWnd, &ps );
|
||||
|
||||
if( g_pDevice )
|
||||
CallAppRender( true );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
AppKey( (int)wParam, lParam&0xFFFF );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
{
|
||||
AppKey( (int)wParam, 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
{
|
||||
AppChar( (int)wParam );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
ShowCursor( FALSE );
|
||||
SetCapture( g_hWnd );
|
||||
g_nCapture++;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
ShowCursor( TRUE );
|
||||
ReleaseCapture( );
|
||||
g_nCapture--;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
{
|
||||
ShowCursor( FALSE );
|
||||
SetCapture( g_hWnd );
|
||||
g_nCapture++;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
ShowCursor( TRUE );
|
||||
ReleaseCapture( );
|
||||
g_nCapture--;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
{
|
||||
if( g_pDevice )
|
||||
DoResize();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
{
|
||||
g_bFocus = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
{
|
||||
g_bFocus = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Sys_Error(const char *pMsg, ...)
|
||||
{
|
||||
char msg[4096];
|
||||
va_list marker;
|
||||
|
||||
va_start( marker, pMsg );
|
||||
V_vsprintf_safe( msg, pMsg, marker );
|
||||
va_end( marker );
|
||||
|
||||
MessageBox( NULL, msg, "Error!", MB_OK );
|
||||
exit(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Sys_Quit()
|
||||
{
|
||||
PostQuitMessage( 0 );
|
||||
}
|
||||
|
||||
|
||||
void Sys_SetWindowText( char const *pMsg, ... )
|
||||
{
|
||||
va_list marker;
|
||||
char msg[4096];
|
||||
|
||||
va_start(marker, pMsg);
|
||||
V_vsprintf_safe(msg, pMsg, marker);
|
||||
va_end(marker);
|
||||
|
||||
SetWindowText( g_hWnd, msg );
|
||||
}
|
||||
|
||||
|
||||
bool Sys_GetKeyState( int key )
|
||||
{
|
||||
int keyTranslations[][2] =
|
||||
{
|
||||
{APPKEY_LBUTTON, VK_LBUTTON},
|
||||
{APPKEY_RBUTTON, VK_RBUTTON},
|
||||
{APPKEY_SPACE, VK_SPACE}
|
||||
};
|
||||
int nKeyTranslations = sizeof(keyTranslations) / sizeof(keyTranslations[0]);
|
||||
|
||||
for( int i=0; i < nKeyTranslations; i++ )
|
||||
{
|
||||
if( key == keyTranslations[i][0] )
|
||||
{
|
||||
key = keyTranslations[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !!( GetAsyncKeyState( key ) & 0x8000 );
|
||||
}
|
||||
|
||||
|
||||
void Sys_Sleep( int ms )
|
||||
{
|
||||
Sleep( (DWORD)ms );
|
||||
}
|
||||
|
||||
|
||||
bool Sys_HasFocus()
|
||||
{
|
||||
return g_bFocus;
|
||||
}
|
||||
|
||||
|
||||
char const* Sys_FindArg( char const *pArg, char const *pDefault )
|
||||
{
|
||||
for( int i=0; i < __argc; i++ )
|
||||
{
|
||||
if( stricmp( __argv[i], pArg ) == 0 )
|
||||
return (i+1) < __argc ? __argv[i+1] : "";
|
||||
}
|
||||
|
||||
return pDefault;
|
||||
}
|
||||
|
||||
|
||||
int Sys_FindArgInt( char const *pArg, int defaultVal )
|
||||
{
|
||||
char const *pVal = Sys_FindArg( pArg, NULL );
|
||||
if( pVal )
|
||||
return atoi( pVal );
|
||||
else
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
|
||||
int Sys_ScreenWidth()
|
||||
{
|
||||
return g_ScreenWidth;
|
||||
}
|
||||
|
||||
|
||||
int Sys_ScreenHeight()
|
||||
{
|
||||
return g_ScreenHeight;
|
||||
}
|
||||
|
||||
|
||||
75
utils/scratchpad3dviewer/d3dapp.h
Normal file
75
utils/scratchpad3dviewer/d3dapp.h
Normal file
@@ -0,0 +1,75 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef D3DAPP_H
|
||||
#define D3DAPP_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include <d3d8.h>
|
||||
|
||||
|
||||
// Globals for the app to access. These are valid whenever the app is called.
|
||||
extern IDirect3D8 *g_pDirect3D;
|
||||
extern IDirect3DDevice8 *g_pDevice;
|
||||
|
||||
|
||||
// Special keys.
|
||||
#define APPKEY_LBUTTON -1
|
||||
#define APPKEY_RBUTTON -2
|
||||
#define APPKEY_SPACE -3
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// Functions for the app to provide.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
void AppInit();
|
||||
|
||||
// Called to update or render the view as often as possible. If bInvalidRect is true,
|
||||
// then you should always render, so the window's contents are valid.
|
||||
void AppRender( float frametime, float mouseDeltaX, float mouseDeltaY, bool bInvalidRect );
|
||||
|
||||
// Release any D3D objects you have here - a resize will happen.
|
||||
void AppPreResize();
|
||||
void AppPostResize();
|
||||
|
||||
void AppExit( );
|
||||
void AppKey( int key, int down );
|
||||
void AppChar( int key );
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// Functions the app can call.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
// Show an error dialog and quit.
|
||||
bool Sys_Error(const char *pMsg, ...);
|
||||
|
||||
// Shutdown the app. AppExit() will be called.
|
||||
void Sys_Quit();
|
||||
|
||||
void Sys_SetWindowText( char const *pMsg, ... );
|
||||
|
||||
// Key can be an ASCII key code or an APPKEY_ define.
|
||||
bool Sys_GetKeyState( int key );
|
||||
|
||||
void Sys_Sleep( int ms );
|
||||
|
||||
// Does the app have the focus?
|
||||
bool Sys_HasFocus();
|
||||
|
||||
char const* Sys_FindArg( char const *pArg, char const *pDefault=NULL );
|
||||
int Sys_FindArgInt( char const *pArg, int defaultVal = -1 );
|
||||
|
||||
int Sys_ScreenWidth();
|
||||
int Sys_ScreenHeight();
|
||||
|
||||
|
||||
#endif // D3DAPP_H
|
||||
34
utils/scratchpad3dviewer/resource.h
Normal file
34
utils/scratchpad3dviewer/resource.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by TERRAINBLEND.RC
|
||||
//
|
||||
#define IDR_MAINFRAME 128
|
||||
#define IDD_TERRAINBLEND_DIALOG 102
|
||||
#define IDD_ABOUTBOX 103
|
||||
#define IDS_APP_TITLE 103
|
||||
#define IDM_ABOUT 104
|
||||
#define IDM_EXIT 105
|
||||
#define IDS_HELLO 106
|
||||
#define IDI_TERRAINBLEND 107
|
||||
#define IDI_SMALL 108
|
||||
#define IDC_TERRAINBLEND 109
|
||||
#define IDC_MYICON 2
|
||||
#define IDC_STATIC -1
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
#define _APS_NEXT_RESOURCE_VALUE 129
|
||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 110
|
||||
#endif
|
||||
#endif
|
||||
928
utils/scratchpad3dviewer/scratchpad3dviewer.cpp
Normal file
928
utils/scratchpad3dviewer/scratchpad3dviewer.cpp
Normal file
@@ -0,0 +1,928 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "d3dapp.h"
|
||||
#include "d3dx8math.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "ScratchPad3D.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
|
||||
#define SPColorExpand( c ) (c).m_vColor.x, (c).m_vColor.y, (c).m_vColor.z, (c).m_flAlpha
|
||||
|
||||
|
||||
class VertPosDiffuse
|
||||
{
|
||||
public:
|
||||
inline void Init(Vector const &vPos, float r, float g, float b, float a)
|
||||
{
|
||||
m_Pos = vPos;
|
||||
SetDiffuse( r, g, b, a );
|
||||
}
|
||||
|
||||
inline void SetDiffuse( float r, float g, float b, float a )
|
||||
{
|
||||
m_Diffuse[0] = (unsigned char)(b * 255.9f);
|
||||
m_Diffuse[1] = (unsigned char)(g * 255.9f);
|
||||
m_Diffuse[2] = (unsigned char)(r * 255.9f);
|
||||
m_Diffuse[3] = (unsigned char)(a * 255.9f);
|
||||
}
|
||||
|
||||
inline void SetDiffuse( Vector const &vColor )
|
||||
{
|
||||
SetDiffuse( vColor.x, vColor.y, vColor.z, 1 );
|
||||
}
|
||||
|
||||
inline void SetTexCoords( const Vector2D &tCoords )
|
||||
{
|
||||
m_tCoords = tCoords;
|
||||
}
|
||||
|
||||
static inline DWORD GetFVF() {return D3DFVF_DIFFUSE | D3DFVF_XYZ | D3DFVF_TEX1;}
|
||||
|
||||
Vector m_Pos;
|
||||
unsigned char m_Diffuse[4];
|
||||
Vector2D m_tCoords;
|
||||
};
|
||||
|
||||
class PosController
|
||||
{
|
||||
public:
|
||||
Vector m_vPos;
|
||||
QAngle m_vAngles;
|
||||
};
|
||||
|
||||
int g_nLines, g_nPolygons;
|
||||
|
||||
PosController g_ViewController;
|
||||
Vector g_IdentityBasis[3] = {Vector(1,0,0), Vector(0,1,0), Vector(0,0,1)};
|
||||
Vector g_ViewerPos;
|
||||
Vector g_ViewerBasis[3];
|
||||
VMatrix g_mModelView;
|
||||
CScratchPad3D *g_pScratchPad = NULL;
|
||||
FILETIME g_LastWriteTime;
|
||||
char g_Filename[256];
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// Helper functions.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
inline float FClamp(float val, float min, float max)
|
||||
{
|
||||
return (val < min) ? min : (val > max ? max : val);
|
||||
}
|
||||
|
||||
inline float FMin(float val1, float val2)
|
||||
{
|
||||
return (val1 < val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
inline float FMax(float val1, float val2)
|
||||
{
|
||||
return (val1 > val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
inline float CosDegrees(float angle)
|
||||
{
|
||||
return (float)cos(DEG2RAD(angle));
|
||||
}
|
||||
|
||||
inline float SinDegrees(float angle)
|
||||
{
|
||||
return (float)sin(DEG2RAD(angle));
|
||||
}
|
||||
|
||||
inline float FRand(float a, float b)
|
||||
{
|
||||
return a + (b - a) * ((float)rand() / VALVE_RAND_MAX);
|
||||
}
|
||||
|
||||
void CheckResult( HRESULT hr )
|
||||
{
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
Assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLine2(const Vector &vFrom, const Vector &vTo, float r1, float g1, float b1, float a1, float r2, float g2, float b2, float a2)
|
||||
{
|
||||
VertPosDiffuse verts[2];
|
||||
|
||||
verts[0].Init( vFrom, r1, g1, b1, 1 );
|
||||
verts[1].Init( vTo, r2, g2, b2, 1 );
|
||||
|
||||
CheckResult ( g_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ) );
|
||||
CheckResult( g_pDevice->SetTexture( 0, NULL ) );
|
||||
CheckResult( g_pDevice->DrawPrimitiveUP( D3DPT_LINELIST, 1, verts, sizeof(verts[0]) ) );
|
||||
|
||||
++g_nLines;
|
||||
}
|
||||
|
||||
|
||||
void DrawLine(const Vector &vFrom, const Vector &vTo, float r, float g, float b, float a)
|
||||
{
|
||||
DrawLine2(vFrom, vTo, r,g,b,a, r,g,b,a);
|
||||
}
|
||||
|
||||
|
||||
// zAngle's range is [-90,90].
|
||||
// When zAngle is 0, the position is in the middle of the sphere (vertically).
|
||||
// When zAngle is 90, the position is at the top of the sphere.
|
||||
// When zAngle is -90, the position is at the bottom of the sphere.
|
||||
Vector CalcSphereVecAngles(float xyAngle, float zAngle, float fRadius)
|
||||
{
|
||||
Vector vec;
|
||||
|
||||
vec.x = CosDegrees(xyAngle) * CosDegrees(zAngle);
|
||||
vec.y = SinDegrees(xyAngle) * CosDegrees(zAngle);
|
||||
vec.z = SinDegrees(zAngle);
|
||||
|
||||
return vec * fRadius;
|
||||
}
|
||||
|
||||
|
||||
// Figure out the rotation to look from vEye to vDest.
|
||||
void SetupLookAt( const Vector &vEye, const Vector &vDest, Vector basis[3] )
|
||||
{
|
||||
basis[0] = (vDest - vEye); // Forward.
|
||||
VectorNormalize( basis[0] );
|
||||
basis[2].Init(0.0f, 0.0f, 1.0f); // Up.
|
||||
|
||||
basis[1] = basis[2].Cross(basis[0]); // Left.
|
||||
VectorNormalize( basis[1] );
|
||||
|
||||
basis[2] = basis[0].Cross(basis[1]); // Regenerate up.
|
||||
VectorNormalize( basis[2] );
|
||||
}
|
||||
|
||||
|
||||
D3DMATRIX* VEngineToTempD3DMatrix( VMatrix const &mat )
|
||||
{
|
||||
static VMatrix ret;
|
||||
ret = mat.Transpose();
|
||||
return (D3DMATRIX*)&ret;
|
||||
}
|
||||
|
||||
|
||||
void UpdateView(float mouseDeltaX, float mouseDeltaY)
|
||||
{
|
||||
VMatrix mRot;
|
||||
PosController *pController;
|
||||
|
||||
|
||||
pController = &g_ViewController;
|
||||
|
||||
// WorldCraft-like interface..
|
||||
if( Sys_HasFocus() )
|
||||
{
|
||||
Vector vForward, vUp, vRight;
|
||||
AngleVectors( pController->m_vAngles, &vForward, &vRight, &vUp );
|
||||
|
||||
static float fAngleScale = 0.4f;
|
||||
static float fDistScale = 0.5f;
|
||||
|
||||
if( Sys_GetKeyState( APPKEY_LBUTTON ) )
|
||||
{
|
||||
if( Sys_GetKeyState( APPKEY_RBUTTON ) )
|
||||
{
|
||||
// Ok, move forward and backwards.
|
||||
pController->m_vPos += vForward * -mouseDeltaY * fDistScale;
|
||||
pController->m_vPos += vRight * mouseDeltaX * fDistScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
pController->m_vAngles.y += -mouseDeltaX * fAngleScale;
|
||||
pController->m_vAngles.x += mouseDeltaY * fAngleScale;
|
||||
}
|
||||
}
|
||||
else if( Sys_GetKeyState( APPKEY_RBUTTON ) )
|
||||
{
|
||||
pController->m_vPos += vUp * -mouseDeltaY * fDistScale;
|
||||
pController->m_vPos += vRight * mouseDeltaX * fDistScale;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the projection matrix to 90 degrees.
|
||||
D3DXMATRIX matProj;
|
||||
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2, Sys_ScreenWidth() / (float)Sys_ScreenHeight(), 1.0f, 10000.0f );
|
||||
g_pDevice->SetTransform( D3DTS_PROJECTION, &matProj );
|
||||
|
||||
|
||||
// This matrix converts from D3D coordinates (X=right, Y=up, Z=forward)
|
||||
// to VEngine coordinates (X=forward, Y=left, Z=up).
|
||||
VMatrix mD3DToVEngine(
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
g_ViewerPos = pController->m_vPos;
|
||||
mRot = SetupMatrixAngles( pController->m_vAngles );
|
||||
|
||||
g_mModelView = ~mD3DToVEngine * mRot.Transpose3x3() * SetupMatrixTranslation(-g_ViewerPos);
|
||||
|
||||
CheckResult( g_pDevice->SetTransform( D3DTS_VIEW, VEngineToTempD3DMatrix(g_mModelView) ) );
|
||||
|
||||
// World matrix is identity..
|
||||
VMatrix mIdentity = SetupMatrixIdentity();
|
||||
CheckResult( g_pDevice->SetTransform( D3DTS_WORLD, (D3DMATRIX*)&mIdentity ) );
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// ScratchPad3D command implementation.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
void CommandRender_Point( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CScratchPad3D::CCommand_Point *pCmd = (CScratchPad3D::CCommand_Point*)pInCmd;
|
||||
|
||||
g_pDevice->SetRenderState( D3DRS_POINTSIZE, *((DWORD*)&pCmd->m_flPointSize) );
|
||||
|
||||
VertPosDiffuse vert;
|
||||
vert.Init( pCmd->m_Vert.m_vPos, SPColorExpand(pCmd->m_Vert.m_vColor) );
|
||||
|
||||
g_pDevice->DrawPrimitiveUP( D3DPT_POINTLIST, 1, &vert, sizeof(vert) );
|
||||
}
|
||||
|
||||
|
||||
VertPosDiffuse g_LineBatchVerts[1024];
|
||||
int g_nLineBatchVerts = 0;
|
||||
|
||||
|
||||
void CommandRender_LinesStart( IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
// Set states for line drawing.
|
||||
CheckResult( g_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ) );
|
||||
CheckResult( g_pDevice->SetTexture( 0, NULL ) );
|
||||
}
|
||||
|
||||
void CommandRender_LinesStop( IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CheckResult( g_pDevice->DrawPrimitiveUP( D3DPT_LINELIST, g_nLineBatchVerts / 2, g_LineBatchVerts, sizeof(g_LineBatchVerts[0]) ) );
|
||||
g_nLines += g_nLineBatchVerts / 2;
|
||||
g_nLineBatchVerts = 0;
|
||||
}
|
||||
|
||||
void CommandRender_Line( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CScratchPad3D::CCommand_Line *pCmd = (CScratchPad3D::CCommand_Line*)pInCmd;
|
||||
|
||||
// Flush out the line cache?
|
||||
if ( g_nLineBatchVerts == sizeof( g_LineBatchVerts ) / sizeof( g_LineBatchVerts[0] ) )
|
||||
{
|
||||
CommandRender_LinesStop( pDevice );
|
||||
}
|
||||
|
||||
g_LineBatchVerts[g_nLineBatchVerts].m_Pos = pCmd->m_Verts[0].m_vPos;
|
||||
g_LineBatchVerts[g_nLineBatchVerts].SetDiffuse( SPColorExpand( pCmd->m_Verts[0].m_vColor ) );
|
||||
++g_nLineBatchVerts;
|
||||
|
||||
g_LineBatchVerts[g_nLineBatchVerts].m_Pos = pCmd->m_Verts[1].m_vPos;
|
||||
g_LineBatchVerts[g_nLineBatchVerts].SetDiffuse( SPColorExpand( pCmd->m_Verts[1].m_vColor ) );
|
||||
++g_nLineBatchVerts;
|
||||
}
|
||||
|
||||
|
||||
void CommandRender_Polygon( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
VertPosDiffuse verts[65];
|
||||
CScratchPad3D::CCommand_Polygon *pCmd = (CScratchPad3D::CCommand_Polygon*)pInCmd;
|
||||
|
||||
int nVerts = min( 64, pCmd->m_Verts.Size() );
|
||||
for( int i=0; i < nVerts; i++ )
|
||||
{
|
||||
verts[i].m_Pos[0] = pCmd->m_Verts[i].m_vPos.x;
|
||||
verts[i].m_Pos[1] = pCmd->m_Verts[i].m_vPos.y;
|
||||
verts[i].m_Pos[2] = pCmd->m_Verts[i].m_vPos.z;
|
||||
verts[i].SetDiffuse( SPColorExpand( pCmd->m_Verts[i].m_vColor ) );
|
||||
}
|
||||
|
||||
// Draw wireframe manually since D3D draws internal edges of the triangle fan.
|
||||
DWORD dwFillMode;
|
||||
g_pDevice->GetRenderState( D3DRS_FILLMODE, &dwFillMode );
|
||||
if( dwFillMode == D3DFILL_WIREFRAME )
|
||||
{
|
||||
if( nVerts >= 2 )
|
||||
{
|
||||
g_pDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, nVerts-1, verts, sizeof(verts[0]) );
|
||||
|
||||
verts[nVerts] = verts[0];
|
||||
g_pDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, 1, &verts[nVerts-1], sizeof(verts[0]) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckResult( g_pDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, nVerts - 2, verts, sizeof(verts[0]) ) );
|
||||
}
|
||||
|
||||
++g_nPolygons;
|
||||
}
|
||||
|
||||
void CommandRender_Matrix( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CScratchPad3D::CCommand_Matrix *pCmd = (CScratchPad3D::CCommand_Matrix*)pInCmd;
|
||||
|
||||
VMatrix mTransposed = pCmd->m_mMatrix.Transpose();
|
||||
CheckResult( g_pDevice->SetTransform( D3DTS_WORLD, (D3DMATRIX*)mTransposed.m ) );
|
||||
}
|
||||
|
||||
void CommandRender_RenderState( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CScratchPad3D::CCommand_RenderState *pCmd = (CScratchPad3D::CCommand_RenderState*)pInCmd;
|
||||
|
||||
switch( pCmd->m_State )
|
||||
{
|
||||
case IScratchPad3D::RS_FillMode:
|
||||
{
|
||||
if( pCmd->m_Val == IScratchPad3D::FillMode_Wireframe )
|
||||
g_pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
|
||||
else
|
||||
g_pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
||||
}
|
||||
break;
|
||||
|
||||
case IScratchPad3D::RS_ZRead:
|
||||
{
|
||||
g_pDevice->SetRenderState( D3DRS_ZENABLE, pCmd->m_Val );
|
||||
}
|
||||
break;
|
||||
|
||||
case IScratchPad3D::RS_ZBias:
|
||||
{
|
||||
g_pDevice->SetRenderState( D3DRS_ZBIAS, pCmd->m_Val );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class CCachedTextData : public CScratchPad3D::ICachedRenderData
|
||||
{
|
||||
public:
|
||||
CCachedTextData()
|
||||
{
|
||||
m_pTexture = NULL;
|
||||
}
|
||||
|
||||
~CCachedTextData()
|
||||
{
|
||||
if ( m_pTexture )
|
||||
m_pTexture->Release();
|
||||
}
|
||||
|
||||
virtual void Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
IDirect3DTexture8 *m_pTexture;
|
||||
int m_BitmapWidth;
|
||||
int m_BitmapHeight;
|
||||
int m_nChars;
|
||||
};
|
||||
|
||||
|
||||
void GenerateTextGreyscaleBitmap(
|
||||
const char *pText,
|
||||
CUtlVector<unsigned char> &bitmap,
|
||||
int *pWidth,
|
||||
int *pHeight )
|
||||
{
|
||||
*pWidth = *pHeight = 0;
|
||||
|
||||
|
||||
// Create a bitmap, font, and HDC.
|
||||
HDC hDC = CreateCompatibleDC( NULL );
|
||||
Assert( hDC );
|
||||
|
||||
HFONT hFont = ::CreateFontA(
|
||||
18, // font height
|
||||
0, 0, 0,
|
||||
FW_MEDIUM,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
ANSI_CHARSET,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS,
|
||||
ANTIALIASED_QUALITY,
|
||||
DEFAULT_PITCH | FF_DONTCARE,
|
||||
"Arial" );
|
||||
Assert( hDC );
|
||||
if ( !hFont )
|
||||
{
|
||||
DeleteDC( hDC );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create a bitmap. Allow for width of 512. Hopefully, that can fit all the text we need.
|
||||
int bigImageWidth = 512;
|
||||
int bigImageHeight = 64;
|
||||
|
||||
BITMAPINFOHEADER bmi;
|
||||
memset( &bmi, 0, sizeof( bmi ) );
|
||||
|
||||
bmi.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.biWidth = bigImageWidth;
|
||||
bmi.biHeight = -bigImageHeight;
|
||||
bmi.biBitCount = 24;
|
||||
bmi.biPlanes = 1;
|
||||
bmi.biCompression = BI_RGB;
|
||||
|
||||
void *pBits = NULL;
|
||||
HBITMAP hBitmap = CreateDIBSection( hDC,
|
||||
(BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0 );
|
||||
Assert( hBitmap && pBits );
|
||||
|
||||
if ( !hBitmap )
|
||||
{
|
||||
DeleteObject( hFont );
|
||||
DeleteDC( hDC );
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the font and bitmap into the DC.
|
||||
HFONT hOldFont = (HFONT)SelectObject( hDC, hFont );
|
||||
HBITMAP hOldBitmap = (HBITMAP)SelectObject( hDC, hBitmap );
|
||||
|
||||
|
||||
// Draw the text into the DC.
|
||||
SIZE size;
|
||||
int textLen = strlen( pText );
|
||||
GetTextExtentPoint32( hDC, pText, textLen, &size );
|
||||
TextOut( hDC, 0, 0, pText, textLen );
|
||||
|
||||
// Now copy the bits out.
|
||||
const unsigned char *pSrcBase = (const unsigned char*)pBits;
|
||||
*pWidth = size.cx;
|
||||
*pHeight = size.cy;
|
||||
bitmap.SetSize( size.cy * size.cx );
|
||||
for ( int y=0; y < size.cy; y++ )
|
||||
{
|
||||
for ( int x=0; x < size.cx; x++ )
|
||||
{
|
||||
const unsigned char *pSrc = &pSrcBase[ (y*bigImageWidth+x) * 3 ];
|
||||
unsigned char *pDest = &bitmap[y * size.cx + x];
|
||||
|
||||
int avg = (pSrc[0] + pSrc[1] + pSrc[2]) / 3;
|
||||
*pDest = 0xFF - (unsigned char)avg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unselect the objects from the DC and cleanup everything.
|
||||
SelectObject( hDC, hOldFont );
|
||||
DeleteObject( hFont );
|
||||
|
||||
SelectObject( hDC, hOldBitmap );
|
||||
DeleteObject( hBitmap );
|
||||
|
||||
DeleteDC( hDC );
|
||||
}
|
||||
|
||||
|
||||
IDirect3DTexture8* MakeD3DTextureFromBitmap(
|
||||
CUtlVector<unsigned char> &bitmap,
|
||||
int width,
|
||||
int height,
|
||||
bool bSolidBackground )
|
||||
{
|
||||
IDirect3DTexture8 *pRet = NULL;
|
||||
HRESULT hr = g_pDevice->CreateTexture(
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
0,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_MANAGED,
|
||||
&pRet );
|
||||
|
||||
if ( !pRet || FAILED( hr ) )
|
||||
return NULL;
|
||||
|
||||
// Lock the texture and fill it up.
|
||||
D3DLOCKED_RECT lockedRect;
|
||||
hr = pRet->LockRect( 0, &lockedRect, NULL, 0 );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
Assert( false );
|
||||
pRet->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Now fill it up.
|
||||
unsigned char *pDestData = (unsigned char*)lockedRect.pBits;
|
||||
for ( int y=0; y < height; y++ )
|
||||
{
|
||||
for ( int x=0; x < width; x++ )
|
||||
{
|
||||
unsigned char *pDestPixel = &pDestData[ (y*lockedRect.Pitch + x*4) ];
|
||||
unsigned char cSrcColor = bitmap[y*width+x];
|
||||
|
||||
if ( bSolidBackground )
|
||||
{
|
||||
pDestPixel[3] = 0xFF;
|
||||
pDestPixel[0] = pDestPixel[1] = pDestPixel[2] = cSrcColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDestPixel[0] = pDestPixel[1] = pDestPixel[2] = pDestPixel[3] = 0xFF;
|
||||
pDestPixel[3] = cSrcColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pRet->UnlockRect( 0 );
|
||||
return pRet;
|
||||
}
|
||||
|
||||
|
||||
void CommandRender_Text( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice )
|
||||
{
|
||||
CScratchPad3D::CCommand_Text *pCmd = (CScratchPad3D::CCommand_Text*)pInCmd;
|
||||
CTextParams *pParams = &pCmd->m_TextParams;
|
||||
|
||||
// First, see if we've already generated the texture for this string.
|
||||
CCachedTextData *pCached = (CCachedTextData*)pCmd->m_pCachedRenderData;
|
||||
if ( !pCached )
|
||||
{
|
||||
// Generate a bitmap for this text string.
|
||||
CUtlVector<unsigned char> bitmap;
|
||||
int width, height;
|
||||
GenerateTextGreyscaleBitmap( pCmd->m_String.Base(), bitmap, &width, &height );
|
||||
|
||||
// Convert the bitmap into a D3D texture.
|
||||
pCached = new CCachedTextData;
|
||||
pCached->m_pTexture = MakeD3DTextureFromBitmap( bitmap, width, height, pParams->m_bSolidBackground );
|
||||
pCached->m_BitmapWidth = width;
|
||||
pCached->m_BitmapHeight = height;
|
||||
pCached->m_nChars = strlen( pCmd->m_String.Base() );
|
||||
|
||||
// Cache it.
|
||||
pCmd->m_pCachedRenderData = pCached;
|
||||
}
|
||||
|
||||
|
||||
// Figure out its orientation vectors.
|
||||
Vector vForward, vRight, vUp;
|
||||
AngleVectors( pParams->m_vAngles, &vForward, &vRight, &vUp );
|
||||
|
||||
// Backface removal?
|
||||
bool bFlip = true;
|
||||
if ( vForward.Dot( g_ViewerPos - pParams->m_vPos ) < 0 )
|
||||
{
|
||||
if ( pParams->m_bTwoSided )
|
||||
bFlip = false;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
// This is really kludgy, but it's the best info we have here.
|
||||
float flTotalWidth = pParams->m_flLetterWidth * pCached->m_nChars;
|
||||
|
||||
float flAvgCharWidth = (float)flTotalWidth / pCached->m_nChars;
|
||||
float flTotalHeight = flAvgCharWidth * 3;
|
||||
|
||||
Vector vShift( 0, 0, 0 );
|
||||
if ( pParams->m_bCentered )
|
||||
vShift = vRight * ( -flTotalWidth/2 ) + vUp * ( flTotalHeight/2 );
|
||||
|
||||
// Now draw the quad with the texture in it.
|
||||
VertPosDiffuse quad[5]; // Leave space for 1 more for the line strip for the border.
|
||||
|
||||
quad[0].m_Pos = pParams->m_vPos;
|
||||
quad[1].m_Pos = pParams->m_vPos + vRight * flTotalWidth;
|
||||
quad[2].m_Pos = quad[1].m_Pos - vUp * flTotalHeight;
|
||||
quad[3].m_Pos = pParams->m_vPos - vUp * flTotalHeight;
|
||||
|
||||
// Set tex coords.
|
||||
if ( bFlip )
|
||||
{
|
||||
quad[0].m_tCoords.Init( 1, 0 );
|
||||
quad[1].m_tCoords.Init( 0, 0 );
|
||||
quad[2].m_tCoords.Init( 0, 1 );
|
||||
quad[3].m_tCoords.Init( 1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
quad[0].m_tCoords.Init( 0, 0 );
|
||||
quad[1].m_tCoords.Init( 1, 0 );
|
||||
quad[2].m_tCoords.Init( 1, 1 );
|
||||
quad[3].m_tCoords.Init( 0, 1 );
|
||||
}
|
||||
|
||||
for ( int i=0; i < 4; i++ )
|
||||
{
|
||||
quad[i].m_Pos += vShift;
|
||||
quad[i].SetDiffuse( pParams->m_vColor.x, pParams->m_vColor.y, pParams->m_vColor.z, pParams->m_flAlpha );
|
||||
}
|
||||
|
||||
|
||||
// Draw.
|
||||
|
||||
// Backup render states.
|
||||
DWORD tss[][3] = {
|
||||
{ D3DTSS_COLOROP, D3DTOP_MODULATE, 0 },
|
||||
{ D3DTSS_COLORARG1, D3DTA_DIFFUSE, 0 },
|
||||
{ D3DTSS_COLORARG2, D3DTA_TEXTURE, 0 },
|
||||
{ D3DTSS_ALPHAOP, D3DTOP_MODULATE, 0 },
|
||||
{ D3DTSS_ALPHAARG1, D3DTA_DIFFUSE, 0 },
|
||||
{ D3DTSS_ALPHAARG2, D3DTA_TEXTURE, 0 }
|
||||
};
|
||||
#define NUM_TSS ( sizeof( tss ) / sizeof( tss[0] ) )
|
||||
|
||||
DWORD rss[][3] = {
|
||||
{ D3DRS_ALPHABLENDENABLE, TRUE, 0 },
|
||||
{ D3DRS_FILLMODE, D3DFILL_SOLID, 0 },
|
||||
{ D3DRS_SRCBLEND, D3DBLEND_SRCALPHA, 0 },
|
||||
{ D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA, 0 },
|
||||
{ D3DRS_FILLMODE, D3DFILL_SOLID, 0 }
|
||||
};
|
||||
#define NUM_RSS ( sizeof( rss ) / sizeof( rss[0] ) )
|
||||
|
||||
for ( int i=0; i < NUM_TSS; i++ )
|
||||
{
|
||||
g_pDevice->GetTextureStageState( 0, (D3DTEXTURESTAGESTATETYPE)tss[i][0], &tss[i][2] );
|
||||
g_pDevice->SetTextureStageState( 0, (D3DTEXTURESTAGESTATETYPE)tss[i][0], tss[i][1] );
|
||||
}
|
||||
for ( int i=0; i < NUM_RSS; i++ )
|
||||
{
|
||||
g_pDevice->GetRenderState( (D3DRENDERSTATETYPE)rss[i][0], &rss[i][2] );
|
||||
g_pDevice->SetRenderState( (D3DRENDERSTATETYPE)rss[i][0], rss[i][1] );
|
||||
}
|
||||
|
||||
|
||||
g_pDevice->SetTexture( 0, pCached->m_pTexture );
|
||||
CheckResult( g_pDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, quad, sizeof(quad[0]) ) );
|
||||
g_pDevice->SetTexture( 0, NULL );
|
||||
|
||||
++g_nPolygons;
|
||||
|
||||
|
||||
// Restore render states.
|
||||
for ( int i=0; i < NUM_TSS; i++ )
|
||||
g_pDevice->SetTextureStageState( 0, (D3DTEXTURESTAGESTATETYPE)tss[i][0], tss[i][2] );
|
||||
|
||||
for ( int i=0; i < NUM_RSS; i++ )
|
||||
g_pDevice->SetRenderState( (D3DRENDERSTATETYPE)rss[i][0], rss[i][2] );
|
||||
|
||||
|
||||
// Draw wireframe outline..
|
||||
if ( pParams->m_bOutline )
|
||||
{
|
||||
DWORD fillMode;
|
||||
g_pDevice->GetRenderState( D3DRS_FILLMODE, &fillMode );
|
||||
g_pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
|
||||
|
||||
quad[4] = quad[0];
|
||||
g_pDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, 4, quad, sizeof(quad[0]) );
|
||||
|
||||
g_pDevice->SetRenderState( D3DRS_FILLMODE, fillMode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef void (*CommandRenderFunction_Start)( IDirect3DDevice8 *pDevice );
|
||||
typedef void (*CommandRenderFunction_Stop)( IDirect3DDevice8 *pDevice );
|
||||
typedef void (*CommandRenderFunction)( CScratchPad3D::CBaseCommand *pInCmd, IDirect3DDevice8 *pDevice );
|
||||
|
||||
class CCommandRenderFunctions
|
||||
{
|
||||
public:
|
||||
CommandRenderFunction_Start m_StartFn;
|
||||
CommandRenderFunction_Start m_StopFn;
|
||||
CommandRenderFunction m_RenderFn;
|
||||
};
|
||||
|
||||
CCommandRenderFunctions g_CommandRenderFunctions[CScratchPad3D::COMMAND_NUMCOMMANDS] =
|
||||
{
|
||||
{ NULL, NULL, CommandRender_Point },
|
||||
{ CommandRender_LinesStart, CommandRender_LinesStop, CommandRender_Line },
|
||||
{ NULL, NULL, CommandRender_Polygon },
|
||||
{ NULL, NULL, CommandRender_Matrix },
|
||||
{ NULL, NULL, CommandRender_RenderState },
|
||||
{ NULL, NULL, CommandRender_Text }
|
||||
};
|
||||
|
||||
|
||||
void RunCommands( )
|
||||
{
|
||||
// Set all the initial states.
|
||||
g_pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
||||
g_pDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
|
||||
|
||||
VMatrix mIdentity = SetupMatrixIdentity();
|
||||
g_pDevice->SetTransform( D3DTS_WORLD, (D3DMATRIX*)&mIdentity );
|
||||
|
||||
int iLastCmd = -1;
|
||||
for( int i=0; i < g_pScratchPad->m_Commands.Size(); i++ )
|
||||
{
|
||||
CScratchPad3D::CBaseCommand *pCmd = g_pScratchPad->m_Commands[i];
|
||||
|
||||
if( pCmd->m_iCommand >= 0 && pCmd->m_iCommand < CScratchPad3D::COMMAND_NUMCOMMANDS )
|
||||
{
|
||||
// Call the start/stop handlers for this command type if they exist.
|
||||
// These can be used to batch primitives.
|
||||
if ( pCmd->m_iCommand != iLastCmd )
|
||||
{
|
||||
if ( iLastCmd != -1 )
|
||||
{
|
||||
if ( g_CommandRenderFunctions[iLastCmd].m_StopFn )
|
||||
g_CommandRenderFunctions[iLastCmd].m_StopFn( g_pDevice );
|
||||
}
|
||||
|
||||
iLastCmd = pCmd->m_iCommand;
|
||||
|
||||
if ( g_CommandRenderFunctions[pCmd->m_iCommand].m_StartFn )
|
||||
g_CommandRenderFunctions[pCmd->m_iCommand].m_StartFn( g_pDevice );
|
||||
}
|
||||
|
||||
g_CommandRenderFunctions[pCmd->m_iCommand].m_RenderFn( pCmd, g_pDevice );
|
||||
}
|
||||
}
|
||||
|
||||
// Call the final stop function.
|
||||
if ( iLastCmd != -1 )
|
||||
{
|
||||
if ( g_CommandRenderFunctions[iLastCmd].m_StopFn )
|
||||
g_CommandRenderFunctions[iLastCmd].m_StopFn( g_pDevice );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CheckForNewFile( bool bForce )
|
||||
{
|
||||
// See if the file has changed..
|
||||
HANDLE hFile = CreateFile(
|
||||
g_pScratchPad->m_pFilename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL );
|
||||
|
||||
if( !hFile )
|
||||
return false;
|
||||
|
||||
FILETIME createTime, accessTime, writeTime;
|
||||
if( !GetFileTime( hFile, &createTime, &accessTime, &writeTime ) )
|
||||
{
|
||||
CloseHandle( hFile );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bChange = false;
|
||||
if( memcmp(&writeTime, &g_LastWriteTime, sizeof(writeTime)) != 0 || bForce )
|
||||
{
|
||||
bChange = g_pScratchPad->LoadCommandsFromFile();
|
||||
if( bChange )
|
||||
{
|
||||
memcpy( &g_LastWriteTime, &writeTime, sizeof(writeTime) );
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle( hFile );
|
||||
return bChange;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// App callbacks.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
void UpdateWindowText()
|
||||
{
|
||||
char str[512];
|
||||
sprintf( str, "ScratchPad3DViewer: <%s> lines: %d, polygons: %d", g_Filename, g_nLines, g_nPolygons );
|
||||
Sys_SetWindowText( str );
|
||||
}
|
||||
|
||||
|
||||
void AppInit()
|
||||
{
|
||||
// Viewer info.
|
||||
g_ViewController.m_vPos.Init( -200, 0, 0 );
|
||||
g_ViewController.m_vAngles.Init( 0, 0, 0 );
|
||||
|
||||
char const *pFilename = Sys_FindArg( "-file", "scratch.pad" );
|
||||
Q_strncpy( g_Filename, pFilename, sizeof( g_Filename ) );
|
||||
|
||||
IFileSystem *pFileSystem = ScratchPad3D_SetupFileSystem();
|
||||
if( !pFileSystem || pFileSystem->Init() != INIT_OK )
|
||||
{
|
||||
Sys_Quit();
|
||||
}
|
||||
|
||||
// FIXME: I took this out of scratchpad 3d, not sure if this is even necessary any more
|
||||
pFileSystem->AddSearchPath( ".", "PLATFORM" );
|
||||
|
||||
g_pScratchPad = new CScratchPad3D( pFilename, pFileSystem, false );
|
||||
|
||||
g_nLines = g_nPolygons = 0;
|
||||
UpdateWindowText();
|
||||
|
||||
g_pDevice->SetRenderState( D3DRS_EDGEANTIALIAS, FALSE );
|
||||
g_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
|
||||
g_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
|
||||
g_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
|
||||
g_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
|
||||
g_pDevice->SetTexture( 0, NULL );
|
||||
|
||||
// Setup point scaling parameters.
|
||||
float flOne=1;
|
||||
float flZero=0;
|
||||
g_pDevice->SetRenderState( D3DRS_POINTSCALEENABLE, TRUE );
|
||||
g_pDevice->SetRenderState( D3DRS_POINTSCALE_A, *((DWORD*)&flZero) );
|
||||
g_pDevice->SetRenderState( D3DRS_POINTSCALE_B, *((DWORD*)&flZero) );
|
||||
g_pDevice->SetRenderState( D3DRS_POINTSCALE_C, *((DWORD*)&flOne) );
|
||||
|
||||
memset( &g_LastWriteTime, 0, sizeof(g_LastWriteTime) );
|
||||
}
|
||||
|
||||
|
||||
void AppRender( float frametime, float mouseDeltaX, float mouseDeltaY, bool bInvalidRect )
|
||||
{
|
||||
g_nLines = 0;
|
||||
g_nPolygons = 0;
|
||||
|
||||
g_pDevice->SetVertexShader( VertPosDiffuse::GetFVF() );
|
||||
|
||||
if( !bInvalidRect &&
|
||||
!Sys_GetKeyState( APPKEY_LBUTTON ) &&
|
||||
!Sys_GetKeyState( APPKEY_RBUTTON ) &&
|
||||
!CheckForNewFile(false) )
|
||||
{
|
||||
Sys_Sleep( 100 );
|
||||
return;
|
||||
}
|
||||
|
||||
g_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1, 0 );
|
||||
|
||||
g_pDevice->BeginScene();
|
||||
|
||||
UpdateView( mouseDeltaX, mouseDeltaY );
|
||||
|
||||
RunCommands();
|
||||
|
||||
g_pDevice->EndScene();
|
||||
|
||||
g_pDevice->Present( NULL, NULL, NULL, NULL );
|
||||
|
||||
UpdateWindowText();
|
||||
}
|
||||
|
||||
|
||||
void AppPreResize()
|
||||
{
|
||||
for( int i=0; i < g_pScratchPad->m_Commands.Size(); i++ )
|
||||
{
|
||||
CScratchPad3D::CBaseCommand *pCmd = g_pScratchPad->m_Commands[i];
|
||||
|
||||
if ( pCmd->m_iCommand == CScratchPad3D::COMMAND_TEXT )
|
||||
{
|
||||
// Delete the cached data if there is any.
|
||||
pCmd->ReleaseCachedRenderData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppPostResize()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void AppExit( )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void AppKey( int key, int down )
|
||||
{
|
||||
if( key == 27 )
|
||||
{
|
||||
Sys_Quit();
|
||||
}
|
||||
else if( toupper(key) == 'U' )
|
||||
{
|
||||
CheckForNewFile( true );
|
||||
AppRender( 0.1f, 0, 0, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AppChar( int key )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
55
utils/scratchpad3dviewer/scratchpad3dviewer.vpc
Normal file
55
utils/scratchpad3dviewer/scratchpad3dviewer.vpc
Normal file
@@ -0,0 +1,55 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// SCRATCHPAD3DVIEWER.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR "..\.."
|
||||
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE,$SRCDIR\dx9sdk\include"
|
||||
$PreprocessorDefinitions "$BASE;NO_MATHLIB_FTOL"
|
||||
}
|
||||
|
||||
$Linker
|
||||
{
|
||||
$AdditionalDependencies "$BASE $SRCDIR\dx9sdk\lib\dxerr8.lib $SRCDIR\dx9sdk\lib\d3d8.lib $SRCDIR\dx9sdk\lib\d3dx.lib odbc32.lib odbccp32.lib"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "ScratchPad3DViewer"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "d3dapp.cpp"
|
||||
$File "$SRCDIR\public\ScratchPad3D.cpp"
|
||||
$File "ScratchPad3DViewer.cpp"
|
||||
$File "StdAfx.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "d3dapp.h"
|
||||
$File "$SRCDIR\public\filesystem.h"
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\IScratchPad3D.h"
|
||||
$File "$SRCDIR\public\mathlib\mathlib.h"
|
||||
$File "resource.h"
|
||||
$File "$SRCDIR\public\ScratchPad3D.h"
|
||||
$File "StdAfx.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\public\mathlib\vector.h"
|
||||
$File "$SRCDIR\public\mathlib\vmatrix.h"
|
||||
}
|
||||
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
$Lib mathlib
|
||||
}
|
||||
}
|
||||
15
utils/scratchpad3dviewer/stdafx.cpp
Normal file
15
utils/scratchpad3dviewer/stdafx.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// TerrainBlend.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
45
utils/scratchpad3dviewer/stdafx.h
Normal file
45
utils/scratchpad3dviewer/stdafx.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
|
||||
#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
|
||||
#include "tier0/basetypes.h"
|
||||
|
||||
// C RunTime Header Files
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <tchar.h>
|
||||
#include <d3d8.h>
|
||||
#include <dxerr8.h>
|
||||
#include "d3dapp.h"
|
||||
|
||||
// Local Header Files
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
|
||||
Reference in New Issue
Block a user