|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
/*
glapp.c - Simple OpenGL shell There are several options allowed on the command line. They are: -height : what window/screen height do you want to use? -width : what window/screen width do you want to use? -bpp : what color depth do you want to use? -window : create a rendering window rather than full-screen -fov : use a field of view other than 90 degrees */
#include "stdafx.h"
#pragma warning(disable:4305)
#pragma warning(disable:4244)
#include <windows.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <mmsystem.h>
#include "matsysapp.h"
#include "cmdlib.h"
#include "mathlib/mathlib.h"
#include "materialsystem/imaterialproxyfactory.h"
#include "filesystem.h"
#include "materialsystem/imaterialproxy.h"
#include "materialsystem/MaterialSystem_Config.h"
#include "tier0/icommandline.h"
#include "filesystem_tools.h"
#include "materialsystem/imesh.h"
#include "vstdlib/cvar.h"
static int g_nCapture = 0;
#define OSR2_BUILD_NUMBER 1111
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
SpewRetval_t MatSysAppSpewFunc( SpewType_t type, char const *pMsg ) { printf( "%s", pMsg ); OutputDebugString( pMsg );
if( type == SPEW_ASSERT ) return SPEW_DEBUGGER; else if( type == SPEW_ERROR ) return SPEW_ABORT; else return SPEW_CONTINUE; }
class MatSysAppMaterialProxyFactory : public IMaterialProxyFactory { public: virtual IMaterialProxy *CreateProxy( const char *proxyName ) { CreateInterfaceFn clientFactory = Sys_GetFactoryThis(); if( !clientFactory ) { return NULL; } // allocate exactly enough memory for the versioned name on the stack.
char proxyVersionedName[1024]; strcpy( proxyVersionedName, proxyName ); strcat( proxyVersionedName, IMATERIAL_PROXY_INTERFACE_VERSION );
IMaterialProxy *materialProxy; materialProxy = ( IMaterialProxy * )clientFactory( proxyVersionedName, NULL ); if( !materialProxy ) { return NULL; } return materialProxy; }
virtual void DeleteProxy( IMaterialProxy *pProxy ) { if( pProxy ) { pProxy->Release(); } } }; MatSysAppMaterialProxyFactory g_MatSysAppMaterialProxyFactory;
MaterialSystemApp g_MaterialSystemApp;
float fAngle = 0.0f;
char *szFSDesc[] = { "Windowed", "Full Screen" };
extern "C" unsigned int g_Time; unsigned int g_Time = 0;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { return g_MaterialSystemApp.WinMain(hInstance, hPrevInstance, szCmdLine, iCmdShow); }
BOOL isdigits( char *s ) { int i; for (i = 0; s[i]; i++) { if ((s[i] > '9') || (s[i] < '0')) { return FALSE; } } return TRUE; }
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { return g_MaterialSystemApp.WndProc(hwnd, iMsg, wParam, lParam); }
// This function builds a list the screen resolutions supported by the display driver
static void BuildModeList(screen_res_t* &pResolutions, int &iResCount) { DEVMODE dm; int mode; mode = 0; while(EnumDisplaySettings(NULL, mode, &dm)) { mode++; } pResolutions = (screen_res_t *)malloc(sizeof(screen_res_t)*mode); mode = 0; while(EnumDisplaySettings(NULL, mode, &dm)) { pResolutions[mode].width = dm.dmPelsWidth; pResolutions[mode].height = dm.dmPelsHeight; pResolutions[mode].bpp = dm.dmBitsPerPel; pResolutions[mode].flags = dm.dmDisplayFlags; pResolutions[mode].frequency = dm.dmDisplayFrequency; mode++; } iResCount = mode; }
bool Sys_Error(const char *pMsg, ...) { va_list marker; char msg[4096]; va_start(marker, pMsg); vsprintf(msg, pMsg, marker); va_end(marker);
MessageBox(NULL, msg, "FATAL ERROR", MB_OK);
g_MaterialSystemApp.Term(); exit(1); return false; }
void con_Printf(const char *pMsg, ...) { char msg[2048]; va_list marker;
va_start(marker, pMsg); vsprintf(msg, pMsg, marker); va_end(marker);
OutputDebugString(msg); }
bool MSA_IsKeyDown(char key) { return !!(GetAsyncKeyState(key) & 0x8000); }
bool MSA_IsMouseButtonDown( int button ) { if( button == MSA_BUTTON_LEFT ) return !!(GetAsyncKeyState(VK_LBUTTON) & 0x8000); else return !!(GetAsyncKeyState(VK_RBUTTON) & 0x8000); }
void MSA_Sleep(unsigned long count) { if(count > 0) Sleep(count); }
static void MaterialSystem_Error( char *fmt, ... ) { char str[4096]; va_list marker; va_start(marker, fmt); vsprintf(str, fmt, marker); va_end(marker); Sys_Error(str); }
static void MaterialSystem_Warning( char *fmt, ... ) { }
void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig) { memset( pConfig, 0, sizeof(*pConfig) ); // pConfig->screenGamma = 2.2f;
// pConfig->texGamma = 2.2;
// pConfig->overbright = 2;
pConfig->bAllowCheats = false; // pConfig->bLinearFrameBuffer = false;
pConfig->skipMipLevels = 0; // pConfig->lightScale = 1.0f;
pConfig->bFilterLightmaps = true; pConfig->bFilterTextures = true; pConfig->bMipMapTextures = true; pConfig->nShowMipLevels = 0; pConfig->bReverseDepth = false; pConfig->bCompressedTextures = true; // pConfig->bBumpmap = true;
pConfig->bShowSpecular = true; pConfig->bShowDiffuse = true; // pConfig->maxFrameLatency = 1;
pConfig->bDrawFlat = false; // pConfig->bLightingOnly = false;
pConfig->bSoftwareLighting = false; pConfig->bEditMode = false; // No, we're not in WorldCraft.
// pConfig->m_bForceTrilinear = false;
pConfig->m_nForceAnisotropicLevel = 0; // pConfig->m_bForceBilinear = false;
}
/*
==================== CalcFov ==================== */ float CalcFov (float fov_x, float width, float height) { float a; float x;
if (fov_x < 1 || fov_x > 179) fov_x = 90; // error, set to 90
x = width/tan(fov_x/360*M_PI);
a = atan (height/x);
a = a*360/M_PI;
return a; }
MaterialSystemApp::MaterialSystemApp() { Clear(); }
MaterialSystemApp::~MaterialSystemApp() { Term(); }
void MaterialSystemApp::Term() { int i;
// Free the command line holder memory
if (m_argc > 0) { // Free in reverse order of allocation
for (i = (m_argc-1); i >= 0; i--) { free(m_argv[i]); } // Free the parameter "pockets"
free(m_argv); } // Free the memory that holds the video resolution list
if (m_pResolutions) free(m_pResolutions);
if (m_hDC) { if (!ReleaseDC((HWND)m_hWnd, (HDC)m_hDC)) { MessageBox(NULL, "ShutdownOpenGL - ReleaseDC failed\n", "ERROR", MB_OK); } m_hDC = NULL; } if (m_bFullScreen) { ChangeDisplaySettings( 0, 0 ); }
Clear(); }
void MaterialSystemApp::Clear() { m_pMaterialSystem = NULL; m_hMaterialSystemInst = 0; m_hInstance = 0; m_iCmdShow = 0; m_hWnd = 0; m_hDC = 0; m_bActive = false; m_bFullScreen = false; m_width = m_height = 0; m_centerx = m_centery = 0; m_bpp = 0; m_bChangeBPP = false; m_bAllowSoft = 0; g_nCapture = 0; m_szCmdLine = 0; m_argc = 0; m_argv = 0; m_glnWidth = 0; m_glnHeight = 0; m_gldAspect = 0; m_NearClip = m_FarClip = 0; m_fov = 90; m_pResolutions = 0; m_iResCount = 0; m_iVidMode = 0; }
int MaterialSystemApp::WinMain(void *hInstance, void *hPrevInstance, char *szCmdLine, int iCmdShow) { MSG msg; HDC hdc; memset(&msg,0,sizeof(msg)); CommandLine()->CreateCmdLine( Plat_GetCommandLine() );
// Not changable by user
m_hInstance = hInstance; m_iCmdShow = iCmdShow; m_pResolutions = 0; m_NearClip = 8.0f; m_FarClip = 28400.0f; // User definable
m_fov = 90.0f; m_bAllowSoft = FALSE; m_bFullScreen = TRUE; // Get the current display device info
hdc = GetDC( NULL ); m_DevInfo.bpp = GetDeviceCaps(hdc, BITSPIXEL); m_DevInfo.width = GetSystemMetrics(SM_CXSCREEN); m_DevInfo.height = GetSystemMetrics(SM_CYSCREEN); ReleaseDC(NULL, hdc); // Parse the command line if there is one
m_argc = 0; if (strlen(szCmdLine) > 0) { m_szCmdLine = szCmdLine; GetParameters(); } // Default to 640 pixels wide
m_width = FindNumParameter("-width", 640); m_height = FindNumParameter("-height", 480); m_bpp = FindNumParameter("-bpp", 32); m_fov = FindNumParameter("-fov", 90); // Check for windowed rendering
m_bFullScreen = FALSE; if (FindParameter("-fullscreen")) { m_bFullScreen = TRUE; } // Build up the video mode list
BuildModeList(m_pResolutions, m_iResCount); // Create the main program window, start up OpenGL and create our viewport
if (CreateMainWindow( m_width, m_height, m_bpp, m_bFullScreen) != TRUE) { ChangeDisplaySettings(0, 0); MessageBox(NULL, "Unable to create main window.\nProgram will now end.", "FATAL ERROR", MB_OK); Term(); return 0; }
// Turn the cursor off for full-screen mode
if (m_bFullScreen == TRUE) { // Probably want to do this all the time anyway
ShowCursor(FALSE); }
// We're live now
m_bActive = TRUE; // Define this funciton to init your app
AppInit();
RECT rect; GetWindowRect( (HWND)m_hWnd, &rect );
m_centerx = ( rect.left + rect.right ) / 2; m_centery = ( rect.top + rect.bottom ) / 2;
// Begin the main program loop
while (m_bActive == TRUE) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage (&msg); DispatchMessage (&msg); } if (m_pMaterialSystem) { RenderScene(); } } if (m_bFullScreen == TRUE) { ShowCursor(TRUE); } // Release the parameter and video resolution lists
Term(); // Tell the app to cleanup.
AppExit(); return msg.wParam; }
long MaterialSystemApp::WndProc(void *inhwnd, long iMsg, long wParam, long lParam) { if(inhwnd != m_hWnd) { return DefWindowProc((HWND)inhwnd, iMsg, wParam, lParam); }
HWND hwnd = (HWND)inhwnd; switch (iMsg) { case WM_CHAR: switch(wParam) { case VK_ESCAPE: SendMessage(hwnd, WM_CLOSE, 0, 0); break; } AppChar( wParam ); break;
case WM_KEYDOWN: AppKey( wParam, true ); break; case WM_KEYUP: AppKey( wParam, false ); break;
case WM_ACTIVATE: if ((LOWORD(wParam) != WA_INACTIVE) && ((HWND)lParam == NULL)) { ShowWindow(hwnd, SW_RESTORE); SetForegroundWindow(hwnd); } else { if (m_bFullScreen) { ShowWindow(hwnd, SW_MINIMIZE); } } return 0; case WM_SETFOCUS: if(g_bCaptureOnFocus) { MouseCapture(); } break;
case WM_KILLFOCUS: if(g_bCaptureOnFocus) { MouseRelease(); } break;
case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: { if(!g_bCaptureOnFocus) { g_nCapture++; MouseCapture(); } } break;
case WM_LBUTTONUP: case WM_RBUTTONUP: { if(!g_bCaptureOnFocus) { g_nCapture--; MouseRelease(); } } break;
case WM_CLOSE: Term(); m_bActive = FALSE; break; case WM_DESTROY: PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); }
bool MaterialSystemApp::InitMaterialSystem() { RECT rect;
// Init libraries.
MathLib_Init( true, true, true, 2.2f, 2.2f, 0.0f, 2.0f ); SpewOutputFunc( MatSysAppSpewFunc ); if ((m_hDC = GetDC((HWND)m_hWnd)) == NULL) { ChangeDisplaySettings(0, 0); MessageBox(NULL, "GetDC on main window failed", "FATAL ERROR", MB_OK); return FALSE; } // Load the material system DLL and get its interface.
char *pDLLName = "MaterialSystem.dll"; m_hMaterialSystemInst = LoadLibrary( pDLLName ); if( !m_hMaterialSystemInst ) { return Sys_Error( "Can't load MaterialSystem.dll\n" ); }
CreateInterfaceFn clientFactory = Sys_GetFactory( pDLLName ); if ( clientFactory ) { m_pMaterialSystem = (IMaterialSystem *)clientFactory( MATERIAL_SYSTEM_INTERFACE_VERSION, NULL ); if ( !m_pMaterialSystem ) { return Sys_Error( "Could not get the material system interface from materialsystem.dll" ); } } else { return Sys_Error( "Could not find factory interface in library MaterialSystem.dll" ); }
const char *pPath = CommandLine()->ParmValue("-game"); if(!pPath) { // If they didn't specify -game on the command line, use VPROJECT.
CmdLib_InitFileSystem( "." ); pPath = "."; } else { CmdLib_InitFileSystem( pPath ); } // BUGBUG: Can't figure out why this is broken. EXECUTABLE_PATH should already be there
// but it isn't so the shader system is computing texture memory on each run...
g_pFullFileSystem->AddSearchPath( "U:\\main\\game\\bin", "EXECUTABLE_PATH", PATH_ADD_TO_TAIL );
const char *pShaderDLL = FindParameterArg("-shaderdll"); char defaultShaderDLL[256]; if(!pShaderDLL) { strcpy(defaultShaderDLL, "shaderapidx9.dll"); pShaderDLL = defaultShaderDLL; }
if(!m_pMaterialSystem->Init(pShaderDLL, &g_MatSysAppMaterialProxyFactory, CmdLib_GetFileSystemFactory())) return Sys_Error("IMaterialSystem::Init failed");
MaterialSystem_Config_t config; InitMaterialSystemConfig(&config); config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); config.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true );
if(!m_pMaterialSystem->SetMode(m_hWnd, config)) return Sys_Error("IMaterialSystem::SetMode failed");
m_pMaterialSystem->OverrideConfig(config, false); GetClientRect((HWND)m_hWnd, &rect); m_glnWidth= rect.right; m_glnHeight = rect.bottom; m_gldAspect = (float)m_glnWidth / m_glnHeight;
GetWindowRect( (HWND)m_hWnd, &rect ); m_centerx = (rect.left + rect.right) / 2; m_centery = (rect.top + rect.bottom) / 2; return true; }
bool MaterialSystemApp::CreateMainWindow(int width, int height, int bpp, bool fullscreen) { HWND hwnd; WNDCLASSEX wndclass; DWORD dwStyle, dwExStyle; int x, y, sx, sy, ex, ey, ty; if ((hwnd = FindWindow(g_szAppName, g_szAppName)) != NULL) { SetForegroundWindow(hwnd); return 0; } wndclass.cbSize = sizeof (wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wndclass.lpfnWndProc = ::WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = (HINSTANCE)m_hInstance; wndclass.hIcon = 0; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)COLOR_GRAYTEXT; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = g_szAppName; wndclass.hIconSm = 0; if (!RegisterClassEx (&wndclass)) { MessageBox(NULL, "Window class registration failed.", "FATAL ERROR", MB_OK); return FALSE; } if (fullscreen) { dwExStyle = WS_EX_TOPMOST; dwStyle = WS_POPUP | WS_VISIBLE; x = y = 0; sx = m_width; sy = m_height; } else { dwExStyle = 0; //dwStyle = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME; // Use this if you want a "normal" window
dwStyle = WS_CAPTION; ex = GetSystemMetrics(SM_CXEDGE); ey = GetSystemMetrics(SM_CYEDGE); ty = GetSystemMetrics(SM_CYSIZE); // Center the window on the screen
x = (m_DevInfo.width / 2) - ((m_width+(2*ex)) / 2); y = (m_DevInfo.height / 2) - ((m_height+(2*ey)+ty) / 2); sx = m_width+(2*ex); sy = m_height+(2*ey)+ty; /*
Check to be sure the requested window size fits on the screen and adjust each dimension to fit if the requested size does not fit. */ if (sx >= m_DevInfo.width) { x = 0; sx = m_DevInfo.width-(2*ex); } if (sy >= m_DevInfo.height) { y = 0; sy = m_DevInfo.height-((2*ey)+ty); } } if ((hwnd = CreateWindowEx (dwExStyle, g_szAppName, // window class name
g_szAppName, // window caption
dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window style
x, // initial x position
y, // initial y position
sx, // initial x size
sy, // initial y size
NULL, // parent window handle
NULL, // window menu handle
(HINSTANCE)m_hInstance, // program instance handle
NULL)) // creation parameters
== NULL) { ChangeDisplaySettings(0, 0); MessageBox(NULL, "Window creation failed.", "FATAL ERROR", MB_OK); return FALSE; } m_hWnd = hwnd; if (!InitMaterialSystem()) { m_hWnd = NULL; return FALSE; } ShowWindow((HWND)m_hWnd, m_iCmdShow); UpdateWindow((HWND)m_hWnd); SetForegroundWindow((HWND)m_hWnd); SetFocus((HWND)m_hWnd); return TRUE; }
void MaterialSystemApp::RenderScene() { if(!m_pMaterialSystem) return;
static DWORD lastTime = 0; POINT cursorPoint; float deltax = 0, deltay = 0, frametime;
DWORD newTime = GetTickCount(); DWORD deltaTime = newTime - lastTime;
if ( deltaTime > 1000 ) deltaTime = 0; lastTime = newTime; frametime = (float) ((double)deltaTime * 0.001); g_Time = newTime;
if ( g_nCapture ) { GetCursorPos( &cursorPoint ); SetCursorPos( m_centerx, m_centery );
deltax = (cursorPoint.x - m_centerx) * 0.1f; deltay = (cursorPoint.y - m_centery) * -0.1f; } else { deltax = deltay = 0; }
CMatRenderContextPtr pRenderContext(m_pMaterialSystem); m_pMaterialSystem->BeginFrame(deltaTime);
pRenderContext->ClearBuffers(true, true); pRenderContext->Viewport( 0, 0, m_width, m_height ); pRenderContext->MatrixMode(MATERIAL_PROJECTION); pRenderContext->LoadIdentity(); pRenderContext->PerspectiveX(m_fov, m_gldAspect, m_NearClip, m_FarClip);
pRenderContext->MatrixMode(MATERIAL_VIEW); pRenderContext->LoadIdentity();
pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->LoadIdentity();
AppRender( frametime, deltax, deltay );
m_pMaterialSystem->SwapBuffers();
m_pMaterialSystem->EndFrame(); }
void MaterialSystemApp::MouseCapture() { SetCapture( (HWND)m_hWnd ); ShowCursor(FALSE); SetCursorPos( m_centerx, m_centery ); }
void MaterialSystemApp::MouseRelease() { ShowCursor(TRUE); ReleaseCapture(); SetCursorPos( m_centerx, m_centery ); }
void MaterialSystemApp::GetParameters() { int count; char *s, *tstring; // Make a copy of the command line to count the parameters - strtok is destructive
tstring = (char *)malloc(sizeof(char)*(strlen(m_szCmdLine)+1)); strcpy(tstring, m_szCmdLine); // Count the parameters
s = strtok(tstring, " "); count = 1; while (strtok(NULL, " ") != NULL) { count++; } free(tstring); // Allocate "pockets" for the parameters
m_argv = (char **)malloc(sizeof(char*)*(count+1)); // Copy first parameter into the "pockets"
m_argc = 0; s = strtok(m_szCmdLine, " "); m_argv[m_argc] = (char *)malloc(sizeof(char)*(strlen(s)+1)); strcpy(m_argv[m_argc], s); m_argc++; // Copy the rest of the parameters
do { // get the next token
s = strtok(NULL, " "); if (s != NULL) { // add it to the list
m_argv[m_argc] = (char *)malloc(sizeof(char)*(strlen(s)+1)); strcpy(m_argv[m_argc], s); m_argc++; } } while (s != NULL); }
int MaterialSystemApp::FindNumParameter(const char *s, int defaultVal) { int i; for (i = 0; i < (m_argc-1); i++) { if (stricmp(m_argv[i], s) == 0) { if (isdigits(m_argv[i+1])) { return(atoi(m_argv[i+1])); } else { return defaultVal; } } } return defaultVal; }
bool MaterialSystemApp::FindParameter(const char *s) { int i; for (i = 0; i < m_argc; i++) { if (stricmp(m_argv[i], s) == 0) { return true; } } return false; }
const char *MaterialSystemApp::FindParameterArg( const char *s ) { int i; for (i = 0; i < m_argc; i++) { if (stricmp(m_argv[i], s) == 0) { if( (i+1) < m_argc ) return m_argv[i+1]; else return ""; } } return NULL; }
void MaterialSystemApp::SetTitleText(const char *fmt, ...) { char str[4096]; va_list marker;
va_start(marker, fmt); vsprintf(str, fmt, marker); va_end(marker);
::SetWindowText((HWND)m_hWnd, str); }
void MaterialSystemApp::MakeWindowTopmost() { ::SetWindowPos((HWND)m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); }
void MaterialSystemApp::AppShutdown() { SendMessage( (HWND)m_hWnd, WM_CLOSE, 0, 0 ); }
void MaterialSystemApp::QuitNextFrame() { PostMessage( (HWND)m_hWnd, WM_CLOSE, 0, 0 ); }
|