/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see .
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "tools/edit_gui_common.h"
#include "qe3.h"
#include "radiant.h"
#include "MainFrm.h"
#include "lightdlg.h"
#include // for _beginthreadex and _endthreadex
#include // for MSGF_DDEMGR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
idCVar radiant_entityMode( "radiant_entityMode", "0", CVAR_TOOL | CVAR_ARCHIVE, "" );
/////////////////////////////////////////////////////////////////////////////
// CRadiantApp
BEGIN_MESSAGE_MAP(CRadiantApp, CWinApp)
//{{AFX_MSG_MAP(CRadiantApp)
ON_COMMAND(ID_HELP, OnHelp)
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRadiantApp construction
CRadiantApp::CRadiantApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CRadiantApp object
CRadiantApp theApp;
HINSTANCE g_DoomInstance = NULL;
bool g_editorAlive = false;
void RadiantPrint( const char *text ) {
if ( g_editorAlive && g_Inspectors ) {
if (g_Inspectors->consoleWnd.GetSafeHwnd()) {
g_Inspectors->consoleWnd.AddText( text );
}
}
}
void RadiantShutdown( void ) {
theApp.ExitInstance();
}
/*
=================
RadiantInit
This is also called when you 'quit' in doom
=================
*/
void RadiantInit( void ) {
// make sure the renderer is initialized
if ( !renderSystem->IsOpenGLRunning() ) {
common->Printf( "no OpenGL running\n" );
return;
}
g_editorAlive = true;
// allocate a renderWorld and a soundWorld
if ( g_qeglobals.rw == NULL ) {
g_qeglobals.rw = renderSystem->AllocRenderWorld();
g_qeglobals.rw->InitFromMap( NULL );
}
if ( g_qeglobals.sw == NULL ) {
g_qeglobals.sw = soundSystem->AllocSoundWorld( g_qeglobals.rw );
}
if ( g_DoomInstance ) {
if ( ::IsWindowVisible( win32.hWnd ) ) {
::ShowWindow( win32.hWnd, SW_HIDE );
g_pParentWnd->ShowWindow( SW_SHOW );
g_pParentWnd->SetFocus();
}
} else {
Sys_GrabMouseCursor( false );
g_DoomInstance = win32.hInstance;
InitAfx();
CWinApp* pApp = AfxGetApp();
CWinThread *pThread = AfxGetThread();
// App global initializations (rare)
pApp->InitApplication();
// Perform specific initializations
pThread->InitInstance();
qglFinish();
//qwglMakeCurrent(0, 0);
qwglMakeCurrent(win32.hDC, win32.hGLRC);
// hide the doom window by default
::ShowWindow( win32.hWnd, SW_HIDE );
}
}
extern void Map_VerifyCurrentMap(const char *map);
void RadiantSync( const char *mapName, const idVec3 &viewOrg, const idAngles &viewAngles ) {
if ( g_DoomInstance == NULL ) {
RadiantInit();
}
if ( g_DoomInstance ) {
idStr osPath;
osPath = fileSystem->RelativePathToOSPath( mapName );
Map_VerifyCurrentMap( osPath );
idAngles flip = viewAngles;
flip.pitch = -flip.pitch;
g_pParentWnd->GetCamera()->SetView( viewOrg, flip );
g_pParentWnd->SetFocus();
Sys_UpdateWindows( W_ALL );
g_pParentWnd->RoutineProcessing();
}
}
void RadiantRun( void ) {
static bool exceptionErr = false;
int show = ::IsWindowVisible(win32.hWnd);
try {
if (!exceptionErr && !show) {
//qglPushAttrib(GL_ALL_ATTRIB_BITS);
qglDepthMask(true);
theApp.Run();
//qglPopAttrib();
//qwglMakeCurrent(0, 0);
if (win32.hDC != NULL && win32.hGLRC != NULL)
qwglMakeCurrent(win32.hDC, win32.hGLRC);
}
}
catch( idException &ex ) {
::MessageBox(NULL, ex.error, "Exception error", MB_OK);
RadiantShutdown();
}
}
/////////////////////////////////////////////////////////////////////////////
// CRadiantApp initialization
HINSTANCE g_hOpenGL32 = NULL;
HINSTANCE g_hOpenGL = NULL;
bool g_bBuildList = false;
BOOL CRadiantApp::InitInstance()
{
//g_hOpenGL32 = ::LoadLibrary("opengl32.dll");
// AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
//AfxEnableMemoryTracking(FALSE);
#ifdef _AFXDLL
//Enable3dControls(); // Call this when using MFC in a shared DLL
#else
//Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// If there's a .INI file in the directory use it instead of registry
char RadiantPath[_MAX_PATH];
GetModuleFileName( NULL, RadiantPath, _MAX_PATH );
// search for exe
CFileFind Finder;
Finder.FindFile( RadiantPath );
Finder.FindNextFile();
// extract root
CString Root = Finder.GetRoot();
// build root\*.ini
CString IniPath = Root + "\\REGISTRY.INI";
// search for ini file
Finder.FindNextFile();
if (Finder.FindFile( IniPath ))
{
Finder.FindNextFile();
// use the .ini file instead of the registry
free((void*)m_pszProfileName);
m_pszProfileName=_tcsdup(_T(Finder.GetFilePath()));
// look for the registry key for void* buffers storage ( these can't go into .INI files )
int i=0;
CString key;
HKEY hkResult;
DWORD dwDisp;
DWORD type;
char iBuf[3];
do
{
sprintf( iBuf, "%d", i );
key = "Software\\Q3Radiant\\IniPrefs" + CString(iBuf);
// does this key exists ?
if ( RegOpenKeyEx( HKEY_CURRENT_USER, key, 0, KEY_ALL_ACCESS, &hkResult ) != ERROR_SUCCESS )
{
// this key doesn't exist, so it's the one we'll use
strcpy( g_qeglobals.use_ini_registry, key.GetBuffer(0) );
RegCreateKeyEx( HKEY_CURRENT_USER, key, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkResult, &dwDisp );
RegSetValueEx( hkResult, "RadiantName", 0, REG_SZ, reinterpret_cast(RadiantPath), strlen( RadiantPath )+1 );
RegCloseKey( hkResult );
break;
}
else
{
char RadiantAux[ _MAX_PATH ];
unsigned long size = _MAX_PATH;
// the key exists, is it the one we are looking for ?
RegQueryValueEx( hkResult, "RadiantName", 0, &type, reinterpret_cast(RadiantAux), &size );
RegCloseKey( hkResult );
if ( !strcmp( RadiantAux, RadiantPath ) )
{
// got it !
strcpy( g_qeglobals.use_ini_registry, key.GetBuffer(0) );
break;
}
}
i++;
} while (1);
g_qeglobals.use_ini = true;
}
else
{
// Change the registry key under which our settings are stored.
SetRegistryKey( EDITOR_REGISTRY_KEY );
g_qeglobals.use_ini = false;
}
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
// CMultiDocTemplate* pDocTemplate;
// pDocTemplate = new CMultiDocTemplate(
// IDR_RADIANTYPE,
// RUNTIME_CLASS(CRadiantDoc),
// RUNTIME_CLASS(CMainFrame), // custom MDI child frame
// RUNTIME_CLASS(CRadiantView));
// AddDocTemplate(pDocTemplate);
// create main MDI Frame window
g_PrefsDlg.LoadPrefs();
qglEnableClientState( GL_VERTEX_ARRAY );
CString strTemp = m_lpCmdLine;
strTemp.MakeLower();
if (strTemp.Find("builddefs") >= 0) {
g_bBuildList = true;
}
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MENU_QUAKE3)) {
return FALSE;
}
if (pMainFrame->m_hAccelTable) {
::DestroyAcceleratorTable(pMainFrame->m_hAccelTable);
}
pMainFrame->LoadAccelTable(MAKEINTRESOURCE(IDR_MINIACCEL));
m_pMainWnd = pMainFrame;
// The main window has been initialized, so show and update it.
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CRadiantApp commands
int CRadiantApp::ExitInstance()
{
common->Shutdown();
g_pParentWnd = NULL;
int ret = CWinApp::ExitInstance();
ExitProcess(0);
return ret;
}
BOOL CRadiantApp::OnIdle(LONG lCount) {
if (g_pParentWnd) {
g_pParentWnd->RoutineProcessing();
}
return FALSE;
//return CWinApp::OnIdle(lCount);
}
void CRadiantApp::OnHelp()
{
ShellExecute(m_pMainWnd->GetSafeHwnd(), "open", "http://www.idDevNet.com", NULL, NULL, SW_SHOW);
}
int CRadiantApp::Run( void )
{
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
#if _MSC_VER >= 1300
MSG *msg = AfxGetCurrentMessage(); // TODO Robert fix me!!
#else
MSG *msg = &m_msgCur;
#endif
// phase1: check to see if we can do idle work
while (bIdle && !::PeekMessage(msg, NULL, NULL, NULL, PM_NOREMOVE)) {
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++)) {
bIdle = FALSE; // assume "no idle" state
}
}
// phase2: pump messages while available
do {
// pump message, but quit on WM_QUIT
if (!PumpMessage()) {
return ExitInstance();
}
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(msg)) {
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(msg, NULL, NULL, NULL, PM_NOREMOVE));
return 0;
}
/*
=============================================================
REGISTRY INFO
=============================================================
*/
bool SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize)
{
SetCvarBinary(pszName, pvBuf, lSize);
common->WriteFlaggedCVarsToFile( "editor.cfg", CVAR_TOOL, "sett" );
return true;
}
bool LoadRegistryInfo(const char *pszName, void *pvBuf, long *plSize)
{
return GetCvarBinary(pszName, pvBuf, *plSize);
}
bool SaveWindowState(HWND hWnd, const char *pszName)
{
RECT rc;
GetWindowRect(hWnd, &rc);
if (hWnd != g_pParentWnd->GetSafeHwnd()) {
if (::GetParent(hWnd) != g_pParentWnd->GetSafeHwnd()) {
::SetParent(hWnd, g_pParentWnd->GetSafeHwnd());
}
MapWindowPoints(NULL, g_pParentWnd->GetSafeHwnd(), (POINT *)&rc, 2);
}
return SaveRegistryInfo(pszName, &rc, sizeof(rc));
}
bool LoadWindowState(HWND hWnd, const char *pszName)
{
RECT rc;
LONG lSize = sizeof(rc);
if (LoadRegistryInfo(pszName, &rc, &lSize))
{
if (rc.left < 0)
rc.left = 0;
if (rc.top < 0)
rc.top = 0;
if (rc.right < rc.left + 16)
rc.right = rc.left + 16;
if (rc.bottom < rc.top + 16)
rc.bottom = rc.top + 16;
MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
return true;
}
return false;
}
/*
===============================================================
STATUS WINDOW
===============================================================
*/
void Sys_UpdateStatusBar( void )
{
extern int g_numbrushes, g_numentities;
char numbrushbuffer[100] = "";
sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
Sys_Status( numbrushbuffer, 2 );
}
void Sys_Status(const char *psz, int part )
{
if ( part < 0 ) {
common->Printf("%s", psz);
part = 0;
}
g_pParentWnd->SetStatusText(part, psz);
}