Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
244 chris 1
//#define SEXY_TRACING_ENABLED
2
//#define SEXY_PERF_ENABLED
3
//#define SEXY_MEMTRACE
4
 
5
#include "SexyAppBase.h"
6
#include "SEHCatcher.h"
7
#include "WidgetManager.h"
8
#include "Widget.h"
9
#include "Debug.h"
10
#include "KeyCodes.h"
11
#include "DDInterface.h"
12
#include "D3DInterface.h"
13
#include "D3DTester.h"
14
#include "DDImage.h"
15
#include "MemoryImage.h"
16
#include "HTTPTransfer.h"
17
#include "Dialog.h"
18
#include "..\ImageLib\ImageLib.h"
19
#include "DSoundManager.h"
20
#include "DSoundInstance.h"
21
#include "Rect.h"
22
#include "FModMusicInterface.h"
23
#include "PropertiesParser.h"
24
#include "PerfTimer.h"
25
#include "MTRand.h"
26
#include "ModVal.h"
27
#include <process.h>
28
#include <direct.h>
29
#include <fstream>
30
#include <time.h>
31
#include <math.h>
32
#include <regstr.h>
33
#include "SysFont.h"
34
#include "ResourceManager.h"
35
#include "BassMusicInterface.h"
36
#include "AutoCrit.h"
37
#include "Debug.h"
38
#include "../PakLib/PakInterface.h"
39
#include <string>
40
#include <shlobj.h>
41
 
42
#include "memmgr.h"
43
 
44
using namespace Sexy;
45
 
46
const int DEMO_FILE_ID = 0x42BEEF78;
47
const int DEMO_VERSION = 2;
48
 
49
SexyAppBase* Sexy::gSexyAppBase = NULL;
50
 
51
SEHCatcher Sexy::gSEHCatcher;
52
 
53
HMODULE gDDrawDLL = NULL;
54
HMODULE gDSoundDLL = NULL;
55
HMODULE gVersionDLL = NULL;
56
 
57
//typedef struct { UINT cbSize; DWORD dwTime; } LASTINPUTINFO;
58
typedef BOOL (WINAPI*GetLastInputInfoFunc)(LASTINPUTINFO *plii);
59
GetLastInputInfoFunc gGetLastInputInfoFunc = NULL;
60
static bool gScreenSaverActive = false;
61
 
62
#ifndef SPI_GETSCREENSAVERRUNNING
63
#define SPI_GETSCREENSAVERRUNNING 114
64
#endif
65
 
66
 
67
//HotSpot: 11 4
68
//Size: 32 32
69
unsigned char gFingerCursorData[] = {
70
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
71
        0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc3,
72
        0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff,
73
        0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xfc, 0x40, 0x01, 0xff, 0xfc, 0x00, 0x01, 0xff,
74
        0xfc, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01,
75
        0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0,
76
        0x03, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff,
77
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
78
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
80
        0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
81
        0x18, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x60, 0x00, 0x00, 0x1b, 0x68, 0x00,
82
        0x00, 0x1b, 0x6c, 0x00, 0x01, 0x9f, 0xec, 0x00, 0x01, 0xdf, 0xfc, 0x00, 0x00, 0xdf, 0xfc,
83
        0x00, 0x00, 0x5f, 0xfc, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x3f,
84
        0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00,
85
        0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87
        0x00
88
};
89
 
90
//HotSpot: 15 10
91
//Size: 32 32
92
unsigned char gDraggingCursorData[] = {
93
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
94
        0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xe0,
95
        0x01, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff,
96
        0xe0, 0x00, 0xff, 0xfe, 0x60, 0x00, 0xff, 0xfc, 0x20, 0x00, 0xff, 0xfc, 0x00, 0x00, 0xff,
97
        0xfe, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x80, 0x00,
98
        0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xf0,
99
        0x03, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff,
100
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
103
        0x80, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x0d, 0xb0, 0x00, 0x00, 0x0d, 0xb6, 0x00, 0x00,
104
        0x0d, 0xb6, 0x00, 0x00, 0x0d, 0xb6, 0x00, 0x00, 0x0d, 0xb6, 0x00, 0x00, 0x0d, 0xb6, 0x00,
105
        0x01, 0x8d, 0xb6, 0x00, 0x01, 0xcf, 0xfe, 0x00, 0x00, 0xef, 0xfe, 0x00, 0x00, 0xff, 0xfe,
106
        0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f,
107
        0xfc, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00,
108
        0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110
        0x00
111
};
112
static DDImage* gFPSImage = NULL;
113
 
114
//////////////////////////////////////////////////////////////////////////
115
 
116
typedef HRESULT (WINAPI *SHGetFolderPathFunc)(HWND, int, HANDLE, DWORD, LPTSTR);
117
void* GetSHGetFolderPath(const char* theDLL, HMODULE* theMod)
118
{
119
        HMODULE aMod = LoadLibrary(theDLL);
120
        SHGetFolderPathFunc aFunc = NULL;
121
 
122
        if (aMod != NULL)
123
        {
124
                *((void**)&aFunc) = (void*)GetProcAddress(aMod, "SHGetFolderPathA");
125
                if (aFunc == NULL)
126
                {
127
                        FreeLibrary(aMod);
128
                        aMod = NULL;
129
                }
130
        }      
131
 
132
        *theMod = aMod;
133
        return aFunc;
134
}
135
 
136
//////////////////////////////////////////////////////////////////////////
137
 
138
SexyAppBase::SexyAppBase()
139
{
140
        gSexyAppBase = this;
141
 
142
        gVersionDLL = LoadLibraryA("version.dll");
143
        gDDrawDLL = LoadLibraryA("ddraw.dll");
144
        gDSoundDLL = LoadLibraryA("dsound.dll");
145
        gGetLastInputInfoFunc = (GetLastInputInfoFunc) GetProcAddress(GetModuleHandleA("user32.dll"),"GetLastInputInfo");
146
 
147
        ImageLib::InitJPEG2000();
148
 
149
        mMutex = NULL;
150
        mNotifyGameMessage = 0;
151
 
152
#ifdef _DEBUG
153
        mOnlyAllowOneCopyToRun = false;
154
#else
155
        mOnlyAllowOneCopyToRun = true;
156
#endif
157
 
158
        // Extract product version
159
        char aPath[_MAX_PATH];
160
        GetModuleFileNameA(NULL, aPath, 256);
161
        mProductVersion = GetProductVersion(aPath);    
162
        mChangeDirTo = GetFileDir(aPath);
163
 
164
        mNoDefer = false;      
165
        mFullScreenPageFlip = true; // should we page flip in fullscreen?
166
        mTimeLoaded = GetTickCount();
167
        mSEHOccured = false;
168
        mProdName = "Product";
169
        mTitle = _S("SexyApp");
170
        mShutdown = false;
171
        mExitToTop = false;
172
        mWidth = 640;
173
        mHeight = 480;
174
        mFullscreenBits = 16;
175
        mIsWindowed = true;
176
        mIsPhysWindowed = true;
177
        mFullScreenWindow = false;
178
        mPreferredX = -1;
179
        mPreferredY = -1;
180
        mIsScreenSaver = false;
181
        mAllowMonitorPowersave = true;
182
        mHWnd = NULL;
183
        mDDInterface = NULL;   
184
        mMusicInterface = NULL;
185
        mInvisHWnd = NULL;
186
        mFrameTime = 10;
187
        mNonDrawCount = 0;
188
        mDrawCount = 0;
189
        mSleepCount = 0;
190
        mUpdateCount = 0;      
191
        mUpdateAppState = 0;
192
        mUpdateAppDepth = 0;
193
        mPendingUpdatesAcc = 0.0;
194
        mUpdateFTimeAcc = 0.0;
195
        mHasPendingDraw = true;
196
        mIsDrawing = false;
197
        mLastDrawWasEmpty = false;     
198
        mLastTimeCheck = 0;
199
        mUpdateMultiplier = 1;
200
        mPaused = false;
201
        mFastForwardToUpdateNum = 0;
202
        mFastForwardToMarker = false;
203
        mFastForwardStep = false;
204
        mSoundManager = NULL;
205
        mCursorNum = CURSOR_POINTER;           
206
        mMouseIn = false;
207
        mRunning = false;
208
        mActive = true;
209
        mProcessInTimer = false;
210
        mMinimized = false;    
211
        mPhysMinimized = false;
212
        mIsDisabled = false;
213
        mLoaded = false;       
214
        mYieldMainThread = false;
215
        mLoadingFailed = false;
216
        mLoadingThreadStarted = false;
217
        mAutoStartLoadingThread = true;
218
        mLoadingThreadCompleted = false;
219
        mCursorThreadRunning = false;
220
        mNumLoadingThreadTasks = 0;
221
        mCompletedLoadingThreadTasks = 0;      
222
        mLastDrawTick = timeGetTime();
223
        mNextDrawTick = timeGetTime();
224
        mSysCursor = true;     
225
        mForceFullscreen = false;
226
        mForceWindowed = false;
227
        mHasFocus = true;                      
228
        mCustomCursorsEnabled = false; 
229
        mCustomCursorDirty = false;
230
        mOverrideCursor = NULL;
231
        mIsOpeningURL = false;         
232
        mInitialized = false;  
233
        mLastShutdownWasGraceful = true;       
234
        mReadFromRegistry = false;     
235
        mCmdLineParsed = false;
236
        mSkipSignatureChecks = false;  
237
        mCtrlDown = false;
238
        mAltDown = false;
239
        mStepMode = 0;
240
        mCleanupSharedImages = false;
241
        mStandardWordWrap = true;
242
        mbAllowExtendedChars = true;
243
        mEnableMaximizeButton = false;
244
 
245
        mMusicVolume = 0.85;
246
        mSfxVolume = 0.85;
247
        mDemoMusicVolume = mDemoSfxVolume = 0.0;
248
        mMuteCount = 0;
249
        mAutoMuteCount = 0;
250
        mDemoMute = false;
251
        mMuteOnLostFocus = true;
252
        mCurHandleNum = 0;
253
        mFPSTime = 0;
254
        mFPSStartTick = GetTickCount();
255
        mFPSFlipCount = 0;
256
        mFPSCount = 0;
257
        mFPSDirtyCount = 0;
258
        mShowFPS = false;
259
        mShowFPSMode = FPS_ShowFPS;
260
        mDrawTime = 0;
261
        mScreenBltTime = 0;
262
        mAlphaDisabled = false;
263
        mDebugKeysEnabled = false;
264
        mOldWndProc = 0;
265
        mNoSoundNeeded = false;
266
        mWantFMod = false;
267
 
268
        mSyncRefreshRate = 100;
269
        mVSyncUpdates = false;
270
        mVSyncBroken = false;
271
        mVSyncBrokenCount = 0;
272
        mVSyncBrokenTestStartTick = 0;
273
        mVSyncBrokenTestUpdates = 0;
274
        mWaitForVSync = false;
275
        mSoftVSyncWait = true;
276
        mUserChanged3DSetting = false;
277
        mAutoEnable3D = false;
278
        mTest3D = false;
279
        mMinVidMemory3D = 6;
280
        mRecommendedVidMemory3D = 14;
281
        mRelaxUpdateBacklogCount = 0;
282
        mWidescreenAware = false;
283
        mEnableWindowAspect = false;
284
        mWindowAspect.Set(4, 3);
285
        mIsWideWindow = false;
286
 
287
        int i;
288
 
289
        for (i = 0; i < NUM_CURSORS; i++)
290
                mCursorImages[i] = NULL;       
291
 
292
        for (i = 0; i < 256; i++)
293
                mAdd8BitMaxTable[i] = i;
294
 
295
        for (i = 256; i < 512; i++)
296
                mAdd8BitMaxTable[i] = 255;
297
 
298
        // Set default strings.  Init could read in overrides from partner.xml
299
        SetString("DIALOG_BUTTON_OK",           L"OK");
300
        SetString("DIALOG_BUTTON_CANCEL",       L"CANCEL");
301
 
302
        SetString("UPDATE_CHECK_TITLE",         L"Update Check");
303
        SetString("UPDATE_CHECK_BODY",          L"Checking if there are any updates available for this product ...");
304
 
305
        SetString("UP_TO_DATE_TITLE",           L"Up to Date");
306
        SetString("UP_TO_DATE_BODY",            L"There are no updates available for this product at this time.");
307
        SetString("NEW_VERSION_TITLE",          L"New Version");
308
        SetString("NEW_VERSION_BODY",           L"There is an update available for this product.  Would you like to visit the web site to download it?");
309
 
310
 
311
        mDemoPrefix = "sexyapp";
312
        mDemoFileName = mDemoPrefix + ".dmo";
313
        mPlayingDemoBuffer = false;
314
        mManualShutdown = false;
315
        mRecordingDemoBuffer = false;
316
        mLastDemoMouseX = 0;
317
        mLastDemoMouseY = 0;
318
        mLastDemoUpdateCnt = 0;
319
        mDemoNeedsCommand = true;
320
        mDemoLoadingComplete = false;
321
        mDemoLength = 0;
322
        mDemoCmdNum = 0;
323
        mDemoCmdOrder = -1; // Means we haven't processed any demo commands yet
324
        mDemoCmdBitPos = 0;
325
 
326
        mWidgetManager = new WidgetManager(this);
327
        mResourceManager = new ResourceManager(this);
328
 
329
        mPrimaryThreadId = 0;
330
 
331
        if (GetSystemMetrics(86)) // check for tablet pc
332
        {
333
                mTabletPC = true;
334
                mFullScreenPageFlip = false; // so that tablet keyboard can show up
335
        }
336
        else
337
                mTabletPC = false;     
338
 
339
        gSEHCatcher.mApp = this;       
340
 
341
        //std::wifstream stringsFile(_wfopen(L".\\properties\\fstrings", L"rb"));
342
        //
343
        //if(!stringsFile)
344
        //{
345
        //      MessageBox(NULL, "file missing: 'install-folder\\properties\\fstrings' Please re-install", "FATAL ERROR", MB_OK);
346
        //      DoExit(1);
347
        //}
348
        //std::getline(stringsFile, mString_HardwareAccelSwitchedOn);
349
        //std::getline(stringsFile, mString_HardwareAccelConfirm);
350
        //std::getline(stringsFile, mString_HardwareAccelNotWorking);
351
        //std::getline(stringsFile, mString_SetColorDepth);
352
        //std::getline(stringsFile, mString_FailedInitDirectDrawColon);
353
        //std::getline(stringsFile, mString_UnableOpenProperties);
354
        //std::getline(stringsFile, mString_SigCheckFailed);
355
        //std::getline(stringsFile, mString_InvalidCommandLineParam);
356
        //std::getline(stringsFile, mString_RequiresDirectX);
357
        //std::getline(stringsFile, mString_YouNeedDirectX);
358
        //std::getline(stringsFile, mString_FailedInitDirectDraw);
359
        //std::getline(stringsFile, mString_FatalError);
360
        //std::getline(stringsFile, mString_UnexpectedErrorOccured);
361
        //std::getline(stringsFile, mString_PleaseHelpBy);
362
        //std::getline(stringsFile, mString_FailedConnectPopcap);
363
        //stringsFile.close();
364
}
365
 
366
SexyAppBase::~SexyAppBase()
367
{
368
        Shutdown();
369
 
370
        // Check if we should write the current 3d setting
371
        bool showedMsgBox = false;
372
        if (mUserChanged3DSetting)
373
        {
374
                bool writeToRegistry = true;
375
                bool is3D = false;
376
                bool is3DOptionSet = RegistryReadBoolean("Is3D", &is3D);
377
                if(!is3DOptionSet) // should we write the option?
378
                {
379
                        if(!Is3DAccelerationRecommended()) // may need to prompt user if he wants to keep 3d acceleration on
380
                        {
381
                                if (Is3DAccelerated())
382
                                {
383
                                        showedMsgBox = true;
384
                                        int aResult = MessageBox(NULL,
385
                                                                        GetString("HARDWARE_ACCEL_SWITCHED_ON",
386
                                                                                                                        _S("Hardware Acceleration was switched on during this session.\r\n")
387
                                                                                                                        _S("If this resulted in slower performance, it should be switched off.\r\n")
388
                                                                                                                        _S("Would you like to keep Hardware Acceleration switched on?")).c_str(),
389
                                                                        (StringToSexyString(mCompanyName) + _S(" ") +
390
                                                                         GetString("HARDWARE_ACCEL_CONFIRMATION", _S("Hardware Acceleration Confirmation"))).c_str(),
391
                                                                        MB_YESNO | MB_ICONQUESTION);
392
 
393
                                        mDDInterface->mIs3D = aResult == IDYES ? true : false;
394
                                        if (aResult!=IDYES)
395
                                                writeToRegistry = false;
396
                                }
397
                                else
398
                                        writeToRegistry = false;
399
                        }
400
                }
401
 
402
                if (writeToRegistry)
403
                        RegistryWriteBoolean("Is3D", mDDInterface->mIs3D);
404
        }
405
 
406
        extern bool gD3DInterfacePreDrawError;
407
        if (!showedMsgBox && gD3DInterfacePreDrawError && !IsScreenSaver())
408
        {
409
                int aResult = MessageBox(NULL,
410
                                                GetString("HARDWARE_ACCEL_NOT_WORKING",
411
                                                                        _S("Hardware Acceleration may not have been working correctly during this session.\r\n")
412
                                                                        _S("If you noticed graphics problems, you may want to turn off Hardware Acceleration.\r\n")
413
                                                                        _S("Would you like to keep Hardware Acceleration switched on?")).c_str(),
414
                                                (StringToSexyString(mCompanyName) + _S(" ") +
415
                                                 GetString("HARDWARE_ACCEL_CONFIRMATION", _S("Hardware Acceleration Confirmation"))).c_str(),
416
                                                MB_YESNO | MB_ICONQUESTION);
417
 
418
                if (aResult==IDNO)
419
                        RegistryWriteBoolean("Is3D", false);
420
        }
421
 
422
 
423
        DialogMap::iterator aDialogItr = mDialogMap.begin();
424
        while (aDialogItr != mDialogMap.end())
425
        {
426
                mWidgetManager->RemoveWidget(aDialogItr->second);
427
                delete aDialogItr->second;
428
                ++aDialogItr;
429
        }
430
        mDialogMap.clear();
431
        mDialogList.clear();
432
 
433
        if (mInvisHWnd != NULL)
434
        {
435
                HWND aWindow = mInvisHWnd;
436
                mInvisHWnd = NULL;
437
                SetWindowLong(aWindow, GWL_USERDATA, NULL);
438
                DestroyWindow(aWindow);
439
        }      
440
 
441
        delete mWidgetManager; 
442
        delete mResourceManager;
443
        delete gFPSImage;
444
        gFPSImage = NULL;
445
 
446
        SharedImageMap::iterator aSharedImageItr = mSharedImageMap.begin();
447
        while (aSharedImageItr != mSharedImageMap.end())
448
        {
449
                SharedImage* aSharedImage = &aSharedImageItr->second;
450
                DBG_ASSERTE(aSharedImage->mRefCount == 0);             
451
                delete aSharedImage->mImage;
452
                mSharedImageMap.erase(aSharedImageItr++);              
453
        }
454
 
455
        delete mDDInterface;
456
        delete mMusicInterface;
457
        delete mSoundManager;                  
458
 
459
        if (mHWnd != NULL)
460
        {
461
                HWND aWindow = mHWnd;
462
                mHWnd = NULL;
463
 
464
                SetWindowLong(aWindow, GWL_USERDATA, NULL);
465
 
466
                /*char aStr[256];
467
                sprintf(aStr, "HWND: %d\r\n", aWindow);
468
                OutputDebugString(aStr);*/
469
 
470
                DestroyWindow(aWindow);
471
        }      
472
 
473
        WaitForLoadingThread();
474
 
475
        DestroyCursor(mHandCursor);
476
        DestroyCursor(mDraggingCursor);                
477
 
478
        gSexyAppBase = NULL;
479
 
480
        WriteDemoBuffer();
481
 
482
        if (mMutex != NULL)
483
                ::CloseHandle(mMutex); 
484
 
485
        FreeLibrary(gDDrawDLL);
486
        FreeLibrary(gDSoundDLL);
487
        FreeLibrary(gVersionDLL);
488
}
489
 
490
static BOOL CALLBACK ChangeDisplayWindowEnumProc(HWND hwnd, LPARAM lParam)
491
{
492
        typedef std::map<HWND,RECT> WindowMap;
493
        static WindowMap aMap;
494
 
495
        if (lParam==0 && aMap.find(hwnd)==aMap.end()) // record
496
        {
497
                RECT aRect;
498
                if (!IsIconic(hwnd) && IsWindowVisible(hwnd))
499
                {
500
                        if (GetWindowRect(hwnd,&aRect))
501
                        {
502
//                              char aBuf[4096];
503
//                              GetWindowText(hwnd,aBuf,4000);
504
//                              DWORD aProcessId = 0;
505
//                              GetWindowThreadProcessId(hwnd,&aProcessId);
506
//                              SEXY_TRACE(StrFormat("%s %d - %d %d %d %d",aBuf,aProcessId,aRect.left,aRect.top,aRect.right,aRect.bottom).c_str());
507
                                aMap[hwnd] = aRect;
508
                        }
509
                }
510
        }
511
        else
512
        {
513
                WindowMap::iterator anItr = aMap.find(hwnd);
514
                if (anItr != aMap.end())
515
                {
516
                        RECT &r = anItr->second;
517
                        MoveWindow(hwnd,r.left,r.top,abs(r.right-r.left),abs(r.bottom-r.top),TRUE);
518
                }
519
        }
520
        return TRUE;
521
}
522
 
523
void SexyAppBase::ClearUpdateBacklog(bool relaxForASecond)
524
{
525
        mLastTimeCheck = timeGetTime();
526
        mUpdateFTimeAcc = 0.0;
527
 
528
        if (relaxForASecond)
529
                mRelaxUpdateBacklogCount = 1000;
530
}
531
 
532
bool SexyAppBase::IsScreenSaver()
533
{
534
        return mIsScreenSaver;
535
}
536
 
537
bool SexyAppBase::AppCanRestore()
538
{
539
        return !mIsDisabled;
540
}
541
 
542
bool SexyAppBase::ReadDemoBuffer(std::string &theError)
543
{
544
        FILE* aFP = fopen(mDemoFileName.c_str(), "rb");
545
 
546
        if (aFP == NULL)
547
        {
548
                theError = "Demo file not found: " + mDemoFileName;
549
                return false;
550
        }
551
 
552
        struct AutoFile { FILE *f; AutoFile(FILE *file) : f(file) {} ~AutoFile() { fclose(f); } };
553
        AutoFile aCloseFile(aFP);
554
 
555
        ulong aFileID;
556
        fread(&aFileID, 4, 1, aFP);
557
 
558
        DBG_ASSERTE(aFileID == DEMO_FILE_ID);
559
        if (aFileID != DEMO_FILE_ID)
560
        {
561
                theError = "Invalid demo file.";
562
                return false;
563
        }
564
 
565
 
566
        ulong aVersion;
567
        fread(&aVersion, 4, 1, aFP);
568
 
569
        fread(&mRandSeed, 4, 1, aFP);
570
        SRand(mRandSeed);
571
 
572
        ushort aStrLen = 4;
573
        fread(&aStrLen, 2, 1, aFP);
574
        if (aStrLen > 255)
575
                aStrLen = 255;
576
        char aStr[256];
577
        fread(aStr, 1, aStrLen, aFP);
578
        aStr[aStrLen] = '\0';
579
 
580
        DBG_ASSERTE(mProductVersion == aStr);
581
        if (mProductVersion != aStr)
582
        {
583
                theError = "This demo file appears to be for '" + std::string(aStr) + "'";
584
                return false;
585
        }
586
 
587
        int aFilePos = ftell(aFP);
588
        fseek(aFP, 0, SEEK_END);
589
        int aBytesLeft = ftell(aFP) - aFilePos;
590
        fseek(aFP, aFilePos, SEEK_SET);
591
 
592
        uchar* aBuffer;
593
        // read marker list
594
        if (aVersion >= 2)
595
        {
596
                int aSize;
597
                fread(&aSize, 4, 1, aFP);
598
                aBytesLeft -= 4;
599
 
600
                if (aSize >= aBytesLeft)
601
                {
602
                        theError = "Invalid demo file.";
603
                        return false;
604
                }
605
 
606
                Buffer aMarkerBuffer;
607
 
608
                aBuffer = new uchar[aSize];
609
                fread(aBuffer, 1, aSize, aFP);
610
                aMarkerBuffer.WriteBytes(aBuffer, aSize);
611
                aMarkerBuffer.SeekFront();
612
 
613
                int aNumItems = aMarkerBuffer.ReadLong();
614
                int i;
615
                for (i=0; i<aNumItems && !aMarkerBuffer.AtEnd(); i++)
616
                {
617
                        mDemoMarkerList.push_back(DemoMarker());
618
                        DemoMarker &aMarker = mDemoMarkerList.back();
619
                        aMarker.first = aMarkerBuffer.ReadString();
620
                        aMarker.second = aMarkerBuffer.ReadLong();
621
                }
622
 
623
                if (i!=aNumItems)
624
                {
625
                        theError = "Invalid demo file.";
626
                        return false;
627
                }
628
 
629
                aBytesLeft -= aSize;
630
 
631
                delete [] aBuffer;                     
632
        }
633
 
634
        // Read demo commands
635
        fread(&mDemoLength, 4, 1, aFP);
636
        aBytesLeft -= 4;
637
 
638
        if (aBytesLeft <= 0)
639
        {
640
                theError = "Invalid demo file.";
641
                return false;
642
        }
643
 
644
 
645
        aBuffer = new uchar[aBytesLeft];
646
        fread(aBuffer, 1, aBytesLeft, aFP);            
647
 
648
        mDemoBuffer.WriteBytes(aBuffer, aBytesLeft);
649
        mDemoBuffer.SeekFront();
650
 
651
        delete [] aBuffer;
652
        return true;
653
}
654
 
655
void SexyAppBase::WriteDemoBuffer()
656
{
657
        if (mRecordingDemoBuffer)
658
        {
659
                FILE* aFP = fopen(mDemoFileName.c_str(), "w+b");
660
 
661
                if (aFP != NULL)
662
                {
663
                        ulong aFileID = DEMO_FILE_ID;
664
                        fwrite(&aFileID, 4, 1, aFP);           
665
 
666
                        ulong aVersion = DEMO_VERSION;
667
                        fwrite(&aVersion, 4, 1, aFP);
668
 
669
                        fwrite(&mRandSeed, 4, 1, aFP);
670
 
671
                        ushort aStrLen = mProductVersion.length();
672
                        fwrite(&aStrLen, 2, 1, aFP);           
673
                        fwrite(mProductVersion.c_str(), 1, mProductVersion.length(), aFP);
674
 
675
                        Buffer aMarkerBuffer;
676
                        aMarkerBuffer.WriteLong(mDemoMarkerList.size());
677
                        for (DemoMarkerList::iterator aMarkerItr = mDemoMarkerList.begin(); aMarkerItr != mDemoMarkerList.end(); ++aMarkerItr)
678
                        {
679
                                aMarkerBuffer.WriteString(aMarkerItr->first);
680
                                aMarkerBuffer.WriteLong(aMarkerItr->second);
681
                        }
682
                        int aMarkerBufferSize = aMarkerBuffer.GetDataLen();
683
                        fwrite(&aMarkerBufferSize, 4, 1, aFP);
684
                        fwrite(aMarkerBuffer.GetDataPtr(), aMarkerBufferSize, 1, aFP);
685
 
686
                        ulong aDemoLength = mUpdateCount;
687
                        fwrite(&aDemoLength, 4, 1, aFP);
688
 
689
                        fwrite(mDemoBuffer.GetDataPtr(), 1, mDemoBuffer.GetDataLen(), aFP);
690
                        fclose(aFP);
691
                }              
692
        }
693
}
694
 
695
void SexyAppBase::DemoSyncBuffer(Buffer* theBuffer)
696
{
697
        if (mPlayingDemoBuffer)
698
        {
699
                if (mManualShutdown)
700
                        return;
701
 
702
                PrepareDemoCommand(true);
703
                mDemoNeedsCommand = true;
704
 
705
                DBG_ASSERTE(!mDemoIsShortCmd);
706
                DBG_ASSERTE(mDemoCmdNum == DEMO_SYNC);
707
 
708
                ulong aLen = mDemoBuffer.ReadLong();
709
 
710
                theBuffer->Clear();
711
                for (int i = 0; i < (int) aLen; i++)
712
                        theBuffer->WriteByte(mDemoBuffer.ReadByte());          
713
        }
714
        else if (mRecordingDemoBuffer)
715
        {
716
                WriteDemoTimingBlock();
717
                mDemoBuffer.WriteNumBits(0, 1);
718
                mDemoBuffer.WriteNumBits(DEMO_SYNC, 5);        
719
                mDemoBuffer.WriteLong(theBuffer->GetDataLen());
720
                mDemoBuffer.WriteBytes((uchar*) theBuffer->GetDataPtr(), theBuffer->GetDataLen());
721
        }
722
}
723
 
724
void SexyAppBase::DemoSyncString(std::string* theString)
725
{
726
        Buffer aBuffer;
727
        aBuffer.WriteString(*theString);
728
        DemoSyncBuffer(&aBuffer);
729
        *theString = aBuffer.ReadString();
730
}
731
 
732
void SexyAppBase::DemoSyncInt(int* theInt)
733
{
734
        Buffer aBuffer;
735
        aBuffer.WriteLong(*theInt);
736
        DemoSyncBuffer(&aBuffer);
737
        *theInt = aBuffer.ReadLong();
738
}
739
 
740
void SexyAppBase::DemoSyncBool(bool* theBool)
741
{
742
        Buffer aBuffer;
743
        aBuffer.WriteBoolean(*theBool);
744
        DemoSyncBuffer(&aBuffer);
745
        *theBool = aBuffer.ReadBoolean();
746
}
747
 
748
void SexyAppBase::DemoAssertStringEqual(const std::string& theString)
749
{
750
        if (mPlayingDemoBuffer)
751
        {
752
                if (mManualShutdown)
753
                        return;
754
 
755
                PrepareDemoCommand(true);
756
                mDemoNeedsCommand = true;
757
 
758
                DBG_ASSERTE(!mDemoIsShortCmd);
759
                DBG_ASSERTE(mDemoCmdNum == DEMO_ASSERT_STRING_EQUAL);
760
 
761
                std::string aString = mDemoBuffer.ReadString();
762
                DBG_ASSERTE(aString == theString);
763
        }
764
        else if (mRecordingDemoBuffer)
765
        {
766
                WriteDemoTimingBlock();
767
                mDemoBuffer.WriteNumBits(0, 1);
768
                mDemoBuffer.WriteNumBits(DEMO_ASSERT_STRING_EQUAL, 5);                         
769
                mDemoBuffer.WriteString(theString);
770
        }
771
}
772
 
773
void SexyAppBase::DemoAddMarker(const std::string& theString)
774
{
775
        if (mPlayingDemoBuffer)
776
        {
777
                mFastForwardToMarker = false;
778
        }
779
        else if (mRecordingDemoBuffer)
780
        {
781
                mDemoMarkerList.push_back(DemoMarker(theString,mUpdateCount));
782
        }
783
}
784
 
785
void SexyAppBase::DemoRegisterHandle(HANDLE theHandle)
786
{
787
        if ((mRecordingDemoBuffer) || (mPlayingDemoBuffer))
788
        {
789
                // Insert the handle into a map with an auto-incrementing number so
790
                //  we can match up the auto-incrementing numbers with the handle
791
                //  later on, as handles may not be the same between executions
792
                std::pair<HandleToIntMap::iterator, bool> aPair = mHandleToIntMap.insert(HandleToIntMap::value_type(theHandle, mCurHandleNum));
793
                DBG_ASSERT(aPair.second);
794
                mCurHandleNum++;
795
        }
796
}
797
 
798
void SexyAppBase::DemoWaitForHandle(HANDLE theHandle)
799
{
800
        WaitForSingleObject(theHandle, INFINITE);
801
 
802
        if ((mRecordingDemoBuffer) || (mPlayingDemoBuffer))
803
        {
804
                // Remove the handle from our waiting map
805
                HandleToIntMap::iterator anItr = mHandleToIntMap.find(theHandle);                                      
806
                DBG_ASSERT(anItr != mHandleToIntMap.end());
807
                mHandleToIntMap.erase(anItr);
808
        }
809
}
810
 
811
bool SexyAppBase::DemoCheckHandle(HANDLE theHandle)
812
{
813
        if (mPlayingDemoBuffer)
814
        {      
815
                // We only need to try to get the result if we think we are waiting for one     
816
                if (gSexyAppBase->PrepareDemoCommand(false))
817
                {
818
                        if ((!gSexyAppBase->mDemoIsShortCmd) && (gSexyAppBase->mDemoCmdNum == DEMO_HANDLE_COMPLETE))
819
                        {
820
                                // Find auto-incrementing handle num from handle
821
                                HandleToIntMap::iterator anItr = mHandleToIntMap.find(theHandle);                                      
822
                                DBG_ASSERT(anItr != mHandleToIntMap.end());
823
 
824
                                int anOldBufferPos = gSexyAppBase->mDemoBuffer.mReadBitPos;
825
 
826
                                // Since we don't require a demo result entry to be here, we must verify
827
                                //  that this is referring to us
828
                                int aDemoHandleNum = gSexyAppBase->mDemoBuffer.ReadLong();
829
 
830
                                if (aDemoHandleNum == anItr->second)
831
                                {
832
                                        // Alright, this was the handle we were waiting for!
833
                                        gSexyAppBase->mDemoNeedsCommand = true;
834
 
835
                                        // Actually wait for our local buddy to complete
836
                                        WaitForSingleObject(theHandle, INFINITE);
837
                                        mHandleToIntMap.erase(anItr);
838
 
839
                                        return true;
840
                                }
841
                                else
842
                                {
843
                                        // Not us, go back
844
                                        gSexyAppBase->mDemoBuffer.mReadBitPos = anOldBufferPos;
845
                                }
846
                        }
847
                }
848
 
849
                return false;  
850
        }
851
        else
852
        {
853
                if (WaitForSingleObject(theHandle, 0) == WAIT_OBJECT_0)
854
                {
855
                        if (mRecordingDemoBuffer)
856
                        {
857
                                // Find auto-incrementing handle num from handle
858
                                HandleToIntMap::iterator anItr = mHandleToIntMap.find(theHandle);                                      
859
                                DBG_ASSERT(anItr != mHandleToIntMap.end());
860
 
861
                                gSexyAppBase->WriteDemoTimingBlock();
862
                                gSexyAppBase->mDemoBuffer.WriteNumBits(0, 1);
863
                                gSexyAppBase->mDemoBuffer.WriteNumBits(DEMO_HANDLE_COMPLETE, 5);
864
                                gSexyAppBase->mDemoBuffer.WriteLong(anItr->second);
865
 
866
                                mHandleToIntMap.erase(anItr);
867
                        }
868
 
869
                        return true;
870
                }
871
 
872
                return false;
873
        }
874
}
875
 
876
void SexyAppBase::DemoAssertIntEqual(int theInt)
877
{
878
        if (mPlayingDemoBuffer)
879
        {
880
                if (mManualShutdown)
881
                        return;
882
 
883
                PrepareDemoCommand(true);
884
                mDemoNeedsCommand = true;
885
 
886
                DBG_ASSERTE(!mDemoIsShortCmd);
887
                DBG_ASSERTE(mDemoCmdNum == DEMO_ASSERT_INT_EQUAL);
888
 
889
                int anInt = mDemoBuffer.ReadLong();
890
                DBG_ASSERTE(anInt == theInt);
891
        }
892
        else if (mRecordingDemoBuffer)
893
        {              
894
                WriteDemoTimingBlock();
895
                mDemoBuffer.WriteNumBits(0, 1);
896
                mDemoBuffer.WriteNumBits(DEMO_ASSERT_INT_EQUAL, 5);                            
897
                mDemoBuffer.WriteLong(theInt);
898
        }
899
}
900
 
901
Dialog* SexyAppBase::NewDialog(int theDialogId, bool isModal, const SexyString& theDialogHeader, const SexyString& theDialogLines, const SexyString& theDialogFooter, int theButtonMode)
902
{      
903
        Dialog* aDialog = new Dialog(NULL, NULL, theDialogId, isModal, theDialogHeader, theDialogLines, theDialogFooter, theButtonMode);               
904
        return aDialog;
905
}
906
 
907
Dialog* SexyAppBase::DoDialog(int theDialogId, bool isModal, const SexyString& theDialogHeader, const SexyString& theDialogLines, const SexyString& theDialogFooter, int theButtonMode)
908
{
909
        KillDialog(theDialogId);
910
 
911
        Dialog* aDialog = NewDialog(theDialogId, isModal, theDialogHeader, theDialogLines, theDialogFooter, theButtonMode);            
912
 
913
        AddDialog(theDialogId, aDialog);
914
 
915
        return aDialog;
916
}
917
 
918
 
919
Dialog* SexyAppBase::GetDialog(int theDialogId)
920
{
921
        DialogMap::iterator anItr = mDialogMap.find(theDialogId);
922
 
923
        if (anItr != mDialogMap.end()) 
924
                return anItr->second;
925
 
926
        return NULL;
927
}
928
 
929
bool SexyAppBase::KillDialog(int theDialogId, bool removeWidget, bool deleteWidget)
930
{
931
        DialogMap::iterator anItr = mDialogMap.find(theDialogId);
932
 
933
        if (anItr != mDialogMap.end())
934
        {
935
                Dialog* aDialog = anItr->second;
936
 
937
                // set the result to something else so DoMainLoop knows that the dialog is gone 
938
                // in case nobody else sets mResult             
939
                if (aDialog->mResult == -1)
940
                        aDialog->mResult = 0;
941
 
942
                DialogList::iterator aListItr = std::find(mDialogList.begin(),mDialogList.end(),aDialog);
943
                if (aListItr != mDialogList.end())
944
                        mDialogList.erase(aListItr);
945
 
946
                mDialogMap.erase(anItr);
947
 
948
                if (removeWidget || deleteWidget)
949
                mWidgetManager->RemoveWidget(aDialog);
950
 
951
                if (aDialog->IsModal())
952
                {                      
953
                        ModalClose();
954
                        mWidgetManager->RemoveBaseModal(aDialog);
955
                }                              
956
 
957
                if (deleteWidget)
958
                SafeDeleteWidget(aDialog);
959
 
960
                return true;
961
        }
962
 
963
        return false;
964
}
965
 
966
bool SexyAppBase::KillDialog(int theDialogId)
967
{
968
        return KillDialog(theDialogId,true,true);
969
}
970
 
971
bool SexyAppBase::KillDialog(Dialog* theDialog)
972
{
973
        return KillDialog(theDialog->mId);
974
}
975
 
976
int SexyAppBase::GetDialogCount()
977
{
978
        return mDialogMap.size();
979
}
980
 
981
void SexyAppBase::AddDialog(int theDialogId, Dialog* theDialog)
982
{
983
        KillDialog(theDialogId);
984
 
985
        if (theDialog->mWidth == 0)
986
        {
987
                // Set the dialog position ourselves
988
                int aWidth = mWidth/2;
989
                theDialog->Resize((mWidth - aWidth)/2, mHeight / 5, aWidth, theDialog->GetPreferredHeight(aWidth));
990
        }
991
 
992
        mDialogMap.insert(DialogMap::value_type(theDialogId, theDialog));
993
        mDialogList.push_back(theDialog);
994
 
995
        mWidgetManager->AddWidget(theDialog);
996
        if (theDialog->IsModal())
997
        {
998
                mWidgetManager->AddBaseModal(theDialog);
999
                ModalOpen();
1000
        }
1001
}
1002
 
1003
void SexyAppBase::AddDialog(Dialog* theDialog)
1004
{
1005
        AddDialog(theDialog->mId, theDialog);
1006
}
1007
 
1008
void SexyAppBase::ModalOpen()
1009
{
1010
}
1011
 
1012
void SexyAppBase::ModalClose()
1013
{
1014
}
1015
 
1016
void SexyAppBase::DialogButtonPress(int theDialogId, int theButtonId)
1017
{      
1018
        if (theButtonId == Dialog::ID_YES)
1019
                ButtonPress(2000 + theDialogId);
1020
        else if (theButtonId == Dialog::ID_NO)
1021
                ButtonPress(3000 + theDialogId);       
1022
}
1023
 
1024
void SexyAppBase::DialogButtonDepress(int theDialogId, int theButtonId)
1025
{
1026
        if (theButtonId == Dialog::ID_YES)
1027
                ButtonDepress(2000 + theDialogId);
1028
        else if (theButtonId == Dialog::ID_NO)
1029
                ButtonDepress(3000 + theDialogId);
1030
}
1031
 
1032
void SexyAppBase::GotFocus()
1033
{      
1034
}
1035
 
1036
void SexyAppBase::LostFocus()
1037
{      
1038
}
1039
 
1040
void SexyAppBase::URLOpenFailed(const std::string& theURL)
1041
{
1042
        mIsOpeningURL = false;
1043
}
1044
 
1045
void SexyAppBase::URLOpenSucceeded(const std::string& theURL)
1046
{      
1047
        mIsOpeningURL = false;
1048
 
1049
        if (mShutdownOnURLOpen)
1050
                Shutdown();    
1051
}
1052
 
1053
bool SexyAppBase::OpenURL(const std::string& theURL, bool shutdownOnOpen)
1054
{
1055
        if ((!mIsOpeningURL) || (theURL != mOpeningURL))
1056
        {
1057
                mShutdownOnURLOpen = shutdownOnOpen;
1058
                mIsOpeningURL = true;
1059
                mOpeningURL = theURL;
1060
                mOpeningURLTime = GetTickCount();              
1061
 
1062
                if ((int) ShellExecuteA(NULL, "open", theURL.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32)
1063
                {
1064
                        return true;
1065
                }
1066
                else
1067
                {
1068
                        URLOpenFailed(theURL);
1069
                        return false;
1070
                }
1071
        }
1072
 
1073
        return true;
1074
}
1075
 
1076
std::string SexyAppBase::GetProductVersion(const std::string& thePath)
1077
{      
1078
        // Dynamically Load Version.dll
1079
        typedef DWORD (APIENTRY *GetFileVersionInfoSizeFunc)(LPSTR lptstrFilename, LPDWORD lpdwHandle);
1080
        typedef BOOL (APIENTRY *GetFileVersionInfoFunc)(LPSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
1081
        typedef BOOL (APIENTRY *VerQueryValueFunc)(const LPVOID pBlock, LPSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen);
1082
 
1083
        static GetFileVersionInfoSizeFunc aGetFileVersionInfoSizeFunc = NULL;
1084
        static GetFileVersionInfoFunc aGetFileVersionInfoFunc = NULL;
1085
        static VerQueryValueFunc aVerQueryValueFunc = NULL;
1086
 
1087
        if (aGetFileVersionInfoSizeFunc==NULL)
1088
        {
1089
                aGetFileVersionInfoSizeFunc = (GetFileVersionInfoSizeFunc)GetProcAddress(gVersionDLL,"GetFileVersionInfoSizeA");
1090
                aGetFileVersionInfoFunc = (GetFileVersionInfoFunc)GetProcAddress(gVersionDLL,"GetFileVersionInfoA");
1091
                aVerQueryValueFunc = (VerQueryValueFunc)GetProcAddress(gVersionDLL,"VerQueryValueA");
1092
        }
1093
 
1094
        // Get Product Version
1095
        std::string aProductVersion;
1096
 
1097
        uint aSize = aGetFileVersionInfoSizeFunc((char*) thePath.c_str(), 0);
1098
        if (aSize > 0)         
1099
        {
1100
                uchar* aVersionBuffer = new uchar[aSize];
1101
                aGetFileVersionInfoFunc((char*) thePath.c_str(), 0, aSize, aVersionBuffer);    
1102
                char* aBuffer; 
1103
                if (aVerQueryValueFunc(aVersionBuffer,
1104
                                  "\\StringFileInfo\\040904B0\\ProductVersion",
1105
                                  (void**) &aBuffer,
1106
                                  &aSize))
1107
                {
1108
                        aProductVersion = aBuffer;
1109
                }
1110
                else if (aVerQueryValueFunc(aVersionBuffer,
1111
                                  "\\StringFileInfo\\040904E4\\ProductVersion",
1112
                                  (void**) &aBuffer,
1113
                                  &aSize))
1114
                {
1115
                        aProductVersion = aBuffer;
1116
                }
1117
 
1118
                delete aVersionBuffer; 
1119
        }
1120
 
1121
        return aProductVersion;
1122
}
1123
 
1124
void SexyAppBase::WaitForLoadingThread()
1125
{
1126
        while ((mLoadingThreadStarted) && (!mLoadingThreadCompleted))
1127
                Sleep(20);
1128
}
1129
 
1130
void SexyAppBase::SetCursorImage(int theCursorNum, Image* theImage)
1131
{
1132
        if ((theCursorNum >= 0) && (theCursorNum < NUM_CURSORS))
1133
        {
1134
                mCursorImages[theCursorNum] = theImage;
1135
                EnforceCursor();
1136
        }
1137
}
1138
 
1139
void SexyAppBase::TakeScreenshot()
1140
{
1141
        if (mDDInterface==NULL || mDDInterface->mDrawSurface==NULL)
1142
                return;
1143
 
1144
        // Get free image name
1145
        std::string anImageDir = GetAppDataFolder() + "_screenshots";
1146
        MkDir(anImageDir);
1147
        anImageDir += "/";
1148
 
1149
        WIN32_FIND_DATAA aData;
1150
        int aMaxId = 0;
1151
        std::string anImagePrefix = "image";
1152
        HANDLE aHandle = FindFirstFileA((anImageDir + "*.png").c_str(), &aData);
1153
        if (aHandle!=INVALID_HANDLE_VALUE)
1154
        {
1155
                do {
1156
                        int aNum = 0;
1157
                        if (sscanf(aData.cFileName,(anImagePrefix + "%d.png").c_str(), &aNum)==1)
1158
                        {
1159
                                if (aNum>aMaxId)
1160
                                        aMaxId = aNum;
1161
                        }
1162
 
1163
                }
1164
                while(FindNextFileA(aHandle,&aData));
1165
                FindClose(aHandle);
1166
        }
1167
        std::string anImageName = anImageDir + anImagePrefix + StrFormat("%d.png",aMaxId+1);
1168
 
1169
        // Capture screen
1170
        LPDIRECTDRAWSURFACE aSurface = mDDInterface->mDrawSurface;
1171
 
1172
        // Temporarily set the mDrawSurface to NULL so DDImage::Check3D 
1173
        // returns false so we can lock the surface.
1174
        mDDInterface->mDrawSurface = NULL;
1175
 
1176
        DDImage anImage(mDDInterface);
1177
        anImage.SetSurface(aSurface);
1178
        anImage.GetBits();
1179
        anImage.DeleteDDSurface();
1180
        mDDInterface->mDrawSurface = aSurface;
1181
 
1182
        if (anImage.mBits==NULL)
1183
                return;
1184
 
1185
        // Write image
1186
        ImageLib::Image aSaveImage;
1187
        aSaveImage.mBits = anImage.mBits;
1188
        aSaveImage.mWidth = anImage.mWidth;
1189
        aSaveImage.mHeight = anImage.mHeight;
1190
        ImageLib::WritePNGImage(anImageName, &aSaveImage);
1191
        aSaveImage.mBits = NULL;
1192
 
1193
 
1194
/*
1195
        keybd_event(VK_MENU,0,0,0);
1196
    keybd_event(VK_SNAPSHOT,0,0,0);
1197
    keybd_event(VK_MENU,0,KEYEVENTF_KEYUP,0);
1198
        if (OpenClipboard(mHWnd))
1199
        {
1200
                HBITMAP aBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
1201
                if (aBitmap!=NULL)
1202
                {
1203
                        BITMAP anObject;
1204
                        ZeroMemory(&anObject,sizeof(anObject));
1205
                        GetObject(aBitmap,sizeof(anObject),&anObject);
1206
 
1207
                        BITMAPINFO anInfo;
1208
                        ZeroMemory(&anInfo,sizeof(anInfo));
1209
                        BITMAPINFOHEADER &aHeader = anInfo.bmiHeader;
1210
                        aHeader.biBitCount = 32;
1211
                        aHeader.biPlanes = 1;
1212
                        aHeader.biHeight = -abs(anObject.bmHeight);
1213
                        aHeader.biWidth = abs(anObject.bmWidth);
1214
                        aHeader.biSize = sizeof(aHeader);
1215
                        aHeader.biSizeImage = aHeader.biHeight*aHeader.biWidth*4;
1216
                        ImageLib::Image aSaveImage;
1217
                        aSaveImage.mBits = new DWORD[abs(anObject.bmWidth*anObject.bmHeight)];
1218
                        aSaveImage.mWidth = abs(anObject.bmWidth);
1219
                        aSaveImage.mHeight = abs(anObject.bmHeight);
1220
 
1221
                        HDC aDC = GetDC(NULL);
1222
                        if (GetDIBits(aDC,aBitmap,0,aSaveImage.mHeight,aSaveImage.mBits,&anInfo,DIB_RGB_COLORS))
1223
                                ImageLib::WritePNGImage(anImageName, &aSaveImage);
1224
 
1225
                        ReleaseDC(NULL,aDC);
1226
                }
1227
                CloseClipboard();
1228
        }*/
1229
 
1230
        ClearUpdateBacklog();
1231
}
1232
 
1233
void SexyAppBase::DumpProgramInfo()
1234
{
1235
        Deltree(GetAppDataFolder() + "_dump");
1236
 
1237
        for (;;)
1238
        {
1239
                if (mkdir((GetAppDataFolder() + "_dump").c_str()))
1240
                        break;
1241
                Sleep(100);
1242
        }
1243
 
1244
        std::fstream aDumpStream((GetAppDataFolder() + "_dump\\imagelist.html").c_str(), std::ios::out);
1245
 
1246
        time_t aTime;
1247
        time(&aTime);
1248
        tm* aTM = localtime(&aTime);
1249
 
1250
        aDumpStream << "<HTML><BODY BGCOLOR=EEEEFF><CENTER><FONT SIZE=+2><B>" << asctime(aTM) << "</B></FONT><BR>" << std::endl;
1251
 
1252
        int anImgNum = 0;
1253
 
1254
        int aThumbWidth = 64;
1255
        int aThumbHeight = 64;
1256
 
1257
        ImageLib::Image anImageLibImage;
1258
        anImageLibImage.mWidth = aThumbWidth;
1259
        anImageLibImage.mHeight = aThumbHeight;
1260
        anImageLibImage.mBits = new unsigned long[aThumbWidth*aThumbHeight];   
1261
 
1262
        typedef std::multimap<int, MemoryImage*, std::greater<int> > SortedImageMap;
1263
 
1264
        int aTotalMemory = 0;
1265
 
1266
        SortedImageMap aSortedImageMap;
1267
        MemoryImageSet::iterator anItr = mMemoryImageSet.begin();
1268
        while (anItr != mMemoryImageSet.end())
1269
        {
1270
                MemoryImage* aMemoryImage = *anItr;                            
1271
 
1272
                int aNumPixels = aMemoryImage->mWidth*aMemoryImage->mHeight;
1273
 
1274
                DDImage* aDDImage = dynamic_cast<DDImage*>(aMemoryImage);
1275
 
1276
                int aBitsMemory = 0;
1277
                int aSurfaceMemory = 0;
1278
                int aPalletizedMemory = 0;
1279
                int aNativeAlphaMemory = 0;
1280
                int aRLAlphaMemory = 0;
1281
                int aRLAdditiveMemory = 0;
1282
                int aTextureMemory = 0;
1283
 
1284
                int aMemorySize = 0;
1285
                if (aMemoryImage->mBits != NULL)
1286
                        aBitsMemory = aNumPixels * 4;
1287
                if ((aDDImage != NULL) && (aDDImage->mSurface != NULL))
1288
                        aSurfaceMemory = aNumPixels * 4; // Assume 32bit screen...
1289
                if (aMemoryImage->mColorTable != NULL)
1290
                        aPalletizedMemory = aNumPixels + 256*4;
1291
                if (aMemoryImage->mNativeAlphaData != NULL)
1292
                {
1293
                        if (aMemoryImage->mColorTable != NULL)
1294
                                aNativeAlphaMemory = 256*4;
1295
                        else
1296
                                aNativeAlphaMemory = aNumPixels * 4;
1297
                }
1298
                if (aMemoryImage->mRLAlphaData != NULL)
1299
                        aRLAlphaMemory = aNumPixels;
1300
                if (aMemoryImage->mRLAdditiveData != NULL)
1301
                        aRLAdditiveMemory = aNumPixels;
1302
                if (aMemoryImage->mD3DData != NULL)
1303
                        aTextureMemory += ((TextureData*)aMemoryImage->mD3DData)->mTexMemSize;
1304
 
1305
                aMemorySize = aBitsMemory + aSurfaceMemory + aPalletizedMemory + aNativeAlphaMemory + aRLAlphaMemory + aRLAdditiveMemory + aTextureMemory;
1306
                aTotalMemory += aMemorySize;
1307
 
1308
                aSortedImageMap.insert(SortedImageMap::value_type(aMemorySize, aMemoryImage));
1309
 
1310
                ++anItr;
1311
        }
1312
 
1313
        aDumpStream << "Total Image Allocation: " << CommaSeperate(aTotalMemory).c_str() << " bytes<BR>";
1314
        aDumpStream << "<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=4>";
1315
 
1316
        int aTotalMemorySize = 0;
1317
        int aTotalBitsMemory = 0;
1318
        int aTotalSurfaceMemory = 0;
1319
        int aTotalPalletizedMemory = 0;
1320
        int aTotalNativeAlphaMemory = 0;
1321
        int aTotalRLAlphaMemory = 0;
1322
        int aTotalRLAdditiveMemory = 0;
1323
        int aTotalTextureMemory = 0;
1324
 
1325
        SortedImageMap::iterator aSortedItr = aSortedImageMap.begin();
1326
        while (aSortedItr != aSortedImageMap.end())
1327
        {
1328
                MemoryImage* aMemoryImage = aSortedItr->second;                        
1329
 
1330
                char anImageName[256];
1331
                sprintf(anImageName, "img%04d.png", anImgNum);
1332
 
1333
                char aThumbName[256];
1334
                sprintf(aThumbName, "thumb%04d.jpg", anImgNum);
1335
 
1336
                aDumpStream << "<TR>" << std::endl;
1337
 
1338
                aDumpStream << "<TD><A HREF=" << anImageName << "><IMG SRC=" << aThumbName << " WIDTH=" << aThumbWidth << " HEIGHT=" << aThumbHeight << "></A></TD>" << std::endl;
1339
 
1340
                int aNumPixels = aMemoryImage->mWidth*aMemoryImage->mHeight;
1341
 
1342
                DDImage* aDDImage = dynamic_cast<DDImage*>(aMemoryImage);
1343
 
1344
                int aMemorySize = aSortedItr->first;
1345
 
1346
                int aBitsMemory = 0;
1347
                int aSurfaceMemory = 0;
1348
                int aPalletizedMemory = 0;
1349
                int aNativeAlphaMemory = 0;
1350
                int aRLAlphaMemory = 0;
1351
                int aRLAdditiveMemory = 0;
1352
                int aTextureMemory = 0;
1353
                std::string aTextureFormatName;
1354
 
1355
                if (aMemoryImage->mBits != NULL)
1356
                        aBitsMemory = aNumPixels * 4;
1357
                if ((aDDImage != NULL) && (aDDImage->mSurface != NULL))
1358
                        aSurfaceMemory = aNumPixels * 4; // Assume 32bit screen...
1359
                if (aMemoryImage->mColorTable != NULL)
1360
                        aPalletizedMemory = aNumPixels + 256*4;
1361
                if (aMemoryImage->mNativeAlphaData != NULL)
1362
                {
1363
                        if (aMemoryImage->mColorTable != NULL)
1364
                                aNativeAlphaMemory = 256*4;
1365
                        else
1366
                                aNativeAlphaMemory = aNumPixels * 4;
1367
                }
1368
                if (aMemoryImage->mRLAlphaData != NULL)
1369
                        aRLAlphaMemory = aNumPixels;
1370
                if (aMemoryImage->mRLAdditiveData != NULL)
1371
                        aRLAdditiveMemory = aNumPixels;        
1372
                if (aMemoryImage->mD3DData != NULL)
1373
                {
1374
                        aTextureMemory += ((TextureData*)aMemoryImage->mD3DData)->mTexMemSize;
1375
 
1376
                        switch (((TextureData*)aMemoryImage->mD3DData)->mPixelFormat)
1377
                        {                              
1378
                        case PixelFormat_A8R8G8B8: aTextureFormatName = "A8R8G8B8"; break;
1379
                        case PixelFormat_A4R4G4B4: aTextureFormatName = "A4R4G4B4"; break;
1380
                        case PixelFormat_R5G6B5: aTextureFormatName = "R5G6B5"; break;
1381
                        case PixelFormat_Palette8: aTextureFormatName = "Palette8"; break;
1382
                        }                      
1383
                }
1384
 
1385
                aTotalMemorySize                += aMemorySize;
1386
                aTotalBitsMemory                += aBitsMemory;
1387
                aTotalTextureMemory             += aTextureMemory;
1388
                aTotalSurfaceMemory             += aSurfaceMemory;
1389
                aTotalPalletizedMemory  += aPalletizedMemory;
1390
                aTotalNativeAlphaMemory += aNativeAlphaMemory;
1391
                aTotalRLAlphaMemory             += aRLAlphaMemory;
1392
                aTotalRLAdditiveMemory  += aRLAdditiveMemory;
1393
 
1394
 
1395
 
1396
                char aStr[256];
1397
                sprintf(aStr, "%d x %d<BR>%s bytes", aMemoryImage->mWidth, aMemoryImage->mHeight, CommaSeperate(aMemorySize).c_str());
1398
                aDumpStream << "<TD ALIGN=RIGHT>" << aStr << "</TD>" << std::endl;
1399
 
1400
                aDumpStream << "<TD>" << SexyStringToString(((aBitsMemory != 0) ? _S("mBits<BR>") + CommaSeperate(aBitsMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;       
1401
                aDumpStream << "<TD>" << SexyStringToString(((aPalletizedMemory != 0) ? _S("Palletized<BR>") + CommaSeperate(aPalletizedMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;                              
1402
                aDumpStream << "<TD>" << SexyStringToString(((aSurfaceMemory != 0) ? _S("DDSurface<BR>") + CommaSeperate(aSurfaceMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;             
1403
                aDumpStream << "<TD>" << SexyStringToString(((aMemoryImage->mD3DData!=NULL) ? _S("Texture<BR>") + StringToSexyString(aTextureFormatName) + _S("<BR>") + CommaSeperate(aTextureMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;
1404
 
1405
                aDumpStream << "<TD>" << SexyStringToString(((aMemoryImage->mIsVolatile) ? _S("Volatile") : _S("&nbsp;"))) << "</TD>" << std::endl;
1406
                aDumpStream << "<TD>" << SexyStringToString(((aMemoryImage->mForcedMode) ? _S("Forced") : _S("&nbsp;"))) << "</TD>" << std::endl;              
1407
                aDumpStream << "<TD>" << SexyStringToString(((aMemoryImage->mHasAlpha) ? _S("HasAlpha") : _S("&nbsp;"))) << "</TD>" << std::endl;
1408
                aDumpStream << "<TD>" << SexyStringToString(((aMemoryImage->mHasTrans) ? _S("HasTrans") : _S("&nbsp;"))) << "</TD>" << std::endl;
1409
                aDumpStream << "<TD>" << SexyStringToString(((aNativeAlphaMemory != 0) ? _S("NativeAlpha<BR>") + CommaSeperate(aNativeAlphaMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;
1410
                aDumpStream << "<TD>" << SexyStringToString(((aRLAlphaMemory != 0) ? _S("RLAlpha<BR>") + CommaSeperate(aRLAlphaMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;
1411
                aDumpStream << "<TD>" << SexyStringToString(((aRLAdditiveMemory != 0) ? _S("RLAdditive<BR>") + CommaSeperate(aRLAdditiveMemory) : _S("&nbsp;"))) << "</TD>" << std::endl;
1412
                aDumpStream << "<TD>" << (aMemoryImage->mFilePath.empty()? "&nbsp;":aMemoryImage->mFilePath) << "</TD>" << std::endl;
1413
 
1414
                aDumpStream << "</TR>" << std::endl;
1415
 
1416
                // Write thumb
1417
 
1418
                MemoryImage aCopiedImage(*aMemoryImage);
1419
 
1420
                ulong* aBits = aCopiedImage.GetBits();
1421
 
1422
                ulong* aThumbBitsPtr = anImageLibImage.mBits;
1423
 
1424
                for (int aThumbY = 0; aThumbY < aThumbHeight; aThumbY++)
1425
                        for (int aThumbX = 0; aThumbX < aThumbWidth; aThumbX++)
1426
                        {
1427
                                int aSrcX = (int) (aCopiedImage.mWidth  * (aThumbX + 0.5)) / aThumbWidth;
1428
                                int aSrcY = (int) (aCopiedImage.mHeight * (aThumbY + 0.5)) / aThumbHeight;
1429
 
1430
                                *(aThumbBitsPtr++) = aBits[aSrcX + (aSrcY*aCopiedImage.mWidth)];
1431
                        }
1432
 
1433
                ImageLib::WriteJPEGImage((GetAppDataFolder() + std::string("_dump\\") + aThumbName).c_str(), &anImageLibImage);
1434
 
1435
                // Write high resolution image
1436
 
1437
                ImageLib::Image anFullImage;
1438
                anFullImage.mBits = aCopiedImage.GetBits();
1439
                anFullImage.mWidth = aCopiedImage.GetWidth();
1440
                anFullImage.mHeight = aCopiedImage.GetHeight();
1441
 
1442
                ImageLib::WritePNGImage((GetAppDataFolder() + std::string("_dump\\") + anImageName).c_str(), &anFullImage);
1443
 
1444
                anFullImage.mBits = NULL;
1445
 
1446
                anImgNum++;
1447
 
1448
                aSortedItr++;          
1449
        }
1450
 
1451
        aDumpStream << "<TD>Totals</TD>" << std::endl;
1452
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalMemorySize)) << "</TD>" << std::endl;  
1453
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalBitsMemory)) << "</TD>" << std::endl;  
1454
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalPalletizedMemory)) << "</TD>" << std::endl;                            
1455
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalSurfaceMemory)) << "</TD>" << std::endl;               
1456
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalTextureMemory)) << "</TD>" << std::endl;               
1457
        aDumpStream << "<TD>&nbsp;</TD>" << std::endl;
1458
        aDumpStream << "<TD>&nbsp;</TD>" << std::endl;
1459
        aDumpStream << "<TD>&nbsp;</TD>" << std::endl;
1460
        aDumpStream << "<TD>&nbsp;</TD>" << std::endl;
1461
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalNativeAlphaMemory)) << "</TD>" << std::endl;
1462
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalRLAlphaMemory)) << "</TD>" << std::endl;
1463
        aDumpStream << "<TD>" << SexyStringToString(CommaSeperate(aTotalRLAdditiveMemory)) << "</TD>" << std::endl;
1464
        aDumpStream << "<TD>&nbsp;</TD>" << std::endl;
1465
 
1466
        aDumpStream << "</TABLE></CENTER></BODY></HTML>" << std::endl;
1467
}
1468
 
1469
double SexyAppBase::GetLoadingThreadProgress()
1470
{
1471
        if (mLoaded)
1472
                return 1.0;
1473
        if (!mLoadingThreadStarted)
1474
                return 0.0;
1475
        if (mNumLoadingThreadTasks == 0)
1476
                return 0.0;
1477
        return min(mCompletedLoadingThreadTasks / (double) mNumLoadingThreadTasks, 1.0);
1478
}
1479
 
1480
bool SexyAppBase::RegistryWrite(const std::string& theValueName, ulong theType, const uchar* theValue, ulong theLength)
1481
{
1482
        if (mRegKey.length() == 0)
1483
                return false;
1484
 
1485
        if (mPlayingDemoBuffer)
1486
        {
1487
                if (mManualShutdown)
1488
                        return true;
1489
 
1490
                PrepareDemoCommand(true);
1491
                mDemoNeedsCommand = true;
1492
 
1493
                DBG_ASSERTE(!mDemoIsShortCmd);         
1494
                DBG_ASSERTE(mDemoCmdNum == DEMO_REGISTRY_WRITE);
1495
 
1496
                return mDemoBuffer.ReadNumBits(1, false) != 0;         
1497
        }
1498
 
1499
        HKEY aGameKey;
1500
 
1501
        std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + mRegKey);
1502
        std::string aValueName;
1503
 
1504
        int aSlashPos = (int) theValueName.rfind('\\');
1505
        if (aSlashPos != -1)
1506
        {
1507
                aKeyName += "\\" + theValueName.substr(0, aSlashPos);
1508
                aValueName = theValueName.substr(aSlashPos + 1);
1509
        }
1510
        else
1511
        {
1512
                aValueName = theValueName;
1513
        }
1514
 
1515
        int aResult = RegOpenKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, KEY_WRITE, &aGameKey);
1516
        if (aResult != ERROR_SUCCESS)
1517
        {
1518
                ulong aDisp;
1519
                aResult = RegCreateKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, "Key", REG_OPTION_NON_VOLATILE,
1520
                        KEY_ALL_ACCESS, NULL, &aGameKey, &aDisp);
1521
        }
1522
 
1523
        if (aResult != ERROR_SUCCESS)
1524
        {
1525
                if (mRecordingDemoBuffer)
1526
                {
1527
                        WriteDemoTimingBlock();
1528
                        mDemoBuffer.WriteNumBits(0, 1);
1529
                        mDemoBuffer.WriteNumBits(DEMO_REGISTRY_WRITE, 5);
1530
                        mDemoBuffer.WriteNumBits(0, 1); // failure
1531
                }
1532
 
1533
                return false;
1534
        }
1535
 
1536
        RegSetValueExA(aGameKey, aValueName.c_str(), 0, theType, theValue, theLength);
1537
        RegCloseKey(aGameKey);
1538
 
1539
        if (mRecordingDemoBuffer)
1540
        {
1541
                WriteDemoTimingBlock();
1542
                mDemoBuffer.WriteNumBits(0, 1);
1543
                mDemoBuffer.WriteNumBits(DEMO_REGISTRY_WRITE, 5);
1544
                mDemoBuffer.WriteNumBits(1, 1); // success
1545
        }
1546
 
1547
        return true;
1548
}
1549
 
1550
bool SexyAppBase::RegistryWriteString(const std::string& theValueName, const std::string& theString)
1551
{
1552
        return RegistryWrite(theValueName, REG_SZ, (uchar*) theString.c_str(), theString.length());
1553
}
1554
 
1555
bool SexyAppBase::RegistryWriteInteger(const std::string& theValueName, int theValue)
1556
{
1557
        return RegistryWrite(theValueName, REG_DWORD, (uchar*) &theValue, sizeof(int));
1558
}
1559
 
1560
bool SexyAppBase::RegistryWriteBoolean(const std::string& theValueName, bool theValue)
1561
{
1562
        int aValue = theValue ? 1 : 0;
1563
        return RegistryWrite(theValueName, REG_DWORD, (uchar*) &aValue, sizeof(int));
1564
}
1565
 
1566
bool SexyAppBase::RegistryWriteData(const std::string& theValueName, const uchar* theValue, ulong theLength)
1567
{
1568
        return RegistryWrite(theValueName, REG_BINARY, (uchar*) theValue, theLength);
1569
}
1570
 
1571
void SexyAppBase::WriteToRegistry()
1572
{      
1573
        RegistryWriteInteger("MusicVolume", (int) (mMusicVolume * 100));
1574
        RegistryWriteInteger("SfxVolume", (int) (mSfxVolume * 100));
1575
        RegistryWriteInteger("Muted", (mMuteCount - mAutoMuteCount > 0) ? 1 : 0);
1576
        RegistryWriteInteger("ScreenMode", mIsWindowed ? 0 : 1);
1577
        RegistryWriteInteger("PreferredX", mPreferredX);
1578
        RegistryWriteInteger("PreferredY", mPreferredY);
1579
        RegistryWriteInteger("CustomCursors", mCustomCursorsEnabled ? 1 : 0);          
1580
        RegistryWriteInteger("InProgress", 0);
1581
        RegistryWriteBoolean("WaitForVSync", mWaitForVSync);   
1582
}
1583
 
1584
bool SexyAppBase::RegistryEraseKey(const SexyString& _theKeyName)
1585
{
1586
        std::string theKeyName = SexyStringToStringFast(_theKeyName);
1587
        if (mRegKey.length() == 0)
1588
                return false;
1589
 
1590
        if (mPlayingDemoBuffer)
1591
        {
1592
                if (mManualShutdown)
1593
                        return true;
1594
 
1595
                PrepareDemoCommand(true);
1596
                mDemoNeedsCommand = true;
1597
 
1598
                DBG_ASSERTE(!mDemoIsShortCmd);         
1599
                DBG_ASSERTE(mDemoCmdNum == DEMO_REGISTRY_ERASE);
1600
 
1601
                return mDemoBuffer.ReadNumBits(1, false) != 0;         
1602
        }      
1603
 
1604
        std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + mRegKey) + "\\" + theKeyName;
1605
 
1606
        int aResult = RegDeleteKeyA(HKEY_CURRENT_USER, aKeyName.c_str());
1607
        if (aResult != ERROR_SUCCESS)
1608
        {
1609
                if (mRecordingDemoBuffer)
1610
                {
1611
                        WriteDemoTimingBlock();
1612
                        mDemoBuffer.WriteNumBits(0, 1);
1613
                        mDemoBuffer.WriteNumBits(DEMO_REGISTRY_ERASE, 5);
1614
                        mDemoBuffer.WriteNumBits(0, 1); // failure
1615
                }
1616
 
1617
                return false;
1618
        }              
1619
 
1620
        if (mRecordingDemoBuffer)
1621
        {
1622
                WriteDemoTimingBlock();
1623
                mDemoBuffer.WriteNumBits(0, 1);
1624
                mDemoBuffer.WriteNumBits(DEMO_REGISTRY_ERASE, 5);
1625
                mDemoBuffer.WriteNumBits(1, 1); // success
1626
        }
1627
 
1628
        return true;
1629
}
1630
 
1631
void SexyAppBase::RegistryEraseValue(const SexyString& _theValueName)
1632
{
1633
        std::string theValueName = SexyStringToStringFast(_theValueName);
1634
        if (mRegKey.length() == 0)
1635
                return;
1636
 
1637
        HKEY aGameKey; 
1638
        std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + mRegKey);
1639
        std::string aValueName;
1640
 
1641
        int aSlashPos = (int) theValueName.rfind('\\');
1642
        if (aSlashPos != -1)
1643
        {
1644
                aKeyName += "\\" + theValueName.substr(0, aSlashPos);
1645
                aValueName = theValueName.substr(aSlashPos + 1);
1646
        }
1647
        else
1648
        {
1649
                aValueName = theValueName;
1650
        }
1651
 
1652
        int aResult = RegOpenKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, KEY_WRITE, &aGameKey);
1653
        if (aResult == ERROR_SUCCESS)
1654
        {              
1655
                RegDeleteValueA(aGameKey, aValueName.c_str());
1656
                RegCloseKey(aGameKey);
1657
        }
1658
}
1659
 
1660
bool SexyAppBase::RegistryGetSubKeys(const std::string& theKeyName, StringVector* theSubKeys)
1661
{
1662
        theSubKeys->clear();
1663
 
1664
        if (mRegKey.length() == 0)
1665
                return false;
1666
 
1667
        if (mPlayingDemoBuffer)
1668
        {
1669
                if (mManualShutdown)
1670
                        return true;
1671
 
1672
                PrepareDemoCommand(true);
1673
                mDemoNeedsCommand = true;
1674
 
1675
                DBG_ASSERTE(!mDemoIsShortCmd);         
1676
                DBG_ASSERTE(mDemoCmdNum == DEMO_REGISTRY_GETSUBKEYS);
1677
 
1678
                bool success = mDemoBuffer.ReadNumBits(1, false) != 0;
1679
                if (!success)
1680
                        return false;
1681
 
1682
                int aNumKeys = mDemoBuffer.ReadLong();
1683
 
1684
                for (int i = 0; i < aNumKeys; i++)
1685
                        theSubKeys->push_back(mDemoBuffer.ReadString());
1686
 
1687
                return true;
1688
        }
1689
        else
1690
        {
1691
                HKEY aKey;
1692
 
1693
                std::string aKeyName = RemoveTrailingSlash(RemoveTrailingSlash("SOFTWARE\\" + mRegKey) + "\\" + theKeyName);   
1694
                int aResult = RegOpenKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, KEY_READ, &aKey);
1695
 
1696
                if (aResult == ERROR_SUCCESS)
1697
                {              
1698
                        for (int anIdx = 0; ; anIdx++)
1699
                        {
1700
                                char aStr[1024];
1701
 
1702
                                aResult = RegEnumKeyA(aKey, anIdx, aStr, 1024);
1703
                                if (aResult != ERROR_SUCCESS)
1704
                                        break;
1705
 
1706
                                theSubKeys->push_back(aStr);
1707
                        }
1708
 
1709
                        RegCloseKey(aKey);
1710
 
1711
                        if (mRecordingDemoBuffer)
1712
                        {
1713
                                WriteDemoTimingBlock();
1714
                                mDemoBuffer.WriteNumBits(0, 1);
1715
                                mDemoBuffer.WriteNumBits(DEMO_REGISTRY_GETSUBKEYS, 5);
1716
                                mDemoBuffer.WriteNumBits(1, 1); // success
1717
                                mDemoBuffer.WriteLong(theSubKeys->size());
1718
 
1719
                                for (int i = 0; i < (int) theSubKeys->size(); i++)
1720
                                        mDemoBuffer.WriteString((*theSubKeys)[i]);                             
1721
                        }
1722
 
1723
                        return true;
1724
                }
1725
                else
1726
                {
1727
                        if (mRecordingDemoBuffer)
1728
                        {
1729
                                WriteDemoTimingBlock();
1730
                                mDemoBuffer.WriteNumBits(0, 1);
1731
                                mDemoBuffer.WriteNumBits(DEMO_REGISTRY_GETSUBKEYS, 5);
1732
                                mDemoBuffer.WriteNumBits(0, 1); // failure
1733
                        }
1734
 
1735
                        return false;  
1736
                }
1737
        }
1738
}
1739
 
1740
bool SexyAppBase::RegistryRead(const std::string& theValueName, ulong* theType, uchar* theValue, ulong* theLength)
1741
{
1742
        return RegistryReadKey(theValueName, theType, theValue, theLength, HKEY_CURRENT_USER);
1743
}
1744
 
1745
bool SexyAppBase::RegistryReadKey(const std::string& theValueName, ulong* theType, uchar* theValue, ulong* theLength, HKEY theKey)
1746
{
1747
        if (mRegKey.length() == 0)
1748
                return false;
1749
 
1750
        if (mPlayingDemoBuffer)
1751
        {
1752
                if (mManualShutdown)
1753
                        return false;
1754
 
1755
                PrepareDemoCommand(true);
1756
                mDemoNeedsCommand = true;
1757
 
1758
                DBG_ASSERTE(!mDemoIsShortCmd);         
1759
                DBG_ASSERTE(mDemoCmdNum == DEMO_REGISTRY_READ);
1760
 
1761
                bool success = mDemoBuffer.ReadNumBits(1, false) != 0;
1762
                if (!success)
1763
                        return false;
1764
 
1765
                *theType = mDemoBuffer.ReadLong();
1766
 
1767
                ulong aLen = mDemoBuffer.ReadLong();
1768
                *theLength = aLen;
1769
 
1770
                if (*theLength >= aLen)
1771
                {                      
1772
                        mDemoBuffer.ReadBytes(theValue, aLen);
1773
                        return true;
1774
                }
1775
                else
1776
                {
1777
                        for (int i = 0; i < (int) aLen; i++)
1778
                                mDemoBuffer.ReadByte();
1779
                        return false;
1780
                }              
1781
        }
1782
        else
1783
        {              
1784
                HKEY aGameKey;
1785
 
1786
                std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + mRegKey);
1787
                std::string aValueName;
1788
 
1789
                int aSlashPos = (int) theValueName.rfind('\\');
1790
                if (aSlashPos != -1)
1791
                {
1792
                        aKeyName += "\\" + theValueName.substr(0, aSlashPos);
1793
                        aValueName = theValueName.substr(aSlashPos + 1);
1794
                }
1795
                else
1796
                {
1797
                        aValueName = theValueName;
1798
                }              
1799
 
1800
                if (RegOpenKeyExA(theKey, aKeyName.c_str(), 0, KEY_READ, &aGameKey) == ERROR_SUCCESS)
1801
                {
1802
                        if (RegQueryValueExA(aGameKey, aValueName.c_str(), 0, theType, (uchar*) theValue, theLength) == ERROR_SUCCESS)
1803
                        {
1804
                                if (mRecordingDemoBuffer)
1805
                                {
1806
                                        WriteDemoTimingBlock();
1807
                                        mDemoBuffer.WriteNumBits(0, 1);
1808
                                        mDemoBuffer.WriteNumBits(DEMO_REGISTRY_READ, 5);
1809
                                        mDemoBuffer.WriteNumBits(1, 1); // success
1810
                                        mDemoBuffer.WriteLong(*theType);
1811
                                        mDemoBuffer.WriteLong(*theLength);
1812
                                        mDemoBuffer.WriteBytes(theValue, *theLength);
1813
                                }
1814
 
1815
                                RegCloseKey(aGameKey);
1816
                                return true;   
1817
                        }
1818
 
1819
                        RegCloseKey(aGameKey);
1820
                }
1821
 
1822
                if (mRecordingDemoBuffer)
1823
                {
1824
                        WriteDemoTimingBlock();
1825
                        mDemoBuffer.WriteNumBits(0, 1);
1826
                        mDemoBuffer.WriteNumBits(DEMO_REGISTRY_READ, 5);
1827
                        mDemoBuffer.WriteNumBits(0, 1); // failure
1828
                }
1829
 
1830
                return false;
1831
        }
1832
}
1833
 
1834
bool SexyAppBase::RegistryReadString(const std::string& theKey, std::string* theString)
1835
{
1836
        char aStr[1024];
1837
 
1838
        ulong aType;   
1839
        ulong aLen = sizeof(aStr) - 1;
1840
        if (!RegistryRead(theKey, &aType, (uchar*) aStr, &aLen))
1841
                return false;
1842
 
1843
        if (aType != REG_SZ)
1844
                return false;
1845
 
1846
        aStr[aLen] = 0;
1847
 
1848
        *theString = aStr;
1849
        return true;
1850
}
1851
 
1852
bool SexyAppBase::RegistryReadInteger(const std::string& theKey, int* theValue)
1853
{
1854
        ulong aType;
1855
        ulong aLong;
1856
        ulong aLen = 4;
1857
        if (!RegistryRead(theKey, &aType, (uchar*) &aLong, &aLen))
1858
                return false;
1859
 
1860
        if (aType != REG_DWORD)
1861
                return false;
1862
 
1863
        *theValue = aLong;
1864
        return true;
1865
}
1866
 
1867
bool SexyAppBase::RegistryReadBoolean(const std::string& theKey, bool* theValue)
1868
{
1869
        int aValue;
1870
        if (!RegistryReadInteger(theKey, &aValue))
1871
                return false;
1872
 
1873
        *theValue = aValue != 0;
1874
        return true;
1875
}
1876
 
1877
bool SexyAppBase::RegistryReadData(const std::string& theKey, uchar* theValue, ulong* theLength)
1878
{              
1879
        ulong aType;
1880
        ulong aLen = *theLength;
1881
        if (!RegistryRead(theKey, &aType, (uchar*) theValue, theLength))
1882
                return false;
1883
 
1884
        if (aType != REG_BINARY)
1885
                return false;
1886
 
1887
        return true;
1888
}
1889
 
1890
void SexyAppBase::ReadFromRegistry()
1891
{
1892
        mReadFromRegistry = true;
1893
        mRegKey = SexyStringToString(GetString("RegistryKey", StringToSexyString(mRegKey)));
1894
 
1895
        if (mRegKey.length() == 0)
1896
                return;                        
1897
 
1898
        int anInt;
1899
        if (RegistryReadInteger("MusicVolume", &anInt))
1900
                mMusicVolume = anInt / 100.0;
1901
 
1902
        if (RegistryReadInteger("SfxVolume", &anInt))
1903
                mSfxVolume = anInt / 100.0;
1904
 
1905
        if (RegistryReadInteger("Muted", &anInt))
1906
                mMuteCount = anInt;
1907
 
1908
        if (RegistryReadInteger("ScreenMode", &anInt))
1909
                mIsWindowed = anInt == 0;
1910
 
1911
        RegistryReadInteger("PreferredX", &mPreferredX);
1912
        RegistryReadInteger("PreferredY", &mPreferredY);       
1913
 
1914
        if (RegistryReadInteger("CustomCursors", &anInt))
1915
                EnableCustomCursors(anInt != 0);       
1916
 
1917
        RegistryReadBoolean("WaitForVSync", &mWaitForVSync);   
1918
 
1919
        if (RegistryReadInteger("InProgress", &anInt))
1920
                mLastShutdownWasGraceful = anInt == 0;
1921
 
1922
        if (!IsScreenSaver())
1923
                RegistryWriteInteger("InProgress", 1); 
1924
}
1925
 
1926
bool SexyAppBase::WriteBytesToFile(const std::string& theFileName, const void *theData, unsigned long theDataLen)
1927
{
1928
        if (mPlayingDemoBuffer)
1929
        {
1930
                if (mManualShutdown)
1931
                        return true;
1932
 
1933
                PrepareDemoCommand(true);
1934
                mDemoNeedsCommand = true;
1935
 
1936
                DBG_ASSERTE(!mDemoIsShortCmd);         
1937
                DBG_ASSERTE(mDemoCmdNum == DEMO_FILE_WRITE);           
1938
 
1939
                bool success = mDemoBuffer.ReadNumBits(1, false) != 0;
1940
                if (!success)
1941
                        return false;
1942
 
1943
                return true;
1944
        }      
1945
 
1946
        MkDir(GetFileDir(theFileName));
1947
        FILE* aFP = fopen(theFileName.c_str(), "w+b");
1948
 
1949
        if (aFP == NULL)
1950
        {
1951
                if (mRecordingDemoBuffer)
1952
                {
1953
                        WriteDemoTimingBlock();
1954
                        mDemoBuffer.WriteNumBits(0, 1);
1955
                        mDemoBuffer.WriteNumBits(DEMO_FILE_WRITE, 5);
1956
                        mDemoBuffer.WriteNumBits(0, 1); // failure                              
1957
                }
1958
 
1959
                return false;
1960
        }
1961
 
1962
        fwrite(theData, 1, theDataLen, aFP);
1963
        fclose(aFP);
1964
 
1965
        if (mRecordingDemoBuffer)
1966
        {
1967
                WriteDemoTimingBlock();
1968
                mDemoBuffer.WriteNumBits(0, 1);
1969
                mDemoBuffer.WriteNumBits(DEMO_FILE_WRITE, 5);
1970
                mDemoBuffer.WriteNumBits(1, 1); // success
1971
        }
1972
 
1973
        return true;
1974
}
1975
 
1976
bool SexyAppBase::WriteBufferToFile(const std::string& theFileName, const Buffer* theBuffer)
1977
{
1978
        return WriteBytesToFile(theFileName,theBuffer->GetDataPtr(),theBuffer->GetDataLen());
1979
}
1980
 
1981
 
1982
bool SexyAppBase::ReadBufferFromFile(const std::string& theFileName, Buffer* theBuffer, bool dontWriteToDemo)
1983
{
1984
        if ((mPlayingDemoBuffer) && (!dontWriteToDemo))
1985
        {
1986
                if (mManualShutdown)
1987
                        return false;
1988
 
1989
                PrepareDemoCommand(true);
1990
                mDemoNeedsCommand = true;
1991
 
1992
                DBG_ASSERTE(!mDemoIsShortCmd);         
1993
                DBG_ASSERTE(mDemoCmdNum == DEMO_FILE_READ);
1994
 
1995
                bool success = mDemoBuffer.ReadNumBits(1, false) != 0;
1996
                if (!success)
1997
                        return false;
1998
 
1999
                ulong aLen = mDemoBuffer.ReadLong();           
2000
 
2001
                theBuffer->Clear();
2002
                for (int i = 0; i < (int) aLen; i++)
2003
                        theBuffer->WriteByte(mDemoBuffer.ReadByte());
2004
 
2005
                return true;           
2006
        }
2007
        else
2008
        {
2009
                PFILE* aFP = p_fopen(theFileName.c_str(), "rb");
2010
 
2011
                if (aFP == NULL)
2012
                {
2013
                        if ((mRecordingDemoBuffer) && (!dontWriteToDemo))
2014
                        {
2015
                                WriteDemoTimingBlock();
2016
                                mDemoBuffer.WriteNumBits(0, 1);
2017
                                mDemoBuffer.WriteNumBits(DEMO_FILE_READ, 5);
2018
                                mDemoBuffer.WriteNumBits(0, 1); // failure                              
2019
                        }
2020
 
2021
                        return false;
2022
                }
2023
 
2024
                p_fseek(aFP, 0, SEEK_END);
2025
                int aFileSize = p_ftell(aFP);
2026
                p_fseek(aFP, 0, SEEK_SET);
2027
 
2028
                uchar* aData = new uchar[aFileSize];
2029
 
2030
                p_fread(aData, 1, aFileSize, aFP);
2031
                p_fclose(aFP);
2032
 
2033
                theBuffer->Clear();
2034
                theBuffer->SetData(aData, aFileSize);
2035
 
2036
                if ((mRecordingDemoBuffer) && (!dontWriteToDemo))
2037
                {
2038
                        WriteDemoTimingBlock();
2039
                        mDemoBuffer.WriteNumBits(0, 1);
2040
                        mDemoBuffer.WriteNumBits(DEMO_FILE_READ, 5);
2041
                        mDemoBuffer.WriteNumBits(1, 1); // success                      
2042
                        mDemoBuffer.WriteLong(aFileSize);
2043
                        mDemoBuffer.WriteBytes(aData, aFileSize);
2044
                }
2045
 
2046
                delete [] aData;
2047
 
2048
                return true;
2049
        }
2050
}
2051
 
2052
bool SexyAppBase::FileExists(const std::string& theFileName)
2053
{
2054
        if (mPlayingDemoBuffer)
2055
        {
2056
                if (mManualShutdown)
2057
                        return true;
2058
 
2059
                PrepareDemoCommand(true);
2060
                mDemoNeedsCommand = true;
2061
 
2062
                DBG_ASSERTE(!mDemoIsShortCmd);         
2063
                DBG_ASSERTE(mDemoCmdNum == DEMO_FILE_EXISTS);          
2064
 
2065
                bool success = mDemoBuffer.ReadNumBits(1, false) != 0;         
2066
                return success;
2067
        }
2068
        else
2069
        {
2070
                PFILE* aFP = p_fopen(theFileName.c_str(), "rb");
2071
 
2072
                if (mRecordingDemoBuffer)
2073
                {
2074
                        WriteDemoTimingBlock();
2075
                        mDemoBuffer.WriteNumBits(0, 1);
2076
                        mDemoBuffer.WriteNumBits(DEMO_FILE_EXISTS, 5);
2077
                        mDemoBuffer.WriteNumBits((aFP != NULL) ? 1 : 0, 1);
2078
                }
2079
 
2080
                if (aFP == NULL)               
2081
                        return false;          
2082
 
2083
                p_fclose(aFP);
2084
                return true;
2085
        }
2086
}
2087
 
2088
bool SexyAppBase::EraseFile(const std::string& theFileName)
2089
{
2090
        if (mPlayingDemoBuffer)
2091
                return true;
2092
 
2093
        return DeleteFileA(theFileName.c_str()) != 0;
2094
}
2095
 
2096
void SexyAppBase::SEHOccured()
2097
{
2098
        SetMusicVolume(0);
2099
        ::ShowWindow(mHWnd, SW_HIDE);
2100
        mSEHOccured = true;
2101
        EnforceCursor();
2102
}
2103
 
2104
std::string SexyAppBase::GetGameSEHInfo()
2105
{
2106
        int aSecLoaded = (GetTickCount() - mTimeLoaded) / 1000;
2107
 
2108
        char aTimeStr[16];
2109
        sprintf(aTimeStr, "%02d:%02d:%02d", (aSecLoaded/60/60), (aSecLoaded/60)%60, aSecLoaded%60);
2110
 
2111
        char aThreadIdStr[16];
2112
        sprintf(aThreadIdStr, "%X", mPrimaryThreadId);
2113
 
2114
        std::string anInfoString =
2115
                "Product: " + mProdName + "\r\n" +             
2116
                "Version: " + mProductVersion + "\r\n";                
2117
 
2118
        anInfoString +=
2119
                "Time Loaded: " + std::string(aTimeStr) + "\r\n"
2120
                "Fullscreen: " + (mIsWindowed ? std::string("No") : std::string("Yes")) + "\r\n"
2121
                "Primary ThreadId: " + aThreadIdStr + "\r\n";  
2122
 
2123
        return anInfoString;                                           
2124
}
2125
 
2126
void SexyAppBase::GetSEHWebParams(DefinesMap* theDefinesMap)
2127
{
2128
}
2129
 
2130
void SexyAppBase::ShutdownHook()
2131
{
2132
}
2133
 
2134
void SexyAppBase::Shutdown()
2135
{
2136
        if ((mPrimaryThreadId != 0) && (GetCurrentThreadId() != mPrimaryThreadId))
2137
        {
2138
                mLoadingFailed = true;
2139
        }
2140
        else if (!mShutdown)
2141
        {
2142
                mExitToTop = true;
2143
                mShutdown = true;
2144
                ShutdownHook();
2145
 
2146
                if (mPlayingDemoBuffer)
2147
                {
2148
                        //if the music/sfx volume is 0, then it means that in playback
2149
                        //someone pressed the "S" key to mute sounds (or that the 
2150
                        //sound volume was set to 0 in the first place). Out of politeness,
2151
                        //return the system sound volume to what it last was in the game.
2152
                        SetMusicVolume(mDemoMusicVolume);
2153
                        SetSfxVolume(mDemoSfxVolume);
2154
                }
2155
 
2156
                // Blah
2157
                while (mCursorThreadRunning)
2158
                {
2159
                        Sleep(10);
2160
                }
2161
 
2162
                if (mMusicInterface != NULL)
2163
                        mMusicInterface->StopAllMusic();               
2164
 
2165
                if ((!mIsPhysWindowed) && (mDDInterface != NULL) && (mDDInterface->mDD != NULL))
2166
                {
2167
                        mDDInterface->mDD->RestoreDisplayMode();
2168
                }
2169
 
2170
                if (mHWnd != NULL)
2171
                {
2172
                        ShowWindow(mHWnd, SW_HIDE);                    
2173
                }
2174
 
2175
                RestoreScreenResolution();
2176
 
2177
                if (mReadFromRegistry)
2178
                        WriteToRegistry();
2179
 
2180
                ImageLib::CloseJPEG2000();
2181
        }
2182
}
2183
 
2184
void SexyAppBase::RestoreScreenResolution()
2185
{
2186
        if (mFullScreenWindow)
2187
        {
2188
                EnumWindows(ChangeDisplayWindowEnumProc,0); // get any windows that appeared while we were running
2189
                ChangeDisplaySettings(NULL,0);
2190
                EnumWindows(ChangeDisplayWindowEnumProc,1); // restore window pos
2191
                mFullScreenWindow = false;
2192
        }
2193
}
2194
 
2195
void SexyAppBase::DoExit(int theCode)
2196
{
2197
        RestoreScreenResolution();
2198
        exit(theCode);
2199
}
2200
 
2201
void SexyAppBase::UpdateFrames()
2202
{
2203
        mUpdateCount++;
2204
 
2205
        if (!mMinimized)
2206
        {              
2207
                if (mWidgetManager->UpdateFrame())
2208
                        ++mFPSDirtyCount;
2209
        }
2210
 
2211
        mMusicInterface->Update();     
2212
        CleanSharedImages();
2213
}
2214
 
2215
void SexyAppBase::DoUpdateFramesF(float theFrac)
2216
{
2217
        if ((mVSyncUpdates) && (!mMinimized))
2218
                mWidgetManager->UpdateFrameF(theFrac); 
2219
}
2220
 
2221
bool SexyAppBase::DoUpdateFrames()
2222
{
2223
        SEXY_AUTO_PERF("SexyAppBase::DoUpdateFrames");
2224
 
2225
        if (gScreenSaverActive)
2226
                return false;
2227
 
2228
        if (mPlayingDemoBuffer)
2229
        {
2230
                if ((mLoadingThreadCompleted) && (!mLoaded) && (mDemoLoadingComplete))
2231
                {                      
2232
                        mLoaded = true;
2233
                        ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_NORMAL);
2234
                        mYieldMainThread = false;
2235
                        LoadingThreadCompleted();
2236
                }
2237
 
2238
                // Hrrm not sure why we check (mUpdateCount != mLastDemoUpdateCnt) here
2239
                if ((mLoaded == mDemoLoadingComplete) && (mUpdateCount != mLastDemoUpdateCnt))         
2240
                {
2241
                        UpdateFrames();        
2242
                        return true;
2243
                }
2244
 
2245
                return false;
2246
        }
2247
        else
2248
        {
2249
                if ((mLoadingThreadCompleted) && (!mLoaded))
2250
                {
2251
                        ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_NORMAL);
2252
                        mLoaded = true;
2253
                        mYieldMainThread = false;
2254
                        LoadingThreadCompleted();
2255
 
2256
                        if (mRecordingDemoBuffer)
2257
                        {
2258
                                WriteDemoTimingBlock();
2259
                                mDemoBuffer.WriteNumBits(0, 1);
2260
                                mDemoBuffer.WriteNumBits(DEMO_LOADING_COMPLETE, 5);    
2261
                        }
2262
                }
2263
 
2264
                UpdateFrames();        
2265
                return true;
2266
        }
2267
}
2268
 
2269
bool gIsFailing = false;
2270
 
2271
void SexyAppBase::Redraw(Rect* theClipRect)
2272
{
2273
        SEXY_AUTO_PERF("SexyAppBase::Redraw");
2274
 
2275
        // Do mIsDrawing check because we could enter here at a bad time if any windows messages
2276
        //  are processed during WidgetManager->Draw
2277
        if ((mIsDrawing) || (mShutdown))
2278
                return;
2279
 
2280
        if (gScreenSaverActive)
2281
                return;
2282
 
2283
        static DWORD aRetryTick = 0;
2284
        if (!mDDInterface->Redraw(theClipRect))
2285
        {
2286
                extern bool gD3DInterfacePreDrawError;
2287
                gD3DInterfacePreDrawError = false; // this predraw error happens naturally when ddraw is failing
2288
                if (!gIsFailing)
2289
                {
2290
                        //gDebugStream << GetTickCount() << " Redraw failed!" << std::endl;
2291
                        gIsFailing = true;
2292
                }
2293
 
2294
                WINDOWPLACEMENT aWindowPlacement;
2295
                ZeroMemory(&aWindowPlacement, sizeof(aWindowPlacement));
2296
                aWindowPlacement.length = sizeof(aWindowPlacement);
2297
                ::GetWindowPlacement(mHWnd, &aWindowPlacement);
2298
 
2299
                DWORD aTick = GetTickCount();
2300
                if ((mActive || (aTick-aRetryTick>1000 && mIsPhysWindowed)) && (aWindowPlacement.showCmd != SW_SHOWMINIMIZED) && (!mMinimized))
2301
                {
2302
                        aRetryTick = aTick;
2303
 
2304
                        mWidgetManager->mImage = NULL;
2305
 
2306
                        // Re-check resolution at this point, because we hit here when you change your resolution.
2307
                        if (((mWidth >= GetSystemMetrics(SM_CXFULLSCREEN)) || (mHeight >= GetSystemMetrics(SM_CYFULLSCREEN))) && (mIsWindowed))
2308
                        {
2309
                                if (mForceWindowed)
2310
                                {
2311
                                        Popup(GetString("PLEASE_SET_COLOR_DEPTH", _S("Please set your desktop color depth to 16 bit.")));
2312
                                        Shutdown();
2313
                                        return;
2314
                                }
2315
                                mForceFullscreen = true;
2316
 
2317
                                SwitchScreenMode(false);
2318
                                return;
2319
                        }
2320
 
2321
 
2322
                        int aResult = InitDDInterface();
2323
 
2324
                        //gDebugStream << GetTickCount() << " ReInit..." << std::endl;
2325
 
2326
                        if ((mIsWindowed) && (aResult == DDInterface::RESULT_INVALID_COLORDEPTH))
2327
                        {
2328
                                //gDebugStream << GetTickCount() << "ReInit Invalid Colordepth" << std::endl;
2329
                                if (!mActive) // don't switch to full screen if not active app
2330
                                        return;
2331
 
2332
                                SwitchScreenMode(false);
2333
                                mForceFullscreen = true;
2334
                                return;
2335
                        }
2336
                        else if (aResult == DDInterface::RESULT_3D_FAIL)
2337
                        {
2338
                                Set3DAcclerated(false);
2339
                                return;
2340
                        }
2341
                        else if (aResult != DDInterface::RESULT_OK)
2342
                        {
2343
                                //gDebugStream << GetTickCount() << " ReInit Failed" << std::endl;
2344
                                //Fail("Failed to initialize DirectDraw");
2345
                                //Sleep(1000);                          
2346
 
2347
                                return;
2348
                        }                                              
2349
 
2350
                        ReInitImages();
2351
 
2352
                        mWidgetManager->mImage = mDDInterface->GetScreenImage();
2353
                        mWidgetManager->MarkAllDirty();
2354
 
2355
                        mLastTime = timeGetTime();
2356
                }
2357
        }
2358
        else
2359
        {
2360
                if (gIsFailing)
2361
                {
2362
                        //gDebugStream << GetTickCount() << " Redraw succeeded" << std::endl;
2363
                        gIsFailing = false;
2364
                        aRetryTick = 0;
2365
                }
2366
        }
2367
 
2368
        mFPSFlipCount++;
2369
}
2370
 
2371
///////////////////////////// FPS Stuff
2372
static PerfTimer gFPSTimer;
2373
static int gFrameCount;
2374
static int gFPSDisplay;
2375
static bool gForceDisplay = false;
2376
static void CalculateFPS()
2377
{
2378
        gFrameCount++;
2379
 
2380
        static SysFont aFont(gSexyAppBase,"Tahoma",8);
2381
        if (gFPSImage==NULL)
2382
        {
2383
                gFPSImage = new DDImage(gSexyAppBase->mDDInterface);
2384
                gFPSImage->Create(50,aFont.GetHeight()+4);
2385
                gFPSImage->SetImageMode(false,false);
2386
                gFPSImage->SetVolatile(true);
2387
                gFPSImage->mPurgeBits = false;
2388
                gFPSImage->mWantDDSurface = true;
2389
                gFPSImage->PurgeBits();
2390
        }
2391
 
2392
        if (gFPSTimer.GetDuration() >= 1000 || gForceDisplay)
2393
        {
2394
                gFPSTimer.Stop();
2395
                if (!gForceDisplay)
2396
                        gFPSDisplay = (int)(gFrameCount*1000/gFPSTimer.GetDuration() + 0.5f);
2397
                else
2398
                {
2399
                        gForceDisplay = false;
2400
                        gFPSDisplay = 0;
2401
                }
2402
 
2403
                gFPSTimer.Start();
2404
                gFrameCount = 0;
2405
 
2406
                Graphics aDrawG(gFPSImage);
2407
                aDrawG.SetFont(&aFont);
2408
                SexyString aFPS = StrFormat(_S("FPS: %d"), gFPSDisplay);
2409
                aDrawG.SetColor(0x000000);
2410
                aDrawG.FillRect(0,0,gFPSImage->GetWidth(),gFPSImage->GetHeight());
2411
                aDrawG.SetColor(0xFFFFFF);
2412
                aDrawG.DrawString(aFPS,2,aFont.GetAscent());
2413
                //gFPSImage->mKeepBits = false;
2414
                //gFPSImage->GenerateDDSurface();
2415
                gFPSImage->mBitsChangedCount++;
2416
        }
2417
}
2418
 
2419
///////////////////////////// FPS Stuff to draw mouse coords
2420
static void FPSDrawCoords(int theX, int theY)
2421
{
2422
        static SysFont aFont(gSexyAppBase,"Tahoma",8);
2423
        if (gFPSImage==NULL)
2424
        {
2425
                gFPSImage = new DDImage(gSexyAppBase->mDDInterface);
2426
                gFPSImage->Create(50,aFont.GetHeight()+4);
2427
                gFPSImage->SetImageMode(false,false);
2428
                gFPSImage->SetVolatile(true);
2429
                gFPSImage->mPurgeBits = false;
2430
                gFPSImage->mWantDDSurface = true;
2431
                gFPSImage->PurgeBits();
2432
        }
2433
 
2434
        Graphics aDrawG(gFPSImage);
2435
        aDrawG.SetFont(&aFont);
2436
        SexyString aFPS = StrFormat(_S("%d,%d"),theX,theY);
2437
        aDrawG.SetColor(0x000000);
2438
        aDrawG.FillRect(0,0,gFPSImage->GetWidth(),gFPSImage->GetHeight());
2439
        aDrawG.SetColor(0xFFFFFF);
2440
        aDrawG.DrawString(aFPS,2,aFont.GetAscent());   
2441
        gFPSImage->mBitsChangedCount++;
2442
}
2443
 
2444
///////////////////////////// Demo TimeLeft Stuff
2445
static DDImage* gDemoTimeLeftImage = NULL;
2446
static void CalculateDemoTimeLeft()
2447
{
2448
        static SysFont aFont(gSexyAppBase,"Tahoma",8);
2449
        static DWORD aLastTick = 0;
2450
 
2451
        if (gDemoTimeLeftImage==NULL)
2452
        {
2453
                gDemoTimeLeftImage = new DDImage(gSexyAppBase->mDDInterface);
2454
                gDemoTimeLeftImage->Create(50,aFont.GetHeight()+4);
2455
                gDemoTimeLeftImage->SetImageMode(false,false);
2456
                gDemoTimeLeftImage->SetVolatile(true);
2457
                gDemoTimeLeftImage->mPurgeBits = false;
2458
                gDemoTimeLeftImage->mWantDDSurface = true;
2459
                gDemoTimeLeftImage->PurgeBits();
2460
        }
2461
 
2462
        DWORD aTick = GetTickCount();
2463
        if (aTick - aLastTick < 1000/gSexyAppBase->mUpdateMultiplier)
2464
                return;
2465
 
2466
        aLastTick = aTick;
2467
 
2468
        int aNumUpdatesLeft = gSexyAppBase->mDemoLength - gSexyAppBase->mUpdateCount;
2469
        Graphics aDrawG(gDemoTimeLeftImage);
2470
        aDrawG.SetFont(&aFont);
2471
 
2472
        int aTotalSeconds = aNumUpdatesLeft*gSexyAppBase->mFrameTime/1000;
2473
        int aSeconds = aTotalSeconds%60;
2474
        int aMinutes = (aTotalSeconds/60)%60;
2475
        int anHours = (aTotalSeconds/3600);
2476
 
2477
        SexyString aFPS = StrFormat(_S("%02d:%02d:%02d"), anHours,aMinutes,aSeconds);
2478
        aDrawG.SetColor(0x000000);
2479
        aDrawG.FillRect(0,0,gDemoTimeLeftImage->GetWidth(),gDemoTimeLeftImage->GetHeight());
2480
        aDrawG.SetColor(0xFFFFFF);
2481
        aDrawG.DrawString(aFPS,2,aFont.GetAscent());   
2482
        gDemoTimeLeftImage->mBitsChangedCount++;
2483
}
2484
 
2485
static void UpdateScreenSaverInfo(DWORD theTick)
2486
{
2487
        if (gSexyAppBase->IsScreenSaver() || !gSexyAppBase->mIsPhysWindowed)
2488
                return;
2489
 
2490
        // Get screen saver timeout             
2491
        static DWORD aPeriodicTick = 0;
2492
        static DWORD aScreenSaverTimeout = 60000;
2493
        static BOOL aScreenSaverEnabled = TRUE;
2494
 
2495
        if (theTick-aPeriodicTick > 10000)
2496
        {
2497
                aPeriodicTick = theTick;
2498
 
2499
                int aTimeout = 0;
2500
 
2501
                SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT,0,&aTimeout,0);
2502
                SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0,&aScreenSaverEnabled,0);
2503
                aTimeout-=2;
2504
 
2505
                if (aTimeout < 1)
2506
                        aTimeout = 1;
2507
 
2508
                aScreenSaverTimeout = aTimeout*1000;
2509
 
2510
                if (!aScreenSaverEnabled)
2511
                        gScreenSaverActive = false;
2512
        }
2513
 
2514
        // Get more accurate last user input time
2515
        if (gGetLastInputInfoFunc)
2516
        {
2517
                LASTINPUTINFO anInfo;
2518
                anInfo.cbSize = sizeof(anInfo);
2519
                if (gGetLastInputInfoFunc(&anInfo))
2520
                {
2521
                        if (anInfo.dwTime > theTick)
2522
                                anInfo.dwTime = theTick;
2523
 
2524
                        gSexyAppBase->mLastUserInputTick = anInfo.dwTime;
2525
                }
2526
        }
2527
 
2528
        if (!aScreenSaverEnabled)
2529
                return;
2530
 
2531
        DWORD anIdleTime = theTick - gSexyAppBase->mLastUserInputTick;
2532
        if (gScreenSaverActive)
2533
        {
2534
                BOOL aBool = FALSE;
2535
                if (SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &aBool, 0))
2536
                {
2537
                        if (aBool) // screen saver not off yet
2538
                                return;
2539
                }
2540
 
2541
                if (anIdleTime < aScreenSaverTimeout)
2542
                {
2543
                        gScreenSaverActive = false;
2544
                        gSexyAppBase->mWidgetManager->MarkAllDirty();
2545
                }
2546
        }
2547
        else if (anIdleTime > aScreenSaverTimeout)
2548
                gScreenSaverActive = true;
2549
}
2550
 
2551
bool SexyAppBase::DrawDirtyStuff()
2552
{
2553
        SEXY_AUTO_PERF("SexyAppBase::DrawDirtyStuff");
2554
        MTAutoDisallowRand aDisallowRand;
2555
 
2556
        if (gIsFailing) // just try to reinit
2557
        {
2558
                Redraw(NULL);
2559
                mHasPendingDraw = false;
2560
                mLastDrawWasEmpty = true;              
2561
                return false;
2562
        }      
2563
 
2564
        if (mShowFPS)
2565
        {
2566
                switch(mShowFPSMode)
2567
                {
2568
                        case FPS_ShowFPS: CalculateFPS(); break;
2569
                        case FPS_ShowCoords:
2570
                                if (mWidgetManager!=NULL)
2571
                                        FPSDrawCoords(mWidgetManager->mLastMouseX, mWidgetManager->mLastMouseY);
2572
                                break;
2573
                }
2574
 
2575
                if (mPlayingDemoBuffer)
2576
                        CalculateDemoTimeLeft();
2577
        }
2578
 
2579
        DWORD aStartTime = timeGetTime();
2580
 
2581
        // Update user input and screen saver info
2582
        static DWORD aPeriodicTick = 0;
2583
        if (aStartTime-aPeriodicTick > 1000)
2584
        {
2585
                aPeriodicTick = aStartTime;
2586
                UpdateScreenSaverInfo(aStartTime);
2587
        }
2588
 
2589
        if (gScreenSaverActive)
2590
        {
2591
                mHasPendingDraw = false;
2592
                mLastDrawWasEmpty = true;              
2593
                return false;
2594
        }
2595
 
2596
        mIsDrawing = true;
2597
        bool drewScreen = mWidgetManager->DrawScreen();
2598
        mIsDrawing = false;
2599
 
2600
        if ((drewScreen || (aStartTime - mLastDrawTick >= 1000) || (mCustomCursorDirty)) &&
2601
                ((int) (aStartTime - mNextDrawTick) >= 0))
2602
        {
2603
                mLastDrawWasEmpty = false;
2604
 
2605
                mDrawCount++;          
2606
 
2607
                DWORD aMidTime = timeGetTime();
2608
 
2609
                mFPSCount++;
2610
                mFPSTime += aMidTime - aStartTime;
2611
 
2612
                mDrawTime += aMidTime - aStartTime;
2613
 
2614
                if (mShowFPS)
2615
                {
2616
                        Graphics g(mDDInterface->GetScreenImage());
2617
                        g.DrawImage(gFPSImage,mWidth-gFPSImage->GetWidth()-10,mHeight-gFPSImage->GetHeight()-10);
2618
 
2619
                        if (mPlayingDemoBuffer)
2620
                                g.DrawImage(gDemoTimeLeftImage,mWidth-gDemoTimeLeftImage->GetWidth()-10,mHeight-gFPSImage->GetHeight()-gDemoTimeLeftImage->GetHeight()-15);
2621
                }
2622
 
2623
                if (mWaitForVSync && mIsPhysWindowed && mSoftVSyncWait)
2624
                {
2625
                        DWORD aTick = timeGetTime();
2626
                        if (aTick-mLastDrawTick < mDDInterface->mMillisecondsPerFrame)
2627
                                Sleep(mDDInterface->mMillisecondsPerFrame - (aTick-mLastDrawTick));
2628
                }
2629
 
2630
                DWORD aPreScreenBltTime = timeGetTime();
2631
                mLastDrawTick = aPreScreenBltTime;
2632
 
2633
                Redraw(NULL);          
2634
 
2635
                // This is our one UpdateFTimeAcc if we are vsynched
2636
                UpdateFTimeAcc();
2637
 
2638
                DWORD aEndTime = timeGetTime();
2639
 
2640
                mScreenBltTime = aEndTime - aPreScreenBltTime;
2641
 
2642
#ifdef _DEBUG
2643
                /*if (mFPSTime >= 5000) // Show FPS about every 5 seconds
2644
                {
2645
                        ulong aTickNow = GetTickCount();
2646
 
2647
                        OutputDebugString(StrFormat(_S("Theoretical FPS: %d\r\n"), (int) (mFPSCount * 1000 / mFPSTime)).c_str());
2648
                        OutputDebugString(StrFormat(_S("Actual      FPS: %d\r\n"), (mFPSFlipCount * 1000) / max((aTickNow - mFPSStartTick), 1)).c_str());
2649
                        OutputDebugString(StrFormat(_S("Dirty Rate     : %d\r\n"), (mFPSDirtyCount * 1000) / max((aTickNow - mFPSStartTick), 1)).c_str());
2650
 
2651
                        mFPSTime = 0;
2652
                        mFPSCount = 0;
2653
                        mFPSFlipCount = 0;
2654
                        mFPSStartTick = aTickNow;
2655
                        mFPSDirtyCount = 0;
2656
                }*/
2657
#endif
2658
 
2659
                if ((mLoadingThreadStarted) && (!mLoadingThreadCompleted))
2660
                {
2661
                        int aTotalTime = aEndTime - aStartTime;
2662
 
2663
                        mNextDrawTick += 35 + max(aTotalTime, 15);
2664
 
2665
                        if ((int) (aEndTime - mNextDrawTick) >= 0)                     
2666
                                mNextDrawTick = aEndTime;                      
2667
 
2668
                        /*char aStr[256];
2669
                        sprintf(aStr, "Next Draw Time: %d\r\n", mNextDrawTick);
2670
                        OutputDebugString(aStr);*/
2671
                }
2672
                else
2673
                        mNextDrawTick = aEndTime;
2674
 
2675
                mHasPendingDraw = false;               
2676
                mCustomCursorDirty = false;
2677
 
2678
                return true;
2679
        }
2680
        else
2681
        {              
2682
                mHasPendingDraw = false;
2683
                mLastDrawWasEmpty = true;              
2684
                return false;
2685
        }
2686
}
2687
 
2688
void SexyAppBase::LogScreenSaverError(const std::string &theError)
2689
{
2690
        static bool firstTime = true;
2691
        char aBuf[512];
2692
 
2693
        const char *aFlag = firstTime?"w":"a+";
2694
        firstTime = false;
2695
 
2696
        FILE *aFile = fopen("ScrError.txt",aFlag);
2697
        if (aFile != NULL)
2698
        {
2699
                fprintf(aFile,"%s %s %u\n",theError.c_str(),_strtime(aBuf),GetTickCount());
2700
                fclose(aFile);
2701
        }
2702
}
2703
 
2704
void SexyAppBase::BeginPopup()
2705
{
2706
        if (!mIsPhysWindowed)
2707
        {
2708
                if (mDDInterface && mDDInterface->mDD)
2709
                {
2710
                        mDDInterface->mDD->FlipToGDISurface();
2711
                        mNoDefer = true;
2712
                }
2713
        }
2714
}
2715
 
2716
void SexyAppBase::EndPopup()
2717
{
2718
        if (!mIsPhysWindowed)
2719
                mNoDefer = false;
2720
 
2721
        ClearUpdateBacklog();
2722
        ClearKeysDown();
2723
 
2724
        if (mWidgetManager->mDownButtons)
2725
        {
2726
                mWidgetManager->DoMouseUps();
2727
                ReleaseCapture();
2728
        }
2729
}
2730
 
2731
int SexyAppBase::MsgBox(const std::string& theText, const std::string& theTitle, int theFlags)
2732
{
2733
//      if (mDDInterface && mDDInterface->mDD)
2734
//              mDDInterface->mDD->FlipToGDISurface();
2735
        if (IsScreenSaver())
2736
        {
2737
                LogScreenSaverError(theText);
2738
                return IDOK;
2739
        }
2740
 
2741
        BeginPopup();
2742
        int aResult = MessageBoxA(mHWnd, theText.c_str(), theTitle.c_str(), theFlags);
2743
        EndPopup();
2744
 
2745
        return aResult;
2746
}
2747
 
2748
int SexyAppBase::MsgBox(const std::wstring& theText, const std::wstring& theTitle, int theFlags)
2749
{
2750
//      if (mDDInterface && mDDInterface->mDD)
2751
//              mDDInterface->mDD->FlipToGDISurface();
2752
        if (IsScreenSaver())
2753
        {
2754
                LogScreenSaverError(WStringToString(theText));
2755
                return IDOK;
2756
        }
2757
 
2758
        BeginPopup();
2759
        int aResult = MessageBoxW(mHWnd, theText.c_str(), theTitle.c_str(), theFlags);
2760
        EndPopup();
2761
 
2762
        return aResult;
2763
}
2764
 
2765
void SexyAppBase::Popup(const std::string& theString)
2766
{
2767
        if (IsScreenSaver())
2768
        {
2769
                LogScreenSaverError(theString);
2770
                return;
2771
        }
2772
 
2773
        BeginPopup();
2774
        if (!mShutdown)
2775
                ::MessageBoxA(mHWnd, theString.c_str(), SexyStringToString(GetString("FATAL_ERROR", _S("FATAL ERROR"))).c_str(), MB_APPLMODAL | MB_ICONSTOP);
2776
        EndPopup();
2777
}
2778
 
2779
void SexyAppBase::Popup(const std::wstring& theString)
2780
{
2781
        if (IsScreenSaver())
2782
        {
2783
                LogScreenSaverError(WStringToString(theString));
2784
                return;
2785
        }
2786
 
2787
        BeginPopup();
2788
        if (!mShutdown)
2789
                ::MessageBoxW(mHWnd, theString.c_str(), SexyStringToWString(GetString("FATAL_ERROR", _S("FATAL ERROR"))).c_str(), MB_APPLMODAL | MB_ICONSTOP);
2790
        EndPopup();
2791
}
2792
 
2793
void SexyAppBase::SafeDeleteWidget(Widget* theWidget)
2794
{
2795
        WidgetSafeDeleteInfo aWidgetSafeDeleteInfo;
2796
        aWidgetSafeDeleteInfo.mUpdateAppDepth = mUpdateAppDepth;
2797
        aWidgetSafeDeleteInfo.mWidget = theWidget;
2798
        mSafeDeleteList.push_back(aWidgetSafeDeleteInfo);
2799
}
2800
 
2801
BOOL CALLBACK EnumCloseThing2(HWND hwnd, LPARAM lParam)
2802
{
2803
        //CloseWindow(hwnd);
2804
        char aClassName[256];
2805
        if (GetClassNameA(hwnd, aClassName, 256) != 0)
2806
        {
2807
                if (strcmp(aClassName, "Internet Explorer_Server") == 0)
2808
                {
2809
                        DestroyWindow(hwnd);                   
2810
                }
2811
                else
2812
                {
2813
                        EnumChildWindows(hwnd, EnumCloseThing2, lParam);
2814
                }
2815
        }
2816
 
2817
        return TRUE;
2818
}
2819
 
2820
BOOL CALLBACK EnumCloseThing(HWND hwnd, LPARAM lParam)
2821
{
2822
        //CloseWindow(hwnd);
2823
        char aClassName[256];
2824
        if (GetClassNameA(hwnd, aClassName, 256) != 0)
2825
        {
2826
                if (strcmp(aClassName, "AmWBC_WClass") == 0)
2827
                {
2828
                        EnumChildWindows(hwnd, EnumCloseThing2, lParam);
2829
                }
2830
        }
2831
 
2832
        return TRUE;
2833
}
2834
 
2835
static INT_PTR CALLBACK MarkerListDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2836
{
2837
        switch (msg)
2838
        {
2839
                case WM_INITDIALOG:
2840
                {
2841
                        HWND aListBox = GetDlgItem(hwnd,100);
2842
 
2843
                        DWORD       dwExtent = 0;
2844
                        HDC         hDCListBox;
2845
                        HFONT       hFontOld, hFontNew;
2846
                        TEXTMETRIC  tm;
2847
                        RECT aRect;
2848
                        SIZE aSize;
2849
 
2850
                        hDCListBox = GetDC(aListBox);
2851
                        hFontNew = (HFONT)SendMessage(aListBox, WM_GETFONT, NULL, NULL);
2852
                        hFontOld = (HFONT)SelectObject(hDCListBox, hFontNew);
2853
                        GetTextMetrics(hDCListBox, (LPTEXTMETRIC)&tm);
2854
                        GetClientRect(hwnd, &aRect);
2855
                        MoveWindow(aListBox,10,10,aRect.right-aRect.left-20,aRect.bottom-aRect.top-20,FALSE);
2856
                        for (SexyAppBase::DemoMarkerList::iterator anItr = gSexyAppBase->mDemoMarkerList.begin(); anItr != gSexyAppBase->mDemoMarkerList.end(); ++anItr)
2857
                        {
2858
                                if (anItr->second <= gSexyAppBase->mUpdateCount)
2859
                                        continue;
2860
 
2861
                                int aTotalSeconds = (gSexyAppBase->mDemoLength - anItr->second)*gSexyAppBase->mFrameTime/1000;
2862
                                int aSeconds = aTotalSeconds%60;
2863
                                int aMinutes = (aTotalSeconds/60)%60;
2864
                                int anHours = (aTotalSeconds/3600);
2865
 
2866
                                SexyString aStr = StrFormat(_S("%s (%02d:%02d:%02d)"), anItr->first.c_str(),anHours,aMinutes,aSeconds);                        
2867
                                GetTextExtentPoint32(hDCListBox, aStr.c_str(), aStr.length(), &aSize);
2868
                                dwExtent = max (aSize.cx + tm.tmAveCharWidth, (int)dwExtent);
2869
                                SendMessage(aListBox, LB_SETHORIZONTALEXTENT, dwExtent, 0);
2870
                                LRESULT anIndex = SendMessage(aListBox, LB_ADDSTRING, 0, (LPARAM)aStr.c_str());
2871
                                SendMessage(aListBox, LB_SETITEMDATA, anIndex, anItr->second);
2872
                        }
2873
 
2874
                        SelectObject(hDCListBox, hFontOld);
2875
                        ReleaseDC(aListBox, hDCListBox);
2876
 
2877
                        return TRUE;
2878
                }
2879
 
2880
                case WM_CLOSE:
2881
                        EndDialog(hwnd,0);
2882
                        return TRUE;
2883
 
2884
                case WM_COMMAND:
2885
                        if (HIWORD(wParam)==LBN_DBLCLK)
2886
                        {
2887
                                HWND aListBox = GetDlgItem(hwnd,100);
2888
 
2889
                                int anIndex = SendMessage(aListBox,LB_GETCURSEL,0,0);
2890
                                if (anIndex >= 0)
2891
                                {
2892
                                        int anUpdateTime = SendMessage(aListBox,LB_GETITEMDATA,anIndex,0);
2893
                                        if (anUpdateTime > gSexyAppBase->mUpdateCount)
2894
                                        {
2895
                                                gSexyAppBase->mFastForwardToUpdateNum = anUpdateTime;
2896
                                                EndDialog(hwnd,0);
2897
                                        }
2898
                                }
2899
                                return TRUE;
2900
                        }
2901
                        break;
2902
 
2903
        }
2904
 
2905
        return FALSE;
2906
}
2907
 
2908
static LPWORD lpdwAlign ( LPWORD lpIn)
2909
{
2910
    ULONG ul;
2911
 
2912
    ul = (ULONG) lpIn;
2913
    ul +=3;
2914
    ul >>=2;
2915
    ul <<=2;
2916
    return (LPWORD) ul;
2917
}
2918
 
2919
static int ListDemoMarkers()
2920
{
2921
        HGLOBAL hgbl;
2922
    LPDLGTEMPLATE lpdt;
2923
    LPDLGITEMTEMPLATE lpdit;
2924
    LPWORD lpw;
2925
    LPWSTR lpwsz;
2926
    LRESULT ret;
2927
    int nchar;
2928
 
2929
    hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
2930
    if (!hgbl)
2931
        return -1;
2932
 
2933
    lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2934
 
2935
    // Define a dialog box. 
2936
    lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT;
2937
    lpdt->cdit = 1;  // number of controls
2938
    lpdt->x  = 10;  lpdt->y  = 10;
2939
    lpdt->cx = 200; lpdt->cy = 200;
2940
 
2941
    lpw = (LPWORD) (lpdt + 1);
2942
    *lpw++ = 0;   // no menu
2943
    *lpw++ = 0;   // predefined dialog box class (by default)
2944
 
2945
    lpwsz = (LPWSTR) lpw;
2946
    nchar = MultiByteToWideChar (CP_ACP, 0, "Marker List", -1, lpwsz, 50);
2947
    lpw   += nchar;
2948
        *lpw++ = 8;
2949
        lpwsz = (LPWSTR) lpw;
2950
    nchar = MultiByteToWideChar (CP_ACP, 0, "Tahoma", -1, lpwsz, 50);
2951
        lpw += nchar;
2952
 
2953
        // Define Listbox
2954
    lpw = lpdwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2955
    lpdit = (LPDLGITEMTEMPLATE) lpw;
2956
    lpdit->x  = 5; lpdit->y  = 5;
2957
    lpdit->cx = 190; lpdit->cy = 195;
2958
    lpdit->id = 100;  
2959
        lpdit->style = WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LBS_NOTIFY;
2960
        lpdit->dwExtendedStyle = WS_EX_CLIENTEDGE;
2961
    lpw = (LPWORD) (lpdit + 1);
2962
    *lpw++ = 0xFFFF;
2963
    *lpw++ = 0x0083;    // listbox class
2964
        *lpw++ = 0;                     // no window text
2965
    *lpw++ = 0;                 // no creation data
2966
 
2967
 
2968
    GlobalUnlock(hgbl);
2969
    ret = DialogBoxIndirect(gHInstance, (LPDLGTEMPLATE) hgbl, gSexyAppBase->mHWnd, (DLGPROC) MarkerListDialogProc);
2970
    GlobalFree(hgbl);
2971
 
2972
        gSexyAppBase->mLastTime = timeGetTime();
2973
 
2974
    return ret;
2975
}
2976
 
2977
static INT_PTR CALLBACK JumpToTimeDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2978
{
2979
        switch (msg)
2980
        {
2981
                case WM_INITDIALOG:
2982
                {
2983
                        HWND anEdit = GetDlgItem(hwnd,100);
2984
                        HKEY aGameKey;
2985
                        std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + gSexyAppBase->mRegKey);
2986
                        if (RegOpenKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, KEY_READ | KEY_WRITE, &aGameKey) == ERROR_SUCCESS)
2987
                        {
2988
                                char aBuf[1024];
2989
                                DWORD aLength = 1000;
2990
                                DWORD aType = REG_SZ;
2991
                                if (RegQueryValueExA(aGameKey, "DemoJumpTime", 0, &aType, (uchar*) aBuf, &aLength) == ERROR_SUCCESS)
2992
                                {
2993
                                        aBuf[aLength] = 0;
2994
                                        SetWindowTextA(anEdit,aBuf);
2995
                                        SendMessage(anEdit,EM_SETSEL,0,-1);
2996
                                }
2997
                                RegCloseKey(aGameKey);
2998
                        }
2999
                        return TRUE;
3000
                }
3001
                break;
3002
 
3003
                case WM_CLOSE:
3004
                        EndDialog(hwnd,0);
3005
                        return TRUE;
3006
 
3007
                case WM_COMMAND:
3008
                        if (HIWORD(wParam)==BN_CLICKED)
3009
                        {
3010
                                if (LOWORD(wParam)==IDOK)
3011
                                {
3012
                                        char aBuf[512];
3013
                                        HWND anEdit = GetDlgItem(hwnd,100);
3014
                                        GetWindowTextA(anEdit,aBuf,500);
3015
 
3016
                                        HKEY aGameKey;
3017
                                        std::string aKeyName = RemoveTrailingSlash("SOFTWARE\\" + gSexyAppBase->mRegKey);
3018
                                        if (RegOpenKeyExA(HKEY_CURRENT_USER, aKeyName.c_str(), 0, KEY_READ | KEY_WRITE, &aGameKey) == ERROR_SUCCESS)
3019
                                        {
3020
                                                RegSetValueExA(aGameKey, "DemoJumpTime", 0, REG_SZ, (const BYTE*)aBuf, strlen(aBuf)+1);
3021
                                                RegCloseKey(aGameKey);
3022
                                        }
3023
 
3024
                                        int aTime = 0;
3025
                                        char *aPtr = strtok(aBuf,":");
3026
                                        while (aPtr != NULL)
3027
                                        {
3028
                                                aTime *= 60;
3029
                                                aTime += atoi(aPtr);
3030
                                                aPtr = strtok(NULL,":");
3031
                                        }
3032
                                        aTime++;
3033
 
3034
                                        int aNumFrames = aTime*1000/gSexyAppBase->mFrameTime;
3035
                                        gSexyAppBase->mFastForwardToUpdateNum = gSexyAppBase->mDemoLength - aNumFrames;                                
3036
 
3037
 
3038
                                }
3039
 
3040
                                EndDialog(hwnd,0);
3041
                                return TRUE;
3042
                        }
3043
                        break;
3044
        }
3045
 
3046
        return FALSE;
3047
}
3048
 
3049
static int DemoJumpToTime()
3050
{
3051
        HGLOBAL hgbl;
3052
    LPDLGTEMPLATE lpdt;
3053
    LPDLGITEMTEMPLATE lpdit;
3054
    LPWORD lpw;
3055
    LPWSTR lpwsz;
3056
    LRESULT ret;
3057
    int nchar;
3058
 
3059
    hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
3060
    if (!hgbl)
3061
        return -1;
3062
 
3063
    lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
3064
 
3065
    // Define a dialog box. 
3066
    lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT;
3067
    lpdt->cdit = 3;  // number of controls
3068
    lpdt->x  = 10;  lpdt->y  = 10;
3069
    lpdt->cx = 200; lpdt->cy = 50;
3070
 
3071
    lpw = (LPWORD) (lpdt + 1);
3072
    *lpw++ = 0;   // no menu
3073
    *lpw++ = 0;   // predefined dialog box class (by default)
3074
 
3075
    lpwsz = (LPWSTR) lpw;
3076
    nchar = MultiByteToWideChar (CP_ACP, 0, "Jump To Time", -1, lpwsz, 50);
3077
    lpw   += nchar;
3078
        *lpw++ = 8;
3079
        lpwsz = (LPWSTR) lpw;
3080
    nchar = MultiByteToWideChar (CP_ACP, 0, "Tahoma", -1, lpwsz, 50);
3081
        lpw += nchar;
3082
 
3083
        // Define Edit
3084
    lpw = lpdwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
3085
    lpdit = (LPDLGITEMTEMPLATE) lpw;
3086
    lpdit->x  = 5; lpdit->y  = 5;
3087
    lpdit->cx = 190; lpdit->cy = 15;
3088
    lpdit->id = 100;  
3089
        lpdit->style = WS_VISIBLE | WS_CHILD;
3090
        lpdit->dwExtendedStyle = WS_EX_CLIENTEDGE;
3091
    lpw = (LPWORD) (lpdit + 1);
3092
    *lpw++ = 0xFFFF;
3093
    *lpw++ = 0x0081;    // edit class
3094
        *lpw++ = 0;                     // no window text
3095
    *lpw++ = 0;                 // no creation data
3096
 
3097
        // Define Button
3098
    lpw = lpdwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
3099
    lpdit = (LPDLGITEMTEMPLATE) lpw;
3100
    lpdit->x  = 30; lpdit->y  = 25;
3101
    lpdit->cx = 60; lpdit->cy = 15;
3102
    lpdit->id = IDOK;  
3103
        lpdit->style = WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON;
3104
//      lpdit->dwExtendedStyle = WS_EX_CLIENTEDGE;
3105
    lpw = (LPWORD) (lpdit + 1);
3106
    *lpw++ = 0xFFFF;
3107
    *lpw++ = 0x0080;    // button class
3108
        lpwsz = (LPWSTR) lpw;
3109
        nchar = MultiByteToWideChar (CP_ACP, 0, "Ok", -1, lpwsz, 50);
3110
    lpw   += nchar;
3111
    lpw = lpdwAlign (lpw); // align creation data on DWORD boundary
3112
    *lpw++ = 0;                 // no creation data
3113
 
3114
 
3115
        // Define Button
3116
    lpw = lpdwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
3117
    lpdit = (LPDLGITEMTEMPLATE) lpw;
3118
    lpdit->x  = 100; lpdit->y  = 25;
3119
    lpdit->cx = 60; lpdit->cy = 15;
3120
    lpdit->id = IDCANCEL;  
3121
        lpdit->style = WS_VISIBLE | WS_CHILD;
3122
//      lpdit->dwExtendedStyle = WS_EX_CLIENTEDGE;
3123
    lpw = (LPWORD) (lpdit + 1);
3124
    *lpw++ = 0xFFFF;
3125
    *lpw++ = 0x0080;    // button class
3126
        lpwsz = (LPWSTR) lpw;
3127
        nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
3128
    lpw   += nchar;
3129
    lpw = lpdwAlign (lpw); // align creation data on DWORD boundary
3130
    *lpw++ = 0;                 // no creation data
3131
 
3132
 
3133
 
3134
 
3135
    GlobalUnlock(hgbl);
3136
    ret = DialogBoxIndirect(gHInstance, (LPDLGTEMPLATE) hgbl, gSexyAppBase->mHWnd, (DLGPROC) JumpToTimeDialogProc);
3137
    GlobalFree(hgbl);
3138
 
3139
        gSexyAppBase->mLastTime = timeGetTime();
3140
 
3141
    return ret;
3142
}
3143
 
3144
static void ToggleDemoSoundVolume()
3145
{
3146
        if (gSexyAppBase->GetMusicVolume() == 0.0)
3147
                gSexyAppBase->SetMusicVolume(gSexyAppBase->mDemoMusicVolume);
3148
        else
3149
        {
3150
                gSexyAppBase->mDemoMusicVolume = gSexyAppBase->mMusicVolume;
3151
                gSexyAppBase->SetMusicVolume(0.0);
3152
        }
3153
 
3154
        if (gSexyAppBase->GetSfxVolume() == 0.0)
3155
                gSexyAppBase->SetSfxVolume(gSexyAppBase->mDemoSfxVolume);
3156
        else
3157
        {
3158
                gSexyAppBase->mDemoSfxVolume = gSexyAppBase->mSfxVolume;
3159
                gSexyAppBase->SetSfxVolume(0.0);
3160
        }
3161
}
3162
 
3163
static DWORD gPowerSaveTick = 0;
3164
static bool ScreenSaverWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &theResult)
3165
{
3166
        static bool gCreated = false;
3167
        static int gMouseMoveCount = 0;
3168
        static int gLastMouseX = 0, gLastMouseY = 0;
3169
        static bool gClosed = false;
3170
        typedef BOOL (WINAPI *VERIFYPWDPROC)(HWND);
3171
        static VERIFYPWDPROC aPasswordFunc = NULL;
3172
        HMODULE aPasswordLib = NULL;
3173
 
3174
        if (gClosed)
3175
                return false;
3176
 
3177
        switch (uMsg)
3178
        {
3179
                case WM_CREATE:
3180
                {
3181
                        if (gCreated)
3182
                                return false;
3183
 
3184
                        gCreated = true;
3185
                        POINT aMousePoint;
3186
                        GetCursorPos(&aMousePoint);
3187
                        gLastMouseX = aMousePoint.x;
3188
                        gLastMouseY = aMousePoint.y;
3189
 
3190
                        // Password checking stuff for 95/98/ME
3191
                        OSVERSIONINFO aVersion;
3192
                        aVersion.dwOSVersionInfoSize = sizeof(aVersion);
3193
                        GetVersionEx(&aVersion);
3194
                        if (aVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
3195
                        {
3196
                                HKEY hKey;
3197
                                if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_SCREENSAVE ,&hKey) == ERROR_SUCCESS)
3198
                                {
3199
                                        DWORD aCheckPwd = 0;
3200
                                        DWORD aSize = sizeof(DWORD);
3201
                                        DWORD aType;
3202
                                        LONG aResult = RegQueryValueEx(hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, &aType, (PBYTE) &aCheckPwd, &aSize);
3203
                                        if (aResult==ERROR_SUCCESS && aCheckPwd)
3204
                                        {
3205
                                                aPasswordLib = LoadLibrary(TEXT("PASSWORD.CPL"));
3206
                                                if (aPasswordLib)
3207
                                                {
3208
                                                        aPasswordFunc = (VERIFYPWDPROC)GetProcAddress(aPasswordLib, "VerifyScreenSavePwd");
3209
                                                        // prevents user from ctrl-alt-deleting the screensaver etc to avoid typing in a password
3210
                                                        int aPrev;
3211
                                                        SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, &aPrev, 0);
3212
                                                }
3213
 
3214
                                        }
3215
                                        RegCloseKey(hKey);
3216
                                }
3217
                        }
3218
                        return false;
3219
                }
3220
                break;
3221
 
3222
                case WM_SYSCOMMAND:
3223
                {
3224
                        switch (wParam)
3225
                        {
3226
                                case SC_CLOSE:
3227
                                case SC_SCREENSAVE:
3228
                                case SC_NEXTWINDOW:
3229
                                case SC_PREVWINDOW:
3230
                                        theResult = FALSE;
3231
                                        return true;
3232
 
3233
                                default:
3234
                                        return false;
3235
                        }
3236
                }
3237
                break;
3238
 
3239
                case WM_MOUSEMOVE:
3240
                {
3241
                        int aMouseX = LOWORD(lParam);
3242
                        int aMouseY = HIWORD(lParam);
3243
//                      SEXY_TRACE(StrFormat("SCR MouseMove: %d %d",aMouseX,aMouseY).c_str());
3244
                        if (aMouseX!=gLastMouseX || aMouseY!=gLastMouseY)
3245
                        {
3246
                                gLastMouseX = aMouseX;
3247
                                gLastMouseY = aMouseY;
3248
                                gMouseMoveCount++;
3249
                        }
3250
 
3251
                        if (gMouseMoveCount < 4)
3252
                        {
3253
                                theResult = 0;
3254
                                return true;
3255
                        }
3256
                }
3257
                break;
3258
 
3259
                case WM_NCACTIVATE:
3260
                case WM_ACTIVATE:
3261
                case WM_ACTIVATEAPP:
3262
                {
3263
                        if (wParam != FALSE)
3264
                                return false;
3265
                }
3266
                break;
3267
 
3268
                case WM_CLOSE:
3269
                case WM_LBUTTONDOWN:
3270
                case WM_RBUTTONDOWN:
3271
                case WM_MBUTTONDOWN:
3272
                case WM_KEYDOWN:
3273
                case WM_SYSKEYDOWN:
3274
                        break;
3275
 
3276
                default:
3277
                        return false;
3278
        }
3279
 
3280
        if (gSexyAppBase!=NULL && gSexyAppBase->mHWnd!=hWnd) // wrong window
3281
                return false;
3282
 
3283
        if (GetTickCount()-gPowerSaveTick < 1000) // powersave just went on so ignore certain messages that seem to come on certain os's at that time
3284
        {
3285
                switch (uMsg)
3286
                {
3287
                        case WM_MOUSEMOVE:
3288
                        case WM_NCACTIVATE:
3289
                        case WM_ACTIVATE:
3290
                        case WM_ACTIVATEAPP:
3291
                        case WM_CLOSE:
3292
                                return false;
3293
                }
3294
        }
3295
 
3296
        if (aPasswordFunc && gSexyAppBase!=NULL && gSexyAppBase->mInitialized) // need to verify password before closing
3297
        {
3298
                if (gSexyAppBase!=NULL && gSexyAppBase->mDDInterface!=NULL && gSexyAppBase->mDDInterface->mDD!=NULL)
3299
                {
3300
                        gSexyAppBase->mDDInterface->mDD->FlipToGDISurface();    // so we can see the password dialog
3301
                        gSexyAppBase->mNoDefer = true;                                                  // so the app doesn't draw over the password dialog
3302
                }
3303
 
3304
                gClosed = true; // prevent this function from doing anything while in the password dialog
3305
                BOOL aPasswordResult = aPasswordFunc(hWnd);
3306
                gClosed = false; // let this functino work again
3307
 
3308
                if (gSexyAppBase!=NULL)
3309
                {
3310
                        gSexyAppBase->mNoDefer = false;
3311
                        gSexyAppBase->ClearUpdateBacklog();
3312
                }
3313
 
3314
                if (!aPasswordResult) // bad password
3315
                {
3316
                        // Get new mouse coordinate
3317
                        POINT aMousePoint;
3318
                        GetCursorPos(&aMousePoint);
3319
                        gLastMouseX = aMousePoint.x;
3320
                        gLastMouseY = aMousePoint.y;
3321
                        gMouseMoveCount = 0;
3322
 
3323
                        return false;
3324
                }
3325
 
3326
 
3327
                // can turn this SPI_SCREENSAVERRUNNING off now since screensaver is about to stop
3328
                int aPrev;
3329
                SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, &aPrev, 0);
3330
 
3331
                // good password -> close and unload dll
3332
                FreeLibrary(aPasswordLib);
3333
                aPasswordLib = NULL;
3334
                aPasswordFunc = NULL;
3335
        }
3336
 
3337
        // Screen saver should shutdown
3338
        gClosed = true;
3339
        PostMessage(hWnd, WM_CLOSE, 0, 0);
3340
 
3341
/*      const char *str = "";
3342
        switch (uMsg)
3343
        {
3344
                case WM_CREATE: str="WM_CREATE"; break;
3345
                case WM_SYSCOMMAND: str="WM_SYSCOMMAND"; break;
3346
                case WM_MOUSEMOVE: str="WM_MOUSEMOVE"; break;
3347
                case WM_NCACTIVATE: str="WM_NCACTIVATE"; break;
3348
                case WM_ACTIVATE: str="WM_ACTIVATE"; break;
3349
                case WM_ACTIVATEAPP: str="WM_ACTIVATEAPP"; break;
3350
                case WM_CLOSE: str="WM_CLOSE"; break;
3351
                case WM_LBUTTONDOWN: str="WM_LBUTTONDOWN"; break;
3352
                case WM_RBUTTONDOWN: str="WM_RBUTTONDOWN"; break;
3353
                case WM_MBUTTONDOWN: str="WM_MBUTTONDOWN"; break;
3354
                case WM_KEYDOWN: str="WM_KEYDOWN"; break;
3355
                case WM_SYSKEYDOWN: str="WM_SYSKEYDOWN"; break;
3356
        }
3357
 
3358
        SEXY_TRACE(StrFormat("Scr shutdown: %s",str).c_str());*/
3359
        return false;
3360
}
3361
 
3362
LRESULT CALLBACK SexyAppBase::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3363
{
3364
        if (gSexyAppBase!=NULL && gSexyAppBase->IsScreenSaver())
3365
        {
3366
                LRESULT aResult;
3367
                if (ScreenSaverWindowProc(hWnd,uMsg,wParam,lParam,aResult))
3368
                        return aResult;
3369
        }
3370
 
3371
        SexyAppBase* aSexyApp = (SexyAppBase*) GetWindowLong(hWnd, GWL_USERDATA);      
3372
        switch (uMsg)
3373
        {              
3374
//  TODO: switch to killfocus/setfocus?
3375
//      case WM_KILLFOCUS:
3376
//      case WM_SETFOCUS:
3377
//      if ((aSexyApp != NULL) && (!aSexyApp->mPlayingDemoBuffer))
3378
//      {
3379
//              if (hWnd == aSexyApp->mHWnd)
3380
//                      aSexyApp->mActive = uMsg==WM_SETFOCUS;
3381
//      }
3382
//      //Fallthrough
3383
 
3384
        case WM_ACTIVATEAPP:
3385
                if ((aSexyApp != NULL) && (!aSexyApp->mPlayingDemoBuffer))
3386
                {
3387
                        if (hWnd == aSexyApp->mHWnd)
3388
                        {
3389
                                aSexyApp->mActive = wParam != 0;
3390
                        }
3391
                }
3392
                //Fallthrough   
3393
 
3394
        case WM_SIZE:
3395
        case WM_MOVE:
3396
        case WM_TIMER:
3397
        case WM_LBUTTONDOWN:           
3398
        case WM_RBUTTONDOWN:
3399
        case WM_MBUTTONDOWN:
3400
        case WM_LBUTTONDBLCLK:
3401
        case WM_RBUTTONDBLCLK:
3402
        case WM_LBUTTONUP:
3403
        case WM_RBUTTONUP:             
3404
        case WM_MBUTTONUP:             
3405
        case WM_MOUSEMOVE:                     
3406
        case WM_KEYDOWN:
3407
        case WM_SYSKEYDOWN:
3408
        case WM_KEYUP:
3409
        case WM_SYSKEYUP:
3410
        case WM_CHAR:  
3411
        case WM_CLOSE:
3412
        case WM_MOUSEWHEEL:
3413
        case WM_DISPLAYCHANGE:
3414
        case WM_SYSCOLORCHANGE:
3415
                {
3416
/*                      if (aSexyApp!=NULL && aSexyApp->mProcessInTimer && !aSexyApp->mShutdown && aSexyApp->mRunning)
3417
                        {
3418
                                if (uMsg==WM_TIMER && wParam==101)
3419
                                {
3420
                                        for (int i=0; i<5; i++)
3421
                                        {
3422
                                                if (GetQueueStatus(QS_INPUT | QS_PAINT))
3423
                                                        break;
3424
 
3425
                                                if (!aSexyApp->Process(false))
3426
                                                        break;
3427
                                        }
3428
                                }
3429
 
3430
                                break;
3431
                        }*/
3432
 
3433
                        /*if ((aSexyApp != NULL) && (aSexyApp->mNoDefer))
3434
                        {
3435
                                // Check to see if we should be windowed
3436
                                WINDOWPLACEMENT aWindowPlacement;
3437
                                aWindowPlacement.length = sizeof(aWindowPlacement);
3438
                                if (GetWindowPlacement(aSexyApp->mHWnd, &aWindowPlacement))
3439
                                {
3440
                                        if (aWindowPlacement.showCmd == SW_SHOWMINIMIZED)
3441
                                        {
3442
                                                aSexyApp->Redraw(NULL);
3443
                                        }
3444
                                }
3445
                        }*/
3446
 
3447
                        if ((aSexyApp != NULL) && (!aSexyApp->mNoDefer))
3448
                        {
3449
                                bool keyDown = (uMsg==WM_KEYDOWN) || (uMsg==WM_SYSKEYDOWN);
3450
 
3451
                                if ((keyDown) || (uMsg==WM_KEYUP) || (uMsg == WM_SYSKEYUP))
3452
                                {      
3453
                                        if (wParam == VK_CONTROL)
3454
                                                aSexyApp->mCtrlDown = keyDown;
3455
                                        if (wParam == VK_MENU)
3456
                                                aSexyApp->mAltDown = keyDown;
3457
                                }
3458
 
3459
                                if ((keyDown) && (aSexyApp->DebugKeyDownAsync(wParam, aSexyApp->mCtrlDown, aSexyApp->mAltDown)))
3460
                                        return 0;
3461
 
3462
                                if (aSexyApp->mPlayingDemoBuffer)
3463
                                {
3464
                                        if (uMsg==WM_CHAR)
3465
                                        {
3466
                                                switch (wParam)
3467
                                                {
3468
                                                case '+':
3469
                                                        aSexyApp->mUpdateMultiplier *= 1.5;
3470
                                                        break;
3471
                                                case '-':
3472
                                                        aSexyApp->mUpdateMultiplier /= 1.5;
3473
                                                        break;
3474
                                                case '=':
3475
                                                        aSexyApp->mUpdateMultiplier = 1;
3476
                                                        break;
3477
                                                case 'p':
3478
                                                case 'P':
3479
                                                        aSexyApp->mPaused = !aSexyApp->mPaused;
3480
                                                        aSexyApp->mLastTimeCheck = timeGetTime();
3481
                                                        aSexyApp->mUpdateFTimeAcc = 0.0;
3482
                                                        break;
3483
 
3484
                                                case 'n':
3485
                                                case 'N':
3486
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mUpdateCount+1;
3487
                                                        aSexyApp->mFastForwardStep = true;
3488
                                                        break;
3489
 
3490
                                                case 'm':
3491
                                                case 'M':
3492
                                                        aSexyApp->mFastForwardToMarker = true;
3493
                                                        break;
3494
 
3495
                                                case 'l':
3496
                                                case 'L':
3497
                                                        ListDemoMarkers();
3498
                                                        break;
3499
 
3500
                                                case 'j':
3501
                                                case 'J':
3502
                                                        DemoJumpToTime();
3503
                                                        break;
3504
 
3505
                                                case 's':
3506
                                                case 'S':
3507
                                                        ToggleDemoSoundVolume();
3508
                                                        break;
3509
 
3510
                                                case '4':
3511
                                                        // Fast foward to 120 seconds before it ends
3512
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (120000 / aSexyApp->mFrameTime);
3513
                                                        break;
3514
                                                case '5':
3515
                                                        // Fast foward to 90 seconds before it ends
3516
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (90000 / aSexyApp->mFrameTime);
3517
                                                        break;
3518
                                                case '6':
3519
                                                        // Fast foward to 60 seconds before it ends
3520
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (60000 / aSexyApp->mFrameTime);
3521
                                                        break;
3522
                                                case '7':
3523
                                                        // Fast foward to 30 seconds before it ends
3524
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (30000 / aSexyApp->mFrameTime);
3525
                                                        break;
3526
                                                case '8':
3527
                                                        // Fast foward to 10 seconds before it ends
3528
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (10000 / aSexyApp->mFrameTime);
3529
                                                        break;
3530
                                                case '9':
3531
                                                        // Fast foward to 5 seconds before it ends
3532
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength - (5000 / aSexyApp->mFrameTime);
3533
                                                        break;
3534
                                                case '0':                                              
3535
                                                        // Fast forward to the end
3536
                                                        aSexyApp->mFastForwardToUpdateNum = aSexyApp->mDemoLength;
3537
                                                        break;
3538
 
3539
                                                }
3540
                                        }
3541
                                        else if (uMsg==WM_KEYDOWN)
3542
                                                aSexyApp->DebugKeyDown(wParam);
3543
                                }
3544
 
3545
                                bool pushMessage = true;
3546
 
3547
                                if (aSexyApp->mDeferredMessages.size() > 0)
3548
                                {
3549
                                        // Don't add any more messages after WM_CLOSE
3550
                                        MSG* aMsg = &aSexyApp->mDeferredMessages.back();
3551
 
3552
                                        if (aMsg->message == WM_CLOSE)
3553
                                                pushMessage = false;
3554
                                        if ((uMsg == WM_TIMER) && (uMsg == aMsg->message))
3555
                                                pushMessage = false; // Don't need more timer messages
3556
 
3557
 
3558
                                        if (pushMessage && (uMsg==WM_SYSCOLORCHANGE || uMsg==WM_DISPLAYCHANGE)) // kill duplicate SysColorChange() events.
3559
                                        {
3560
                                                WindowsMessageList::iterator aMsgListItr = aSexyApp->mDeferredMessages.begin();
3561
                                                while (pushMessage && aMsgListItr != aSexyApp->mDeferredMessages.end())
3562
                                                {
3563
                                                        MSG& aMsg = *aMsgListItr;
3564
 
3565
                                                        if (aMsg.message == WM_SYSCOLORCHANGE || aMsg.message == WM_DISPLAYCHANGE)
3566
                                                                pushMessage = false;
3567
 
3568
                                                        ++aMsgListItr;
3569
                                                }
3570
                                        }
3571
                                }
3572
 
3573
                                if (pushMessage)
3574
                                {
3575
                                        MSG msg;
3576
                                        msg.hwnd = hWnd;
3577
                                        msg.message = uMsg;
3578
                                        msg.lParam = lParam;
3579
                                        msg.wParam = wParam;   
3580
 
3581
                                        aSexyApp->mDeferredMessages.push_back(msg);
3582
                                }
3583
 
3584
                                if (uMsg == WM_SIZE)
3585
                                {
3586
                                        aSexyApp->mPhysMinimized = wParam == SIZE_MINIMIZED;
3587
                                }
3588
                                else if (uMsg == WM_SYSKEYDOWN)
3589
                                {
3590
                                        if (wParam != VK_F4)
3591
                                                return 0;              
3592
                                }
3593
                                else if (uMsg == WM_CLOSE)
3594
                                {
3595
                                        /*char aStr[256];
3596
                                        sprintf(aStr, "CLOSED HWND: %d\r\n", hWnd);
3597
                                        OutputDebugString(aStr);*/
3598
 
3599
                                        aSexyApp->CloseRequestAsync();
3600
                                        return 0;
3601
                                }
3602
                        }                      
3603
                }
3604
                break;
3605
 
3606
        case WM_ENABLE:
3607
                if (aSexyApp != NULL)
3608
                {
3609
                        aSexyApp->mIsDisabled = wParam == 0;
3610
                }
3611
                break;
3612
 
3613
        case WM_QUERYOPEN:
3614
                if ((aSexyApp != NULL) && (!aSexyApp->AppCanRestore()))
3615
                        return 0;
3616
                break;
3617
 
3618
        case WM_SYSCHAR:
3619
                if ((aSexyApp != NULL) && (aSexyApp->IsAltKeyUsed(wParam)))
3620
                        return 0;
3621
                break;
3622
 
3623
        case WM_NCLBUTTONDOWN:
3624
                if (aSexyApp!=NULL)
3625
                {
3626
//                      aSexyApp->mProcessInTimer = true;
3627
                        LRESULT aResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
3628
//                      aSexyApp->mProcessInTimer = false;
3629
                        aSexyApp->ClearUpdateBacklog();
3630
                        return aResult;
3631
                }
3632
                break;
3633
 
3634
 
3635
        case WM_SYSCOMMAND:
3636
                if (wParam==SC_MONITORPOWER)
3637
                {
3638
                        gPowerSaveTick = GetTickCount();
3639
                        if (aSexyApp!=NULL && (!aSexyApp->mAllowMonitorPowersave || !aSexyApp->mLoaded))
3640
                                return FALSE;
3641
                }
3642
                if (wParam==SC_SCREENSAVE && aSexyApp!=NULL && (!aSexyApp->mLoaded || !aSexyApp->mIsPhysWindowed))
3643
                        return FALSE;
3644
 
3645
                break;
3646
 
3647
/*      case WM_DISPLAYCHANGE:
3648
                SEXY_TRACE("WM_DISPLAYCHANGE 1");
3649
                if (aSexyApp!=NULL && aSexyApp->mIsWindowed && aSexyApp->mDDInterface!=NULL && aSexyApp->mHWnd==hWnd && aSexyApp->mLoaded)
3650
                {
3651
                        SEXY_TRACE("WM_DISPLAYCHANGE 2");
3652
                        aSexyApp->mDDInterface->Init(aSexyApp->mHWnd,aSexyApp->mIsWindowed);
3653
                        aSexyApp->mWidgetManager->mImage = aSexyApp->mDDInterface->GetScreenImage();
3654
                        aSexyApp->mWidgetManager->MarkAllDirty();
3655
                }
3656
                break;*/
3657
 
3658
        case WM_DESTROY:
3659
                {
3660
                        char aStr[256];
3661
                        sprintf(aStr, "DESTROYED HWND: %d\r\n", hWnd);
3662
                        OutputDebugStringA(aStr);
3663
                }
3664
                break; 
3665
        case WM_SETCURSOR:
3666
                if (!aSexyApp->mSEHOccured)
3667
                        aSexyApp->EnforceCursor();
3668
                return TRUE;           
3669
        case WM_ERASEBKGND:
3670
                return TRUE;           
3671
        case WM_ENDSESSION:
3672
                aSexyApp->Shutdown();
3673
                break;
3674
        case WM_PAINT:
3675
                if ((aSexyApp->mInitialized) && (!gInAssert) && (!aSexyApp->mSEHOccured))
3676
                {
3677
                        RECT aClientRect;
3678
                        GetClientRect(hWnd, &aClientRect);                     
3679
 
3680
                        PAINTSTRUCT ps;
3681
                        BeginPaint(hWnd, &ps);                 
3682
 
3683
                        if (aSexyApp->mRunning)
3684
                                aSexyApp->Redraw(NULL);
3685
 
3686
                        EndPaint(hWnd, &ps);
3687
 
3688
                        return 0;
3689
                }
3690
                break;
3691
        }
3692
 
3693
        if ((aSexyApp != NULL) && (uMsg == aSexyApp->mNotifyGameMessage) && (hWnd == aSexyApp->mHWnd))
3694
        {
3695
                // Oh, we are trying to open another instance of ourselves.
3696
                // Bring up the original window instead
3697
                aSexyApp->HandleNotifyGameMessage(wParam,lParam);              
3698
                return 0;
3699
        }
3700
 
3701
        if (gSexyAppBase->mIsWideWindow)
3702
                return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3703
        else
3704
                return DefWindowProcA(hWnd, uMsg, wParam, lParam);
3705
}
3706
 
3707
void SexyAppBase::HandleNotifyGameMessage(int theType, int theParam)
3708
{
3709
        if (theType==0) // bring to front message
3710
        {
3711
                WINDOWPLACEMENT aWindowPlacement;
3712
                aWindowPlacement.length = sizeof(WINDOWPLACEMENT);
3713
                GetWindowPlacement(mHWnd, &aWindowPlacement);          
3714
 
3715
                if (aWindowPlacement.showCmd == SW_SHOWMINIMIZED)
3716
                        ShowWindow(mHWnd, SW_RESTORE);
3717
 
3718
                ::SetForegroundWindow(mHWnd);
3719
        }
3720
}
3721
 
3722
void SexyAppBase::RehupFocus()
3723
{
3724
        bool wantHasFocus = mActive && !mMinimized;
3725
 
3726
        if (wantHasFocus != mHasFocus)
3727
        {                                      
3728
                mHasFocus = wantHasFocus;
3729
 
3730
                if (mHasFocus)
3731
                {
3732
                        if (mMuteOnLostFocus)
3733
                                Unmute(true);
3734
 
3735
                        mWidgetManager->GotFocus();
3736
                        GotFocus();
3737
                }
3738
                else
3739
                {
3740
                        if (mMuteOnLostFocus)
3741
                                Mute(true);
3742
 
3743
                        mWidgetManager->LostFocus();
3744
                        LostFocus();
3745
 
3746
                        ReleaseCapture();
3747
                        mWidgetManager->DoMouseUps();
3748
                }
3749
        }
3750
}
3751
 
3752
void SexyAppBase::ClearKeysDown()
3753
{
3754
        if (mWidgetManager != NULL) // fix stuck alt-key problem
3755
        {
3756
                for (int aKeyNum = 0; aKeyNum < 0xFF; aKeyNum++)
3757
                        mWidgetManager->mKeyDown[aKeyNum] = false;
3758
        }
3759
        mCtrlDown = false;
3760
        mAltDown = false;
3761
}
3762
 
3763
void SexyAppBase::WriteDemoTimingBlock()
3764
{
3765
        // Demo writing functions can only be called from the main thread and after SexyAppBase::Init
3766
        DBG_ASSERTE(GetCurrentThreadId() == mPrimaryThreadId);
3767
 
3768
        while (mUpdateCount - mLastDemoUpdateCnt > 15)
3769
        {
3770
                mDemoBuffer.WriteNumBits(15, 4);
3771
                mLastDemoUpdateCnt += 15;
3772
 
3773
                mDemoBuffer.WriteNumBits(0, 1);
3774
                mDemoBuffer.WriteNumBits(DEMO_IDLE, 5);
3775
                mDemoCmdOrder++;
3776
        }
3777
 
3778
        mDemoBuffer.WriteNumBits(mUpdateCount - mLastDemoUpdateCnt, 4);
3779
        mLastDemoUpdateCnt = mUpdateCount;
3780
        mDemoCmdOrder++;
3781
}
3782
 
3783
int aNumBigMoveMessages = 0;
3784
int aNumSmallMoveMessages = 0;
3785
int aNumTimerMessages = 0;
3786
 
3787
bool SexyAppBase::PrepareDemoCommand(bool required)
3788
{
3789
        if (mDemoNeedsCommand)
3790
        {
3791
                mDemoCmdBitPos = mDemoBuffer.mReadBitPos;
3792
 
3793
                mLastDemoUpdateCnt += mDemoBuffer.ReadNumBits(4, false);
3794
 
3795
                mDemoIsShortCmd = mDemoBuffer.ReadNumBits(1, false) == 1;
3796
 
3797
                if (mDemoIsShortCmd)           
3798
                        mDemoCmdNum = mDemoBuffer.ReadNumBits(1, false);
3799
                else
3800
                        mDemoCmdNum = mDemoBuffer.ReadNumBits(5, false);
3801
 
3802
                mDemoNeedsCommand = false;
3803
 
3804
                mDemoCmdOrder++;
3805
        }
3806
 
3807
        DBG_ASSERTE((mUpdateCount == mLastDemoUpdateCnt) || (!required));
3808
 
3809
        return mUpdateCount == mLastDemoUpdateCnt;
3810
}
3811
 
3812
void SexyAppBase::ProcessDemo()
3813
{
3814
        if (mPlayingDemoBuffer)
3815
        {
3816
                // At end of demo buffer?  How dare you!
3817
                DBG_ASSERTE(!mDemoBuffer.AtEnd());
3818
 
3819
                while ((!mShutdown) && (mUpdateCount == mLastDemoUpdateCnt) && (!mDemoBuffer.AtEnd()))
3820
                {
3821
                        if (PrepareDemoCommand(false))
3822
                        {
3823
                                mDemoNeedsCommand = true;
3824
 
3825
                                if (mDemoIsShortCmd)
3826
                                {
3827
                                        switch (mDemoCmdNum)
3828
                                        {
3829
                                        case 0:
3830
                                                {
3831
                                                        int aDeltaX = mDemoBuffer.ReadNumBits(6, true);
3832
                                                        int aDeltaY = mDemoBuffer.ReadNumBits(6, true);
3833
                                                        mLastDemoMouseX += aDeltaX;
3834
                                                        mLastDemoMouseY += aDeltaY;
3835
 
3836
                                                        mWidgetManager->MouseMove(mLastDemoMouseX, mLastDemoMouseY);
3837
                                                }
3838
                                                break;
3839
                                        case 1:
3840
                                                {
3841
                                                        bool down = mDemoBuffer.ReadNumBits(1, false) != 0;
3842
                                                        int aBtnCount = mDemoBuffer.ReadNumBits(3, true);                                                      
3843
 
3844
                                                        if (down)
3845
                                                                mWidgetManager->MouseDown(mLastDemoMouseX, mLastDemoMouseY, aBtnCount);
3846
                                                        else
3847
                                                                mWidgetManager->MouseUp(mLastDemoMouseX, mLastDemoMouseY, aBtnCount);
3848
                                                }
3849
                                                break;
3850
                                        }
3851
                                }
3852
                                else
3853
                                {                              
3854
                                        switch (mDemoCmdNum)
3855
                                        {
3856
                                        case DEMO_MOUSE_POSITION:
3857
                                                {
3858
                                                        mLastDemoMouseX = mDemoBuffer.ReadNumBits(12, false);
3859
                                                        mLastDemoMouseY = mDemoBuffer.ReadNumBits(12, false);
3860
 
3861
                                                        mWidgetManager->MouseMove(mLastDemoMouseX, mLastDemoMouseY);                                           
3862
                                                }
3863
                                                break;
3864
                                        case DEMO_ACTIVATE_APP:
3865
                                                {
3866
                                                        mActive = mDemoBuffer.ReadNumBits(1, false) != 0;
3867
 
3868
                                                        RehupFocus();
3869
 
3870
                                                        if ((mActive) && (!mIsWindowed))
3871
                                                                mWidgetManager->MarkAllDirty();
3872
 
3873
                                                        if ((mIsOpeningURL) && (!mActive))
3874
                                                                URLOpenSucceeded(mOpeningURL);
3875
                                                }
3876
                                                break;
3877
                                        case DEMO_SIZE:
3878
                                                {
3879
                                                        bool isMinimized = mDemoBuffer.ReadBoolean();
3880
 
3881
                                                        if ((!mShutdown) && (isMinimized != mMinimized))
3882
                                                        {
3883
                                                                mMinimized = isMinimized;
3884
 
3885
                                                                // We don't want any sounds (or music) playing while its minimized
3886
                                                                if (mMinimized)
3887
                                                                        Mute(true);
3888
                                                                else
3889
                                                                {
3890
                                                                        Unmute(true);
3891
                                                                        mWidgetManager->MarkAllDirty();
3892
                                                                }
3893
                                                        }
3894
 
3895
                                                        RehupFocus();
3896
                                                }
3897
                                                break;
3898
                                        case DEMO_MOUSE_WHEEL:
3899
                                                {
3900
                                                        int aScroll = mDemoBuffer.ReadNumBits(8, true);
3901
                                                        mWidgetManager->MouseWheel(aScroll);
3902
                                                }
3903
                                                break;
3904
                                        case DEMO_KEY_DOWN:
3905
                                                {
3906
                                                        KeyCode aKeyCode = (KeyCode) mDemoBuffer.ReadNumBits(8, false);
3907
                                                        mWidgetManager->KeyDown(aKeyCode);
3908
                                                }
3909
                                                break;
3910
                                        case DEMO_KEY_UP:
3911
                                                {
3912
                                                        KeyCode aKeyCode = (KeyCode) mDemoBuffer.ReadNumBits(8, false);
3913
                                                        mWidgetManager->KeyUp(aKeyCode);
3914
                                                }
3915
                                                break;
3916
                                        case DEMO_KEY_CHAR:
3917
                                                {
3918
                                                        int sizeMult = (int)mDemoBuffer.ReadNumBits(1, false) + 1; // will be 1 for single, 2 for double
3919
                                                        SexyChar aChar = (SexyChar) mDemoBuffer.ReadNumBits(8*sizeMult, false);
3920
                                                        mWidgetManager->KeyChar(aChar);
3921
                                                }
3922
                                                break;
3923
                                        case DEMO_CLOSE:
3924
                                                Shutdown();
3925
                                                break;
3926
                                        case DEMO_MOUSE_ENTER:
3927
                                                mMouseIn = true;
3928
                                                EnforceCursor();
3929
                                                break;
3930
                                        case DEMO_MOUSE_EXIT:
3931
                                                mWidgetManager->MouseExit(mLastDemoMouseX, mLastDemoMouseY);
3932
                                                mMouseIn = false;
3933
                                                EnforceCursor();
3934
                                                break;
3935
                                        case DEMO_LOADING_COMPLETE:
3936
                                                mDemoLoadingComplete = true;
3937
                                                break;
3938
                                        case DEMO_VIDEO_DATA:
3939
                                                mIsWindowed = mDemoBuffer.ReadBoolean();
3940
                                                mSyncRefreshRate = mDemoBuffer.ReadByte();
3941
                                                break;
3942
                                        case DEMO_IDLE:
3943
                                                break;
3944
                                        default:
3945
                                                DBG_ASSERTE("Invalid Demo Command" == 0);
3946
                                                break;
3947
                                        }
3948
                                }
3949
                        }
3950
                }
3951
        }
3952
}
3953
 
3954
void SexyAppBase::ShowMemoryUsage()
3955
{
3956
        DWORD aTotal = 0;
3957
        DWORD aFree = 0;
3958
 
3959
        if (mDDInterface->mDD7 != NULL)
3960
        {
3961
                DDSCAPS2 aCaps;
3962
                ZeroMemory(&aCaps,sizeof(aCaps));
3963
                aCaps.dwCaps = DDSCAPS_VIDEOMEMORY;    
3964
                mDDInterface->mDD7->GetAvailableVidMem(&aCaps,&aTotal,&aFree);
3965
        }
3966
 
3967
        MemoryImageSet::iterator anItr = mMemoryImageSet.begin();
3968
        typedef std::pair<int,int> FormatUsage;
3969
        typedef std::map<PixelFormat,FormatUsage> FormatMap;
3970
        FormatMap aFormatMap;
3971
        int aTextureMemory = 0;
3972
        while (anItr != mMemoryImageSet.end())
3973
        {
3974
                MemoryImage* aMemoryImage = *anItr;                            
3975
                if (aMemoryImage->mD3DData != NULL)
3976
                {
3977
                        TextureData *aData = (TextureData*)aMemoryImage->mD3DData;
3978
                        aTextureMemory += aData->mTexMemSize;
3979
 
3980
                        FormatUsage &aUsage = aFormatMap[aData->mPixelFormat];
3981
                        aUsage.first++;
3982
                        aUsage.second += aData->mTexMemSize;
3983
                }
3984
 
3985
                ++anItr;
3986
        }
3987
 
3988
        std::string aStr;
3989
 
3990
        const char *aDesc;
3991
        if (Is3DAccelerationRecommended())
3992
                aDesc = "Recommended";
3993
        else if (Is3DAccelerationSupported())
3994
                aDesc = "Supported";
3995
        else
3996
                aDesc = "Unsupported";
3997
 
3998
        aStr += StrFormat("3D-Mode is %s (3D is %s on this system)\r\n\r\n",Is3DAccelerated()?"On":"Off",aDesc);
3999
 
4000
        aStr += StrFormat("Num Images: %d\r\n",(int)mMemoryImageSet.size());
4001
        aStr += StrFormat("Num Sounds: %d\r\n",mSoundManager->GetNumSounds());
4002
        aStr += StrFormat("Video Memory: %s/%s KB\r\n", SexyStringToString(CommaSeperate((aTotal-aFree)/1024)).c_str(), SexyStringToString(CommaSeperate(aTotal/1024)).c_str());
4003
        aStr += StrFormat("Texture Memory: %s KB\r\n",CommaSeperate(aTextureMemory/1024).c_str());
4004
 
4005
        FormatUsage aUsage = aFormatMap[PixelFormat_A8R8G8B8];
4006
        aStr += StrFormat("A8R8G8B8: %d - %s KB\r\n",aUsage.first,SexyStringToString(CommaSeperate(aUsage.second/1024)).c_str());
4007
        aUsage = aFormatMap[PixelFormat_A4R4G4B4];
4008
        aStr += StrFormat("A4R4G4B4: %d - %s KB\r\n",aUsage.first,SexyStringToString(CommaSeperate(aUsage.second/1024)).c_str());
4009
        aUsage = aFormatMap[PixelFormat_R5G6B5];
4010
        aStr += StrFormat("R5G6B5: %d - %s KB\r\n",aUsage.first,SexyStringToString(CommaSeperate(aUsage.second/1024)).c_str());
4011
        aUsage = aFormatMap[PixelFormat_Palette8];
4012
        aStr += StrFormat("Palette8: %d - %s KB\r\n",aUsage.first,SexyStringToString(CommaSeperate(aUsage.second/1024)).c_str());
4013
 
4014
        MsgBox(aStr,"Video Stats",MB_OK);
4015
        mLastTime = timeGetTime();
4016
}
4017
 
4018
bool SexyAppBase::IsAltKeyUsed(WPARAM wParam)
4019
{
4020
        int aChar = tolower(wParam);
4021
        switch (aChar)
4022
        {
4023
                case 13: // alt-enter
4024
                case 'r':
4025
                        return true;           
4026
                default:
4027
                        return false;
4028
        }
4029
}
4030
 
4031
bool SexyAppBase::DebugKeyDown(int theKey)
4032
{
4033
        if ((theKey == 'R') && (mWidgetManager->mKeyDown[KEYCODE_MENU]))
4034
        {      
4035
#ifndef RELEASEFINAL
4036
                if (ReparseModValues())
4037
                        PlaySoundA("c:\\windows\\media\\Windows XP Menu Command.wav", NULL, SND_ASYNC);                        
4038
                else
4039
                {
4040
                        for (int aKeyNum = 0; aKeyNum < 0xFF; aKeyNum++) // prevent alt from getting stuck
4041
                                mWidgetManager->mKeyDown[aKeyNum] = false;
4042
                }
4043
#endif
4044
        }
4045
        else if (theKey == VK_F3)
4046
        {
4047
                if(mWidgetManager->mKeyDown[KEYCODE_SHIFT])
4048
                {
4049
                        mShowFPS = true;
4050
                        if (++mShowFPSMode >= Num_FPS_Types)
4051
                                mShowFPSMode = 0;
4052
                }
4053
                else
4054
                        mShowFPS = !mShowFPS;
4055
 
4056
                mWidgetManager->MarkAllDirty();
4057
 
4058
                if (mShowFPS)
4059
                {
4060
                        gFPSTimer.Start();
4061
                        gFrameCount = 0;
4062
                        gFPSDisplay = 0;
4063
                        gForceDisplay = true;
4064
                }
4065
        }
4066
        else if (theKey == VK_F8)
4067
        {
4068
                if(mWidgetManager->mKeyDown[KEYCODE_SHIFT])
4069
                {
4070
                        Set3DAcclerated(!Is3DAccelerated());
4071
 
4072
                        char aBuf[512];
4073
                        sprintf(aBuf,"3D-Mode: %s",Is3DAccelerated()?"ON":"OFF");
4074
                        MsgBox(aBuf,"Mode Switch",MB_OK);
4075
                        mLastTime = timeGetTime();
4076
                }
4077
                else
4078
                        ShowMemoryUsage();
4079
 
4080
                return true;
4081
        }
4082
        else if (theKey == VK_F10)
4083
        {
4084
#ifndef RELEASEFINAL
4085
                if (mWidgetManager->mKeyDown[KEYCODE_CONTROL])
4086
                {
4087
                        if (mUpdateMultiplier==0.25)
4088
                                mUpdateMultiplier = 1.0;
4089
                        else
4090
                                mUpdateMultiplier = 0.25;
4091
                }
4092
                else if(mWidgetManager->mKeyDown[KEYCODE_SHIFT])
4093
                {
4094
                        mStepMode = 0;
4095
                        ClearUpdateBacklog();
4096
                }
4097
                else
4098
                        mStepMode = 1;
4099
#endif
4100
 
4101
                return true;
4102
        }
4103
        else if (theKey == VK_F11)
4104
        {
4105
                if (mWidgetManager->mKeyDown[KEYCODE_SHIFT])
4106
                        DumpProgramInfo();
4107
                else
4108
                        TakeScreenshot();
4109
 
4110
                return true;
4111
        }
4112
        else if (theKey == VK_F2)
4113
        {
4114
                bool isPerfOn = !SexyPerf::IsPerfOn();
4115
                if (isPerfOn)
4116
                {
4117
//                      MsgBox("Perf Monitoring: ON", "Perf Monitoring", MB_OK);
4118
                        ClearUpdateBacklog();
4119
                        SexyPerf::BeginPerf();
4120
                }
4121
                else
4122
                {
4123
                        SexyPerf::EndPerf();
4124
                        MsgBox(SexyPerf::GetResults().c_str(), "Perf Results", MB_OK);
4125
                        ClearUpdateBacklog();
4126
                }
4127
        }
4128
        else
4129
                return false;
4130
 
4131
        return false;
4132
}
4133
 
4134
bool SexyAppBase::DebugKeyDownAsync(int theKey, bool ctrlDown, bool altDown)
4135
{
4136
        return false;
4137
}
4138
 
4139
void SexyAppBase::CloseRequestAsync()
4140
{
4141
}
4142
 
4143
// Why did I defer messages?  Oh, incase a dialog comes up such as a crash
4144
//  it won't keep crashing and stuff
4145
bool SexyAppBase::ProcessDeferredMessages(bool singleMessage)
4146
{
4147
        while (mDeferredMessages.size() > 0)
4148
        {
4149
                MSG aMsg = mDeferredMessages.front();
4150
                mDeferredMessages.pop_front();
4151
 
4152
                UINT uMsg = aMsg.message;
4153
                LPARAM lParam = aMsg.lParam;
4154
                WPARAM wParam = aMsg.wParam;
4155
                HWND hWnd = aMsg.hwnd;
4156
 
4157
                if ((mRecordingDemoBuffer) && (!mShutdown))
4158
                {
4159
                        switch (uMsg)
4160
                        {
4161
//  TODO: switch to killfocus/setfocus?
4162
//                      case WM_SETFOCUS:
4163
//                      case WM_KILLFOCUS:
4164
//                              if (hWnd == mHWnd)
4165
//                              {                                       
4166
//                                      WriteDemoTimingBlock();
4167
//                                      mDemoBuffer.WriteNumBits(0, 1);
4168
//                                      mDemoBuffer.WriteNumBits(DEMO_ACTIVATE_APP, 5);
4169
//                                      mDemoBuffer.WriteNumBits(uMsg==WM_SETFOCUS ? 1 : 0, 1);
4170
//                              }
4171
//                              break;                  
4172
 
4173
                        case WM_ACTIVATEAPP:
4174
                                if (hWnd == mHWnd)
4175
                                {                                      
4176
                                        WriteDemoTimingBlock();
4177
                                        mDemoBuffer.WriteNumBits(0, 1);
4178
                                        mDemoBuffer.WriteNumBits(DEMO_ACTIVATE_APP, 5);
4179
                                        mDemoBuffer.WriteNumBits((wParam != 0) ? 1 : 0, 1);
4180
                                }
4181
                                break;                 
4182
 
4183
                        case WM_SIZE:
4184
                                {
4185
                                        bool isMinimized = wParam == SIZE_MINIMIZED;
4186
 
4187
                                        WriteDemoTimingBlock();
4188
                                        mDemoBuffer.WriteNumBits(0, 1);
4189
                                        mDemoBuffer.WriteNumBits(DEMO_SIZE, 5);
4190
                                        mDemoBuffer.WriteBoolean(isMinimized);         
4191
                                }
4192
                                break;
4193
                        case WM_LBUTTONDOWN:
4194
                        case WM_RBUTTONDOWN:
4195
                        case WM_MBUTTONDOWN:
4196
                        case WM_LBUTTONDBLCLK:
4197
                        case WM_RBUTTONDBLCLK:
4198
                        case WM_LBUTTONUP:
4199
                        case WM_RBUTTONUP:
4200
                        case WM_MBUTTONUP:
4201
                        case WM_MOUSEMOVE:
4202
                                {
4203
                                        int aCurX = (short) LOWORD(lParam);
4204
                                        int aCurY = (short) HIWORD(lParam);
4205
 
4206
                                        int aDiffX = aCurX - mLastDemoMouseX;
4207
                                        int aDiffY = aCurY - mLastDemoMouseY;
4208
 
4209
                                        if ((abs(aCurX - mLastDemoMouseX) < 32) && (abs(aCurY - mLastDemoMouseY) < 32))
4210
                                        {
4211
                                                if ((aDiffX != 0) || (aDiffY != 0))
4212
                                                {
4213
                                                        WriteDemoTimingBlock();
4214
                                                        mDemoBuffer.WriteNumBits(1, 1);
4215
                                                        mDemoBuffer.WriteNumBits(0, 1);
4216
                                                        mDemoBuffer.WriteNumBits(aDiffX, 6);
4217
                                                        mDemoBuffer.WriteNumBits(aDiffY, 6);
4218
                                                }                                              
4219
                                        }
4220
                                        else
4221
                                        {
4222
                                                WriteDemoTimingBlock();
4223
                                                mDemoBuffer.WriteNumBits(0, 1);
4224
                                                mDemoBuffer.WriteNumBits(DEMO_MOUSE_POSITION, 5);
4225
                                                mDemoBuffer.WriteNumBits(aCurX, 12);
4226
                                                mDemoBuffer.WriteNumBits(aCurY, 12);
4227
                                        }
4228
 
4229
                                        bool down = true;
4230
                                        int aBtnNum = 0;
4231
                                        switch (uMsg)
4232
                                        {
4233
                                                case WM_LBUTTONDOWN:
4234
                                                        aBtnNum = 1;
4235
                                                        break;
4236
                                                case WM_RBUTTONDOWN:
4237
                                                        aBtnNum = -1;
4238
                                                        break;
4239
                                                case WM_MBUTTONDOWN:
4240
                                                        aBtnNum = 3;
4241
                                                        break;
4242
                                                case WM_LBUTTONDBLCLK:
4243
                                                        aBtnNum = 2;
4244
                                                        break;
4245
                                                case WM_RBUTTONDBLCLK:
4246
                                                        aBtnNum = -2;
4247
                                                        break;
4248
                                                case WM_LBUTTONUP:
4249
                                                        aBtnNum = 1;
4250
                                                        down = false;
4251
                                                        break;
4252
                                                case WM_RBUTTONUP:
4253
                                                        aBtnNum = -1;
4254
                                                        down = false;
4255
                                                        break;
4256
                                                case WM_MBUTTONUP:
4257
                                                        aBtnNum = 3;
4258
                                                        down = false;
4259
                                                        break;
4260
                                        }
4261
 
4262
                                        if (aBtnNum != 0)
4263
                                        {
4264
                                                WriteDemoTimingBlock();
4265
                                                mDemoBuffer.WriteNumBits(1, 1);
4266
                                                mDemoBuffer.WriteNumBits(1, 1);
4267
                                                mDemoBuffer.WriteNumBits(down ? 1 : 0, 1);
4268
                                                mDemoBuffer.WriteNumBits(aBtnNum, 3);
4269
                                        }
4270
 
4271
                                        mLastDemoMouseX = aCurX;
4272
                                        mLastDemoMouseY = aCurY;
4273
                                }
4274
                                break;
4275
                        case WM_MOUSEWHEEL:
4276
                                {
4277
                                        int aZDelta = ((short)HIWORD(wParam)) / 120;
4278
 
4279
                                        WriteDemoTimingBlock();
4280
                                        mDemoBuffer.WriteNumBits(0, 1);
4281
                                        mDemoBuffer.WriteNumBits(DEMO_MOUSE_WHEEL, 5);
4282
                                        mDemoBuffer.WriteNumBits(aZDelta, 8);
4283
                                }
4284
                                break;
4285
                        case WM_KEYDOWN:
4286
                        case WM_SYSKEYDOWN:
4287
                                {
4288
                                        KeyCode aKeyCode = (KeyCode) wParam;
4289
 
4290
                                        WriteDemoTimingBlock();
4291
                                        mDemoBuffer.WriteNumBits(0, 1);
4292
                                        mDemoBuffer.WriteNumBits(DEMO_KEY_DOWN, 5);
4293
                                        mDemoBuffer.WriteNumBits(aKeyCode, 8);
4294
                                }
4295
                                break;
4296
                        case WM_KEYUP: 
4297
                        case WM_SYSKEYUP:
4298
                                {
4299
                                        KeyCode aKeyCode = (KeyCode) wParam;
4300
 
4301
                                        WriteDemoTimingBlock();
4302
                                        mDemoBuffer.WriteNumBits(0, 1);
4303
                                        mDemoBuffer.WriteNumBits(DEMO_KEY_UP, 5);
4304
                                        mDemoBuffer.WriteNumBits((int) aKeyCode, 8);
4305
                                }
4306
                                break;
4307
                        case WM_CHAR:
4308
                                {
4309
                                        SexyChar aChar = (SexyChar) wParam;
4310
 
4311
                                        WriteDemoTimingBlock();
4312
                                        mDemoBuffer.WriteNumBits(0, 1);
4313
                                        mDemoBuffer.WriteNumBits(DEMO_KEY_CHAR, 5);
4314
                                        mDemoBuffer.WriteNumBits(sizeof(SexyChar) == 2, 1);
4315
                                        mDemoBuffer.WriteNumBits(aChar, sizeof(SexyChar)*8);
4316
                                }                              
4317
                                break; 
4318
                        case WM_CLOSE:
4319
                                if ((hWnd == mHWnd) || (hWnd == mInvisHWnd))
4320
                                {
4321
                                        WriteDemoTimingBlock();
4322
                                        mDemoBuffer.WriteNumBits(0, 1);
4323
                                        mDemoBuffer.WriteNumBits(DEMO_CLOSE, 5);
4324
                                }
4325
                                break;
4326
                        }
4327
 
4328
                        int aBufferSize = mDemoBuffer.GetDataLen();
4329
                }
4330
 
4331
                if (!mPlayingDemoBuffer)
4332
                {
4333
                        switch (uMsg)
4334
                        {      
4335
//  TODO: switch to killfocus/setfocus?
4336
//                      case WM_KILLFOCUS:
4337
//                      case WM_SETFOCUS:
4338
                        case WM_ACTIVATEAPP:
4339
                                if ((hWnd == mHWnd) && (!gInAssert) && (!mSEHOccured) && (!mShutdown))
4340
                                {
4341
//                                      mActive = uMsg==WM_SETFOCUS;
4342
 
4343
                                        RehupFocus();
4344
 
4345
                                        if ((mActive) && (!mIsWindowed))
4346
                                                mWidgetManager->MarkAllDirty();
4347
 
4348
                                        if ((mIsOpeningURL) && (!mActive))                     
4349
                                                URLOpenSucceeded(mOpeningURL);
4350
                                }
4351
                                break; 
4352
                        case WM_LBUTTONDOWN:           
4353
                        case WM_RBUTTONDOWN:
4354
                        case WM_MBUTTONDOWN:
4355
                        case WM_LBUTTONDBLCLK:
4356
                        case WM_RBUTTONDBLCLK:
4357
                        case WM_LBUTTONUP:             
4358
                        case WM_RBUTTONUP:             
4359
                        case WM_MBUTTONUP:
4360
                        case WM_MOUSEMOVE:             
4361
                                if ((!gInAssert) && (!mSEHOccured))
4362
                                {
4363
                                        int x = (short) LOWORD(lParam);
4364
                                        int y = (short) HIWORD(lParam);
4365
                                        mWidgetManager->RemapMouse(x, y);
4366
 
4367
                                        mLastUserInputTick = mLastTimerTime;
4368
 
4369
                                        mWidgetManager->MouseMove(x, y);               
4370
 
4371
                                        if (!mMouseIn)
4372
                                        {
4373
                                                if (mRecordingDemoBuffer)
4374
                                                {
4375
                                                        WriteDemoTimingBlock();
4376
                                                        mDemoBuffer.WriteNumBits(0, 1);                                                
4377
                                                        mDemoBuffer.WriteNumBits(DEMO_MOUSE_ENTER, 5);
4378
                                                }
4379
 
4380
                                                mMouseIn = true;
4381
                                                EnforceCursor();
4382
                                        }
4383
 
4384
                                        switch (uMsg)
4385
                                        {
4386
                                        case WM_LBUTTONDOWN:           
4387
                                                SetCapture(hWnd);
4388
                                                mWidgetManager->MouseDown(x, y, 1);                                            
4389
                                                break;
4390
                                        case WM_RBUTTONDOWN:
4391
                                                SetCapture(hWnd);
4392
                                                mWidgetManager->MouseDown(x, y, -1);                                           
4393
                                                break;
4394
                                        case WM_MBUTTONDOWN:
4395
                                                SetCapture(hWnd);
4396
                                                mWidgetManager->MouseDown(x, y, 3);                                            
4397
                                                break;
4398
                                        case WM_LBUTTONDBLCLK:
4399
                                                SetCapture(hWnd);
4400
                                                mWidgetManager->MouseDown(x, y, 2);                                            
4401
                                                break;
4402
                                        case WM_RBUTTONDBLCLK:
4403
                                                SetCapture(hWnd);
4404
                                                mWidgetManager->MouseDown(x, y, -2);                                           
4405
                                                break;
4406
                                        case WM_LBUTTONUP:             
4407
                                                if ((mWidgetManager->mDownButtons & ~1) == 0)
4408
                                                        ReleaseCapture();
4409
                                                mWidgetManager->MouseUp(x, y, 1);                                              
4410
                                                break;
4411
                                        case WM_RBUTTONUP:             
4412
                                                if ((mWidgetManager->mDownButtons & ~2) == 0)
4413
                                                        ReleaseCapture();
4414
                                                mWidgetManager->MouseUp(x, y, -1);                                                             
4415
                                                break;
4416
                                        case WM_MBUTTONUP:             
4417
                                                if ((mWidgetManager->mDownButtons & ~4) == 0)
4418
                                                        ReleaseCapture();
4419
                                                mWidgetManager->MouseUp(x, y, 3);                                                              
4420
                                                break;
4421
                                        }
4422
                                }
4423
                                break;         
4424
                        case WM_MOUSEWHEEL:
4425
                                {
4426
                                        char aZDelta = ((short)HIWORD(wParam)) / 120;
4427
                                        mWidgetManager->MouseWheel(aZDelta);
4428
                                }
4429
                                break;
4430
                        case WM_KEYDOWN:
4431
                        case WM_SYSKEYDOWN:
4432
                                mLastUserInputTick = mLastTimerTime;
4433
 
4434
                                if (wParam==VK_RETURN && uMsg==WM_SYSKEYDOWN && !mForceFullscreen && !mForceWindowed)
4435
                                {
4436
                                        SwitchScreenMode(!mIsWindowed);
4437
                                        ClearKeysDown();
4438
                                        break;
4439
                                }
4440
                                else if ((wParam == 'D') && (mWidgetManager != NULL) && (mWidgetManager->mKeyDown[KEYCODE_CONTROL]) && (mWidgetManager->mKeyDown[KEYCODE_MENU]))
4441
                                {
4442
                                        PlaySoundA("c:\\windows\\media\\Windows XP Menu Command.wav", NULL, SND_ASYNC);
4443
                                        mDebugKeysEnabled = !mDebugKeysEnabled;                                        
4444
                                }
4445
 
4446
                                if (mDebugKeysEnabled)
4447
                                {
4448
                                        if (DebugKeyDown(wParam))
4449
                                                break;
4450
                                }
4451
 
4452
                                mWidgetManager->KeyDown((KeyCode) wParam);
4453
                                break;
4454
 
4455
                        case WM_KEYUP:
4456
                        case WM_SYSKEYUP:
4457
                                mLastUserInputTick = mLastTimerTime;
4458
                                mWidgetManager->KeyUp((KeyCode) wParam);
4459
                                break;
4460
                        case WM_CHAR:          
4461
                                mLastUserInputTick = mLastTimerTime;
4462
                                mWidgetManager->KeyChar((SexyChar) wParam);            
4463
                                break;
4464
                        case WM_MOVE:
4465
                                {
4466
                                        if ((hWnd == mHWnd) && (mIsWindowed))
4467
                                        {
4468
                                                WINDOWPLACEMENT aWindowPlacment;
4469
                                                aWindowPlacment.length = sizeof(aWindowPlacment);
4470
 
4471
                                                GetWindowPlacement(hWnd, &aWindowPlacment);
4472
                                                if ((aWindowPlacment.showCmd == SW_SHOW) ||
4473
                                                        (aWindowPlacment.showCmd == SW_SHOWNORMAL))
4474
                                                {                                                                              
4475
                                                        mPreferredX = aWindowPlacment.rcNormalPosition.left;
4476
                                                        mPreferredY = aWindowPlacment.rcNormalPosition.top;
4477
                                                }
4478
                                        }
4479
                                }
4480
                                break;
4481
                        case WM_SIZE:
4482
                                {      
4483
                                        bool isMinimized = wParam == SIZE_MINIMIZED;
4484
 
4485
                                        if ((hWnd == mHWnd) && (!mShutdown) && (isMinimized != mMinimized))
4486
                                        {
4487
                                                mMinimized = isMinimized;
4488
 
4489
                                                // We don't want any sounds (or music) playing while its minimized
4490
                                                if (mMinimized)
4491
                                                {
4492
                                                        if (mMuteOnLostFocus)
4493
                                                                Mute(true);
4494
                                                }
4495
                                                else
4496
                                                {
4497
                                                        if (mMuteOnLostFocus)
4498
                                                                Unmute(true);
4499
 
4500
                                                        mWidgetManager->MarkAllDirty();
4501
                                                }
4502
                                        }
4503
 
4504
                                        RehupFocus();
4505
                                        if (wParam==SIZE_MAXIMIZED)
4506
                                                SwitchScreenMode(false);
4507
                                }
4508
                                break;
4509
                        case WM_TIMER:
4510
                                if ((!gInAssert) && (!mSEHOccured) && (mRunning))
4511
                                {      
4512
                                        DWORD aTimeNow = GetTickCount();
4513
                                        if (aTimeNow - mLastTimerTime > 500)
4514
                                                mLastBigDelayTime = aTimeNow;
4515
 
4516
                                        mLastTimerTime = aTimeNow;
4517
 
4518
                                        if ((mIsOpeningURL) &&                                         
4519
                                                (aTimeNow - mLastBigDelayTime > 5000))
4520
                                        {
4521
                                                if ((aTimeNow - mOpeningURLTime > 8000) && (!mActive))
4522
                                                {
4523
                                                        //TODO: Have some demo message thing
4524
                                                        URLOpenSucceeded(mOpeningURL);
4525
                                                }
4526
                                                else if ((aTimeNow - mOpeningURLTime > 12000) && (mActive))                                            
4527
                                                {
4528
                                                        URLOpenFailed(mOpeningURL);
4529
                                                }
4530
                                        }
4531
 
4532
                                        POINT aULCorner = {0, 0};
4533
                                        ::ClientToScreen(hWnd, &aULCorner);
4534
 
4535
                                        POINT aBRCorner = {mDDInterface->mDisplayWidth, mDDInterface->mDisplayHeight};
4536
                                        ::ClientToScreen(hWnd, &aBRCorner);
4537
 
4538
                                        POINT aPoint;
4539
                                        ::GetCursorPos(&aPoint);                       
4540
 
4541
                                        HWND aWindow = ::WindowFromPoint(aPoint);
4542
                                        bool isMouseIn = (aWindow == hWnd) &&
4543
                                                (aPoint.x >= aULCorner.x) && (aPoint.y >= aULCorner.y) &&
4544
                                                (aPoint.x < aBRCorner.x) && (aPoint.y < aBRCorner.y);
4545
 
4546
                                        if (mMouseIn != isMouseIn)
4547
                                        {
4548
                                                if ((mRecordingDemoBuffer) && (!mShutdown))
4549
                                                {
4550
                                                        WriteDemoTimingBlock();
4551
                                                        mDemoBuffer.WriteNumBits(0, 1);
4552
 
4553
                                                        if (isMouseIn)
4554
                                                                mDemoBuffer.WriteNumBits(DEMO_MOUSE_ENTER, 5);
4555
                                                        else
4556
                                                                mDemoBuffer.WriteNumBits(DEMO_MOUSE_EXIT, 5);
4557
                                                }
4558
 
4559
                                                if (!isMouseIn)
4560
                                                {
4561
                                                        int x = aPoint.x - aULCorner.x;
4562
                                                        int y = aPoint.y - aULCorner.y;
4563
                                                        mWidgetManager->RemapMouse(x, y);
4564
                                                        mWidgetManager->MouseExit(x, y);
4565
                                                }
4566
 
4567
                                                mMouseIn = isMouseIn;
4568
                                                EnforceCursor();
4569
                                        }                      
4570
                                }
4571
                                break;
4572
 
4573
                        case WM_SYSCOLORCHANGE:
4574
                        case WM_DISPLAYCHANGE:
4575
                                mWidgetManager->SysColorChangedAll();
4576
                                mWidgetManager->MarkAllDirty();
4577
                                break;
4578
                        }
4579
                }
4580
 
4581
                switch (uMsg)
4582
                {
4583
                case WM_CLOSE:
4584
                        if ((hWnd == mHWnd) || (hWnd == mInvisHWnd))
4585
                        {
4586
                                // This should short-circuit all demo calls, otherwise we will get
4587
                                //  all sorts of weird asserts because we are changing
4588
                                //  program flow
4589
                                mManualShutdown = true;
4590
 
4591
                                Shutdown();
4592
                        }
4593
                        break;
4594
                }
4595
 
4596
                if (singleMessage)
4597
                        break;
4598
        }
4599
 
4600
        return (mDeferredMessages.size() > 0);
4601
}
4602
 
4603
void SexyAppBase::Done3dTesting()
4604
{
4605
}
4606
 
4607
// return file name that you want to upload
4608
std::string     SexyAppBase::NotifyCrashHook()
4609
{
4610
        return "";
4611
}
4612
 
4613
void SexyAppBase::MakeWindow()
4614
{
4615
        //OutputDebugString("MAKING WINDOW\r\n");
4616
 
4617
        if (mHWnd != NULL)
4618
        {
4619
                SetWindowLong(mHWnd, GWL_USERDATA, NULL);
4620
                HWND anOldWindow = mHWnd;
4621
                mHWnd = NULL;          
4622
                DestroyWindow(anOldWindow);    
4623
                mWidgetManager->mImage = NULL;
4624
        }
4625
 
4626
 
4627
        if ((mPlayingDemoBuffer) || (mIsWindowed && !mFullScreenWindow))
4628
        {
4629
                DWORD aWindowStyle = WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
4630
                if (mEnableMaximizeButton)
4631
                        aWindowStyle |= WS_MAXIMIZEBOX;
4632
 
4633
                RECT aRect;
4634
                aRect.left = 0;
4635
                aRect.top = 0;
4636
                aRect.right = mWidth;
4637
                aRect.bottom = mHeight;
4638
 
4639
                BOOL worked = AdjustWindowRect(&aRect, aWindowStyle, FALSE);
4640
 
4641
                int aWidth = aRect.right - aRect.left;
4642
                int aHeight = aRect.bottom - aRect.top;
4643
 
4644
                // Get the work area of the desktop to allow us to center
4645
                RECT aDesktopRect;
4646
                ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &aDesktopRect, NULL);
4647
 
4648
                int aPlaceX = 64;
4649
                int aPlaceY = 64;
4650
 
4651
                if (mPreferredX != -1)
4652
                {
4653
                        aPlaceX = mPreferredX;
4654
                        aPlaceY = mPreferredY;
4655
 
4656
                        int aSpacing = 4;
4657
 
4658
                        if (aPlaceX < aDesktopRect.left + aSpacing)
4659
                                aPlaceX = aDesktopRect.left + aSpacing;
4660
 
4661
                        if (aPlaceY < aDesktopRect.top + aSpacing)
4662
                                aPlaceY = aDesktopRect.top + aSpacing;
4663
 
4664
                        if (aPlaceX + aWidth >= aDesktopRect.right - aSpacing)
4665
                                aPlaceX = aDesktopRect.right - aWidth - aSpacing;
4666
 
4667
                        if (aPlaceY + aHeight >= aDesktopRect.bottom - aSpacing)
4668
                                aPlaceY = aDesktopRect.bottom - aHeight - aSpacing;
4669
                }
4670
 
4671
                if (CheckFor98Mill())
4672
                {
4673
                        mHWnd = CreateWindowExA(
4674
                                0,
4675
                                "MainWindow",
4676
                                SexyStringToStringFast(mTitle).c_str(),
4677
                                aWindowStyle,
4678
                                aPlaceX,
4679
                                aPlaceY,
4680
                                aWidth,
4681
                                aHeight,
4682
                                NULL,
4683
                                NULL,
4684
                                gHInstance,
4685
                                0);
4686
                }
4687
                else
4688
                {
4689
                        mHWnd = CreateWindowEx(
4690
                                0,
4691
                                _S("MainWindow"),
4692
                                mTitle.c_str(),
4693
                                aWindowStyle,
4694
                                aPlaceX,
4695
                                aPlaceY,
4696
                                aWidth,
4697
                                aHeight,
4698
                                NULL,
4699
                                NULL,
4700
                                gHInstance,
4701
                                0);    
4702
                }
4703
 
4704
                if (mPreferredX == -1)
4705
                {                              
4706
                        ::MoveWindow(mHWnd,
4707
                                aDesktopRect.left + ((aDesktopRect.right - aDesktopRect.left) - aWidth)/2,
4708
                                aDesktopRect.top + (int) (((aDesktopRect.bottom - aDesktopRect.top) - aHeight)*0.382),
4709
                                aWidth, aHeight, FALSE);
4710
                }
4711
 
4712
                mIsPhysWindowed = true;
4713
        }
4714
        else
4715
        {
4716
                if (CheckFor98Mill())
4717
                {
4718
                        mHWnd = CreateWindowExA(
4719
                                WS_EX_TOPMOST,
4720
                                "MainWindow",
4721
                                SexyStringToStringFast(mTitle).c_str(),
4722
                                WS_POPUP | WS_VISIBLE,
4723
                                0,
4724
                                0,
4725
                                mWidth,
4726
                                mHeight,
4727
                                NULL,
4728
                                NULL,
4729
                                gHInstance,
4730
                                0);
4731
                }
4732
                else
4733
                {
4734
                        mHWnd = CreateWindowEx(
4735
                                WS_EX_TOPMOST,
4736
                                _S("MainWindow"),
4737
                                mTitle.c_str(),
4738
                                WS_POPUP | WS_VISIBLE,
4739
                                0,
4740
                                0,
4741
                                mWidth,
4742
                                mHeight,
4743
                                NULL,
4744
                                NULL,
4745
                                gHInstance,
4746
                                0);
4747
                }
4748
 
4749
                mIsPhysWindowed = false;
4750
        }
4751
 
4752
        /*char aStr[256];
4753
        sprintf(aStr, "HWND: %d\r\n", mHWnd);
4754
        OutputDebugString(aStr);*/
4755
 
4756
        SetWindowLong(mHWnd, GWL_USERDATA, (LONG) this);       
4757
 
4758
        if (mDDInterface == NULL)
4759
        {
4760
                mDDInterface = new DDInterface(this);
4761
 
4762
                // Enable 3d setting
4763
                bool is3D = false;
4764
                bool is3DOptionSet = RegistryReadBoolean("Is3D", &is3D);
4765
                if (is3DOptionSet)
4766
                {
4767
                        if (mAutoEnable3D)
4768
                        {
4769
                                mAutoEnable3D = false;
4770
                                mTest3D = true;
4771
                        }
4772
 
4773
                        if (is3D)
4774
                                mTest3D = true;
4775
 
4776
                        mDDInterface->mIs3D = is3D;
4777
                }
4778
        }
4779
 
4780
        int aResult = InitDDInterface();
4781
 
4782
        if (mDDInterface->mD3DTester!=NULL && mDDInterface->mD3DTester->ResultsChanged())
4783
                RegistryEraseValue(_S("Is3D"));
4784
 
4785
        if ((mIsWindowed) && (aResult == DDInterface::RESULT_INVALID_COLORDEPTH))
4786
        {
4787
                if (mForceWindowed)
4788
                {
4789
                        Popup(GetString("PLEASE_SET_COLOR_DEPTH", _S("Please set your desktop color depth to 16 bit.")));
4790
                        DoExit(1);
4791
                }
4792
                else
4793
                {
4794
                        mForceFullscreen = true;
4795
                        SwitchScreenMode(false);
4796
                }
4797
                return;
4798
        }
4799
        else if ((!mIsWindowed) &&
4800
                ((aResult == DDInterface::RESULT_EXCLUSIVE_FAIL) ||
4801
                 (aResult == DDInterface::RESULT_DISPCHANGE_FAIL)))
4802
        {
4803
                mForceWindowed = true;
4804
                SwitchScreenMode(true);
4805
        }
4806
        else if (aResult == DDInterface::RESULT_3D_FAIL)
4807
        {
4808
                Set3DAcclerated(false);
4809
                return;
4810
        }
4811
        else if (aResult != DDInterface::RESULT_OK)
4812
        {
4813
                if (Is3DAccelerated())
4814
                {
4815
                        Set3DAcclerated(false);
4816
                        return;
4817
                }
4818
                else
4819
                {
4820
                        Popup(GetString("FAILED_INIT_DIRECTDRAW", _S("Failed to initialize DirectDraw: ")) + StringToSexyString(DDInterface::ResultToString(aResult) + " " + mDDInterface->mErrorString));
4821
                        DoExit(1);
4822
                }
4823
        }
4824
 
4825
        bool isActive = mActive;
4826
        mActive = GetActiveWindow() == mHWnd;
4827
 
4828
        mPhysMinimized = false;
4829
        if (mMinimized)
4830
        {
4831
                if (mMuteOnLostFocus)
4832
                        Unmute(true);
4833
 
4834
                mMinimized = false;
4835
                isActive = mActive; // set this here so we don't call RehupFocus again.
4836
                RehupFocus();
4837
        }
4838
 
4839
        if (isActive != mActive)
4840
                RehupFocus();
4841
 
4842
        ReInitImages();
4843
 
4844
        mWidgetManager->mImage = mDDInterface->GetScreenImage();
4845
        mWidgetManager->MarkAllDirty();
4846
 
4847
        SetTimer(mHWnd, 100, mFrameTime, NULL);
4848
}
4849
 
4850
void SexyAppBase::DeleteNativeImageData()
4851
{
4852
        MemoryImageSet::iterator anItr = mMemoryImageSet.begin();
4853
        while (anItr != mMemoryImageSet.end())
4854
        {
4855
                MemoryImage* aMemoryImage = *anItr;            
4856
                aMemoryImage->DeleteNativeData();                      
4857
                ++anItr;
4858
        }
4859
}
4860
 
4861
void SexyAppBase::DeleteExtraImageData()
4862
{
4863
        AutoCrit anAutoCrit(mDDInterface->mCritSect);
4864
        MemoryImageSet::iterator anItr = mMemoryImageSet.begin();
4865
        while (anItr != mMemoryImageSet.end())
4866
        {
4867
                MemoryImage* aMemoryImage = *anItr;
4868
                aMemoryImage->DeleteExtraBuffers();
4869
                ++anItr;
4870
        }
4871
}
4872
 
4873
void SexyAppBase::ReInitImages()
4874
{
4875
        MemoryImageSet::iterator anItr = mMemoryImageSet.begin();
4876
        while (anItr != mMemoryImageSet.end())
4877
        {
4878
                MemoryImage* aMemoryImage = *anItr;                            
4879
                aMemoryImage->ReInit();
4880
                ++anItr;
4881
        }
4882
}
4883
 
4884
 
4885
void SexyAppBase::LoadingThreadProc()
4886
{
4887
}
4888
 
4889
void SexyAppBase::LoadingThreadCompleted()
4890
{
4891
}
4892
 
4893
void SexyAppBase::LoadingThreadProcStub(void *theArg)
4894
{
4895
        SexyAppBase* aSexyApp = (SexyAppBase*) theArg;
4896
 
4897
        aSexyApp->LoadingThreadProc();         
4898
 
4899
        char aStr[256];
4900
        sprintf(aStr, "Resource Loading Time: %d\r\n", (GetTickCount() - aSexyApp->mTimeLoaded));
4901
        OutputDebugStringA(aStr);
4902
 
4903
        aSexyApp->mLoadingThreadCompleted = true;
4904
}
4905
 
4906
void SexyAppBase::StartLoadingThread()
4907
{      
4908
        if (!mLoadingThreadStarted)
4909
        {
4910
                mYieldMainThread = true;
4911
                ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);               
4912
                mLoadingThreadStarted = true;
4913
                _beginthread(LoadingThreadProcStub, 0, this);
4914
        }
4915
}
4916
void SexyAppBase::CursorThreadProc()
4917
{
4918
        ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4919
 
4920
        POINT aLastCursorPos = {0, 0};
4921
        int aLastDrawCount = 0;
4922
 
4923
        while (!mShutdown)
4924
        {
4925
//              if (mProcessInTimer)
4926
//                      PostMessage(mHWnd,WM_TIMER,101,0);
4927
 
4928
                POINT aCursorPos;
4929
 
4930
                if (mPlayingDemoBuffer)
4931
                {
4932
                        aCursorPos.x = mLastDemoMouseX;
4933
                        aCursorPos.y = mLastDemoMouseY;
4934
                }
4935
                else
4936
                {
4937
                        ::GetCursorPos(&aCursorPos);
4938
                        ::ScreenToClient(mHWnd, &aCursorPos);
4939
                }
4940
 
4941
                if (aLastDrawCount != mDrawCount)
4942
                {
4943
                        // We did a draw so we may have committed a pending mNextCursorX/Y 
4944
                        aLastCursorPos.x = mDDInterface->mCursorX;
4945
                        aLastCursorPos.y = mDDInterface->mCursorY;
4946
                }
4947
 
4948
                if ((aCursorPos.x != aLastCursorPos.x) ||
4949
                        (aCursorPos.y != aLastCursorPos.y))
4950
                {      
4951
                        DWORD aTimeNow = timeGetTime();
4952
                        if (aTimeNow - mNextDrawTick > mDDInterface->mMillisecondsPerFrame + 5)
4953
                        {
4954
                                // Do the special drawing if we are rendering at less than full framerate                               
4955
                                mDDInterface->SetCursorPos(aCursorPos.x, aCursorPos.y);
4956
                                aLastCursorPos = aCursorPos;
4957
                        }
4958
                        else
4959
                        {
4960
                                // Set them up to get assigned in the next screen redraw
4961
                                mDDInterface->mNextCursorX = aCursorPos.x;
4962
                                mDDInterface->mNextCursorY = aCursorPos.y;
4963
                        }                      
4964
                }              
4965
 
4966
                Sleep(10);
4967
        }
4968
 
4969
        mCursorThreadRunning = false;
4970
}
4971
 
4972
void SexyAppBase::CursorThreadProcStub(void *theArg)
4973
{
4974
        CoInitialize(NULL);
4975
        SexyAppBase* aSexyApp = (SexyAppBase*) theArg;
4976
        aSexyApp->CursorThreadProc();
4977
}
4978
 
4979
void SexyAppBase::StartCursorThread()
4980
{
4981
        if (!mCursorThreadRunning)
4982
        {
4983
                mCursorThreadRunning = true;
4984
                ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4985
                _beginthread(CursorThreadProcStub, 0, this);
4986
        }
4987
}
4988
 
4989
void SexyAppBase::SwitchScreenMode(bool wantWindowed, bool is3d, bool force)
4990
{
4991
        if (mForceFullscreen)
4992
                wantWindowed = false;
4993
 
4994
        if (mIsWindowed == wantWindowed && !force)
4995
        {
4996
                Set3DAcclerated(is3d);
4997
                return;
4998
        }
4999
 
5000
        // Set 3d acceleration preference
5001
        Set3DAcclerated(is3d,false);
5002
 
5003
        // Always make the app windowed when playing demos, in order to
5004
        //  make it easier to track down bugs.  We place this after the
5005
        //  sanity check just so things get re-initialized and stuff
5006
        //if (mPlayingDemoBuffer)
5007
        //      wantWindowed = true;
5008
 
5009
        mIsWindowed = wantWindowed;    
5010
 
5011
        MakeWindow();
5012
 
5013
        // We need to do this check to allow IE to get focus instead of
5014
        //  stealing it away for ourselves
5015
        if (!mIsOpeningURL)
5016
        {
5017
                ::ShowWindow(mHWnd, SW_NORMAL);
5018
                ::SetForegroundWindow(mHWnd);
5019
        }
5020
        else
5021
        {
5022
                // Show it but don't activate it
5023
                ::ShowWindow(mHWnd, SW_SHOWNOACTIVATE);
5024
        }
5025
 
5026
        if (mSoundManager!=NULL)
5027
        {
5028
                mSoundManager->SetCooperativeWindow(mHWnd,mIsWindowed);
5029
        }      
5030
 
5031
        mLastTime = timeGetTime();
5032
}
5033
 
5034
void SexyAppBase::SwitchScreenMode(bool wantWindowed)
5035
{
5036
        SwitchScreenMode(wantWindowed, Is3DAccelerated());
5037
}
5038
 
5039
void SexyAppBase::SwitchScreenMode()
5040
{
5041
        SwitchScreenMode(mIsWindowed, Is3DAccelerated(), true);
5042
}
5043
 
5044
void SexyAppBase::SetAlphaDisabled(bool isDisabled)
5045
{
5046
        if (mAlphaDisabled != isDisabled)
5047
        {
5048
                mAlphaDisabled = isDisabled;
5049
                mDDInterface->SetVideoOnlyDraw(mAlphaDisabled);        
5050
                mWidgetManager->mImage = mDDInterface->GetScreenImage();
5051
                mWidgetManager->MarkAllDirty();
5052
        }
5053
}
5054
 
5055
void SexyAppBase::EnforceCursor()
5056
{
5057
        bool wantSysCursor = true;
5058
 
5059
        if (mDDInterface == NULL)
5060
                return;
5061
 
5062
        if ((mSEHOccured) || (!mMouseIn))
5063
        {
5064
                ::SetCursor(::LoadCursor(NULL, IDC_ARROW));    
5065
                if (mDDInterface->SetCursorImage(NULL))
5066
                        mCustomCursorDirty = true;
5067
        }
5068
        else
5069
        {
5070
                if ((mCursorImages[mCursorNum] == NULL) ||
5071
                        ((!mPlayingDemoBuffer) && (!mCustomCursorsEnabled) && (mCursorNum != CURSOR_CUSTOM)))
5072
                {
5073
                        if (mOverrideCursor != NULL)
5074
                                ::SetCursor(mOverrideCursor);
5075
                        else if (mCursorNum == CURSOR_POINTER)
5076
                                ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
5077
                        else if (mCursorNum == CURSOR_HAND)
5078
                                ::SetCursor(mHandCursor);
5079
                        else if (mCursorNum == CURSOR_TEXT)
5080
                                ::SetCursor(::LoadCursor(NULL, IDC_IBEAM));
5081
                        else if (mCursorNum == CURSOR_DRAGGING)
5082
                                ::SetCursor(mDraggingCursor);
5083
                        else if (mCursorNum == CURSOR_CIRCLE_SLASH)
5084
                                ::SetCursor(::LoadCursor(NULL, IDC_NO));
5085
                        else if (mCursorNum == CURSOR_SIZEALL)
5086
                                ::SetCursor(::LoadCursor(NULL, IDC_SIZEALL));
5087
                        else if (mCursorNum == CURSOR_SIZENESW)
5088
                                ::SetCursor(::LoadCursor(NULL, IDC_SIZENESW));
5089
                        else if (mCursorNum == CURSOR_SIZENS)
5090
                                ::SetCursor(::LoadCursor(NULL, IDC_SIZENS));
5091
                        else if (mCursorNum == CURSOR_SIZENWSE)
5092
                                ::SetCursor(::LoadCursor(NULL, IDC_SIZENWSE));
5093
                        else if (mCursorNum == CURSOR_SIZEWE)
5094
                                ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
5095
                        else if (mCursorNum == CURSOR_WAIT)
5096
                                ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
5097
                        else if (mCursorNum == CURSOR_CUSTOM)
5098
                                ::SetCursor(NULL); // Default to not showing anything
5099
                        else if (mCursorNum == CURSOR_NONE)
5100
                                ::SetCursor(NULL);                     
5101
                        else
5102
                                ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
5103
 
5104
                        if (mDDInterface->SetCursorImage(NULL))
5105
                                mCustomCursorDirty = true;
5106
                }
5107
                else
5108
                {
5109
                        if (mDDInterface->SetCursorImage(mCursorImages[mCursorNum]))
5110
                                mCustomCursorDirty = true;
5111
 
5112
                        if (!mPlayingDemoBuffer)
5113
                        {
5114
                                ::SetCursor(NULL);
5115
                        }
5116
                        else
5117
                        {
5118
                                // Give the NO cursor in the client area and an arrow on the title bar
5119
 
5120
                                POINT aULCorner = {0, 0};
5121
                                ::ClientToScreen(mHWnd, &aULCorner);
5122
 
5123
                                POINT aBRCorner = {mWidth, mHeight};
5124
                                ::ClientToScreen(mHWnd, &aBRCorner);
5125
 
5126
                                POINT aPoint;
5127
                                ::GetCursorPos(&aPoint);                       
5128
 
5129
                                if ((aPoint.x >= aULCorner.x) && (aPoint.y >= aULCorner.y) &&
5130
                                        (aPoint.x < aBRCorner.x) && (aPoint.y < aBRCorner.y))
5131
                                {
5132
                                        ::SetCursor(::LoadCursor(NULL, IDC_NO));
5133
                                }
5134
                                else
5135
                                {
5136
                                        ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
5137
                                }
5138
                        }
5139
 
5140
                        wantSysCursor = false;
5141
                }
5142
        }
5143
 
5144
        if (wantSysCursor != mSysCursor)
5145
        {
5146
                mSysCursor = wantSysCursor;
5147
 
5148
                // Don't hide the hardware cursor when playing back a demo buffer
5149
//              if (!mPlayingDemoBuffer)
5150
//                      ::ShowCursor(mSysCursor);
5151
        }
5152
}
5153
 
5154
void SexyAppBase::ProcessSafeDeleteList()
5155
{
5156
        MTAutoDisallowRand aDisallowRand;
5157
 
5158
        WidgetSafeDeleteList::iterator anItr = mSafeDeleteList.begin();
5159
        while (anItr != mSafeDeleteList.end())
5160
        {
5161
                WidgetSafeDeleteInfo* aWidgetSafeDeleteInfo = &(*anItr);
5162
                if (mUpdateAppDepth <= aWidgetSafeDeleteInfo->mUpdateAppDepth)
5163
                {
5164
                        delete aWidgetSafeDeleteInfo->mWidget;
5165
                        anItr = mSafeDeleteList.erase(anItr);
5166
                }
5167
                else
5168
                        ++anItr;
5169
        }      
5170
}
5171
 
5172
void SexyAppBase::UpdateFTimeAcc()
5173
{
5174
        DWORD aCurTime = timeGetTime();
5175
 
5176
        if (mLastTimeCheck != 0)
5177
        {                              
5178
                int aDeltaTime = aCurTime - mLastTimeCheck;            
5179
 
5180
                mUpdateFTimeAcc = min(mUpdateFTimeAcc + aDeltaTime, 200.0);
5181
 
5182
                if (mRelaxUpdateBacklogCount > 0)                              
5183
                        mRelaxUpdateBacklogCount = max(mRelaxUpdateBacklogCount - aDeltaTime, 0);                              
5184
        }
5185
 
5186
        mLastTimeCheck = aCurTime;
5187
}
5188
 
5189
//int aNumCalls = 0;
5190
//DWORD aLastCheck = 0;
5191
 
5192
bool SexyAppBase::Process(bool allowSleep)
5193
{
5194
        /*DWORD aTimeNow = GetTickCount();
5195
        if (aTimeNow - aLastCheck >= 10000)
5196
        {
5197
                OutputDebugString(StrFormat(_S("FUpdates: %d\n"), aNumCalls).c_str());
5198
                aLastCheck = aTimeNow;
5199
                aNumCalls = 0;
5200
        }*/
5201
 
5202
        if (mLoadingFailed)
5203
                Shutdown();
5204
 
5205
        bool isVSynched = (!mPlayingDemoBuffer) && (mVSyncUpdates) && (!mLastDrawWasEmpty) && (!mVSyncBroken) &&
5206
                ((!mIsPhysWindowed) || (mIsPhysWindowed && mWaitForVSync && !mSoftVSyncWait));
5207
        double aFrameFTime;
5208
        double anUpdatesPerUpdateF;
5209
 
5210
        if (mVSyncUpdates)
5211
        {
5212
                aFrameFTime = (1000.0 / mSyncRefreshRate) / mUpdateMultiplier;
5213
                anUpdatesPerUpdateF = (float) (1000.0 / (mFrameTime * mSyncRefreshRate));
5214
        }
5215
        else
5216
        {
5217
                aFrameFTime = mFrameTime / mUpdateMultiplier;
5218
                anUpdatesPerUpdateF = 1.0;
5219
        }
5220
 
5221
        // Do we need to fast forward?
5222
        if (mPlayingDemoBuffer)
5223
        {
5224
                if (mUpdateCount < mFastForwardToUpdateNum || mFastForwardToMarker)
5225
                {
5226
                        if (!mDemoMute && !mFastForwardStep)
5227
                        {
5228
                                mDemoMute = true;
5229
                                Mute(true);
5230
                        }
5231
 
5232
                        static DWORD aTick = GetTickCount();
5233
                        while (mUpdateCount < mFastForwardToUpdateNum || mFastForwardToMarker)
5234
                        {
5235
                                ClearUpdateBacklog();
5236
                                int aLastUpdateCount = mUpdateCount;
5237
 
5238
                                // Actual updating code below
5239
                                //////////////////////////////////////////////////////////////////////////
5240
 
5241
                                bool hadRealUpdate = DoUpdateFrames();
5242
 
5243
                                if (hadRealUpdate)
5244
                                {                                      
5245
                                        mPendingUpdatesAcc += anUpdatesPerUpdateF;
5246
                                        mPendingUpdatesAcc -= 1.0;
5247
                                        ProcessSafeDeleteList();
5248
 
5249
                                        // Process any extra updates
5250
                                        while (mPendingUpdatesAcc >= 1.0)
5251
                                        {                                              
5252
                                                // These should just be IDLE commands we have to clear out
5253
                                                ProcessDemo();                                                                                         
5254
 
5255
                                                bool hasRealUpdate = DoUpdateFrames();
5256
                                                DBG_ASSERTE(hasRealUpdate);
5257
 
5258
                                                if (!hasRealUpdate)
5259
                                                        break;
5260
 
5261
                                                ProcessSafeDeleteList();
5262
                                                mPendingUpdatesAcc -= 1.0;
5263
                                        }
5264
 
5265
                                        DoUpdateFramesF((float) anUpdatesPerUpdateF);                                  
5266
                                        ProcessSafeDeleteList();
5267
                                }
5268
 
5269
                                //////////////////////////////////////////////////////////////////////////                              
5270
 
5271
                                // If the update count doesn't change, its because we are
5272
                                //  playing back a demo and need to read more
5273
                                if (aLastUpdateCount == mUpdateCount)
5274
                                        return true;
5275
 
5276
                                DWORD aNewTick = GetTickCount();
5277
                                if (aNewTick - aTick >= 1000 || mFastForwardStep) // let the app draw some
5278
                                {
5279
                                        mFastForwardStep = false;
5280
                                        aTick = GetTickCount();
5281
                                        DrawDirtyStuff();                      
5282
                                        return true;
5283
                                }
5284
                        }
5285
                }
5286
 
5287
                if (mDemoMute)
5288
                {
5289
                        mDemoMute = false;
5290
                        mSoundManager->StopAllSounds();
5291
                        Unmute(true);
5292
                }
5293
        }
5294
 
5295
        // Make sure we're not paused
5296
        if ((!mPaused) && (mUpdateMultiplier > 0))
5297
        {
5298
                ulong aStartTime = timeGetTime();
5299
 
5300
                ulong aCurTime = aStartTime;           
5301
                int aCumSleepTime = 0;
5302
 
5303
                // When we are VSynching, only calculate this FTimeAcc right after drawing
5304
 
5305
                if (!isVSynched)               
5306
                        UpdateFTimeAcc();                                      
5307
 
5308
                // mNonDrawCount is used to make sure we draw the screen at least
5309
                // 10 times per second, even if it means we have to slow down
5310
                // the updates to make it draw 10 times per second in "game time"
5311
 
5312
                bool didUpdate = false;
5313
 
5314
                if (mUpdateAppState == UPDATESTATE_PROCESS_1)
5315
                {
5316
                        if ((++mNonDrawCount < (int) ceil(10*mUpdateMultiplier)) || (!mLoaded))
5317
                        {
5318
                                bool doUpdate = false;
5319
 
5320
                                if (isVSynched)
5321
                                {
5322
                                        // Synch'ed to vertical refresh, so update as soon as possible after draw
5323
                                        doUpdate = (!mHasPendingDraw) || (mUpdateFTimeAcc >= (int) (aFrameFTime * 0.75));
5324
                                }
5325
                                else if (mUpdateFTimeAcc >= aFrameFTime)
5326
                                {
5327
                                        doUpdate = true;
5328
                                }
5329
 
5330
                                if (doUpdate)
5331
                                {
5332
                                        // Do VSyncBroken test.  This test fails if we're in fullscreen and
5333
                                        // "don't vsync" has been forced in Advanced settings up Display Properties
5334
                                        if ((!mPlayingDemoBuffer) && (mUpdateMultiplier == 1.0))
5335
                                        {
5336
                                                mVSyncBrokenTestUpdates++;
5337
                                                if (mVSyncBrokenTestUpdates >= (DWORD) ((1000+mFrameTime-1)/mFrameTime))
5338
                                                {
5339
                                                        // It has to be running 33% fast to be "broken" (25% = 1/0.800)
5340
                                                        if (aStartTime - mVSyncBrokenTestStartTick <= 800)
5341
                                                        {
5342
                                                                // The test has to fail 3 times in a row before we decide that
5343
                                                                //  vsync is broken overall
5344
                                                                mVSyncBrokenCount++;
5345
                                                                if (mVSyncBrokenCount >= 3)
5346
                                                                        mVSyncBroken = true;
5347
                                                        }
5348
                                                        else
5349
                                                                mVSyncBrokenCount = 0;
5350
 
5351
                                                        mVSyncBrokenTestStartTick = aStartTime;
5352
                                                        mVSyncBrokenTestUpdates = 0;
5353
                                                }
5354
                                        }
5355
 
5356
                                        bool hadRealUpdate = DoUpdateFrames();
5357
                                        if (hadRealUpdate)
5358
                                                mUpdateAppState = UPDATESTATE_PROCESS_2;                                       
5359
 
5360
                                        mHasPendingDraw = true;
5361
                                        didUpdate = true;
5362
                                }
5363
                        }
5364
                }
5365
                else if (mUpdateAppState == UPDATESTATE_PROCESS_2)
5366
                {
5367
                        mUpdateAppState = UPDATESTATE_PROCESS_DONE;
5368
 
5369
                        mPendingUpdatesAcc += anUpdatesPerUpdateF;
5370
                        mPendingUpdatesAcc -= 1.0;
5371
                        ProcessSafeDeleteList();
5372
 
5373
                        // Process any extra updates
5374
                        while (mPendingUpdatesAcc >= 1.0)
5375
                        {      
5376
                                // These should just be IDLE commands we have to clear out
5377
                                ProcessDemo();                                                                                         
5378
 
5379
                                ++mNonDrawCount;
5380
                                bool hasRealUpdate = DoUpdateFrames();
5381
                                DBG_ASSERTE(hasRealUpdate);
5382
 
5383
                                if (!hasRealUpdate)
5384
                                        break;
5385
 
5386
                                ProcessSafeDeleteList();
5387
                                mPendingUpdatesAcc -= 1.0;
5388
                        }                                      
5389
 
5390
                        //aNumCalls++;
5391
                        DoUpdateFramesF((float) anUpdatesPerUpdateF);
5392
                        ProcessSafeDeleteList();               
5393
 
5394
                        // Don't let mUpdateFTimeAcc dip below 0
5395
                        //  Subtract an extra 0.2ms, because sometimes refresh rates have some
5396
                        //  fractional component that gets truncated, and it's better to take off
5397
                        //  too much to keep our timing tending toward occuring right after 
5398
                        //  redraws
5399
                        if (isVSynched)
5400
                                mUpdateFTimeAcc = max(mUpdateFTimeAcc - aFrameFTime - 0.2f, 0.0);
5401
                        else
5402
                                mUpdateFTimeAcc -= aFrameFTime;
5403
 
5404
                        if (mRelaxUpdateBacklogCount > 0)
5405
                                mUpdateFTimeAcc = 0;
5406
 
5407
                        didUpdate = true;
5408
                }
5409
 
5410
                if (!didUpdate)
5411
                {                      
5412
                        mUpdateAppState = UPDATESTATE_PROCESS_DONE;
5413
 
5414
                        mNonDrawCount = 0;
5415
 
5416
                        if (mHasPendingDraw)
5417
                        {
5418
                                DrawDirtyStuff();
5419
                        }
5420
                        else
5421
                        {
5422
                                // Let us take into account the time it took to draw dirty stuff                        
5423
                                int aTimeToNextFrame = (int) (aFrameFTime - mUpdateFTimeAcc);
5424
                                if (aTimeToNextFrame > 0)
5425
                                {
5426
                                        if (!allowSleep)
5427
                                                return false;
5428
 
5429
                                        // Wait till next processing cycle
5430
                                        ++mSleepCount;
5431
                                        Sleep(aTimeToNextFrame);
5432
 
5433
                                        aCumSleepTime += aTimeToNextFrame;                                     
5434
                                }
5435
                        }
5436
                }
5437
 
5438
                if (mYieldMainThread)
5439
                {
5440
                        // This is to make sure that the title screen doesn't take up any more than 
5441
                        // 1/3 of the processor time
5442
 
5443
                        ulong anEndTime = timeGetTime();
5444
                        int anElapsedTime = (anEndTime - aStartTime) - aCumSleepTime;
5445
                        int aLoadingYieldSleepTime = min(250, (anElapsedTime * 2) - aCumSleepTime);
5446
 
5447
                        if (aLoadingYieldSleepTime >= 0)
5448
                        {
5449
                                if (!allowSleep)
5450
                                        return false;
5451
 
5452
                                Sleep(aLoadingYieldSleepTime);
5453
                        }
5454
                }
5455
        }
5456
 
5457
        ProcessSafeDeleteList();       
5458
        return true;
5459
}
5460
 
5461
/*void SexyAppBase::DoMainLoop()
5462
{
5463
        Dialog* aDialog = NULL;
5464
        if (theModalDialogId != -1)
5465
        {
5466
                aDialog = GetDialog(theModalDialogId);
5467
                DBG_ASSERTE(aDialog != NULL);
5468
                if (aDialog == NULL)
5469
                        return;
5470
        }
5471
 
5472
        while (!mShutdown)
5473
        {              
5474
                MSG msg;
5475
                while ((PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) && (!mShutdown))
5476
                {
5477
                        TranslateMessage(&msg);
5478
                        DispatchMessage(&msg);
5479
                }
5480
 
5481
                ProcessDemo();         
5482
                ProcessDeferredMessages();
5483
 
5484
                if ((aDialog != NULL) && (aDialog->mResult != -1))
5485
                        return;
5486
 
5487
                if (!mShutdown)
5488
                {
5489
                        //++aCount;
5490
                        Process();
5491
                }              
5492
        }
5493
}*/
5494
 
5495
void SexyAppBase::DoMainLoop()
5496
{
5497
        while (!mShutdown)
5498
        {
5499
                if (mExitToTop)
5500
                        mExitToTop = false;
5501
                UpdateApp();
5502
        }
5503
}
5504
 
5505
bool SexyAppBase::UpdateAppStep(bool* updated)
5506
{
5507
        if (updated != NULL)
5508
                *updated = false;
5509
 
5510
        if (mExitToTop)
5511
                return false;
5512
 
5513
        if (mUpdateAppState == UPDATESTATE_PROCESS_DONE)
5514
                mUpdateAppState = UPDATESTATE_MESSAGES;
5515
 
5516
        mUpdateAppDepth++;
5517
 
5518
        // We update in two stages to avoid doing a Process if our loop termination
5519
        //  condition has already been met by processing windows messages               
5520
        if (mUpdateAppState == UPDATESTATE_MESSAGES)
5521
        {              
5522
                MSG msg;
5523
                while ((PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) && (!mShutdown))
5524
                {
5525
                        TranslateMessage(&msg);
5526
                        DispatchMessage(&msg);
5527
                }
5528
 
5529
                ProcessDemo();
5530
                if (!ProcessDeferredMessages(true))
5531
                {                      
5532
                        mUpdateAppState = UPDATESTATE_PROCESS_1;
5533
                }
5534
        }
5535
        else
5536
        {
5537
                // Process changes state by itself
5538
                if (mStepMode)
5539
                {
5540
                        if (mStepMode==2)
5541
                        {
5542
                                Sleep(mFrameTime);
5543
                                mUpdateAppState = UPDATESTATE_PROCESS_DONE; // skip actual update until next step
5544
                        }
5545
                        else
5546
                        {
5547
                                mStepMode = 2;
5548
                                DoUpdateFrames();
5549
                                DoUpdateFramesF(1.0f);
5550
                                DrawDirtyStuff();
5551
                        }
5552
                }
5553
                else
5554
                {
5555
                        int anOldUpdateCnt = mUpdateCount;
5556
                        Process();             
5557
                        if (updated != NULL)
5558
                                *updated = mUpdateCount != anOldUpdateCnt;                     
5559
                }
5560
        }
5561
 
5562
        mUpdateAppDepth--;
5563
 
5564
        return true;
5565
}
5566
 
5567
bool SexyAppBase::UpdateApp()
5568
{
5569
        bool updated;
5570
        for (;;)
5571
        {
5572
                if (!UpdateAppStep(&updated))
5573
                        return false;
5574
                if (updated)
5575
                        return true;
5576
        }
5577
}
5578
 
5579
int SexyAppBase::InitDDInterface()
5580
{
5581
        PreDDInterfaceInitHook();
5582
        DeleteNativeImageData();
5583
        int aResult = mDDInterface->Init(mHWnd, mIsPhysWindowed);
5584
        DemoSyncRefreshRate();
5585
        if ( DDInterface::RESULT_OK == aResult )
5586
        {
5587
                mScreenBounds.mX = ( mWidth - mDDInterface->mWidth ) / 2;
5588
                mScreenBounds.mY = ( mHeight - mDDInterface->mHeight ) / 2;
5589
                mScreenBounds.mWidth = mDDInterface->mWidth;
5590
                mScreenBounds.mHeight = mDDInterface->mHeight;
5591
                mWidgetManager->Resize(mScreenBounds, mDDInterface->mPresentationRect);
5592
                PostDDInterfaceInitHook();
5593
        }
5594
        return aResult;
5595
}
5596
 
5597
void SexyAppBase::PreTerminate()
5598
{
5599
}
5600
 
5601
void SexyAppBase::Start()
5602
{
5603
        if (mShutdown)
5604
                return;
5605
 
5606
        StartCursorThread();
5607
 
5608
        if (mAutoStartLoadingThread)
5609
                StartLoadingThread();
5610
 
5611
        ::ShowWindow(mHWnd, SW_SHOW);  
5612
        ::SetFocus(mHWnd);
5613
 
5614
        timeBeginPeriod(1);
5615
 
5616
        int aCount = 0;
5617
        int aSleepCount = 0;
5618
 
5619
        DWORD aStartTime = timeGetTime();              
5620
 
5621
        mRunning = true;
5622
        mLastTime = aStartTime;
5623
        mLastUserInputTick = aStartTime;
5624
        mLastTimerTime = aStartTime;
5625
 
5626
        DoMainLoop();
5627
        ProcessSafeDeleteList();
5628
 
5629
        mRunning = false;
5630
 
5631
        WaitForLoadingThread();
5632
 
5633
        char aString[256];
5634
        sprintf(aString, "Seconds       = %g\r\n", (timeGetTime() - aStartTime) / 1000.0);
5635
        OutputDebugStringA(aString);
5636
        //sprintf(aString, "Count         = %d\r\n", aCount);
5637
        //OutputDebugString(aString);
5638
        sprintf(aString, "Sleep Count   = %d\r\n", mSleepCount);
5639
        OutputDebugStringA(aString);
5640
        sprintf(aString, "Update Count  = %d\r\n", mUpdateCount);
5641
        OutputDebugStringA(aString);
5642
        sprintf(aString, "Draw Count    = %d\r\n", mDrawCount);
5643
        OutputDebugStringA(aString);
5644
        sprintf(aString, "Draw Time     = %d\r\n", mDrawTime);
5645
        OutputDebugStringA(aString);
5646
        sprintf(aString, "Screen Blt    = %d\r\n", mScreenBltTime);
5647
        OutputDebugStringA(aString);
5648
        if (mDrawTime+mScreenBltTime > 0)
5649
        {
5650
                sprintf(aString, "Avg FPS       = %d\r\n", (mDrawCount*1000)/(mDrawTime+mScreenBltTime));
5651
                OutputDebugStringA(aString);
5652
        }
5653
 
5654
        timeEndPeriod(1);      
5655
 
5656
        PreTerminate();
5657
 
5658
        WriteToRegistry();
5659
}
5660
 
5661
bool SexyAppBase::CheckSignature(const Buffer& theBuffer, const std::string& theFileName)
5662
{
5663
        // Add your own signature checking code here
5664
        return false;
5665
}
5666
 
5667
bool SexyAppBase::LoadProperties(const std::string& theFileName, bool required, bool checkSig)
5668
{
5669
        Buffer aBuffer;
5670
        if (!ReadBufferFromFile(theFileName, &aBuffer))
5671
        {
5672
                if (!required)
5673
                        return true;
5674
                else
5675
                {
5676
                        Popup(GetString("UNABLE_OPEN_PROPERTIES", _S("Unable to open properties file ")) + StringToSexyString(theFileName));
5677
                        return false;
5678
                }
5679
        }
5680
        if (checkSig)
5681
        {
5682
                if (!CheckSignature(aBuffer, theFileName))
5683
                {
5684
                        Popup(GetString("PROPERTIES_SIG_FAILED", _S("Signature check failed on ")) + StringToSexyString(theFileName + "'"));
5685
                        return false;
5686
                }
5687
        }
5688
 
5689
        PropertiesParser aPropertiesParser(this);
5690
 
5691
        // Load required language-file properties
5692
                if (!aPropertiesParser.ParsePropertiesBuffer(aBuffer))
5693
                {
5694
                        Popup(aPropertiesParser.GetErrorText());               
5695
                        return false;
5696
                }
5697
                else
5698
                        return true;
5699
}
5700
 
5701
bool SexyAppBase::LoadProperties()
5702
{
5703
        // Load required language-file properties
5704
        return LoadProperties("properties\\default.xml", true, false);
5705
}
5706
 
5707
void SexyAppBase::LoadResourceManifest()
5708
{
5709
        if (!mResourceManager->ParseResourcesFile("properties\\resources.xml"))
5710
                ShowResourceError(true);
5711
}
5712
 
5713
void SexyAppBase::ShowResourceError(bool doExit)
5714
{
5715
        Popup(mResourceManager->GetErrorText());       
5716
        if (doExit)
5717
                DoExit(0);
5718
}
5719
 
5720
bool SexyAppBase::GetBoolean(const std::string& theId)
5721
{
5722
        StringBoolMap::iterator anItr = mBoolProperties.find(theId);
5723
        DBG_ASSERTE(anItr != mBoolProperties.end());
5724
 
5725
        if (anItr != mBoolProperties.end())    
5726
                return anItr->second;
5727
        else
5728
                return false;
5729
}
5730
 
5731
bool SexyAppBase::GetBoolean(const std::string& theId, bool theDefault)
5732
{
5733
        StringBoolMap::iterator anItr = mBoolProperties.find(theId);   
5734
 
5735
        if (anItr != mBoolProperties.end())    
5736
                return anItr->second;
5737
        else
5738
                return theDefault;     
5739
}
5740
 
5741
int SexyAppBase::GetInteger(const std::string& theId)
5742
{
5743
        StringIntMap::iterator anItr = mIntProperties.find(theId);
5744
        DBG_ASSERTE(anItr != mIntProperties.end());
5745
 
5746
        if (anItr != mIntProperties.end())     
5747
                return anItr->second;
5748
        else
5749
                return false;
5750
}
5751
 
5752
int SexyAppBase::GetInteger(const std::string& theId, int theDefault)
5753
{
5754
        StringIntMap::iterator anItr = mIntProperties.find(theId);     
5755
 
5756
        if (anItr != mIntProperties.end())     
5757
                return anItr->second;
5758
        else
5759
                return theDefault;     
5760
}
5761
 
5762
double SexyAppBase::GetDouble(const std::string& theId)
5763
{
5764
        StringDoubleMap::iterator anItr = mDoubleProperties.find(theId);
5765
        DBG_ASSERTE(anItr != mDoubleProperties.end());
5766
 
5767
        if (anItr != mDoubleProperties.end())  
5768
                return anItr->second;
5769
        else
5770
                return false;
5771
}
5772
 
5773
double SexyAppBase::GetDouble(const std::string& theId, double theDefault)
5774
{
5775
        StringDoubleMap::iterator anItr = mDoubleProperties.find(theId);       
5776
 
5777
        if (anItr != mDoubleProperties.end())  
5778
                return anItr->second;
5779
        else
5780
                return theDefault;     
5781
}
5782
 
5783
SexyString SexyAppBase::GetString(const std::string& theId)
5784
{
5785
        StringWStringMap::iterator anItr = mStringProperties.find(theId);
5786
        DBG_ASSERTE(anItr != mStringProperties.end());
5787
 
5788
        if (anItr != mStringProperties.end())  
5789
                return WStringToSexyString(anItr->second);
5790
        else
5791
                return _S("");
5792
}
5793
 
5794
SexyString SexyAppBase::GetString(const std::string& theId, const SexyString& theDefault)
5795
{
5796
        StringWStringMap::iterator anItr = mStringProperties.find(theId);      
5797
 
5798
        if (anItr != mStringProperties.end())  
5799
                return WStringToSexyString(anItr->second);
5800
        else
5801
                return theDefault;     
5802
}
5803
 
5804
StringVector SexyAppBase::GetStringVector(const std::string& theId)
5805
{
5806
        StringStringVectorMap::iterator anItr = mStringVectorProperties.find(theId);
5807
        DBG_ASSERTE(anItr != mStringVectorProperties.end());
5808
 
5809
        if (anItr != mStringVectorProperties.end())    
5810
                return anItr->second;
5811
        else
5812
                return StringVector();
5813
}
5814
 
5815
void SexyAppBase::SetString(const std::string& theId, const std::wstring& theValue)
5816
{
5817
        std::pair<StringWStringMap::iterator, bool> aPair = mStringProperties.insert(StringWStringMap::value_type(theId, theValue));
5818
        if (!aPair.second) // Found it, change value
5819
                aPair.first->second = theValue;
5820
}
5821
 
5822
 
5823
void SexyAppBase::SetBoolean(const std::string& theId, bool theValue)
5824
{
5825
        std::pair<StringBoolMap::iterator, bool> aPair = mBoolProperties.insert(StringBoolMap::value_type(theId, theValue));
5826
        if (!aPair.second) // Found it, change value
5827
                aPair.first->second = theValue;
5828
}
5829
 
5830
void SexyAppBase::SetInteger(const std::string& theId, int theValue)
5831
{
5832
        std::pair<StringIntMap::iterator, bool> aPair = mIntProperties.insert(StringIntMap::value_type(theId, theValue));
5833
        if (!aPair.second) // Found it, change value
5834
                aPair.first->second = theValue;
5835
}
5836
 
5837
void SexyAppBase::SetDouble(const std::string& theId, double theValue)
5838
{
5839
        std::pair<StringDoubleMap::iterator, bool> aPair = mDoubleProperties.insert(StringDoubleMap::value_type(theId, theValue));
5840
        if (!aPair.second) // Found it, change value
5841
                aPair.first->second = theValue;
5842
}
5843
 
5844
void SexyAppBase::DoParseCmdLine()
5845
{
5846
        char* aCmdLine = GetCommandLineA();    
5847
        char* aCmdLinePtr = aCmdLine;
5848
        if (aCmdLinePtr[0] == '"')
5849
        {
5850
                aCmdLinePtr = strchr(aCmdLinePtr + 1, '"');
5851
                if (aCmdLinePtr != NULL)
5852
                        aCmdLinePtr++;
5853
        }
5854
 
5855
        if (aCmdLinePtr != NULL)
5856
        {
5857
                aCmdLinePtr = strchr(aCmdLinePtr, ' ');
5858
                if (aCmdLinePtr != NULL)
5859
                        ParseCmdLine(aCmdLinePtr+1);   
5860
        }
5861
 
5862
        mCmdLineParsed = true;
5863
}
5864
 
5865
void SexyAppBase::ParseCmdLine(const std::string& theCmdLine)
5866
{
5867
        // Command line example:  -play -demofile="game demo.dmo"
5868
        // Results in HandleCmdLineParam("-play", ""); HandleCmdLineParam("-demofile", "game demo.dmo");
5869
        std::string aCurParamName;
5870
        std::string aCurParamValue;
5871
 
5872
        int aSpacePos = 0;
5873
        bool inQuote = false;
5874
        bool onValue = false;
5875
 
5876
        for (int i = 0; i < (int) theCmdLine.length(); i++)
5877
        {
5878
                char c = theCmdLine[i];
5879
                bool atEnd = false;
5880
 
5881
                if (c == '"')
5882
                {
5883
                        inQuote = !inQuote;
5884
 
5885
                        if (!inQuote)
5886
                                atEnd = true;
5887
                }
5888
                else if ((c == ' ') && (!inQuote))
5889
                        atEnd = true;
5890
                else if (c == '=')
5891
                        onValue = true;
5892
                else if (onValue)
5893
                        aCurParamValue += c;
5894
                else
5895
                        aCurParamName += c;
5896
 
5897
                if (i == theCmdLine.length() - 1)
5898
                        atEnd = true;
5899
 
5900
                if (atEnd && !aCurParamName.empty())
5901
                {
5902
                        HandleCmdLineParam(aCurParamName, aCurParamValue);
5903
                        aCurParamName = "";
5904
                        aCurParamValue = "";
5905
                        onValue = false;
5906
                }      
5907
        }
5908
}
5909
 
5910
static int GetMaxDemoFileNum(const std::string& theDemoPrefix, int theMaxToKeep, bool doErase)
5911
{
5912
        WIN32_FIND_DATAA aData;
5913
        HANDLE aHandle = FindFirstFileA((theDemoPrefix + "*.dmo").c_str(), &aData);
5914
        if (aHandle==INVALID_HANDLE_VALUE)
5915
                return 0;
5916
 
5917
        typedef std::set<int> IntSet;
5918
        IntSet aSet;
5919
 
5920
        do {
5921
                int aNum = 0;
5922
                if (sscanf(aData.cFileName,(theDemoPrefix + "%d.dmo").c_str(), &aNum)==1)
5923
                        aSet.insert(aNum);
5924
 
5925
        } while(FindNextFileA(aHandle,&aData));
5926
        FindClose(aHandle);
5927
 
5928
        IntSet::iterator anItr = aSet.begin();
5929
        if ((int)aSet.size()>theMaxToKeep-1 && doErase)
5930
                DeleteFile(StrFormat((theDemoPrefix + "%d.dmo").c_str(),*anItr).c_str());
5931
 
5932
        if (aSet.empty())
5933
                return 0;
5934
 
5935
        anItr = aSet.end();
5936
        --anItr;
5937
        return (*anItr);
5938
}
5939
 
5940
void SexyAppBase::HandleCmdLineParam(const std::string& theParamName, const std::string& theParamValue)
5941
{
5942
        if (theParamName == "-play")
5943
        {
5944
                mPlayingDemoBuffer = true;
5945
                mRecordingDemoBuffer = false;
5946
        }
5947
        else if (theParamName == "-recnum")
5948
        {
5949
                int aNum = atoi(theParamValue.c_str());
5950
                if (aNum<=0)
5951
                        aNum=5;
5952
 
5953
                int aDemoFileNum = GetMaxDemoFileNum(mDemoPrefix, aNum, true) + 1;
5954
                mDemoFileName = SexyStringToString(StrFormat(StringToSexyString(mDemoPrefix + "%d.dmo").c_str(),aDemoFileNum));
5955
                if (mDemoFileName.length() < 2 || (mDemoFileName[1] != ':' && mDemoFileName[2] != '\\'))
5956
                {
5957
                        mDemoFileName = GetAppDataFolder() + mDemoFileName;
5958
                }
5959
                mRecordingDemoBuffer = true;
5960
                mPlayingDemoBuffer = false;
5961
        }
5962
        else if (theParamName == "-playnum")
5963
        {
5964
                int aNum = atoi(theParamValue.c_str())-1;
5965
                if (aNum<0)
5966
                        aNum=0;
5967
 
5968
                int aDemoFileNum = GetMaxDemoFileNum(mDemoPrefix, aNum, false)-aNum;
5969
                mDemoFileName = SexyStringToString(StrFormat(StringToSexyString(mDemoPrefix + "%d.dmo").c_str(),aDemoFileNum));
5970
                mRecordingDemoBuffer = false;
5971
                mPlayingDemoBuffer = true;
5972
        }
5973
        else if (theParamName == "-record")
5974
        {
5975
                mRecordingDemoBuffer = true;
5976
                mPlayingDemoBuffer = false;
5977
        }
5978
        else if (theParamName == "-demofile")
5979
        {
5980
                mDemoFileName = theParamValue;
5981
                if (mDemoFileName.length() < 2 || (mDemoFileName[1] != ':' && mDemoFileName[2] != '\\'))
5982
                {
5983
                        mDemoFileName = GetAppDataFolder() + mDemoFileName;
5984
                }
5985
        }      
5986
        else if (theParamName == "-crash")
5987
        {
5988
                // Try to access NULL
5989
                char* a = 0;
5990
                *a = '!';              
5991
        }
5992
        else if (theParamName == "-screensaver")
5993
        {
5994
                mIsScreenSaver = true;
5995
        }
5996
        else if (theParamName == "-changedir")
5997
        {
5998
                mChangeDirTo = theParamValue;
5999
        }
6000
        else
6001
        {
6002
                Popup(GetString("INVALID_COMMANDLINE_PARAM", _S("Invalid command line parameter: ")) + StringToSexyString(theParamName));
6003
                DoExit(0);
6004
        }
6005
}
6006
 
6007
void SexyAppBase::PreDisplayHook()
6008
{
6009
}
6010
 
6011
void SexyAppBase::PreDDInterfaceInitHook()
6012
{
6013
}
6014
 
6015
void SexyAppBase::PostDDInterfaceInitHook()
6016
{
6017
}
6018
 
6019
bool SexyAppBase::ChangeDirHook(const char *theIntendedPath)
6020
{
6021
        return false;
6022
}
6023
 
6024
MusicInterface* SexyAppBase::CreateMusicInterface(HWND theWindow)
6025
{
6026
        if (mNoSoundNeeded)
6027
                return new MusicInterface;
6028
        else if (mWantFMod)
6029
                return new FModMusicInterface(mInvisHWnd);
6030
        else
6031
                return new BassMusicInterface(mInvisHWnd);
6032
}
6033
 
6034
void SexyAppBase::InitPropertiesHook()
6035
{
6036
}
6037
 
6038
void SexyAppBase::InitHook()
6039
{
6040
}
6041
 
6042
void SexyAppBase::Init()
6043
{
6044
        mPrimaryThreadId = GetCurrentThreadId();       
6045
 
6046
        if (mShutdown)
6047
                return;
6048
 
6049
        if (gDDrawDLL==NULL || gDSoundDLL==NULL)
6050
        {
6051
                MessageBox(NULL,
6052
                                                GetString("APP_REQUIRES_DIRECTX", _S("This application requires DirectX to run.  You can get DirectX at http://www.microsoft.com/directx")).c_str(),
6053
                                                GetString("YOU_NEED_DIRECTX", _S("You need DirectX")).c_str(),
6054
                                                MB_OK | MB_ICONERROR);
6055
                DoExit(0);
6056
        }      
6057
 
6058
        InitPropertiesHook();
6059
        ReadFromRegistry();    
6060
 
6061
        if (CheckForVista())
6062
        {
6063
                HMODULE aMod;
6064
                SHGetFolderPathFunc aFunc = (SHGetFolderPathFunc)GetSHGetFolderPath("shell32.dll", &aMod);
6065
                if (aFunc == NULL || aMod == NULL)
6066
                        SHGetFolderPathFunc aFunc = (SHGetFolderPathFunc)GetSHGetFolderPath("shfolder.dll", &aMod);
6067
 
6068
                if (aMod != NULL)
6069
                {
6070
                        char aPath[MAX_PATH];
6071
                        aFunc(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, aPath);
6072
 
6073
                        std::string aDataPath = RemoveTrailingSlash(aPath) + "\\" + mFullCompanyName + "\\" + mProdName;
6074
                        SetAppDataFolder(aDataPath + "\\");
6075
                        //MkDir(aDataPath);
6076
                        //AllowAllAccess(aDataPath);
6077
                        if (mDemoFileName.length() < 2 || (mDemoFileName[1] != ':' && mDemoFileName[2] != '\\'))
6078
                        {
6079
                                mDemoFileName = GetAppDataFolder() + mDemoFileName;
6080
                        }
6081
 
6082
                        FreeLibrary(aMod);
6083
                }
6084
        }
6085
 
6086
        if (!mCmdLineParsed)
6087
                DoParseCmdLine();
6088
 
6089
        if (IsScreenSaver())   
6090
                mOnlyAllowOneCopyToRun = false;
6091
 
6092
 
6093
        if(gHInstance==NULL)
6094
                gHInstance = (HINSTANCE)GetModuleHandle(NULL);
6095
 
6096
        // Change directory
6097
        if (!ChangeDirHook(mChangeDirTo.c_str()))
6098
                chdir(mChangeDirTo.c_str());
6099
 
6100
        gPakInterface->AddPakFile("main.pak");
6101
 
6102
        // Create a message we can use to talk to ourselves inter-process
6103
        mNotifyGameMessage = RegisterWindowMessage((_S("Notify") + StringToSexyString(mProdName)).c_str());
6104
 
6105
        // Create a globally unique mutex
6106
        mMutex = CreateMutex(NULL, TRUE, (StringToSexyString(mProdName) + _S("Mutex")).c_str());
6107
        if (::GetLastError() == ERROR_ALREADY_EXISTS)
6108
                HandleGameAlreadyRunning();
6109
 
6110
        mRandSeed = GetTickCount();
6111
        SRand(mRandSeed);      
6112
 
6113
        // Set up demo recording stuff
6114
        if (mPlayingDemoBuffer)
6115
        {
6116
                std::string anError;
6117
                if (!ReadDemoBuffer(anError))
6118
                {
6119
                        mPlayingDemoBuffer = false;
6120
                        Popup(anError);
6121
                        DoExit(0);
6122
                }
6123
        }
6124
 
6125
 
6126
        srand(GetTickCount());
6127
 
6128
        if (CheckFor98Mill())
6129
        {
6130
                mIsWideWindow = false;
6131
 
6132
                WNDCLASSA wc;
6133
                wc.style = CS_DBLCLKS;
6134
                wc.cbClsExtra = 0;
6135
                wc.cbWndExtra = 0;
6136
                wc.hbrBackground = NULL;
6137
                wc.hCursor = NULL;
6138
                wc.hIcon = ::LoadIconA(gHInstance, "IDI_MAIN_ICON");
6139
                wc.hInstance = gHInstance;
6140
                wc.lpfnWndProc = WindowProc;
6141
                wc.lpszClassName = "MainWindow";
6142
                wc.lpszMenuName = NULL;
6143
                bool success = RegisterClassA(&wc) != 0;
6144
                DBG_ASSERTE(success);
6145
 
6146
                wc.style = 0;
6147
                wc.cbClsExtra = 0;
6148
                wc.cbWndExtra = 0;
6149
                wc.hbrBackground = NULL;
6150
                wc.hCursor = NULL;
6151
                wc.hIcon = NULL;
6152
                wc.hInstance = gHInstance;
6153
                wc.lpfnWndProc = WindowProc;
6154
                wc.lpszClassName = "InvisWindow";
6155
                wc.lpszMenuName = NULL;
6156
                success = RegisterClassA(&wc) != 0;
6157
                DBG_ASSERTE(success);
6158
 
6159
                mInvisHWnd = CreateWindowExA(
6160
                                0,
6161
                                "InvisWindow",
6162
                                SexyStringToStringFast(mTitle).c_str(),
6163
                                0,
6164
                                0,
6165
                                0,
6166
                                0,
6167
                                0,
6168
                                NULL,
6169
                                NULL,
6170
                                gHInstance,
6171
                                0);    
6172
                SetWindowLong(mInvisHWnd, GWL_USERDATA, (LONG) this);
6173
        }
6174
        else
6175
        {
6176
                mIsWideWindow = sizeof(SexyChar) == sizeof(wchar_t);
6177
 
6178
                WNDCLASS wc;
6179
                wc.style = CS_DBLCLKS;
6180
                wc.cbClsExtra = 0;
6181
                wc.cbWndExtra = 0;
6182
                wc.hbrBackground = NULL;
6183
                wc.hCursor = NULL;
6184
                wc.hIcon = ::LoadIconA(gHInstance, "IDI_MAIN_ICON");
6185
                wc.hInstance = gHInstance;
6186
                wc.lpfnWndProc = WindowProc;
6187
                wc.lpszClassName = _S("MainWindow");
6188
                wc.lpszMenuName = NULL;
6189
                bool success = RegisterClass(&wc) != 0;
6190
                DBG_ASSERTE(success);
6191
 
6192
                wc.style = 0;
6193
                wc.cbClsExtra = 0;
6194
                wc.cbWndExtra = 0;
6195
                wc.hbrBackground = NULL;
6196
                wc.hCursor = NULL;
6197
                wc.hIcon = NULL;
6198
                wc.hInstance = gHInstance;
6199
                wc.lpfnWndProc = WindowProc;
6200
                wc.lpszClassName = _S("InvisWindow");
6201
                wc.lpszMenuName = NULL;
6202
                success = RegisterClass(&wc) != 0;
6203
                DBG_ASSERTE(success);
6204
 
6205
                mInvisHWnd = CreateWindowEx(
6206
                                0,
6207
                                _S("InvisWindow"),
6208
                                mTitle.c_str(),
6209
                                0,
6210
                                0,
6211
                                0,
6212
                                0,
6213
                                0,
6214
                                NULL,
6215
                                NULL,
6216
                                gHInstance,
6217
                                0);    
6218
                SetWindowLong(mInvisHWnd, GWL_USERDATA, (LONG) this);
6219
        }
6220
 
6221
        mHandCursor = CreateCursor(gHInstance, 11, 4, 32, 32, gFingerCursorData, gFingerCursorData+sizeof(gFingerCursorData)/2);
6222
        mDraggingCursor = CreateCursor(gHInstance, 15, 10, 32, 32, gDraggingCursorData, gDraggingCursorData+sizeof(gDraggingCursorData)/2);
6223
 
6224
        // Let app do something before showing window, or switching to fullscreen mode
6225
        // NOTE: Moved call to PreDisplayHook above mIsWindowed and GetSystemsMetrics
6226
        // checks because the checks below use values that could change in PreDisplayHook.
6227
        // PreDisplayHook must call mWidgetManager->Resize if it changes mWidth or mHeight.
6228
        PreDisplayHook();
6229
 
6230
        mWidgetManager->Resize(Rect(0, 0, mWidth, mHeight), Rect(0, 0, mWidth, mHeight));
6231
 
6232
        // Check to see if we CAN run windowed or not...
6233
        if (mIsWindowed && !mFullScreenWindow)
6234
        {
6235
                // How can we be windowed if our screen isn't even big enough?
6236
                if ((mWidth >= GetSystemMetrics(SM_CXFULLSCREEN)) ||
6237
                        (mHeight >= GetSystemMetrics(SM_CYFULLSCREEN)))
6238
                {
6239
                        mIsWindowed = false;
6240
                        mForceFullscreen = true;
6241
                }
6242
        }
6243
 
6244
        if (mFullScreenWindow) // change resoultion using ChangeDisplaySettings
6245
        {
6246
                EnumWindows(ChangeDisplayWindowEnumProc,0); // record window pos
6247
                DEVMODE dm;
6248
                EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm );
6249
 
6250
                // Switch resolutions
6251
                if (dm.dmPelsWidth!=mWidth || dm.dmPelsHeight!=mHeight || (dm.dmBitsPerPel!=16 && dm.dmBitsPerPel!=32))
6252
                {
6253
                        dm.dmPelsWidth = mWidth;
6254
                        dm.dmPelsHeight = mHeight;
6255
                        dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
6256
 
6257
                        if (dm.dmBitsPerPel!=16 && dm.dmBitsPerPel!=32) // handle 24-bit/256 color case
6258
                        {
6259
                                dm.dmBitsPerPel = 16;
6260
                                dm.dmFields |= DM_BITSPERPEL;
6261
                        }
6262
 
6263
                        if (ChangeDisplaySettings(&dm,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
6264
                        {
6265
                                mFullScreenWindow = false;
6266
                                mIsWindowed = false;
6267
                        }
6268
                }
6269
        }
6270
 
6271
        MakeWindow();
6272
 
6273
        if (mPlayingDemoBuffer)
6274
        {
6275
                // Get video data
6276
 
6277
                PrepareDemoCommand(true);
6278
                mDemoNeedsCommand = true;
6279
 
6280
                DBG_ASSERTE(!mDemoIsShortCmd);
6281
                DBG_ASSERTE(mDemoCmdNum == DEMO_VIDEO_DATA);
6282
 
6283
                mIsWindowed = mDemoBuffer.ReadBoolean();
6284
                mSyncRefreshRate = mDemoBuffer.ReadByte();
6285
        }
6286
 
6287
        if (mSoundManager == NULL)             
6288
                mSoundManager = new DSoundManager(mNoSoundNeeded?NULL:mHWnd, mWantFMod);
6289
 
6290
        SetSfxVolume(mSfxVolume);
6291
 
6292
        mMusicInterface = CreateMusicInterface(mInvisHWnd);    
6293
 
6294
        SetMusicVolume(mMusicVolume);  
6295
 
6296
        if (IsScreenSaver())
6297
        {
6298
                SetCursor(CURSOR_NONE);
6299
        }
6300
 
6301
        InitHook();
6302
 
6303
        mInitialized = true;
6304
}
6305
 
6306
void SexyAppBase::HandleGameAlreadyRunning()
6307
{
6308
        if(mOnlyAllowOneCopyToRun)
6309
        {
6310
                // Notify the other window and then shut ourselves down
6311
                if (mNotifyGameMessage != 0)
6312
                        PostMessage(HWND_BROADCAST, mNotifyGameMessage, 0, 0);
6313
 
6314
                DoExit(0);
6315
        }
6316
}
6317
 
6318
void SexyAppBase::CopyToClipboard(const std::string& theString)
6319
{
6320
        if (mPlayingDemoBuffer)
6321
                return;
6322
 
6323
        HGLOBAL                         aGlobalHandle;
6324
        char*                           theData;       
6325
        WCHAR*                          theWData;
6326
 
6327
        if (OpenClipboard(mHWnd))
6328
        {
6329
                EmptyClipboard();
6330
 
6331
                aGlobalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, theString.length()+1);
6332
                theData = (char*) GlobalLock(aGlobalHandle);
6333
                strcpy(theData, theString.c_str());
6334
                GlobalUnlock(aGlobalHandle);
6335
                SetClipboardData(CF_TEXT, aGlobalHandle);
6336
                SetClipboardData(CF_OEMTEXT, aGlobalHandle);           
6337
                SetClipboardData(CF_LOCALE, aGlobalHandle);
6338
 
6339
                int aSize = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, theString.c_str(), theString.length(), NULL, 0);
6340
                aGlobalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (aSize + 1) * sizeof(WCHAR));
6341
                theWData = (WCHAR*) GlobalLock(aGlobalHandle);
6342
                MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, theString.c_str(), theString.length(), theWData, aSize);
6343
                theWData[aSize] = '\0';
6344
                GlobalUnlock(aGlobalHandle);
6345
                SetClipboardData(CF_UNICODETEXT, aGlobalHandle);
6346
 
6347
                CloseClipboard();
6348
        }
6349
}
6350
 
6351
std::string     SexyAppBase::GetClipboard()
6352
{
6353
        HGLOBAL                         aGlobalHandle; 
6354
        std::string                     aString;
6355
 
6356
        if (!mPlayingDemoBuffer)
6357
        {
6358
                if (OpenClipboard(mHWnd))
6359
                {
6360
                        aGlobalHandle = GetClipboardData(CF_TEXT);     
6361
                        if (aGlobalHandle != NULL)
6362
                        {
6363
                                char* theData = (char*) GlobalLock(aGlobalHandle);
6364
                                if (theData != NULL)
6365
                                {
6366
                                        aString = theData;             
6367
                                        GlobalUnlock(aGlobalHandle);
6368
                                }
6369
                        }
6370
 
6371
                        CloseClipboard();
6372
                }
6373
        }
6374
 
6375
        DemoSyncString(&aString);
6376
 
6377
        return aString;
6378
}
6379
 
6380
void SexyAppBase::SetCursor(int theCursorNum)
6381
{
6382
        mCursorNum = theCursorNum;
6383
        EnforceCursor();
6384
}
6385
 
6386
int SexyAppBase::GetCursor()
6387
{
6388
        return mCursorNum;
6389
}
6390
 
6391
void SexyAppBase::EnableCustomCursors(bool enabled)
6392
{
6393
        mCustomCursorsEnabled = enabled;
6394
        EnforceCursor();
6395
}
6396
 
6397
Sexy::DDImage* SexyAppBase::GetImage(const std::string& theFileName, bool commitBits)
6398
{      
6399
        ImageLib::Image* aLoadedImage = ImageLib::GetImage(theFileName, true);
6400
 
6401
        if (aLoadedImage == NULL)
6402
                return NULL;   
6403
 
6404
        DDImage* anImage = new DDImage(mDDInterface);
6405
        anImage->mFilePath = theFileName;
6406
        anImage->SetBits(aLoadedImage->GetBits(), aLoadedImage->GetWidth(), aLoadedImage->GetHeight(), commitBits);    
6407
        anImage->mFilePath = theFileName;
6408
        delete aLoadedImage;
6409
 
6410
        return anImage;
6411
}
6412
 
6413
Sexy::DDImage* SexyAppBase::CreateCrossfadeImage(Sexy::Image* theImage1, const Rect& theRect1, Sexy::Image* theImage2, const Rect& theRect2, double theFadeFactor)
6414
{
6415
        MemoryImage* aMemoryImage1 = dynamic_cast<MemoryImage*>(theImage1);
6416
        MemoryImage* aMemoryImage2 = dynamic_cast<MemoryImage*>(theImage2);
6417
 
6418
        if ((aMemoryImage1 == NULL) || (aMemoryImage2 == NULL))
6419
                return NULL;
6420
 
6421
        if ((theRect1.mX < 0) || (theRect1.mY < 0) ||
6422
                (theRect1.mX + theRect1.mWidth > theImage1->GetWidth()) ||
6423
                (theRect1.mY + theRect1.mHeight > theImage1->GetHeight()))
6424
        {
6425
                DBG_ASSERTE("Crossfade Rect1 out of bounds");
6426
                return NULL;
6427
        }
6428
 
6429
        if ((theRect2.mX < 0) || (theRect2.mY < 0) ||
6430
                (theRect2.mX + theRect2.mWidth > theImage2->GetWidth()) ||
6431
                (theRect2.mY + theRect2.mHeight > theImage2->GetHeight()))
6432
        {
6433
                DBG_ASSERTE("Crossfade Rect2 out of bounds");
6434
                return NULL;
6435
        }
6436
 
6437
        int aWidth = theRect1.mWidth;
6438
        int aHeight = theRect1.mHeight;
6439
 
6440
        DDImage* anImage = new DDImage(mDDInterface);
6441
        anImage->Create(aWidth, aHeight);
6442
 
6443
        ulong* aDestBits = anImage->GetBits();
6444
        ulong* aSrcBits1 = aMemoryImage1->GetBits();
6445
        ulong* aSrcBits2 = aMemoryImage2->GetBits();
6446
 
6447
        int aSrc1Width = aMemoryImage1->GetWidth();
6448
        int aSrc2Width = aMemoryImage2->GetWidth();
6449
        ulong aMult = (int) (theFadeFactor*256);
6450
        ulong aOMM = (256 - aMult);
6451
 
6452
        for (int y = 0; y < aHeight; y++)
6453
        {
6454
                ulong* s1 = &aSrcBits1[(y+theRect1.mY)*aSrc1Width+theRect1.mX];
6455
                ulong* s2 = &aSrcBits2[(y+theRect2.mY)*aSrc2Width+theRect2.mX];
6456
                ulong* d = &aDestBits[y*aWidth];
6457
 
6458
                for (int x = 0; x < aWidth; x++)
6459
                {
6460
                        ulong p1 = *s1++;
6461
                        ulong p2 = *s2++;
6462
 
6463
                        //p1 = 0;
6464
                        //p2 = 0xFFFFFFFF;
6465
 
6466
                        *d++ =
6467
                                ((((p1 & 0x000000FF)*aOMM + (p2 & 0x000000FF)*aMult)>>8) & 0x000000FF) |
6468
                                ((((p1 & 0x0000FF00)*aOMM + (p2 & 0x0000FF00)*aMult)>>8) & 0x0000FF00) |
6469
                                ((((p1 & 0x00FF0000)*aOMM + (p2 & 0x00FF0000)*aMult)>>8) & 0x00FF0000) |
6470
                                ((((p1 >> 24)*aOMM + (p2 >> 24)*aMult)<<16) & 0xFF000000);
6471
                }
6472
        }
6473
 
6474
        anImage->BitsChanged();
6475
 
6476
        return anImage;
6477
}
6478
 
6479
void SexyAppBase::ColorizeImage(Image* theImage, const Color& theColor)
6480
{
6481
        MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
6482
 
6483
        if (aSrcMemoryImage == NULL)
6484
                return;
6485
 
6486
        ulong* aBits;  
6487
        int aNumColors;
6488
 
6489
        if (aSrcMemoryImage->mColorTable == NULL)
6490
        {
6491
                aBits = aSrcMemoryImage->GetBits();            
6492
                aNumColors = theImage->GetWidth()*theImage->GetHeight();                               
6493
        }
6494
        else
6495
        {
6496
                aBits = aSrcMemoryImage->mColorTable;          
6497
                aNumColors = 256;                              
6498
        }
6499
 
6500
        if ((theColor.mAlpha <= 255) && (theColor.mRed <= 255) &&
6501
                (theColor.mGreen <= 255) && (theColor.mBlue <= 255))
6502
        {
6503
                for (int i = 0; i < aNumColors; i++)
6504
                {
6505
                        ulong aColor = aBits[i];
6506
 
6507
                        aBits[i] =
6508
                                ((((aColor & 0xFF000000) >> 8) * theColor.mAlpha) & 0xFF000000) |
6509
                                ((((aColor & 0x00FF0000) * theColor.mRed) >> 8) & 0x00FF0000) |
6510
                                ((((aColor & 0x0000FF00) * theColor.mGreen) >> 8) & 0x0000FF00)|
6511
                                ((((aColor & 0x000000FF) * theColor.mBlue) >> 8) & 0x000000FF);
6512
                }
6513
        }
6514
        else
6515
        {
6516
                for (int i = 0; i < aNumColors; i++)
6517
                {
6518
                        ulong aColor = aBits[i];
6519
 
6520
                        int aAlpha = ((aColor >> 24) * theColor.mAlpha) / 255;
6521
                        int aRed = (((aColor >> 16) & 0xFF) * theColor.mRed) / 255;
6522
                        int aGreen = (((aColor >> 8) & 0xFF) * theColor.mGreen) / 255;
6523
                        int aBlue = ((aColor & 0xFF) * theColor.mBlue) / 255;
6524
 
6525
                        if (aAlpha > 255)
6526
                                aAlpha = 255;
6527
                        if (aRed > 255)
6528
                                aRed = 255;
6529
                        if (aGreen > 255)
6530
                                aGreen = 255;
6531
                        if (aBlue > 255)
6532
                                aBlue = 255;
6533
 
6534
                        aBits[i] = (aAlpha << 24) | (aRed << 16) | (aGreen << 8) | (aBlue);
6535
                }
6536
        }      
6537
 
6538
        aSrcMemoryImage->BitsChanged();
6539
}
6540
 
6541
DDImage* SexyAppBase::CreateColorizedImage(Image* theImage, const Color& theColor)
6542
{
6543
        MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
6544
 
6545
        if (aSrcMemoryImage == NULL)
6546
                return NULL;
6547
 
6548
        DDImage* anImage = new DDImage(mDDInterface);
6549
 
6550
        anImage->Create(theImage->GetWidth(), theImage->GetHeight());
6551
 
6552
        ulong* aSrcBits;
6553
        ulong* aDestBits;
6554
        int aNumColors;
6555
 
6556
        if (aSrcMemoryImage->mColorTable == NULL)
6557
        {
6558
                aSrcBits = aSrcMemoryImage->GetBits();
6559
                aDestBits = anImage->GetBits();
6560
                aNumColors = theImage->GetWidth()*theImage->GetHeight();                               
6561
        }
6562
        else
6563
        {
6564
                aSrcBits = aSrcMemoryImage->mColorTable;
6565
                aDestBits = anImage->mColorTable = new ulong[256];
6566
                aNumColors = 256;
6567
 
6568
                anImage->mColorIndices = new uchar[anImage->mWidth*theImage->mHeight];
6569
                memcpy(anImage->mColorIndices, aSrcMemoryImage->mColorIndices, anImage->mWidth*theImage->mHeight);
6570
        }
6571
 
6572
        if ((theColor.mAlpha <= 255) && (theColor.mRed <= 255) &&
6573
                (theColor.mGreen <= 255) && (theColor.mBlue <= 255))
6574
        {
6575
                for (int i = 0; i < aNumColors; i++)
6576
                {
6577
                        ulong aColor = aSrcBits[i];
6578
 
6579
                        aDestBits[i] =
6580
                                ((((aColor & 0xFF000000) >> 8) * theColor.mAlpha) & 0xFF000000) |
6581
                                ((((aColor & 0x00FF0000) * theColor.mRed) >> 8) & 0x00FF0000) |
6582
                                ((((aColor & 0x0000FF00) * theColor.mGreen) >> 8) & 0x0000FF00)|
6583
                                ((((aColor & 0x000000FF) * theColor.mBlue) >> 8) & 0x000000FF);
6584
                }
6585
        }
6586
        else
6587
        {
6588
                for (int i = 0; i < aNumColors; i++)
6589
                {
6590
                        ulong aColor = aSrcBits[i];
6591
 
6592
                        int aAlpha = ((aColor >> 24) * theColor.mAlpha) / 255;
6593
                        int aRed = (((aColor >> 16) & 0xFF) * theColor.mRed) / 255;
6594
                        int aGreen = (((aColor >> 8) & 0xFF) * theColor.mGreen) / 255;
6595
                        int aBlue = ((aColor & 0xFF) * theColor.mBlue) / 255;
6596
 
6597
                        if (aAlpha > 255)
6598
                                aAlpha = 255;
6599
                        if (aRed > 255)
6600
                                aRed = 255;
6601
                        if (aGreen > 255)
6602
                                aGreen = 255;
6603
                        if (aBlue > 255)
6604
                                aBlue = 255;
6605
 
6606
                        aDestBits[i] = (aAlpha << 24) | (aRed << 16) | (aGreen << 8) | (aBlue);
6607
                }
6608
        }      
6609
 
6610
        anImage->BitsChanged();
6611
 
6612
        return anImage;
6613
}
6614
 
6615
DDImage* SexyAppBase::CopyImage(Image* theImage, const Rect& theRect)
6616
{
6617
        DDImage* anImage = new DDImage(mDDInterface);
6618
 
6619
        anImage->Create(theRect.mWidth, theRect.mHeight);
6620
 
6621
        Graphics g(anImage);
6622
        g.DrawImage(theImage, -theRect.mX, -theRect.mY);
6623
 
6624
        anImage->CopyAttributes(theImage);
6625
 
6626
        return anImage;
6627
}
6628
 
6629
DDImage* SexyAppBase::CopyImage(Image* theImage)
6630
{
6631
        return CopyImage(theImage, Rect(0, 0, theImage->GetWidth(), theImage->GetHeight()));
6632
}
6633
 
6634
void SexyAppBase::MirrorImage(Image* theImage)
6635
{
6636
        MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);   
6637
 
6638
        ulong* aSrcBits = aSrcMemoryImage->GetBits();
6639
 
6640
        int aPhysSrcWidth = aSrcMemoryImage->mWidth;
6641
        for (int y = 0; y < aSrcMemoryImage->mHeight; y++)
6642
        {
6643
                ulong* aLeftBits = aSrcBits + (y * aPhysSrcWidth);             
6644
                ulong* aRightBits = aLeftBits + (aPhysSrcWidth - 1);
6645
 
6646
                for (int x = 0; x < (aPhysSrcWidth >> 1); x++)
6647
                {
6648
                        ulong aSwap = *aLeftBits;
6649
 
6650
                        *(aLeftBits++) = *aRightBits;
6651
                        *(aRightBits--) = aSwap;
6652
                }
6653
        }
6654
 
6655
        aSrcMemoryImage->BitsChanged();
6656
}
6657
 
6658
void SexyAppBase::FlipImage(Image* theImage)
6659
{
6660
        MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
6661
 
6662
        ulong* aSrcBits = aSrcMemoryImage->GetBits();
6663
 
6664
        int aPhysSrcHeight = aSrcMemoryImage->mHeight;
6665
        int aPhysSrcWidth = aSrcMemoryImage->mWidth;
6666
        for (int x = 0; x < aPhysSrcWidth; x++)
6667
        {
6668
                ulong* aTopBits    = aSrcBits + x;
6669
                ulong* aBottomBits = aTopBits + (aPhysSrcWidth * (aPhysSrcHeight - 1));
6670
 
6671
                for (int y = 0; y < (aPhysSrcHeight >> 1); y++)
6672
                {
6673
                        ulong aSwap = *aTopBits;
6674
 
6675
                        *aTopBits = *aBottomBits;
6676
                        aTopBits += aPhysSrcWidth;
6677
                        *aBottomBits = aSwap;
6678
                        aBottomBits -= aPhysSrcWidth;
6679
                }
6680
        }
6681
 
6682
        aSrcMemoryImage->BitsChanged();
6683
}
6684
 
6685
void SexyAppBase::RotateImageHue(Sexy::MemoryImage *theImage, int theDelta)
6686
{
6687
        while (theDelta < 0)
6688
                theDelta += 256;
6689
 
6690
        int aSize = theImage->mWidth * theImage->mHeight;
6691
        DWORD *aPtr = theImage->GetBits();
6692
        for (int i=0; i<aSize; i++)
6693
        {
6694
                DWORD aPixel = *aPtr;
6695
                int alpha = aPixel&0xff000000;
6696
                int r = (aPixel>>16)&0xff;
6697
                int g = (aPixel>>8) &0xff;
6698
                int b = aPixel&0xff;
6699
 
6700
                int maxval = max(r, max(g, b));
6701
                int minval = min(r, min(g, b));
6702
                int h = 0;
6703
                int s = 0;
6704
                int l = (minval+maxval)/2;
6705
                int delta = maxval - minval;
6706
 
6707
                if (delta != 0)
6708
                {                      
6709
                        s = (delta * 256) / ((l <= 128) ? (minval + maxval) : (512 - maxval - minval));
6710
 
6711
                        if (r == maxval)
6712
                                h = (g == minval ? 1280 + (((maxval-b) * 256) / delta) :  256 - (((maxval - g) * 256) / delta));
6713
                        else if (g == maxval)
6714
                                h = (b == minval ?  256 + (((maxval-r) * 256) / delta) :  768 - (((maxval - b) * 256) / delta));
6715
                        else
6716
                                h = (r == minval ?  768 + (((maxval-g) * 256) / delta) : 1280 - (((maxval - r) * 256) / delta));
6717
 
6718
                        h /= 6;
6719
                }
6720
 
6721
                h += theDelta;
6722
                if (h >= 256)
6723
                        h -= 256;
6724
 
6725
                double v= (l < 128) ? (l * (255+s))/255 :
6726
                                (l+s-l*s/255);
6727
 
6728
                int y = (int) (2*l-v);
6729
 
6730
                int aColorDiv = (6 * h) / 256;
6731
                int x = (int)(y+(v-y)*((h - (aColorDiv * 256 / 6)) * 6)/255);
6732
                if (x > 255)
6733
                        x = 255;
6734
 
6735
                int z = (int) (v-(v-y)*((h - (aColorDiv * 256 / 6)) * 6)/255);
6736
                if (z < 0)
6737
                        z = 0;
6738
 
6739
                switch (aColorDiv)
6740
                {
6741
                        case 0: r = (int) v; g = x; b = y; break;
6742
                        case 1: r = z; g= (int) v; b = y; break;
6743
                        case 2: r = y; g= (int) v; b = x; break;
6744
                        case 3: r = y; g = z; b = (int) v; break;
6745
                        case 4: r = x; g = y; b = (int) v; break;
6746
                        case 5: r = (int) v; g = y; b = z; break;
6747
                        default: r = (int) v; g = x; b = y; break;
6748
                }
6749
 
6750
                *aPtr++ = alpha | (r<<16) | (g << 8) | (b);      
6751
 
6752
        }
6753
 
6754
        theImage->BitsChanged();
6755
}
6756
 
6757
ulong SexyAppBase::HSLToRGB(int h, int s, int l)
6758
{
6759
        int r;
6760
        int g;
6761
        int b;
6762
 
6763
        double v= (l < 128) ? (l * (255+s))/255 :
6764
                        (l+s-l*s/255);
6765
 
6766
        int y = (int) (2*l-v);
6767
 
6768
        int aColorDiv = (6 * h) / 256;
6769
        int x = (int)(y+(v-y)*((h - (aColorDiv * 256 / 6)) * 6)/255);
6770
        if (x > 255)
6771
                x = 255;
6772
 
6773
        int z = (int) (v-(v-y)*((h - (aColorDiv * 256 / 6)) * 6)/255);
6774
        if (z < 0)
6775
                z = 0;
6776
 
6777
        switch (aColorDiv)
6778
        {
6779
                case 0: r = (int) v; g = x; b = y; break;
6780
                case 1: r = z; g= (int) v; b = y; break;
6781
                case 2: r = y; g= (int) v; b = x; break;
6782
                case 3: r = y; g = z; b = (int) v; break;
6783
                case 4: r = x; g = y; b = (int) v; break;
6784
                case 5: r = (int) v; g = y; b = z; break;
6785
                default: r = (int) v; g = x; b = y; break;
6786
        }
6787
 
6788
        return 0xFF000000 | (r << 16) | (g << 8) | (b);
6789
}
6790
 
6791
ulong SexyAppBase::RGBToHSL(int r, int g, int b)
6792
{                                      
6793
        int maxval = max(r, max(g, b));
6794
        int minval = min(r, min(g, b));
6795
        int hue = 0;
6796
        int saturation = 0;
6797
        int luminosity = (minval+maxval)/2;
6798
        int delta = maxval - minval;
6799
 
6800
        if (delta != 0)
6801
        {                      
6802
                saturation = (delta * 256) / ((luminosity <= 128) ? (minval + maxval) : (512 - maxval - minval));
6803
 
6804
                if (r == maxval)
6805
                        hue = (g == minval ? 1280 + (((maxval-b) * 256) / delta) :  256 - (((maxval - g) * 256) / delta));
6806
                else if (g == maxval)
6807
                        hue = (b == minval ?  256 + (((maxval-r) * 256) / delta) :  768 - (((maxval - b) * 256) / delta));
6808
                else
6809
                        hue = (r == minval ?  768 + (((maxval-g) * 256) / delta) : 1280 - (((maxval - r) * 256) / delta));
6810
 
6811
                hue /= 6;
6812
        }
6813
 
6814
        return 0xFF000000 | (hue) | (saturation << 8) | (luminosity << 16);      
6815
}
6816
 
6817
void SexyAppBase::HSLToRGB(const ulong* theSource, ulong* theDest, int theSize)
6818
{
6819
        for (int i = 0; i < theSize; i++)
6820
        {
6821
                ulong src = theSource[i];
6822
                theDest[i] = (src & 0xFF000000) | (HSLToRGB((src & 0xFF), (src >> 8) & 0xFF, (src >> 16) & 0xFF) & 0x00FFFFFF);
6823
        }
6824
}
6825
 
6826
void SexyAppBase::RGBToHSL(const ulong* theSource, ulong* theDest, int theSize)
6827
{
6828
        for (int i = 0; i < theSize; i++)
6829
        {
6830
                ulong src = theSource[i];
6831
                theDest[i] = (src & 0xFF000000) | (RGBToHSL(((src >> 16) & 0xFF), (src >> 8) & 0xFF, (src & 0xFF)) & 0x00FFFFFF);
6832
        }
6833
}
6834
 
6835
void SexyAppBase::PrecacheAdditive(MemoryImage* theImage)
6836
{
6837
        theImage->GetRLAdditiveData(mDDInterface);
6838
}
6839
 
6840
void SexyAppBase::PrecacheAlpha(MemoryImage* theImage)
6841
{
6842
        theImage->GetRLAlphaData();
6843
}
6844
 
6845
void SexyAppBase::PrecacheNative(MemoryImage* theImage)
6846
{
6847
        theImage->GetNativeAlphaData(mDDInterface);
6848
}
6849
 
6850
 
6851
void SexyAppBase::PlaySample(int theSoundNum)
6852
{
6853
        if (!mSoundManager)
6854
                return;
6855
 
6856
        SoundInstance* aSoundInstance = mSoundManager->GetSoundInstance(theSoundNum);
6857
        if (aSoundInstance != NULL)
6858
        {
6859
                aSoundInstance->Play(false, true);
6860
        }
6861
}
6862
 
6863
 
6864
void SexyAppBase::PlaySample(int theSoundNum, int thePan)
6865
{
6866
        if (!mSoundManager)
6867
                return;
6868
 
6869
        SoundInstance* aSoundInstance = mSoundManager->GetSoundInstance(theSoundNum);
6870
        if (aSoundInstance != NULL)
6871
        {
6872
                aSoundInstance->SetPan(thePan);
6873
                aSoundInstance->Play(false, true);
6874
        }
6875
}
6876
 
6877
bool SexyAppBase::IsMuted()
6878
{
6879
        return mMuteCount > 0;
6880
}
6881
 
6882
void SexyAppBase::Mute(bool autoMute)
6883
{      
6884
        mMuteCount++;
6885
        if (autoMute)
6886
                mAutoMuteCount++;
6887
 
6888
        SetMusicVolume(mMusicVolume);
6889
        SetSfxVolume(mSfxVolume);
6890
}
6891
 
6892
void SexyAppBase::Unmute(bool autoMute)
6893
{      
6894
        if (mMuteCount > 0)
6895
        {
6896
                mMuteCount--;
6897
                if (autoMute)
6898
                        mAutoMuteCount--;
6899
        }
6900
 
6901
        SetMusicVolume(mMusicVolume);
6902
        SetSfxVolume(mSfxVolume);
6903
}
6904
 
6905
 
6906
double SexyAppBase::GetMusicVolume()
6907
{
6908
        return mMusicVolume;
6909
}
6910
 
6911
void SexyAppBase::SetMusicVolume(double theVolume)
6912
{
6913
        mMusicVolume = theVolume;
6914
 
6915
        if (mMusicInterface != NULL)
6916
                mMusicInterface->SetVolume((mMuteCount > 0) ? 0.0 : mMusicVolume);
6917
}
6918
 
6919
double SexyAppBase::GetSfxVolume()
6920
{
6921
        return mSfxVolume;
6922
}
6923
 
6924
void SexyAppBase::SetSfxVolume(double theVolume)
6925
{
6926
        mSfxVolume = theVolume;
6927
 
6928
        if (mSoundManager != NULL)
6929
                mSoundManager->SetVolume((mMuteCount > 0) ? 0.0 : mSfxVolume);
6930
}
6931
 
6932
double SexyAppBase::GetMasterVolume()
6933
{
6934
        return mSoundManager->GetMasterVolume();
6935
}
6936
 
6937
void SexyAppBase::SetMasterVolume(double theMasterVolume)
6938
{
6939
        mSfxVolume = theMasterVolume;
6940
        mSoundManager->SetMasterVolume(mSfxVolume);
6941
}
6942
 
6943
void SexyAppBase::AddMemoryImage(MemoryImage* theMemoryImage)
6944
{
6945
        AutoCrit anAutoCrit(mDDInterface->mCritSect);
6946
        mMemoryImageSet.insert(theMemoryImage);
6947
}
6948
 
6949
void SexyAppBase::RemoveMemoryImage(MemoryImage* theMemoryImage)
6950
{
6951
        AutoCrit anAutoCrit(mDDInterface->mCritSect);
6952
        MemoryImageSet::iterator anItr = mMemoryImageSet.find(theMemoryImage);
6953
        if (anItr != mMemoryImageSet.end())
6954
                mMemoryImageSet.erase(anItr);
6955
 
6956
        Remove3DData(theMemoryImage);
6957
}
6958
 
6959
void SexyAppBase::Remove3DData(MemoryImage* theMemoryImage)
6960
{
6961
        if (mDDInterface)
6962
                mDDInterface->Remove3DData(theMemoryImage);
6963
}
6964
 
6965
 
6966
bool SexyAppBase::Is3DAccelerated()
6967
{
6968
        return mDDInterface->mIs3D;
6969
}
6970
 
6971
bool SexyAppBase::Is3DAccelerationSupported()
6972
{
6973
        if (mDDInterface->mD3DTester)
6974
                return mDDInterface->mD3DTester->Is3DSupported();
6975
        else
6976
                return false;
6977
}
6978
 
6979
bool SexyAppBase::Is3DAccelerationRecommended()
6980
{
6981
        if (mDDInterface->mD3DTester)
6982
                return mDDInterface->mD3DTester->Is3DRecommended();
6983
        else
6984
                return false;
6985
}
6986
 
6987
void SexyAppBase::DemoSyncRefreshRate()
6988
{
6989
        mSyncRefreshRate = mDDInterface->mRefreshRate;
6990
 
6991
        if (mRecordingDemoBuffer)
6992
        {
6993
                WriteDemoTimingBlock();
6994
                mDemoBuffer.WriteNumBits(0, 1);
6995
                mDemoBuffer.WriteNumBits(DEMO_VIDEO_DATA, 5);
6996
                mDemoBuffer.WriteBoolean(mIsWindowed);
6997
                uchar aByte = (uchar) mSyncRefreshRate;
6998
                mDemoBuffer.WriteByte(aByte);          
6999
        }
7000
}
7001
 
7002
void SexyAppBase::Set3DAcclerated(bool is3D, bool reinit)
7003
{
7004
        if (mDDInterface->mIs3D == is3D)
7005
                return;
7006
 
7007
        mUserChanged3DSetting = true;
7008
        mDDInterface->mIs3D = is3D;
7009
 
7010
        if (reinit)
7011
        {
7012
                int aResult = InitDDInterface();
7013
 
7014
                if (is3D && aResult != DDInterface::RESULT_OK)
7015
                {
7016
                        Set3DAcclerated(false, reinit);
7017
                        return;
7018
                }
7019
                else if (aResult != DDInterface::RESULT_OK)
7020
                {
7021
                        Popup(GetString("FAILED_INIT_DIRECTDRAW", _S("Failed to initialize DirectDraw: ")) + StringToSexyString(DDInterface::ResultToString(aResult) + " " + mDDInterface->mErrorString));
7022
                        DoExit(1);
7023
                }
7024
 
7025
                ReInitImages();
7026
 
7027
                mWidgetManager->mImage = mDDInterface->GetScreenImage();
7028
                mWidgetManager->MarkAllDirty();
7029
        }
7030
}
7031
 
7032
SharedImageRef SexyAppBase::GetSharedImage(const std::string& theFileName, const std::string& theVariant, bool* isNew)
7033
{      
7034
        std::string anUpperFileName = StringToUpper(theFileName);
7035
        std::string anUpperVariant = StringToUpper(theVariant);
7036
 
7037
        std::pair<SharedImageMap::iterator, bool> aResultPair;
7038
        SharedImageRef aSharedImageRef;
7039
 
7040
        {
7041
                AutoCrit anAutoCrit(mDDInterface->mCritSect);  
7042
                aResultPair = mSharedImageMap.insert(SharedImageMap::value_type(SharedImageMap::key_type(anUpperFileName, anUpperVariant), SharedImage()));
7043
                aSharedImageRef = &aResultPair.first->second;
7044
        }
7045
 
7046
        if (isNew != NULL)
7047
                *isNew = aResultPair.second;
7048
 
7049
        if (aResultPair.second)
7050
        {
7051
                // Pass in a '!' as the first char of the file name to create a new image
7052
                if ((theFileName.length() > 0) && (theFileName[0] == '!'))
7053
                        aSharedImageRef.mSharedImage->mImage = new DDImage(mDDInterface);
7054
                else
7055
                        aSharedImageRef.mSharedImage->mImage = GetImage(theFileName,false);
7056
        }
7057
 
7058
        return aSharedImageRef;
7059
}
7060
 
7061
void SexyAppBase::CleanSharedImages()
7062
{
7063
        AutoCrit anAutoCrit(mDDInterface->mCritSect);  
7064
 
7065
        if (mCleanupSharedImages)
7066
        {
7067
                // Delete shared images with reference counts of 0
7068
                // This doesn't occur in ~SharedImageRef because sometimes we can not only access the image
7069
                //  through the SharedImageRef returned by GetSharedImage, but also by calling GetSharedImage
7070
                //  again with the same params -- so we can have instances where we do the 'final' deref on
7071
                //  an image but immediately re-request it via GetSharedImage
7072
                SharedImageMap::iterator aSharedImageItr = mSharedImageMap.begin();
7073
                while (aSharedImageItr != mSharedImageMap.end())
7074
                {
7075
                        SharedImage* aSharedImage = &aSharedImageItr->second;
7076
                        if (aSharedImage->mRefCount == 0)
7077
                        {
7078
                                delete aSharedImage->mImage;
7079
                                mSharedImageMap.erase(aSharedImageItr++);
7080
                        }
7081
                        else
7082
                                ++aSharedImageItr;
7083
                }
7084
 
7085
                mCleanupSharedImages = false;
7086
        }
7087
}