Assembla home | Assembla project page
 

root/week1oplossing/GameEngine.cpp

Revision 1, 81.1 kB (checked in by machiel.sleeuwaert, 1 year ago)

--

Line 
1 //-----------------------------------------------------------------
2 // Game Engine Object
3 // C++ Source - GameEngine.cpp - version 2008 v3_02
4 // Copyright Kevin Hoefman - kevin.hoefman@howest.be
5 // http://www.digitalartsandentertainment.be/
6 //-----------------------------------------------------------------
7
8 //-----------------------------------------------------------------
9 // Include Files
10 //-----------------------------------------------------------------
11 #include "GameEngine.h"
12
13 #define _USE_MATH_DEFINES       // necessary for including (among other values) PI  - see math.h
14 #include <math.h>                       // used in various draw methods
15 #include <stdio.h>
16 #include <tchar.h>                      // used for unicode strings
17
18 #include <memory.h>
19 #include <vector>                       // using std::vector for tab control logic
20
21 //-----------------------------------------------------------------
22 // Static Variable Initialization
23 //-----------------------------------------------------------------
24 GameEngine* GameEngine::m_GameEnginePtr = NULL;
25
26 //-----------------------------------------------------------------
27 // Windows Functions
28 //-----------------------------------------------------------------
29 LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
30 {
31         // Route all Windows messages to the game engine
32         return GameEngine::GetSingleton()->HandleEvent(hWindow, msg, wParam, lParam);
33 }
34
35 DWORD WINAPI KeybThreadProc(GameEngine* gamePtr)
36 {
37         return gamePtr->KeybThreadProc();
38 }
39
40 //-----------------------------------------------------------------
41 // GameEngine Constructor(s)/Destructor
42 //-----------------------------------------------------------------
43 GameEngine::GameEngine() :      m_hInstance(NULL),
44                                                         m_hWindow(NULL),
45                                                         m_TitlePtr(0),
46                                                         m_iFrameDelay(50),              // 20 FPS default
47                                                         m_bSleep(true),
48                                                         m_bRunGameLoop(false),
49                                                         m_bKeybRunning(true),   // create the keyboard monitoring thread
50                                                         m_KeyListPtr(NULL),
51                                                         m_KeybMonitor(0x0),             // binary ; 0 = key not pressed, 1 = key pressed
52                                                         m_isPainting(false),
53                                                         m_isDoublebuffering(false),
54                                                         m_colDraw(RGB(0,0,0)),
55                                                         m_FontDraw(0),
56                                                         m_GamePtr(0),
57                                                         m_PaintDoublebuffered(false),
58                                                         m_Fullscreen(false),
59                                                         m_WindowRegionPtr(0)
60 {
61         m_hKeybThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ::KeybThreadProc, this, NULL, &m_dKeybThreadID);
62 }
63
64 GameEngine::~GameEngine()
65 {
66         // Clean up the keyboard monitoring thread
67         m_bKeybRunning = false;
68         WaitForSingleObject( m_hKeybThread, INFINITE );
69         CloseHandle( m_hKeybThread );   
70        
71         // clean up keyboard monitor buffer after the thread that uses it is closed
72         if (m_KeyListPtr != 0)
73         {
74                 delete m_KeyListPtr;
75                 m_KeyListPtr = 0;
76         }
77
78         // clean up the font
79         if (m_FontDraw != 0)
80         {
81                 DeleteObject(m_FontDraw);
82                 m_FontDraw = 0;
83         }
84
85         // clean up the AbstractGame object
86         delete m_GamePtr;
87 }
88
89 //-----------------------------------------------------------------
90 // Game Engine Static Methods
91 //-----------------------------------------------------------------
92
93 GameEngine* GameEngine::GetSingleton()
94 {
95         if ( m_GameEnginePtr == NULL) m_GameEnginePtr = new GameEngine();
96         return m_GameEnginePtr;
97 }
98
99 void GameEngine::SetGame(AbstractGame* gamePtr)
100 {
101         m_GamePtr = gamePtr;
102 }
103
104 DWORD GameEngine::KeybThreadProc()
105 {
106         while (m_bKeybRunning)
107         {
108                 if (m_KeyListPtr != NULL)
109                 {
110                         int count = 0;
111                         int key = m_KeyListPtr[0];
112
113                         while (key != '\0' && count < (8 * sizeof(unsigned int)))
114                         {       
115                                 if ( !(GetAsyncKeyState(key)<0) ) // key is not pressed
116                                 {           
117                                         if (m_KeybMonitor & (0x1 << count)) {
118                                                 m_GamePtr->KeyPressed(key); // als de bit op 1 stond, dan firet dit een keypress
119                                         }
120                                         m_KeybMonitor &= ~(0x1 << count);   // de bit wordt op 0 gezet: key is not pressed
121                                 }
122                                 else m_KeybMonitor |= (0x1 << count);   // de bit wordt op 1 gezet: key is pressed
123
124                                 key = m_KeyListPtr[++count]; // increase count and get next key
125                         }
126                 }       
127
128                 Sleep(1000 / KEYBCHECKRATE);
129         }
130         return 0;
131 }
132
133 //-----------------------------------------------------------------
134 // Game Engine General Methods
135 //-----------------------------------------------------------------
136
137 void GameEngine::SetTitle(const tstring& titleRef)
138 {
139         delete m_TitlePtr; // delete the title string if it already exists
140         m_TitlePtr = new tstring(titleRef);
141 }
142
143 bool GameEngine::Run(HINSTANCE hInstance, int iCmdShow)
144 {
145         MSG msg;
146         int iTickTrigger = 0;
147         int iTickCount;
148
149         // create the game engine object, exit if failure
150         if (GameEngine::GetSingleton() == NULL) return false;
151
152         // set the instance member variable of the game engine
153         GameEngine::GetSingleton()->SetInstance(hInstance);
154
155         // Game Initialization
156         m_GamePtr->GameInitialize(hInstance);
157
158         // Initialize the game engine
159         if (!GameEngine::GetSingleton()->ClassRegister(iCmdShow)) return false;
160
161         // Attach the keyboard thread to the main thread. This gives the keyboard events access to the window state
162         // In plain English: this allows a KeyPressed() event to hide the cursor of the window.
163         AttachThreadInput(m_dKeybThreadID, GetCurrentThreadId(), true);
164
165         // Enter the main message loop
166         while (true)
167         {
168                 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
169                 {
170                         // Process the message
171                         if (msg.message == WM_QUIT) break;
172                         TranslateMessage(&msg);
173                         DispatchMessage(&msg);
174                 }
175                 else
176                 {
177                         // Make sure the game engine isn't sleeping
178                         if (!GameEngine::GetSingleton()->GetSleep() && m_bRunGameLoop)
179                         {
180                                 // Check the tick count to see if a game cycle has elapsed
181                                 iTickCount = GetTickCount();
182                                 if (iTickCount > iTickTrigger)
183                                 {
184                                         iTickTrigger = iTickCount + GameEngine::GetSingleton()->GetFrameDelay();
185
186                                         // Do user defined keyboard check
187                                         m_GamePtr->CheckKeyboard();
188
189                                         // Get window, rectangle and HDC
190                                         HWND hWindow = GetWindow();
191                                         RECT rect;
192                                         HDC hDC = GetDC(hWindow);
193                                         GetClientRect(hWindow, &rect);
194
195                                         // Double buffering code
196                                         HDC hBufferDC = CreateCompatibleDC(hDC);
197                                         int iWidth = GetWidth();
198                                         int iHeight = GetHeight();
199                                         // Create the buffer
200                                         HBITMAP hBufferBmp = CreateCompatibleBitmap(hDC, iWidth, iHeight);
201                                         HBITMAP hOldBmp = (HBITMAP) SelectObject(hBufferDC, hBufferBmp);
202
203                                         // Do user defined drawing functions on the buffer, parameters added
204                                         // for ease of drawing
205                                         m_HdcDraw = hBufferDC;
206                                         m_RectDraw = rect;
207                                         m_isDoublebuffering = true;
208                                         m_GamePtr->GameCycle(rect);
209                                         m_isDoublebuffering = false;
210
211                                         // As a last step copy the memdc to the hdc
212                                         BitBlt(hDC, 0, 0, iWidth, iHeight, hBufferDC, 0, 0, SRCCOPY);
213
214                                         // Reset the old bmp of the buffer, mainly for show since we kill it anyway
215                                         SelectObject(hBufferDC, hOldBmp);
216                                         // Kill the buffer
217                                         DeleteObject(hBufferBmp);
218                                         DeleteDC(hBufferDC);
219
220                                         // Release HDC
221                                         ReleaseDC(hWindow, hDC);
222                                 }                             
223                                 else Sleep(1);//Sleep for one ms te bring cpu load from 100% to 1%. if removed this loops like roadrunner
224                         }
225                         else WaitMessage(); // if the engine is sleeping or the game loop isn't supposed to run, wait for the next windows message.
226                 }
227         }
228         return msg.wParam?true:false;
229 }
230
231 bool GameEngine::SetGameValues(const tstring& titleRef, WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480)
232 {
233         SetTitle(titleRef);
234         SetIcon(wIcon);
235         SetSmallIcon(wSmallIcon);
236         SetWidth(iWidth);
237         SetHeight(iHeight);
238
239         return true;
240 }
241
242 void GameEngine::ShowMousePointer(bool value) const
243 {
244         // set the value
245         ShowCursor(value);     
246        
247         // redraw the screen
248         InvalidateRect(m_hWindow, 0, true);
249 }
250
251 bool GameEngine::SetWindowRegion(const HitRegion* regionPtr)
252 {
253         if (m_Fullscreen) return false;
254
255         if (regionPtr == 0)
256         {       
257                 // turn off window region
258                 SetWindowRgn(m_hWindow, 0, true);
259
260                 // delete the buffered window region (if it exists)
261                 delete m_WindowRegionPtr;
262                 m_WindowRegionPtr = 0;
263         }
264         else
265         {
266                 // if there is already a window region set, release the buffered region object
267                 if (m_WindowRegionPtr != 0)
268                 {
269                         // turn off window region for safety
270                         SetWindowRgn(m_hWindow, 0, true);
271                                
272                         // delete the buffered window region
273                         delete m_WindowRegionPtr;
274                         m_WindowRegionPtr = 0;
275                 }
276
277                 // create a copy of the submitted region (windows will lock the region handle that it receives)
278                 m_WindowRegionPtr = regionPtr->Clone();
279
280                 // translate region coordinates in the client field to window coordinates, taking title bar and frame into account
281                 m_WindowRegionPtr->Move(GetSystemMetrics(SM_CXFIXEDFRAME), GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION));
282
283                 // set the window region
284                 SetWindowRgn(m_hWindow, m_WindowRegionPtr->GetHandle(), true);
285         }
286
287         return true;
288 }
289
290 bool GameEngine::HasWindowRegion() const
291 {
292         return (m_WindowRegionPtr?true:false);
293 }
294
295 bool GameEngine::GoFullscreen()
296 {
297         // exit if already in fullscreen mode
298         if (m_Fullscreen) return false;
299
300         // turn off window region without redraw
301         SetWindowRgn(m_hWindow, 0, false);
302
303         DEVMODE newSettings;   
304
305         // request current screen settings
306         EnumDisplaySettings(0, 0, &newSettings);
307
308         //  set desired screen size/res
309         newSettings.dmPelsWidth  = GetWidth();         
310         newSettings.dmPelsHeight = GetHeight();         
311         newSettings.dmBitsPerPel = 32;         
312
313         //specify which aspects of the screen settings we wish to change
314         newSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
315
316         // attempt to apply the new settings
317         long result = ChangeDisplaySettings(&newSettings, CDS_FULLSCREEN);
318
319         // exit if failure, else set datamember to fullscreen and return true
320         if ( result != DISP_CHANGE_SUCCESSFUL ) return false;
321         else
322         {
323                 // store the location of the window
324                 m_oldLoc = GetLocation();
325
326                 // switch off the title bar
327             DWORD dwStyle = GetWindowLong(m_hWindow, GWL_STYLE);
328             dwStyle &= ~WS_CAPTION;
329             SetWindowLong(m_hWindow, GWL_STYLE, dwStyle);
330
331                 // move the window to (0,0)
332                 SetWindowPos(m_hWindow, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
333                 InvalidateRect(m_hWindow, 0, true);             
334
335                 m_Fullscreen = true;
336
337                 return true;
338         }
339 }
340
341 bool GameEngine::GoWindowedMode()
342 {
343         // exit if already in windowed mode
344         if (!m_Fullscreen) return false;
345
346         // this resets the screen to the registry-stored values
347         ChangeDisplaySettings(0, 0);
348
349         // replace the title bar
350         DWORD dwStyle = GetWindowLong(m_hWindow, GWL_STYLE);
351     dwStyle = dwStyle | WS_CAPTION;
352     SetWindowLong(m_hWindow, GWL_STYLE, dwStyle);
353
354         // move the window back to its old position
355         SetWindowPos(m_hWindow, 0, m_oldLoc.x, m_oldLoc.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
356         InvalidateRect(m_hWindow, 0, true);
357
358         m_Fullscreen = false;
359
360         return true;
361 }
362
363 bool GameEngine::IsFullscreen() const
364 {
365         return m_Fullscreen;
366 }
367
368 bool GameEngine::ClassRegister(int iCmdShow)
369 {
370   WNDCLASSEX    wndclass;
371
372   // Create the window class for the main window
373   wndclass.cbSize         = sizeof(wndclass);
374   wndclass.style          = CS_HREDRAW | CS_VREDRAW;
375   wndclass.lpfnWndProc    = WndProc;
376   wndclass.cbClsExtra     = 0;
377   wndclass.cbWndExtra     = 0;
378   wndclass.hInstance      = m_hInstance;
379   wndclass.hIcon          = LoadIcon(m_hInstance, MAKEINTRESOURCE(GetIcon()));
380   wndclass.hIconSm        = LoadIcon(m_hInstance, MAKEINTRESOURCE(GetSmallIcon()));
381   wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
382   wndclass.hbrBackground  = m_PaintDoublebuffered?NULL:(HBRUSH)(COLOR_WINDOW + 1);
383   wndclass.lpszMenuName   = NULL;
384   wndclass.lpszClassName  = m_TitlePtr->c_str();
385
386   // Register the window class
387   if (!RegisterClassEx(&wndclass))
388     return false;
389
390   // Calculate the window size and position based upon the game size
391   int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
392       iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
393         GetSystemMetrics(SM_CYCAPTION);
394   if (wndclass.lpszMenuName != NULL)
395     iWindowHeight += GetSystemMetrics(SM_CYMENU);
396   int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
397       iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;
398
399   // Create the window
400   m_hWindow = CreateWindow(     m_TitlePtr->c_str(),
401                                                         m_TitlePtr->c_str(),
402                                                         WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_CLIPCHILDREN,
403                                                         iXWindowPos,
404                                                         iYWindowPos,
405                                                         iWindowWidth,
406                                                         iWindowHeight,
407                                                         NULL,
408                                                         NULL,
409                                                         m_hInstance,
410                                                         NULL);
411   if (!m_hWindow)
412     return false;
413
414   // Show and update the window
415   ShowWindow(m_hWindow, iCmdShow);
416   UpdateWindow(m_hWindow);
417
418   return true;
419 }
420
421 bool GameEngine::IsKeyDown(int vKey) const
422 {
423         if (GetAsyncKeyState(vKey) < 0) return true;
424         else return false;
425 }
426
427 void GameEngine::SetKeyList(const tstring& keyListRef)
428 {
429         if (keyListRef.c_str() != NULL) delete m_KeyListPtr; // clear lijst als er al een lijst bestaat
430
431         /*
432         int iLength = 0;
433
434         while (keyListRef.c_str()[iLength] != '\0') iLength++; // tellen hoeveel tekens er zijn
435         */
436
437         m_KeyListPtr = (TCHAR*) malloc((keyListRef.size() + 1) * sizeof(TCHAR)); // maak plaats voor zoveel tekens + 1
438
439         for (int count = 0; count < (int) keyListRef.size() + 1; ++count)
440         {
441                 TCHAR key = keyListRef.c_str()[count];
442                 m_KeyListPtr[count] = (key > 96 && key < 123)? key-32 : key; // vul het teken in, in uppercase indien kleine letter
443         }
444 }
445
446 void GameEngine::QuitGame() const
447 {
448         PostMessage(GameEngine::GetWindow(), WM_DESTROY, 0, 0);
449 }
450
451 void GameEngine::MessageBox(const tstring& textRef) const
452 {
453         #ifdef UNICODE                                          // MessageBox define is undef'd at begin of GameEngine.h
454         #define MessageBox  MessageBoxW         // but is needed here
455         #else
456         #define MessageBox  MessageBoxA
457         #endif
458
459         MessageBox(GetWindow(), textRef.c_str(), m_TitlePtr->c_str(), MB_ICONEXCLAMATION | MB_OK);
460
461         #undef  MessageBox                                      // undefining it again
462 }
463
464 void GameEngine::MessageBox(int value) const
465 {
466         tstringstream buffer;
467         buffer << value;
468
469         MessageBox(buffer.str());
470 }
471
472 void GameEngine::MessageBox(size_t value) const
473 {
474         tstringstream buffer;
475         buffer << value;
476
477         MessageBox(buffer.str());
478 }
479
480 void GameEngine::MessageBox(double value) const
481 {
482         tstringstream buffer;
483         buffer << value;
484
485         MessageBox(buffer.str());
486 }
487
488 static bool CALLBACK EnumInsertChildrenProc(HWND hwnd, LPARAM lParam)
489 {
490         std::vector<HWND> *row = (std::vector<HWND> *) lParam; // std::vector niet te kennen 1e jaar DAE
491
492         row->push_back(hwnd); // elk element invullen in de vector
493
494         return true;
495 }
496
497 void GameEngine::TabNext(HWND ChildWindow) const
498 {
499         std::vector<HWND> childWindows; // std::vector niet te kennen 1e jaar DAE
500
501         EnumChildWindows(m_hWindow, (WNDENUMPROC) EnumInsertChildrenProc, (LPARAM) &childWindows);
502
503         int position = 0;
504         HWND temp = childWindows[position];
505         while(temp != ChildWindow) temp = childWindows[++position]; // positie van childWindow in de vector opzoeken
506
507         if (position == childWindows.size() - 1) SetFocus(childWindows[0]);
508         else SetFocus(childWindows[position + 1]);
509 }
510
511 void GameEngine::TabPrevious(HWND ChildWindow) const
512 {       
513         std::vector<HWND> childWindows;
514
515         EnumChildWindows(m_hWindow, (WNDENUMPROC) EnumInsertChildrenProc, (LPARAM) &childWindows);
516
517         int position = (int) childWindows.size() - 1;
518         HWND temp = childWindows[position];
519         while(temp != ChildWindow) temp = childWindows[--position]; // positie van childWindow in de vector opzoeken
520
521         if (position == 0) SetFocus(childWindows[childWindows.size() - 1]);
522         else SetFocus(childWindows[position - 1]);
523 }
524
525 bool GameEngine::DrawLine(int x1, int y1, int x2, int y2, HDC hDC) const
526 {
527         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
528         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
529         MoveToEx(hDC, x1, y1, NULL);
530         LineTo(hDC, x2, y2);
531         MoveToEx(hDC, 0, 0, NULL); // reset van de positie - zorgt ervoor dat bvb AngleArc vanaf 0,0 gaat tekenen ipv de laatste positie van de DrawLine
532         SelectObject(hDC, hOldPen);
533         DeleteObject(hNewPen);
534        
535         return true;
536 }
537
538 bool GameEngine::DrawLine(int x1, int y1, int x2, int y2) const
539 {
540         if (m_isDoublebuffering || m_isPainting) return DrawLine(x1, y1, x2, y2, m_HdcDraw);
541         else return false;
542 }
543
544 bool GameEngine::DrawPolygon(const POINT ptsArr[], int count, bool close, HDC hDC) const
545 {
546         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
547         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
548
549         FormPolygon(ptsArr, count, close, hDC);
550
551         SelectObject(hDC, hOldPen);
552         DeleteObject(hNewPen); 
553
554         return true;
555 }
556
557 bool GameEngine::DrawPolygon(const POINT ptsArr[], int count, bool close) const
558 {
559         if (m_isDoublebuffering || m_isPainting) return DrawPolygon(ptsArr, count, close, m_HdcDraw);
560         else return false;
561 }
562
563 bool GameEngine::DrawPolygon(const POINT ptsArr[], int count) const
564 {
565         if (m_isDoublebuffering || m_isPainting) return DrawPolygon(ptsArr, count, false, m_HdcDraw);
566         else return false;
567 }
568
569 bool GameEngine::FillPolygon(const POINT ptsArr[], int count, bool close, HDC hDC) const
570 {
571         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
572         HBRUSH hOldBrush, hNewBrush = CreateSolidBrush(m_colDraw);
573         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
574         hOldBrush = (HBRUSH) SelectObject(hDC, hNewBrush);
575
576         BeginPath(hDC);
577
578         FormPolygon(ptsArr, count, close, hDC);
579
580         EndPath(hDC);
581         StrokeAndFillPath(hDC);
582
583         SelectObject(hDC, hOldPen);
584         SelectObject(hDC, hOldBrush);
585
586         DeleteObject(hNewPen);
587         DeleteObject(hNewBrush);
588
589         return true;
590 }
591
592 bool GameEngine::FillPolygon(const POINT ptsArr[], int count, bool close) const
593 {
594         if (m_isDoublebuffering || m_isPainting) return FillPolygon(ptsArr, count, close, m_HdcDraw);
595         else return false;
596 }
597
598 bool GameEngine::FillPolygon(const POINT ptsArr[], int count) const
599 {
600         if (m_isDoublebuffering || m_isPainting) return FillPolygon(ptsArr, count, false, m_HdcDraw);
601         else return false;
602 }
603
604 void GameEngine::FormPolygon(const POINT ptsArr[], int count, bool close, HDC hDC) const
605 {
606         if (!close) Polyline(hDC, ptsArr, count);
607         else
608         {
609                 POINT* newPtsArr= new POINT[count+1]; // interessant geval: deze code werkt niet met memory allocation at compile time => demo case for dynamic memory use
610                 for (int i = 0; i < count; i++) newPtsArr[i] = ptsArr[i];
611                 newPtsArr[count] = ptsArr[0];
612
613                 Polyline(hDC, newPtsArr, count+1);
614
615                 delete[] newPtsArr;
616         }
617 }
618
619 bool GameEngine::DrawRect(int x, int y, int width, int height, HDC hDC) const
620 {
621         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
622         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
623        
624         POINT pts[4] = {x, y, x + width -1, y, x + width-1, y + height-1, x, y + height-1};
625         DrawPolygon(pts, 4, true, hDC);
626
627         SelectObject(hDC, hOldPen);
628         DeleteObject(hNewPen); 
629
630         return true;
631 }
632
633 bool GameEngine::DrawRect(int x, int y, int width, int height) const
634 {
635         if (m_isDoublebuffering || m_isPainting) return DrawRect(x, y, width, height, m_HdcDraw);
636         else return false;
637 }
638
639 bool GameEngine::FillRect(int x, int y, int width, int height, HDC hDC) const
640 {
641         HBRUSH hOldBrush, hNewBrush = CreateSolidBrush(m_colDraw);
642         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
643
644         hOldBrush = (HBRUSH) SelectObject(hDC, hNewBrush);
645         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
646        
647         Rectangle(hDC, x, y, x + width, y + height);
648                                                
649         SelectObject(hDC, hOldPen);
650         SelectObject(hDC, hOldBrush);
651
652         DeleteObject(hNewPen);
653         DeleteObject(hNewBrush);
654
655         return true;
656 }
657
658 bool GameEngine::FillRect(int x, int y, int width, int height) const
659 {
660         if (m_isDoublebuffering || m_isPainting) return FillRect(x, y, width, height, m_HdcDraw);
661         else return false;
662 }
663
664 bool GameEngine::DrawRoundRect(int x, int y, int width, int height, int radius, HDC hDC) const
665 {
666         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
667         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
668        
669         BeginPath(hDC);
670
671         RoundRect(hDC, x, y, x + width, y + height, radius, radius);
672
673         EndPath(hDC);
674         StrokePath(hDC);
675
676         SelectObject(hDC, hOldPen);
677         DeleteObject(hNewPen); 
678
679         return true;
680 }
681
682 bool GameEngine::DrawRoundRect(int x, int y, int width, int height, int radius) const
683 {
684         if (m_isDoublebuffering || m_isPainting) return DrawRoundRect(x, y, width, height, radius, m_HdcDraw);
685         else return false;
686 }
687
688 bool GameEngine::FillRoundRect(int x, int y, int width, int height, int radius, HDC hDC) const
689 {
690         HBRUSH hOldBrush, hNewBrush = CreateSolidBrush(m_colDraw);
691         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
692
693         hOldBrush = (HBRUSH) SelectObject(hDC, hNewBrush);
694         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
695        
696         RoundRect(hDC, x, y, x + width, y + height, radius, radius);
697                                                
698         SelectObject(hDC, hOldPen);
699         SelectObject(hDC, hOldBrush);
700
701         DeleteObject(hNewPen);
702         DeleteObject(hNewBrush);
703
704         return true;
705 }
706
707 bool GameEngine::FillRoundRect(int x, int y, int width, int height, int radius) const
708 {
709         if (m_isDoublebuffering || m_isPainting) return FillRoundRect(x, y, width, height, radius, m_HdcDraw);
710         else return false;
711 }
712
713 bool GameEngine::DrawOval(int x, int y, int width, int height, HDC hDC) const
714 {
715         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
716         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
717        
718         Arc(hDC, x, y, x + width, y + height, x, y + height/2, x, y + height/2);
719
720         SelectObject(hDC, hOldPen);
721         DeleteObject(hNewPen); 
722
723         return true;
724 }
725
726 bool GameEngine::DrawOval(int x, int y, int width, int height) const
727 {
728         if (m_isDoublebuffering || m_isPainting) return DrawOval(x, y, width, height, m_HdcDraw);
729         else return false;
730 }
731
732 bool GameEngine::FillOval(int x, int y, int width, int height, HDC hDC) const
733 {
734         HBRUSH hOldBrush, hNewBrush = CreateSolidBrush(m_colDraw);
735         HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
736
737         hOldBrush = (HBRUSH) SelectObject(hDC, hNewBrush);
738         hOldPen = (HPEN) SelectObject(hDC, hNewPen);
739        
740         Ellipse(hDC, x, y, x + width, y + height);
741                                                
742         SelectObject(hDC, hOldPen);
743         SelectObject(hDC, hOldBrush);
744
745         DeleteObject(hNewPen);
746         DeleteObject(hNewBrush);
747
748         return true;
749 }
750
751 bool GameEngine::FillOval(int x, int y, int width, int height) const
752 {
753         if (m_isDoublebuffering || m_isPainting) return FillOval(x, y, width, height, m_HdcDraw);
754         else return false;
755 }
756
757 bool GameEngine::DrawArc(int x, int y, int width, int height, int startDegree, int angle, HDC hDC) const
758 {
759         if (angle == 0) return false;
760         if (angle > 360) { DrawOval(x, y, width, height, hDC); }
761         else
762         {
763                 HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
764                 hOldPen = (HPEN) SelectObject(hDC, hNewPen);
765                
766                 POINT ptStart = AngleToPoint(x, y, width, height, startDegree);
767                 POINT ptEnd = AngleToPoint(x, y, width, height, startDegree + angle);
768                
769                 if (angle > 0) Arc(hDC, x, y, x + width, y + height, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
770                 else Arc(hDC, x, y, x + width, y + height, ptEnd.x, ptEnd.y, ptStart.x, ptStart.y);
771
772                 SelectObject(hDC, hOldPen);
773                 DeleteObject(hNewPen); 
774         }
775
776         return true;
777 }
778
779 bool GameEngine::DrawArc(int x, int y, int width, int height, int startDegree, int angle) const
780 {
781         if (m_isDoublebuffering || m_isPainting) return DrawArc(x, y, width, height, startDegree, angle, m_HdcDraw);
782         else return false;
783 }
784
785 bool GameEngine::FillArc(int x, int y, int width, int height, int startDegree, int angle, HDC hDC) const
786 {       
787         if (angle == 0) return false;
788         if (angle > 360) { FillOval(x, y, width, height, hDC); }
789         else
790         {
791                 HBRUSH hOldBrush, hNewBrush = CreateSolidBrush(m_colDraw);
792                 HPEN hOldPen, hNewPen = CreatePen(PS_SOLID, 1, m_colDraw);
793
794                 hOldBrush = (HBRUSH) SelectObject(hDC, hNewBrush);
795                 hOldPen = (HPEN) SelectObject(hDC, hNewPen);
796
797                 POINT ptStart = AngleToPoint(x, y, width, height, startDegree);
798                 POINT ptEnd = AngleToPoint(x, y, width, height, startDegree + angle);
799                
800                 if (angle >0) Pie(hDC, x, y, x + width, y + height, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
801                 else Pie(hDC, x, y, x + width, y + height, ptEnd.x, ptEnd.y, ptStart.x, ptStart.y);
802
803                 SelectObject(hDC, hOldPen);
804                 SelectObject(hDC, hOldBrush);
805
806                 DeleteObject(hNewPen);
807                 DeleteObject(hNewBrush);
808         }
809
810         return true;
811 }
812
813
814 bool GameEngine::FillArc(int x, int y, int width, int height, int startDegree, int angle) const
815 {
816         if (m_isDoublebuffering || m_isPainting) return FillArc(x, y, width, height, startDegree, angle, m_HdcDraw);
817         else return false;
818 }
819
820 POINT GameEngine::AngleToPoint(int x, int y, int width, int height, int angle) const
821 {
822         POINT pt;
823
824         // if necessary adjust angle so that it has a value between 0 and 360 degrees
825         if (angle > 360 || angle < -360) angle = angle % 360;
826         if (angle < 0) angle += 360;
827
828         // default values for standard angles
829         if (angle == 0) { pt.x = x + width; pt.y = y + (int) (height / 2); }
830         else if (angle == 90) { pt.x = x + (int) (width / 2); pt.y = y; }
831         else if (angle == 180) { pt.x = x; pt.y = y + (int) (height / 2); }
832         else if (angle == 270) { pt.x = x + (int) (width / 2); pt.y = y + height; }
833         // else calculate non-default values
834         else
835         {
836                 // point on the ellipse = "stelsel" of the cartesian equation of the ellipse combined with y = tg(alpha) * x
837                 // using the equation for ellipse with 0,0 in the center of the ellipse
838                 double aSquare = pow(width/2.0, 2);
839                 double bSquare = pow(height/2.0, 2);
840                 double tangens = tan(angle * M_PI / 180);
841                 double tanSquare = pow(tangens, 2);
842
843                 // calculate x
844                 pt.x = (long) sqrt( aSquare * bSquare / (bSquare + tanSquare * aSquare));
845                 if (angle > 90 && angle < 270) pt.x *= -1; // sqrt returns the positive value of the square, take the negative value if necessary
846
847                 // calculate y
848                 pt.y = (long) (tangens * pt.x);
849                 pt.y *= -1;     // reverse the sign because of inverted y-axis
850
851                 // offset the ellipse into the screen
852                 pt.x += x + (int)(width / 2);
853                 pt.y += y + (int)(height / 2);
854         }
855
856         return pt;
857 }
858
859 int GameEngine::DrawString(const tstring& textRef, int x, int y, int width, int height, HDC hDC) const
860 {
861         HFONT hOldFont;
862         COLORREF oldColor;
863
864         if (m_FontDraw != 0) hOldFont = (HFONT) SelectObject(hDC, m_FontDraw);
865
866         oldColor = SetTextColor(hDC, m_colDraw);
867         SetBkMode(hDC, TRANSPARENT);
868        
869         RECT rc = {x, y, x + width - 1, y + height - 1};
870         int result = DrawText(hDC, textRef.c_str(), -1, &rc, DT_WORDBREAK);
871
872         SetBkMode(hDC, OPAQUE);
873         SetTextColor(hDC, oldColor);
874         if (m_FontDraw != 0) SelectObject(hDC, hOldFont);
875
876         return result;
877 }
878
879 int GameEngine::DrawString(const tstring& textRef, int x, int y, int width, int height) const
880 {
881         if (m_isDoublebuffering || m_isPainting) return DrawString(textRef, x, y, width, height, m_HdcDraw);
882         else return -1;
883 }
884
885 int GameEngine::DrawString(const tstring& textRef, int x, int y, HDC hDC) const
886 {
887         HFONT hOldFont;
888         COLORREF oldColor;
889
890         if (m_FontDraw != 0) hOldFont = (HFONT) SelectObject(hDC, m_FontDraw);
891        
892         oldColor = SetTextColor(hDC, m_colDraw);
893         SetBkMode(hDC, TRANSPARENT);
894
895         /*
896         int count = 0;
897         while (textRef.c_str()[count] != '\0') count++;
898         */
899
900         int result = TextOut(hDC, x, y, textRef.c_str(), (int) textRef.size());
901
902         SetBkMode(hDC, OPAQUE);
903         SetTextColor(hDC, oldColor);
904
905         if (m_FontDraw != 0) SelectObject(hDC, hOldFont);
906
907         return result;
908 }
909
910 int GameEngine::DrawString(const tstring& textRef, int x, int y) const
911 {
912         if (m_isDoublebuffering || m_isPainting) return DrawString(textRef, x, y, m_HdcDraw);
913         else return -1;
914 }
915
916 bool GameEngine::DrawBitmap(Bitmap* bitmapPtr, int x, int y, RECT rect, HDC hDC) const
917 {
918         if (!bitmapPtr->Exists()) return false;
919
920         int opacity = bitmapPtr->GetOpacity();
921
922         if (opacity == 0 && bitmapPtr->HasAlphaChannel()) return true; // don't draw if opacity == 0 and opacity is used
923
924         HDC hdcMem = CreateCompatibleDC(hDC);
925         HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, bitmapPtr->GetHandle());
926
927         if (bitmapPtr->HasAlphaChannel())
928         {
929                 BLENDFUNCTION blender={AC_SRC_OVER, 0, (int) (2.55 * opacity), AC_SRC_ALPHA}; // blend function combines opacity and pixel based transparency
930                 AlphaBlend(hDC, x, y, rect.right - rect.left, rect.bottom - rect.top, hdcMem, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, blender);
931         }
932         else TransparentBlt(hDC, x, y, rect.right - rect.left, rect.bottom - rect.top, hdcMem, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, bitmapPtr->GetTransparencyColor());
933
934         SelectObject(hdcMem, hbmOld);
935         DeleteDC(hdcMem);
936
937         return true;
938 }
939
940 bool GameEngine::DrawBitmap(Bitmap* bitmapPtr, int x, int y, RECT rect) const
941 {
942         if (m_isDoublebuffering || m_isPainting) return DrawBitmap(bitmapPtr, x, y, rect, m_HdcDraw);
943         else return false;
944 }
945
946 bool GameEngine::DrawBitmap(Bitmap* bitmapPtr, int x, int y, HDC hDC) const
947 {
948         if (!bitmapPtr->Exists()) return false;
949
950     BITMAP bm;
951     GetObject(bitmapPtr->GetHandle(), sizeof(bm), &bm);
952         RECT rect = {0, 0, bm.bmWidth, bm.bmHeight};
953
954     return DrawBitmap(bitmapPtr, x, y, rect, hDC);
955 }
956
957 bool GameEngine::DrawBitmap(Bitmap* bitmapPtr, int x, int y) const
958 {
959         if (m_isDoublebuffering || m_isPainting) return DrawBitmap(bitmapPtr, x, y, m_HdcDraw);
960         else return false;
961 }
962
963 bool GameEngine::DrawSolidBackground(COLORREF color, HDC hDC, RECT rect)
964 {
965         COLORREF oldColor = GetDrawColor();
966         SetColor(color);
967         FillRect(0, 0, rect.right, rect.bottom, hDC);
968         SetColor(oldColor);
969
970         return true;
971 }
972
973 bool GameEngine::DrawSolidBackground(COLORREF color)
974 {       
975         if (m_isDoublebuffering || m_isPainting) return DrawSolidBackground(color, m_HdcDraw, m_RectDraw);
976         else return false;
977 }
978
979 bool GameEngine::Repaint() const
980 {
981         return InvalidateRect(m_hWindow, NULL, true)?true:false;
982 }
983
984 POINT GameEngine::GetLocation() const
985 {
986         RECT info;
987         POINT pos;
988
989         GetWindowRect(m_hWindow, &info);
990         pos.x = info.left;
991         pos.y = info.top;
992
993         return pos;
994 }
995
996 void GameEngine::SetLocation(int x, int y)
997 {
998         SetWindowPos(m_hWindow, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
999         InvalidateRect(m_hWindow, 0, TRUE);
1000 }
1001
1002 void GameEngine::SetFont(const tstring& fontNameRef, bool bold, bool italic, bool underline, int size)
1003 {
1004         if (m_FontDraw != 0) DeleteObject(m_FontDraw);
1005
1006         LOGFONT ft;
1007         ZeroMemory(&ft, sizeof(ft));
1008
1009         //_tcscpy_s(ft.lfFaceName, sizeof(ft.lfFaceName) / sizeof(TCHAR), fontName.c_str());
1010         for (int teller = 0; teller < (int) fontNameRef.size() && teller < LF_FACESIZE; ++teller)
1011         {
1012                 ft.lfFaceName[teller] = fontNameRef[teller];
1013         }
1014
1015         ft.lfStrikeOut = 0;
1016         ft.lfUnderline = underline?1:0;
1017         ft.lfHeight = size;
1018     ft.lfEscapement = 0;
1019         ft.lfWeight = bold?FW_BOLD:0;
1020         ft.lfItalic = italic?1:0;
1021
1022     m_FontDraw = CreateFontIndirect(&ft);
1023 }
1024
1025 void GameEngine::RunGameLoop(bool value)
1026 {
1027         m_bRunGameLoop = value;
1028 }
1029
1030 LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
1031 {
1032         RECT rect;
1033         HDC         hDC;
1034         PAINTSTRUCT ps;
1035
1036 //                              HWND hWindow;
1037 //                      RECT rect;
1038 //                      HDC hDC;
1039
1040                         // Double buffering code
1041                         HDC hBufferDC;
1042                         HBITMAP hBufferBmp;
1043                         HBITMAP hOldBmp;
1044
1045                         int iWidth, iHeight;
1046                         static int count = 0;
1047
1048         // Route Windows messages to game engine member functions
1049         switch (msg)
1050         {
1051                 case WM_CREATE:
1052                         // Set the game window and start the game
1053                         SetWindow(hWindow);
1054                         // User defined functions for start of the game
1055                         m_GamePtr->GameStart(); 
1056                         // Seed the random number generator
1057                         srand(GetTickCount());
1058                         return 0;
1059
1060                 case WM_ACTIVATE:
1061                         // Activate/deactivate the game and update the Sleep status
1062                         if (wParam != WA_INACTIVE)
1063                         {
1064                                 // Get window rectangle and HDC
1065                                 GetClientRect(hWindow, &rect);
1066                                 hDC = GetDC(hWindow);
1067
1068                                 // Do user defined drawing functions
1069                                 m_GamePtr->GameActivate(hDC, rect);
1070
1071                                 // Release HDC
1072                                 ReleaseDC(hWindow, hDC);
1073
1074                                 SetSleep(false);
1075                         }
1076                         else
1077                         {                       
1078                                 // Get window rectangle and HDC
1079                                 GetClientRect(hWindow, &rect);
1080                                 hDC = GetDC(hWindow);
1081
1082                                 // Do user defined drawing functions
1083                                 m_GamePtr->GameDeactivate(hDC, rect);
1084
1085                                 // Release HDC
1086                                 ReleaseDC(hWindow, hDC);
1087                         }
1088                         return 0;
1089
1090                 case WM_PAINT:
1091                         if (m_PaintDoublebuffered)
1092                         {
1093                                 // Get window, rectangle and HDC
1094                                 hDC = BeginPaint(hWindow, &ps);
1095                                 GetClientRect(hWindow, &rect);
1096
1097                                 // Double buffering code
1098                                 hBufferDC = CreateCompatibleDC(hDC);
1099                                 iWidth = GameEngine::GetSingleton()->GetWidth();
1100                                 iHeight = GameEngine::GetSingleton()->GetHeight();
1101                                 // Create the buffer
1102                                 hBufferBmp = CreateCompatibleBitmap(hDC, iWidth, iHeight);
1103                                 hOldBmp = (HBITMAP) SelectObject(hBufferDC, hBufferBmp);
1104
1105                                 // Do user defined drawing functions on the buffer, parameters added
1106                                 // for ease of drawing
1107                                 m_HdcDraw = hBufferDC;
1108                                 m_RectDraw = rect;
1109
1110                                 m_isPainting = true;
1111                                 m_GamePtr->GamePaint(rect);
1112                                 m_isPainting = false;
1113
1114                                 // As a last step copy the memdc to the hdc
1115                                 BitBlt(hDC, 0, 0, iWidth, iHeight, hBufferDC, 0, 0, SRCCOPY);
1116
1117                                 // Reset the old bmp of the buffer, mainly for show since we kill it anyway
1118                                 SelectObject(hBufferDC, hOldBmp);
1119                                 // Kill the buffer
1120                                 DeleteObject(hBufferBmp);
1121                                 DeleteDC(hBufferDC);
1122
1123                                 // end paint
1124                                 EndPaint(hWindow, &ps);
1125                         }
1126                         else
1127                         {
1128                                 m_HdcDraw = BeginPaint(hWindow, &ps);   
1129                                 GetClientRect(hWindow, &m_RectDraw);
1130
1131                                 m_isPainting = true;
1132                                 m_GamePtr->GamePaint(m_RectDraw);
1133                                 m_isPainting = false;
1134
1135                                 EndPaint(hWindow, &ps);
1136                         }
1137
1138                         return 0;
1139
1140                 case WM_CTLCOLOREDIT:
1141                         return SendMessage((HWND) lParam, WM_CTLCOLOREDIT, wParam, lParam);     // delegate this message to the child window
1142
1143                 case WM_CTLCOLORBTN:
1144                         return SendMessage((HWND) lParam, WM_CTLCOLOREDIT, wParam, lParam);     // delegate this message to the child window
1145
1146                 case WM_LBUTTONDOWN:
1147                         m_GamePtr->MouseButtonAction(true, true, LOWORD(lParam), HIWORD(lParam), wParam);
1148                         return 0;
1149
1150                 case WM_LBUTTONUP:
1151                         m_GamePtr->MouseButtonAction(true, false, LOWORD(lParam), HIWORD(lParam), wParam);
1152                         return 0;
1153
1154                 case WM_RBUTTONDOWN:
1155                         m_GamePtr->MouseButtonAction(false, true, LOWORD(lParam), HIWORD(lParam), wParam);
1156                         return 0;
1157
1158                 case WM_RBUTTONUP:
1159                         m_GamePtr->MouseButtonAction(false, false, LOWORD(lParam), HIWORD(lParam), wParam);
1160                         return 0;
1161
1162                 case WM_MOUSEMOVE:
1163                         m_GamePtr->MouseMove(LOWORD(lParam), HIWORD(lParam), wParam);
1164                         return 0;
1165                        
1166                 case WM_SYSCOMMAND:     // trapping this message prevents a freeze after the ALT key is released
1167                         if (wParam == SC_KEYMENU) return 0;                     // see win32 API : WM_KEYDOWN
1168                         else break;   
1169
1170                 case WM_DESTROY:
1171                         // User defined code for exiting the game
1172                         m_GamePtr->GameEnd();
1173                         // Delete the game engine
1174                         delete GameEngine::GetSingleton();
1175                        
1176                         // End the game and exit the application
1177                         PostQuitMessage(0);
1178                         return 0;
1179
1180         }
1181         return DefWindowProc(hWindow, msg, wParam, lParam);
1182 }
1183
1184 //-----------------------------------------------------------------
1185 // Caller methods
1186 //-----------------------------------------------------------------
1187 bool Caller::AddActionListener(Callable* targetPtr)
1188 {
1189         return AddListenerObject(targetPtr);
1190 }       
1191
1192 bool Caller::RemoveActionListener(const Callable* targetPtr)
1193 {
1194         return RemoveListenerObject(targetPtr);
1195 }
1196
1197 class CallAllActions
1198 {
1199 public:
1200         CallAllActions(Caller* callerPtr) : m_CallerPtr(callerPtr)
1201         {}
1202
1203         void operator()(Callable* callablePtr)
1204         {
1205                 callablePtr->CallAction(m_CallerPtr);
1206         }
1207
1208 private:
1209         Caller* m_CallerPtr;
1210 };
1211
1212 bool Caller::CallListeners()   
1213 {       
1214         /*
1215         for (vector<Callable*>::iterator it = m_TargetList.begin(); it != m_TargetList.end(); ++it)
1216         {
1217                 (*it)->CallAction(this);       
1218         }
1219         */
1220         for_each(m_TargetList.begin(), m_TargetList.end(), CallAllActions(this));
1221
1222         return (m_TargetList.size() > 0);
1223 }
1224
1225 bool Caller::AddListenerObject(Callable* targetPtr)
1226 {
1227         /*
1228         for (vector<Callable*>::iterator it = m_TargetList.begin(); it != m_TargetList.end(); ++it)
1229         {
1230                 if ((*it) == target) return false;
1231         }*/
1232         vector<Callable*>::iterator pos = find(m_TargetList.begin(), m_TargetList.end(), targetPtr);
1233
1234         if (pos != m_TargetList.end()) return false;
1235        
1236         m_TargetList.push_back(targetPtr);
1237         return true;
1238 }
1239        
1240 bool Caller::RemoveListenerObject(const Callable* targetPtr)
1241 {
1242         vector<Callable*>::iterator pos = find(m_TargetList.begin(), m_TargetList.end(), targetPtr); // find algorithm from STL
1243
1244         if (pos == m_TargetList.end()) return false;
1245
1246         m_TargetList.erase(pos);
1247         return true;
1248 }
1249
1250 //-----------------------------------------------------------------
1251 // Bitmap methods
1252 //-----------------------------------------------------------------
1253
1254 // set static datamember to zero
1255 int Bitmap::m_nr = 0;
1256
1257 Bitmap::Bitmap(const tstring& nameRef, bool createAlphaChannel): m_Handle(0), m_TransparencyKey(-1), m_Opacity(100), m_PixelsPtr(0), m_Exists(false)
1258 {
1259         // check if the file to load is a targa
1260         size_t len = nameRef.length();
1261
1262         if (len > 4 && nameRef.substr(len-4) == _T(".tga"))
1263         {
1264                 m_IsTarga = true;
1265                 m_HasAlphaChannel = true;
1266                 TargaLoader* targa = new TargaLoader();
1267
1268                 if (targa->Load((TCHAR*) nameRef.c_str()) == 1)
1269                 {
1270                         m_Handle = CreateBitmap(targa->GetWidth(), targa->GetHeight(), 1, targa->GetBPP(), (void*)targa->GetImg());
1271                         if (m_Handle != 0) m_Exists = true;
1272                 }
1273                
1274                 delete targa;
1275         }
1276         // else load as bitmap
1277         else
1278         {
1279                 m_IsTarga = false;
1280                 m_HasAlphaChannel = createAlphaChannel;
1281                 m_Handle = (HBITMAP) LoadImage(GameEngine::GetSingleton()->GetInstance(), nameRef.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
1282                 if (m_Handle != 0) m_Exists = true;             
1283         }
1284
1285         if (m_IsTarga || createAlphaChannel) LoadBitInfo();
1286 }
1287
1288 Bitmap::Bitmap(int IDBitmap, const tstring& typeRef, bool createAlphaChannel): m_TransparencyKey(-1), m_Opacity(100), m_Exists(false)
1289 {
1290         if (typeRef == _T("BITMAP"))
1291         {       
1292                 m_IsTarga = false;
1293                 m_HasAlphaChannel = createAlphaChannel;
1294
1295                 m_Handle = LoadBitmap(GameEngine::GetSingleton()->GetInstance(), MAKEINTRESOURCE(IDBitmap));
1296                
1297                 if (m_Handle != 0) m_Exists = true;
1298                
1299                 if (createAlphaChannel) LoadBitInfo();
1300         }
1301         else if (typeRef == _T("TGA"))
1302         {
1303                 m_IsTarga = true;
1304                 m_HasAlphaChannel = true;
1305
1306                 tstringstream buffer;
1307                 buffer << "temp\\targa";
1308                 buffer << m_nr++;
1309                 buffer << ".tga";
1310
1311                 tstring fileName = buffer.str();
1312
1313                 Extract(IDBitmap, _T("TGA"), fileName);
1314
1315                 TargaLoader* targa = new TargaLoader();
1316
1317                 if (targa->Load((TCHAR*) fileName.c_str()) == 1)
1318                 {
1319                         m_Handle = CreateBitmap(targa->GetWidth(), targa->GetHeight(), 1, targa->GetBPP(), (void*)targa->GetImg());
1320                         if (m_Handle != 0) m_Exists = true;
1321                 }
1322                
1323                 delete targa;
1324                
1325                 LoadBitInfo();
1326         }
1327 }
1328
1329 void Bitmap::LoadBitInfo()
1330 {
1331         BITMAPINFOHEADER bminfoheader;
1332         ::ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
1333         bminfoheader.biSize        = sizeof(BITMAPINFOHEADER);
1334         bminfoheader.biWidth       = GetWidth();
1335         bminfoheader.biHeight      = GetHeight();
1336         bminfoheader.biPlanes      = 1;
1337         bminfoheader.biBitCount    = 32;
1338         bminfoheader.biCompression = BI_RGB;
1339        
1340         HDC windowDC = GetWindowDC(GameEngine::GetSingleton()->GetWindow());
1341         m_PixelsPtr = new unsigned char[this->GetWidth() * this->GetHeight() * 4];
1342        
1343         GetDIBits(windowDC, m_Handle, 0, GetHeight(), m_PixelsPtr, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // load pixel info
1344
1345         // premultiply if it's a targa
1346         if (m_IsTarga)
1347         {
1348                 for (int count = 0; count < GetWidth() * GetHeight(); count++)
1349                 {
1350                         if (m_PixelsPtr[count * 4 + 3] < 255)
1351                         {
1352                                 m_PixelsPtr[count * 4 + 2] = (unsigned char)((int) m_PixelsPtr[count * 4 + 2] * (int) m_PixelsPtr[count * 4 + 3] / 0xff);
1353                                 m_PixelsPtr[count * 4 + 1] = (unsigned char)((int) m_PixelsPtr[count * 4 + 1] * (int) m_PixelsPtr[count * 4 + 3] / 0xff);
1354                                 m_PixelsPtr[count * 4] = (unsigned char)((int) m_PixelsPtr[count * 4] * (int) m_PixelsPtr[count * 4 + 3] / 0xff);
1355                         }
1356                 }
1357                        
1358                 SetDIBits(windowDC, m_Handle, 0, GetHeight(), m_PixelsPtr, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // save the pixel info for later manipulation
1359         }       
1360         // add alpha channel values of 255 for every pixel if bmp
1361         else
1362         {               
1363                 for (int count = 0; count < GetWidth() * GetHeight(); count++)
1364                 {
1365                         m_PixelsPtr[count * 4 + 3] = 255;
1366                 }
1367         }
1368        
1369         SetDIBits(windowDC, m_Handle, 0, GetHeight(), m_PixelsPtr, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // save the pixel info for later manipulation
1370 }
1371
1372 /*
1373 void Bitmap::Premultiply() // Multiply R, G and B with Alpha
1374 {
1375     //Note that the APIs use premultiplied alpha, which means that the red,
1376     //green and blue channel values in the bitmap must be premultiplied with
1377     //the alpha channel value. For example, if the alpha channel value is x,
1378     //the red, green and blue channels must be multiplied by x and divided by
1379     //0xff prior to the call.
1380
1381     unsigned long Index,nPixels;
1382     unsigned char *bCur;
1383     short iPixelSize;
1384
1385         // Set ptr to start of image
1386     bCur=pImage;
1387
1388     // Calc number of pixels
1389     nPixels=iWidth*iHeight;
1390
1391         // Get pixel size in bytes
1392     iPixelSize=iBPP/8;
1393
1394     for(Index=0;Index!=nPixels;Index++)  // For each pixel
1395     {
1396
1397         *bCur=(unsigned char)((int)*bCur* (int)*(bCur+3)/0xff);
1398         *(bCur+1)=(unsigned char)((int)*(bCur+1)* (int)*(bCur+3)/0xff);
1399         *(bCur+2)=(unsigned char)((int)*(bCur+2)* (int)*(bCur+3)/0xff);
1400
1401         bCur+=iPixelSize; // Jump to next pixel
1402     }
1403 }
1404 */
1405
1406 Bitmap::~Bitmap()
1407 {
1408         if (HasAlphaChannel())
1409         {
1410                 delete[] m_PixelsPtr;
1411                 m_PixelsPtr = 0;
1412         }
1413
1414         DeleteObject(m_Handle);
1415 }
1416
1417 bool Bitmap::Exists() const
1418 {
1419         return m_Exists;
1420 }
1421
1422 void Bitmap::Extract(WORD id, tstring sType, tstring fileName) const
1423 {
1424         CreateDirectory(_T("temp\\"), NULL);
1425
1426     HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(id), sType.c_str());
1427     HGLOBAL hLoaded = LoadResource( NULL, hrsrc);
1428     LPVOID lpLock =  LockResource(hLoaded);
1429     DWORD dwSize = SizeofResource(NULL, hrsrc);
1430     HANDLE hFile = CreateFile(fileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1431     DWORD dwByteWritten;
1432     WriteFile(hFile, lpLock , dwSize , &dwByteWritten , NULL);
1433     CloseHandle(hFile);
1434     FreeResource(hLoaded);
1435 }
1436
1437 HBITMAP Bitmap::GetHandle() const
1438 {
1439     return m_Handle;
1440 }
1441
1442 int Bitmap::GetWidth() const
1443 {
1444         if (!Exists()) return 0;
1445
1446     BITMAP bm;
1447
1448     GetObject(m_Handle, sizeof(bm), &bm);
1449
1450     return bm.bmWidth;
1451 }
1452
1453 int Bitmap::GetHeight() const
1454 {
1455         if (!Exists()) return 0;
1456
1457         BITMAP bm;
1458
1459     GetObject(m_Handle, sizeof(bm), &bm);
1460
1461     return bm.bmHeight;
1462 }
1463
1464 void Bitmap::SetTransparencyColor(COLORREF color) // converts transparency value to pixel-based alpha
1465 {
1466         m_TransparencyKey = color;
1467
1468         if (HasAlphaChannel())
1469         {
1470                 BITMAPINFOHEADER bminfoheader;
1471                 ::ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
1472                 bminfoheader.biSize        = sizeof(BITMAPINFOHEADER);
1473                 bminfoheader.biWidth       = GetWidth();
1474                 bminfoheader.biHeight      = GetHeight();
1475                 bminfoheader.biPlanes      = 1;
1476                 bminfoheader.biBitCount    = 32;
1477                 bminfoheader.biCompression = BI_RGB;
1478                
1479                 HDC windowDC = GetWindowDC(GameEngine::GetSingleton()->GetWindow());
1480
1481                 unsigned char* NewPixels = new unsigned char[this->GetWidth() * this->GetHeight() * 4]; // create 32 bit buffer
1482
1483                 for (int count = 0; count < this->GetWidth() * this->GetHeight(); ++count)
1484                 {
1485                         if (RGB(m_PixelsPtr[count * 4 + 2], m_PixelsPtr[count * 4 + 1], m_PixelsPtr[count * 4]) == color) // if the color of this pixel == transparency color
1486                         {
1487                                 ((int*) NewPixels)[count] = 0; // set all four values to zero, this assumes sizeof(int) == 4 on this system
1488                                                                                                 // setting values to zero means premultiplying the RGB values to an alpha of 0
1489                         }
1490                         else ((int*) NewPixels)[count] = ((int*) m_PixelsPtr)[count]; // copy all four values from m_PixelsPtr to NewPixels
1491                 }
1492
1493                 SetDIBits(windowDC, m_Handle, 0, GetHeight(), NewPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // insert pixels into bitmap
1494
1495                 delete[] NewPixels; //destroy buffer
1496
1497                 ReleaseDC(GameEngine::GetSingleton()->GetWindow(), windowDC); // release DC
1498         }
1499 }
1500
1501 COLORREF Bitmap::GetTransparencyColor() const
1502 {
1503         return m_TransparencyKey;
1504 }
1505
1506 void Bitmap::SetOpacity(int opacity)
1507 {
1508         if (HasAlphaChannel())
1509         {
1510                 if (opacity > 100) m_Opacity = 100;
1511                 else if (opacity < 0) m_Opacity = 0;
1512                 else m_Opacity = opacity;
1513         }
1514 }
1515
1516 int Bitmap::GetOpacity() const
1517 {
1518         return m_Opacity;
1519 }
1520
1521 bool Bitmap::IsTarga() const
1522 {
1523         return m_IsTarga;
1524 }
1525
1526 bool Bitmap::HasAlphaChannel() const
1527 {
1528         return m_HasAlphaChannel;
1529 }
1530
1531 //-----------------------------------------------------------------
1532 // Audio methods
1533 //-----------------------------------------------------------------
1534
1535 // set static datamember to zero
1536 int Audio::m_nr = 0;
1537
1538 #pragma warning(disable:4311)
1539 #pragma warning(disable:4312)
1540 Audio::Audio(const tstring& nameRef) : m_Playing(false), m_Paused(false), m_MustRepeat(false), m_hWnd(0), m_Volume(100)
1541 {       
1542         size_t len = nameRef.length();
1543
1544         ASSERT(len >= 4, _T("Audio name length must be longer than 4 characters!"));
1545         if (len < 4) return;
1546
1547         tstring end = nameRef.substr(len - 4);
1548
1549         if (end == _T(".mp3") || end == _T(".wav") || end == _T(".mid"))
1550         {
1551                 tstringstream buffer;
1552                 buffer << _T("audio");
1553                 buffer << m_nr++;
1554
1555                 m_Alias = buffer.str();
1556                 m_FileName = nameRef;
1557
1558                 Create(nameRef);
1559         }
1560 }
1561
1562 Audio::Audio(int IDAudio, const tstring& typeRef) : m_Playing(false), m_Paused(false), m_MustRepeat(false), m_hWnd(0), m_Volume(100)
1563 {
1564         if (typeRef == _T("MP3") || typeRef == _T("WAV") || typeRef == _T("MID"))
1565         {
1566                 tstringstream buffer;
1567                 buffer << _T("audio");
1568                 buffer << m_nr++;
1569
1570                 m_Alias = buffer.str();
1571                 m_FileName = tstring(_T("temp\\")) + m_Alias;
1572
1573                 if (typeRef == _T("MP3")) m_FileName += _T(".mp3");
1574                 else if (typeRef == _T("WAV")) m_FileName += _T(".wav");
1575                 else m_FileName += _T(".mid");
1576                        
1577                 Extract(IDAudio, typeRef, m_FileName);
1578
1579                 Create(m_FileName);
1580         }
1581 }
1582
1583 void Audio::Create(const tstring& nameRef)
1584 {
1585         TCHAR response[100];
1586
1587         tstringstream buffer;
1588
1589         size_t len = nameRef.length();
1590
1591         ASSERT(len >= 4, _T("Audio name length must be longer than 4 characters!"));
1592         if (len < 4) return;
1593
1594         tstring end = nameRef.substr(len - 4);
1595
1596         if (end == _T(".mp3"))
1597         {
1598                 buffer << _T("open \"") + m_FileName + _T("\" type mpegvideo alias ");
1599                 buffer << m_Alias;
1600         }
1601         else if (end == _T(".wav"))
1602         {
1603                 buffer << _T("open \"") + m_FileName + _T("\" type waveaudio alias ");
1604                 buffer << m_Alias;
1605         }
1606         else if (end == _T(".mid"))
1607         {
1608                 buffer << _T("open \"") + m_FileName + _T("\" type sequencer alias ");
1609                 buffer << m_Alias;
1610         }
1611
1612         int result = mciSendString(buffer.str().c_str(), 0, 0, 0);     
1613         if (result != 0) return;
1614        
1615         buffer.str(_T(""));
1616         buffer << _T("set ") + m_Alias + _T(" time format milliseconds");
1617         mciSendString(buffer.str().c_str(), 0, 0, 0);
1618
1619         buffer.str(_T(""));
1620         buffer << _T("status ") + m_Alias + _T(" length");
1621         mciSendString(buffer.str().c_str(), response, 100, 0);
1622
1623         buffer.str(_T(""));
1624         buffer << response;
1625         buffer >> m_Duration;
1626        
1627         // Create a window to catch the MM_MCINOTIFY message with
1628         m_hWnd = CreateWindow(TEXT("STATIC"), TEXT(""), 0, 0, 0, 0, 0, 0, 0, GameEngine::GetSingleton()->GetInstance(), 0);
1629         SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG) AudioProcStatic);     // set the custom message loop (subclassing)
1630         SetWindowLong(m_hWnd, GWL_USERDATA, (LONG) this);                       // set this object as the parameter for the Proc
1631 }
1632
1633 void Audio::Extract(WORD id , const tstring& typeRef, const tstring& fileNameRef) const
1634 {
1635         CreateDirectory(TEXT("temp\\"), NULL);
1636
1637     HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(id), typeRef.c_str());
1638     HGLOBAL hLoaded = LoadResource( NULL, hrsrc);
1639     LPVOID lpLock =  LockResource(hLoaded);
1640     DWORD dwSize = SizeofResource(NULL, hrsrc);
1641     HANDLE hFile = CreateFile(fileNameRef.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1642     DWORD dwByteWritten;
1643     WriteFile(hFile, lpLock , dwSize , &dwByteWritten , NULL);
1644     CloseHandle(hFile);
1645     FreeResource(hLoaded);
1646 }
1647
1648 #pragma warning(default:4311)
1649 #pragma warning(default:4312)
1650
1651 Audio::~Audio()
1652 {
1653         Stop();
1654
1655         tstring sendString = tstring(_T("close")) + m_Alias;
1656         mciSendString(sendString.c_str(), 0, 0, 0);
1657
1658         // release the window resources if necessary
1659         if (m_hWnd)
1660         {
1661                 DestroyWindow(m_hWnd);
1662                 m_hWnd = 0;
1663         }
1664 }
1665
1666 void Audio::Play(int msecStart, int msecStop)
1667 {
1668         if (!m_Playing)
1669         {
1670                 m_Playing = true;
1671                 m_Paused = false;
1672
1673                 if (msecStop == -1) QueuePlayCommand(msecStart);
1674                 else QueuePlayCommand(msecStart, msecStop);
1675         }       
1676         else if (m_Paused)
1677         {
1678                 m_Paused = false;
1679
1680                 QueueResumeCommand();
1681         }
1682 }
1683
1684 void Audio::Pause()
1685 {
1686         if (m_Playing && !m_Paused)
1687         {
1688                 m_Paused = true;
1689
1690                 QueuePauseCommand();
1691         }
1692 }
1693
1694 void Audio::Stop()
1695 {
1696         if (m_Playing)
1697         {
1698                 m_Playing = false;
1699                 m_Paused = false;
1700
1701                 QueueStopCommand();
1702         }
1703 }
1704
1705 void Audio::QueuePlayCommand(int msecStart)
1706 {
1707         tstringstream buffer;
1708         buffer << _T("play ") + m_Alias + _T(" from ");
1709         buffer << msecStart;
1710         buffer << _T(" notify");
1711        
1712         QueueCommand(buffer.str());
1713 }
1714
1715 void Audio::QueuePlayCommand(int msecStart, int msecStop)
1716 {
1717         tstringstream buffer;
1718         buffer << _T("play ") + m_Alias + _T(" from ");
1719         buffer << msecStart;
1720         buffer << _T(" to ");
1721         buffer << msecStop;
1722         buffer << _T(" notify");
1723        
1724         QueueCommand(buffer.str());
1725 }
1726
1727 void Audio::QueuePauseCommand()
1728 {
1729         QueueCommand(_T("pause ") + m_Alias);
1730 }
1731
1732 void Audio::QueueResumeCommand()
1733 {
1734         QueueCommand(_T("resume ") + m_Alias);
1735 }
1736
1737 void Audio::QueueStopCommand()
1738 {
1739         QueueCommand(_T("stop ") + m_Alias);
1740 }
1741
1742 void Audio::QueueVolumeCommand(int volume)
1743 {
1744         tstringstream buffer;
1745         buffer << _T("setaudio ") + m_Alias + _T(" volume to ");
1746         buffer << volume * 10;
1747        
1748         QueueCommand(buffer.str());
1749 }
1750
1751 void Audio::QueueCommand(const tstring& commandRef)
1752 {
1753         m_CommandQueue.push(commandRef);
1754 }
1755
1756 void Audio::Tick()
1757 {
1758         if (!m_CommandQueue.empty())
1759         {
1760                 SendMCICommand(m_CommandQueue.front());
1761                 m_CommandQueue.pop();
1762         }
1763 }
1764
1765 void Audio::SendMCICommand(const tstring& commandRef) const
1766 {
1767         int result = mciSendString(commandRef.c_str(), 0, 0, m_hWnd);
1768 }
1769
1770 const tstring& Audio::GetName() const
1771 {
1772         return m_FileName;
1773 }
1774        
1775 const tstring& Audio::GetAlias() const
1776 {
1777         return m_Alias;
1778 }
1779
1780 bool Audio::IsPlaying() const
1781 {
1782         return m_Playing;
1783 }
1784
1785 bool Audio::IsPaused() const
1786 {
1787         return m_Paused;
1788 }
1789
1790 void Audio::SwitchPlayingOff()
1791 {
1792         m_Playing = false;
1793         m_Paused = false;
1794 }
1795
1796 void Audio::SetRepeat(bool repeat)
1797 {
1798         m_MustRepeat = repeat;
1799 }
1800
1801 bool Audio::GetRepeat() const
1802 {
1803         return m_MustRepeat;
1804 }
1805
1806 int Audio::GetDuration() const
1807 {
1808         return m_Duration;
1809 }
1810
1811 void Audio::SetVolume(int volume)
1812 {
1813         m_Volume = min(100, max(0, volume));    // values below 0 and above 100 are trimmed to 0 and 100, respectively
1814
1815         QueueVolumeCommand(volume);
1816 }
1817
1818 int Audio::GetVolume() const
1819 {
1820         return m_Volume;
1821 }
1822
1823 bool Audio::Exists() const
1824 {
1825         return m_hWnd?true:false;
1826 }
1827
1828 int Audio::GetType() const
1829 {
1830         return Caller::Audio;
1831 }
1832
1833 LRESULT Audio::AudioProcStatic(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1834 {       
1835         #pragma warning(disable: 4312)
1836         Audio* audio = reinterpret_cast<Audio*>(GetWindowLong(hWnd, GWL_USERDATA));
1837         #pragma warning(default: 4312)
1838
1839         switch (msg)
1840         {               
1841         case MM_MCINOTIFY: // message received when an audio file has finished playing - used for repeat function
1842
1843                 if (wParam == MCI_NOTIFY_SUCCESSFUL && audio->IsPlaying())
1844                 {
1845                         audio->SwitchPlayingOff();
1846
1847                         if (audio->GetRepeat()) audio->Play();  // repeat the audio
1848                         else audio->CallListeners();                    // notify listeners that the audio file has come to an end
1849                 }
1850         }
1851         return 0;       
1852 }
1853
1854 //-----------------------------------------------------------------
1855 // TextBox methods
1856 //-----------------------------------------------------------------
1857
1858 #pragma warning(disable:4311)   
1859 #pragma warning(disable:4312)
1860 TextBox::TextBox(const tstring& textRef) : m_x(0), m_y(0), m_BgColor(RGB(255, 255, 255)), m_ForeColor(RGB(0, 0, 0)), m_BgColorBrush(0), m_Font(0), m_OldFont(0)
1861 {
1862         // Create the edit box
1863         m_hWndEdit = CreateWindow(_T("EDIT"), textRef.c_str(), WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 0, 0, 0, 0, GameEngine::GetSingleton()->GetWindow(), NULL, GameEngine::GetSingleton()->GetInstance(), NULL);
1864
1865         // Set de nieuwe WNDPROC voor de edit box, en houd de oude bij
1866         m_procOldEdit = (WNDPROC) SetWindowLong(m_hWndEdit, GWL_WNDPROC, (LONG) EditProcStatic);
1867
1868         // Stel dit object in als userdata voor de statische wndproc functie van de edit box zodat deze members kan aanroepen
1869         SetWindowLong(m_hWndEdit, GWL_USERDATA, (LONG) this);
1870 }
1871
1872 TextBox::TextBox() : m_x(0), m_y(0), m_BgColor(RGB(255, 255, 255)), m_ForeColor(RGB(0, 0, 0)), m_BgColorBrush(0), m_Font(0), m_OldFont(0)
1873 {
1874         // Create the edit box
1875         m_hWndEdit = CreateWindow(_T("EDIT"), _T(""), WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 0, 0, 0, 0, GameEngine::GetSingleton()->GetWindow(), NULL, GameEngine::GetSingleton()->GetInstance(), NULL);
1876
1877         // Set de nieuwe WNDPROC voor de edit box, en houd de oude bij
1878         m_procOldEdit = (WNDPROC) SetWindowLong(m_hWndEdit, GWL_WNDPROC, (LONG) EditProcStatic);
1879
1880         // Stel dit object in als userdata voor de statische wndproc functie van de edit box zodat deze members kan aanroepen
1881         SetWindowLong(m_hWndEdit, GWL_USERDATA, (LONG) this);
1882 }
1883 #pragma warning(default:4311)
1884 #pragma warning(default:4312)
1885
1886 TextBox::~TextBox()
1887 {
1888         // release the background brush if necessary
1889         if (m_BgColorBrush != 0)
1890         {
1891                 DeleteObject(m_BgColorBrush);
1892                 m_BgColorBrush = 0;
1893         }
1894
1895         // release the font if necessary
1896         if (m_Font != 0)
1897         {
1898                 SelectObject(GetDC(m_hWndEdit), m_OldFont);
1899                 DeleteObject(m_Font);
1900                 m_Font = m_OldFont = 0;
1901         }
1902                
1903         // release the window resources
1904         DestroyWindow(m_hWndEdit);
1905         m_hWndEdit = NULL;
1906 }
1907
1908 void TextBox::SetBounds(int x, int y, int width, int height)
1909 {
1910         m_x = x;
1911         m_y = y;
1912
1913         MoveWindow(m_hWndEdit, x, y, width, height, true);
1914 }
1915
1916 RECT TextBox::GetRect() const
1917 {
1918         RECT rc;
1919
1920         GetClientRect(m_hWndEdit, &rc);
1921
1922         rc.left += m_x;
1923         rc.right += m_x;
1924         rc.top += m_y;
1925         rc.bottom += m_y;
1926
1927         return rc;
1928 }
1929
1930 void TextBox::SetEnabled(bool bEnable)
1931 {
1932         EnableWindow(m_hWndEdit, bEnable);
1933 }
1934
1935 void TextBox::Update() const
1936 {
1937         UpdateWindow(m_hWndEdit);
1938 }
1939
1940 void TextBox::Show() const
1941 {
1942         // Show and update the edit box
1943         ShowWindow(m_hWndEdit, SW_SHOW);
1944         UpdateWindow(m_hWndEdit);
1945 }
1946
1947 void TextBox::Hide() const
1948 {
1949         // Show and update the edit box
1950         ShowWindow(m_hWndEdit, SW_HIDE);
1951         UpdateWindow(m_hWndEdit);
1952 }
1953
1954 tstring TextBox::GetText() const
1955 {
1956         int textLength = (int) SendMessage(m_hWndEdit, (UINT) WM_GETTEXTLENGTH, 0, 0);
1957        
1958         TCHAR* buffer = new TCHAR[textLength + 1];
1959
1960         SendMessage(m_hWndEdit, (UINT) WM_GETTEXT, (WPARAM) textLength + 1, (LPARAM) buffer);
1961
1962         tstring newString(buffer);
1963
1964         delete buffer;
1965
1966         return newString;
1967 }
1968
1969 void TextBox::SetText(const tstring& textRef)
1970 {
1971         SendMessage(m_hWndEdit, WM_SETTEXT, 0, (LPARAM) textRef.c_str());
1972 }
1973
1974 void TextBox::SetFont(const tstring& fontNameRef, bool bold, bool italic, bool underline, int size)
1975 {
1976         LOGFONT ft;
1977
1978         //_tcscpy_s(ft.lfFaceName, sizeof(ft.lfFaceName) / sizeof(TCHAR), fontName.c_str());
1979         for (int teller = 0; teller < (int) fontNameRef.size() && teller < LF_FACESIZE; ++teller)
1980         {
1981                 ft.lfFaceName[teller] = fontNameRef[teller];
1982         }
1983
1984         ft.lfStrikeOut = 0;
1985         ft.lfUnderline = underline?1:0;
1986         ft.lfHeight = size;
1987     ft.lfEscapement = 0;
1988         ft.lfWeight = bold?FW_BOLD:0;
1989         ft.lfItalic = italic?1:0;
1990
1991         // clean up if another custom font was already in place
1992         if (m_Font != 0) { DeleteObject(m_Font); }
1993
1994         // create the new font. The WM_CTLCOLOREDIT message will set the font when the textbox is about to redraw
1995     m_Font = CreateFontIndirect(&ft);
1996
1997         // redraw the textbox
1998         InvalidateRect(m_hWndEdit, NULL, true);
1999 }
2000
2001 void TextBox::SetForecolor( COLORREF color )
2002 {
2003         m_ForeColor = color;
2004        
2005         // redraw the textbox
2006         InvalidateRect(m_hWndEdit, NULL, true);
2007 }
2008
2009 void TextBox::SetBackcolor( COLORREF color )
2010 {
2011         m_BgColor = color;
2012        
2013         if (m_BgColorBrush != 0) DeleteObject(m_BgColorBrush);
2014         m_BgColorBrush = CreateSolidBrush( color );
2015        
2016         // redraw the textbox
2017         InvalidateRect(m_hWndEdit, NULL, true);
2018 }
2019
2020 COLORREF TextBox::GetForecolor() const
2021 {
2022         return m_ForeColor;
2023 }
2024
2025 COLORREF TextBox::GetBackcolor() const
2026 {
2027         return m_BgColor;
2028 }
2029
2030 HBRUSH TextBox::GetBackcolorBrush() const
2031 {
2032         return m_BgColorBrush;
2033 }
2034
2035 LRESULT TextBox::EditProcStatic(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2036 {
2037         #pragma warning(disable: 4312)
2038         return reinterpret_cast<TextBox*>(GetWindowLong(hWnd, GWL_USERDATA))->EditProc(hWnd, msg, wParam, lParam);
2039         #pragma warning(default: 4312)
2040 }
2041
2042 LRESULT TextBox::EditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2043 {
2044         switch (msg)
2045         {               
2046         case WM_CTLCOLOREDIT:
2047                 SetBkColor((HDC) wParam, GetBackcolor() );
2048                 SetTextColor((HDC) wParam, GetForecolor() );
2049                 if (m_Font != 0)
2050                 {
2051                         if (m_OldFont == 0) m_OldFont = (HFONT) SelectObject((HDC) wParam, m_Font);
2052                         else SelectObject((HDC) wParam, m_Font);
2053                 }
2054                 return (LRESULT) GetBackcolorBrush();
2055
2056         case WM_CHAR:
2057                 if (wParam == VK_TAB) return 0;
2058                 if (wParam == VK_RETURN) return 0;
2059                 break;
2060
2061         case WM_KEYDOWN :
2062                 switch (wParam)
2063                 {
2064                 case VK_TAB:
2065                         if (GameEngine::GetSingleton()->IsKeyDown(VK_SHIFT)) GameEngine::GetSingleton()->TabPrevious(hWnd);
2066                         else GameEngine::GetSingleton()->TabNext(hWnd);
2067                         return 0;
2068                 case VK_ESCAPE:
2069                         SetFocus(GetParent(hWnd));
2070                         return 0;
2071                 case VK_RETURN:
2072                         //if (m_Target) result = m_Target->CallAction(this);
2073                         CallListeners();
2074                         break;
2075                 }
2076         }
2077         return CallWindowProc(m_procOldEdit, hWnd, msg, wParam, lParam);
2078 }
2079
2080
2081
2082 //-----------------------------------------------------------------
2083 // Button methods
2084 //-----------------------------------------------------------------
2085
2086 #pragma warning(disable:4311)
2087 #pragma warning(disable:4312)
2088 Button::Button(const tstring& textRef) : m_x(0), m_y(0), m_Armed(false), m_Font(0), m_OldFont(0)
2089 {
2090         // Create the button object
2091         m_hWndButton = CreateWindow(_T("BUTTON"), textRef.c_str(), WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | BS_PUSHBUTTON, 0, 0, 0, 0, GameEngine::GetSingleton()->GetWindow(), NULL, GameEngine::GetSingleton()->GetInstance(), NULL);
2092
2093         // Set de new WNDPROC for the button, and store the old one
2094         m_procOldButton = (WNDPROC) SetWindowLong(m_hWndButton, GWL_WNDPROC, (LONG) ButtonProcStatic);
2095
2096         // Store 'this' as data for the Button object so that the static PROC can call the member proc
2097         SetWindowLong(m_hWndButton, GWL_USERDATA, (LONG) this);
2098 }
2099
2100 Button::Button() : m_x(0), m_y(0), m_Armed(false), m_Font(0), m_OldFont(0)
2101 {
2102         // Create the button object
2103         m_hWndButton = CreateWindow(_T("BUTTON"), _T(""), WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | BS_PUSHBUTTON, 0, 0, 0, 0, GameEngine::GetSingleton()->GetWindow(), NULL, GameEngine::GetSingleton()->GetInstance(), NULL);
2104
2105         // Set de new WNDPROC for the button, and store the old one
2106         m_procOldButton = (WNDPROC) SetWindowLong(m_hWndButton, GWL_WNDPROC, (LONG) ButtonProcStatic);
2107
2108         // Store 'this' as data for the Button object so that the static PROC can call the member proc
2109         SetWindowLong(m_hWndButton, GWL_USERDATA, (LONG) this);
2110 }
2111 #pragma warning(default:4311)
2112 #pragma warning(default:4312)
2113
2114 Button::~Button()
2115 {
2116         // release the font if necessary
2117         if (m_Font != 0)
2118         {
2119                 SelectObject(GetDC(m_hWndButton), m_OldFont);
2120                 DeleteObject(m_Font);
2121                 m_Font = m_OldFont = 0;
2122         }
2123                
2124         // release the window resource
2125         DestroyWindow(m_hWndButton);
2126         m_hWndButton = NULL;   
2127 }
2128
2129 void Button::SetBounds(int x, int y, int width, int height)
2130 {
2131         m_x = x;
2132         m_y = y;
2133
2134         MoveWindow(m_hWndButton, x, y, width, height, true);
2135 }
2136
2137 RECT Button::GetRect() const
2138 {
2139         RECT rc;
2140
2141         GetClientRect(m_hWndButton, &rc);
2142        
2143         rc.left += m_x;
2144         rc.right += m_x;
2145         rc.top += m_y;
2146         rc.bottom += m_y;
2147
2148         return rc;
2149 }
2150
2151 void Button::SetEnabled(bool bEnable)
2152 {
2153         EnableWindow(m_hWndButton, bEnable);
2154 }
2155
2156 void Button::Update() const
2157 {
2158         UpdateWindow(m_hWndButton);
2159 }
2160
2161 void Button::Show() const
2162 {
2163         // Show and update the button
2164         ShowWindow(m_hWndButton, SW_SHOW);
2165         UpdateWindow(m_hWndButton);
2166 }
2167
2168 void Button::Hide() const
2169 {
2170         // Show and update the button
2171         ShowWindow(m_hWndButton, SW_HIDE);
2172         UpdateWindow(m_hWndButton);
2173 }
2174
2175 tstring Button::GetText() const
2176 {
2177         int textLength = (int) SendMessage(m_hWndButton, (UINT) WM_GETTEXTLENGTH, 0, 0);
2178        
2179         TCHAR* buffer = new TCHAR[textLength + 1];
2180
2181         SendMessage(m_hWndButton, (UINT) WM_GETTEXT, (WPARAM) textLength + 1, (LPARAM) buffer);
2182
2183         tstring newString(buffer);
2184
2185         delete buffer;
2186
2187         return newString;
2188 }
2189
2190 void Button::SetText(const tstring& textRef)
2191 {
2192         SendMessage(m_hWndButton, WM_SETTEXT, 0, (LPARAM) textRef.c_str());
2193 }
2194
2195 void Button::SetFont(const tstring& fontNameRef, bool bold, bool italic, bool underline, int size)
2196 {
2197         LOGFONT ft;
2198
2199         //_tcscpy_s(ft.lfFaceName, sizeof(ft.lfFaceName) / sizeof(TCHAR), fontName.c_str());
2200         for (int teller = 0; teller < (int) fontNameRef.size() && teller < LF_FACESIZE; ++teller)
2201         {
2202                 ft.lfFaceName[teller] = fontNameRef[teller];
2203         }
2204
2205         ft.lfStrikeOut = 0;
2206         ft.lfUnderline = underline?1:0;
2207         ft.lfHeight = size;
2208     ft.lfEscapement = 0;
2209         ft.lfWeight = bold?FW_BOLD:0;
2210         ft.lfItalic = italic?1:0;
2211
2212         // clean up if another custom font was already in place
2213         if (m_Font != 0) { DeleteObject(m_Font); }
2214
2215         // create the new font. The WM_CTLCOLOREDIT message will set the font when the button is about to redraw
2216     m_Font = CreateFontIndirect(&ft);
2217
2218         // redraw the button
2219         InvalidateRect(m_hWndButton, NULL, true);
2220 }
2221
2222 LRESULT Button::ButtonProcStatic(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2223 {
2224         #pragma warning(disable: 4312)
2225         return reinterpret_cast<Button*>(GetWindowLong(hWnd, GWL_USERDATA))->ButtonProc(hWnd, msg, wParam, lParam);
2226         #pragma warning(default: 4312)
2227 }
2228
2229 LRESULT Button::ButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2230 {
2231         switch (msg)
2232         {
2233         case WM_CTLCOLOREDIT:
2234                 if (m_Font != 0)
2235                 {
2236                         if (m_OldFont == 0) m_OldFont = (HFONT) SelectObject((HDC) wParam, m_Font);
2237                         else SelectObject((HDC) wParam, m_Font);
2238                 }
2239                 return 0;
2240
2241         case WM_CHAR:
2242                 if (wParam == VK_TAB) return 0;
2243                 if (wParam == VK_RETURN) return 0;
2244                 break;
2245
2246         case WM_KEYDOWN :
2247                 switch (wParam)
2248                 {
2249                 case VK_TAB:                   
2250                         if (GameEngine::GetSingleton()->IsKeyDown(VK_SHIFT)) GameEngine::GetSingleton()->TabPrevious(hWnd);
2251                         else GameEngine::GetSingleton()->TabNext(hWnd);
2252                         return 0;
2253                 case VK_ESCAPE:
2254                         SetFocus(GetParent(hWnd));
2255                         return 0;
2256                 case VK_SPACE:
2257                         //if (m_Target) result = m_Target->CallAction(this);
2258                         CallListeners();
2259                         break;
2260                 }
2261                 break;
2262         case WM_LBUTTONDOWN :
2263         case WM_LBUTTONDBLCLK:                                  // clicking fast will throw LBUTTONDBLCLK's as well as LBUTTONDOWN's, you need to capture both to catch all button clicks
2264                 m_Armed = true;
2265                 break;
2266         case WM_LBUTTONUP :
2267                 if (m_Armed)
2268                 {
2269                         RECT rc;
2270                         POINT pt;
2271                         GetWindowRect(hWnd, &rc);
2272                         GetCursorPos(&pt);
2273
2274                         //if (PtInRect(&rc, pt) && m_Target) result = m_Target->CallAction(this);
2275                         if (PtInRect(&rc, pt)) CallListeners();
2276
2277                         m_Armed = false;
2278                 }
2279         }
2280         return CallWindowProc(m_procOldButton, hWnd, msg, wParam, lParam);
2281 }
2282
2283 //-----------------------------------------------------------------
2284 // Timer methods
2285 //-----------------------------------------------------------------
2286
2287 Timer::Timer(int msec, Callable* targetPtr) : m_IsRunning(false)
2288 {
2289         m_Delay = msec;
2290
2291         AddActionListener(targetPtr);
2292 }
2293
2294 Timer::~Timer()
2295 {
2296         if (m_IsRunning) Stop(); // stop closes the handle
2297
2298         // no objects to delete
2299 }
2300
2301 void Timer::Start()
2302 {
2303         if (m_IsRunning == false)
2304         {
2305                 CreateTimerQueueTimer(&m_TimerHandle, NULL, TimerProcStatic, (void*) this, m_Delay, m_Delay, WT_EXECUTEINTIMERTHREAD); 
2306                 m_IsRunning = true;
2307         }
2308 }
2309
2310 void Timer::Stop()
2311 {       
2312         if (m_IsRunning == true)
2313         {
2314                 DeleteTimerQueueTimer(NULL, m_TimerHandle, NULL); 
2315                 //CloseHandle (m_TimerHandle);          DeleteTimerQueueTimer automatically closes the handle? MSDN Documentation seems to suggest this
2316                 
2317                 m_IsRunning = false;
2318         }
2319 }
2320
2321 bool Timer::IsRunning() const
2322 {
2323         return m_IsRunning;
2324 }
2325
2326 void Timer::SetDelay(int msec)
2327 {
2328         m_Delay = max(msec, 1); // timer will not accept values less than 1 msec
2329
2330         if (m_IsRunning)
2331         {
2332                 Stop();
2333                 Start();
2334         }
2335 }
2336
2337 int Timer::GetDelay() const
2338 {
2339         return m_Delay;
2340 }
2341
2342 void CALLBACK Timer::TimerProcStatic(void* lpParameter, BOOLEAN TimerOrWaitFired)
2343 {
2344         Timer* timer = reinterpret_cast<Timer*>(lpParameter);
2345
2346         //if (timer->m_IsRunning) timer->m_Target->CallAction(timer);
2347         if (timer->m_IsRunning) timer->CallListeners();
2348 }
2349
2350 //-----------------------------------------------------------------
2351 // Targa loader code
2352 //-----------------------------------------------------------------
2353  
2354 #define IMG_OK              0x1
2355 #define IMG_ERR_NO_FILE     0x2
2356 #define IMG_ERR_MEM_FAIL    0x4
2357 #define IMG_ERR_BAD_FORMAT  0x8
2358 #define IMG_ERR_UNSUPPORTED 0x40
2359  
2360 TargaLoader::TargaLoader()
2361 {
2362         pImage=pPalette=pData=NULL;
2363         iWidth=iHeight=iBPP=bEnc=0;
2364         lImageSize=0;
2365 }
2366  
2367 TargaLoader::~TargaLoader()
2368 {
2369         if(pImage)
2370         {
2371                 delete [] pImage;
2372                 pImage=NULL;
2373         }
2374  
2375         if(pPalette)
2376         {
2377                 delete [] pPalette;
2378                 pPalette=NULL;
2379         }
2380  
2381         if(pData)
2382         {
2383                 delete [] pData;
2384                 pData=NULL;
2385         }
2386 }
2387  
2388 int TargaLoader::Load(const TCHAR* fileNamePtr)
2389 {
2390         using namespace std;
2391         ifstream fIn;
2392         unsigned long ulSize;
2393         int iRet;
2394  
2395         // Clear out any existing image and palette
2396         if(pImage)
2397     {
2398                 delete [] pImage;
2399                 pImage=NULL;
2400     }
2401  
2402         if(pPalette)
2403     {
2404                 delete [] pPalette;
2405                 pPalette=NULL;
2406     }
2407  
2408         // Open the specified file
2409         //fIn.open(szFilename,ios::binary);
2410         fIn.open(fileNamePtr,ios::binary);
2411    
2412         if(fIn==NULL) return IMG_ERR_NO_FILE;
2413  
2414         // Get file size
2415         fIn.seekg(0,ios_base::end);
2416         ulSize=fIn.tellg();
2417         fIn.seekg(0,ios_base::beg);
2418  
2419         // Allocate some space
2420         // Check and clear pDat, just in case
2421         if(pData) delete [] pData;
2422  
2423         pData=new unsigned char[ulSize];
2424  
2425         if(pData==NULL)
2426     {
2427                 fIn.close();
2428                 return IMG_ERR_MEM_FAIL;
2429         }
2430  
2431         // Read the file into memory
2432         fIn.read((char*)pData,ulSize);
2433  
2434         fIn.close();
2435  
2436         // Process the header
2437         iRet=ReadHeader();
2438  
2439         if(iRet!=IMG_OK) return iRet;
2440  
2441         switch(bEnc)
2442         {
2443     case 1: // Raw Indexed
2444                 // Check filesize against header values
2445         if((lImageSize+18+pData[0]+768)>ulSize) return IMG_ERR_BAD_FORMAT;
2446  
2447                 // Double check image type field
2448                 if(pData[1]!=1) return IMG_ERR_BAD_FORMAT;
2449  
2450                 // Load image data
2451                 iRet=LoadRawData();
2452        
2453                 if(iRet!=IMG_OK) return iRet;
2454  
2455                 // Load palette
2456         iRet=LoadTgaPalette();
2457        
2458                 if(iRet!=IMG_OK) return iRet;
2459  
2460        break;
2461  
2462     case 2: // Raw RGB
2463                 // Check filesize against header values
2464                 if((lImageSize+18+pData[0])>ulSize) return IMG_ERR_BAD_FORMAT;
2465  
2466                 // Double check image type field
2467         if(pData[1]!=0) return IMG_ERR_BAD_FORMAT;
2468  
2469                 // Load image data
2470                 iRet=LoadRawData();
2471        
2472                 if(iRet!=IMG_OK) return iRet;
2473  
2474                 //BGRtoRGB(); // Convert to RGB
2475                 break;
2476  
2477     case 9: // RLE Indexed
2478         // Double check image type field
2479         if(pData[1]!=1) return IMG_ERR_BAD_FORMAT;
2480  
2481                 // Load image data
2482                 iRet=LoadTgaRLEData();
2483                        
2484                 if(iRet!=IMG_OK) return iRet;
2485  
2486                 // Load palette
2487                 iRet=LoadTgaPalette();
2488        
2489                 if(iRet!=IMG_OK) return iRet;
2490  
2491                 break;
2492        
2493         case 10: // RLE RGB
2494        // Double check image type field
2495        if(pData[1]!=0) return IMG_ERR_BAD_FORMAT;
2496  
2497        // Load image data
2498        iRet=LoadTgaRLEData();
2499        
2500            if(iRet!=IMG_OK) return iRet;
2501  
2502        //BGRtoRGB(); // Convert to RGB
2503        break;
2504  
2505         default:
2506                 return IMG_ERR_UNSUPPORTED;
2507     }
2508  
2509         // Check flip bit
2510         if((pData[17] & 0x20)==0) FlipImg();
2511  
2512         // Release file memory
2513         delete [] pData;
2514         pData=NULL;
2515
2516         return IMG_OK;
2517 }
2518  
2519 int TargaLoader::ReadHeader() // Examine the header and populate our class attributes
2520 {
2521         short ColMapStart,ColMapLen;
2522         short x1,y1,x2,y2;
2523  
2524         if(pData==NULL)
2525                 return IMG_ERR_NO_FILE;
2526  
2527         if(pData[1]>1)    // 0 (RGB) and 1 (Indexed) are the only types we know about
2528                 return IMG_ERR_UNSUPPORTED;
2529  
2530         bEnc=pData[2];     // Encoding flag  1 = Raw indexed image
2531                       //                2 = Raw RGB
2532                       //                3 = Raw greyscale
2533                       //                9 = RLE indexed
2534                       //               10 = RLE RGB
2535                       //               11 = RLE greyscale
2536                       //               32 & 33 Other compression, indexed
2537  
2538         if(bEnc>11)       // We don't want 32 or 33
2539                 return IMG_ERR_UNSUPPORTED;
2540  
2541  
2542         // Get palette info
2543         memcpy(&ColMapStart,&pData[3],2);
2544         memcpy(&ColMapLen,&pData[5],2);
2545  
2546         // Reject indexed images if not a VGA palette (256 entries with 24 bits per entry)
2547         if(pData[1]==1) // Indexed
2548     {
2549                 if(ColMapStart!=0 || ColMapLen!=256 || pData[7]!=24) return IMG_ERR_UNSUPPORTED;
2550     }
2551  
2552         // Get image window and produce width & height values
2553         memcpy(&x1,&pData[8],2);
2554         memcpy(&y1,&pData[10],2);
2555         memcpy(&x2,&pData[12],2);
2556         memcpy(&y2,&pData[14],2);
2557  
2558         iWidth=(x2-x1);
2559         iHeight=(y2-y1);
2560  
2561         if(iWidth<1 || iHeight<1) return IMG_ERR_BAD_FORMAT;
2562  
2563         // Bits per Pixel
2564         iBPP=pData[16];
2565  
2566         // Check flip / interleave byte
2567         if(pData[17]>32) // Interleaved data
2568                 return IMG_ERR_UNSUPPORTED;
2569  
2570         // Calculate image size
2571         lImageSize=(iWidth * iHeight * (iBPP/8));
2572  
2573         return IMG_OK;
2574 }
2575  
2576 int TargaLoader::LoadRawData() // Load uncompressed image data
2577 {
2578         short iOffset;
2579  
2580         if(pImage) // Clear old data if present
2581                 delete [] pImage;
2582  
2583         pImage=new unsigned char[lImageSize];
2584  
2585         if(pImage==NULL) return IMG_ERR_MEM_FAIL;
2586  
2587         iOffset=pData[0]+18; // Add header to ident field size
2588  
2589         if(pData[1]==1) // Indexed images
2590                 iOffset+=768;  // Add palette offset
2591  
2592         memcpy(pImage,&pData[iOffset],lImageSize);
2593  
2594         return IMG_OK;
2595 }
2596  
2597 int TargaLoader::LoadTgaRLEData() // Load RLE compressed image data
2598 {
2599         short iOffset,iPixelSize;
2600         unsigned char *pCur;
2601         unsigned long Index=0;
2602         unsigned char bLength,bLoop;
2603  
2604         // Calculate offset to image data
2605         iOffset=pData[0]+18;
2606  
2607         // Add palette offset for indexed images
2608         if(pData[1]==1) iOffset+=768;
2609  
2610         // Get pixel size in bytes
2611         iPixelSize=iBPP/8;
2612  
2613         // Set our pointer to the beginning of the image data
2614         pCur=&pData[iOffset];
2615  
2616         // Allocate space for the image data
2617         if(pImage!=NULL) delete [] pImage;
2618  
2619         pImage=new unsigned char[lImageSize];
2620  
2621         if(pImage==NULL) return IMG_ERR_MEM_FAIL;
2622  
2623         // Decode
2624         while(Index<lImageSize)
2625     {
2626                 if(*pCur & 0x80) // Run length chunk (High bit = 1)
2627                 {
2628                         bLength=*pCur-127; // Get run length
2629                         pCur++;            // Move to pixel data 
2630  
2631                         // Repeat the next pixel bLength times
2632                         for(bLoop=0;bLoop!=bLength;++bLoop,Index+=iPixelSize)
2633                         memcpy(&pImage[Index],pCur,iPixelSize);
2634  
2635                         pCur+=iPixelSize; // Move to the next descriptor chunk
2636                 }
2637                 else // Raw chunk
2638                 {
2639                         bLength=*pCur+1; // Get run length
2640                         pCur++;          // Move to pixel data
2641  
2642                         // Write the next bLength pixels directly
2643                         for(bLoop=0;bLoop!=bLength;++bLoop,Index+=iPixelSize,pCur+=iPixelSize)
2644                         memcpy(&pImage[Index],pCur,iPixelSize);
2645                 }
2646     }
2647  
2648         return IMG_OK;
2649 }
2650  
2651 int TargaLoader::LoadTgaPalette() // Load a 256 color palette
2652 {
2653         unsigned char bTemp;
2654         short iIndex,iPalPtr;
2655  
2656         // Delete old palette if present
2657         if(pPalette)
2658     {
2659                 delete [] pPalette;
2660                 pPalette=NULL;
2661     }
2662  
2663         // Create space for new palette
2664         pPalette=new unsigned char[768];
2665  
2666         if(pPalette==NULL) return IMG_ERR_MEM_FAIL;
2667  
2668         // VGA palette is the 768 bytes following the header
2669         memcpy(pPalette,&pData[pData[0]+18],768);
2670  
2671         // Palette entries are BGR ordered so we have to convert to RGB
2672         for(iIndex=0,iPalPtr=0;iIndex!=256;++iIndex,iPalPtr+=3)
2673     {
2674                 bTemp=pPalette[iPalPtr];               // Get Blue value
2675                 pPalette[iPalPtr]=pPalette[iPalPtr+2]; // Copy Red to Blue
2676                 pPalette[iPalPtr+2]=bTemp;             // Replace Blue at the end
2677         }
2678  
2679         return IMG_OK;
2680 }
2681  
2682 void TargaLoader::BGRtoRGB() // Convert BGR to RGB (or back again)
2683 {
2684         unsigned long Index,nPixels;
2685         unsigned char *bCur;
2686         unsigned char bTemp;
2687         short iPixelSize;
2688  
2689         // Set ptr to start of image
2690         bCur=pImage;
2691  
2692         // Calc number of pixels
2693         nPixels=iWidth*iHeight;
2694  
2695         // Get pixel size in bytes
2696         iPixelSize=iBPP/8;
2697  
2698         for(Index=0;Index!=nPixels;Index++)  // For each pixel
2699     {
2700                 bTemp=*bCur;      // Get Blue value
2701                 *bCur=*(bCur+2);  // Swap red value into first position
2702                 *(bCur+2)=bTemp;  // Write back blue to last position
2703  
2704                 bCur+=iPixelSize; // Jump to next pixel
2705     }
2706 }
2707  
2708 void TargaLoader::FlipImg() // Flips the image vertically (Why store images upside down?)
2709 {
2710         unsigned char bTemp;
2711         unsigned char *pLine1, *pLine2;
2712         int iLineLen,iIndex;
2713  
2714         iLineLen=iWidth*(iBPP/8);
2715         pLine1=pImage;
2716         pLine2=&pImage[iLineLen * (iHeight - 1)];
2717  
2718         for( ;pLine1<pLine2;pLine2-=(iLineLen*2))
2719     {
2720                 for(iIndex=0;iIndex!=iLineLen;pLine1++,pLine2++,iIndex++)
2721                 {
2722                         bTemp=*pLine1;
2723                         *pLine1=*pLine2;
2724                         *pLine2=bTemp;       
2725                 }
2726         } 
2727 }
2728  
2729 int TargaLoader::GetBPP() const
2730 {
2731         return iBPP;
2732 }
2733  
2734 int TargaLoader::GetWidth() const
2735 {
2736         return iWidth;
2737 }
2738  
2739 int TargaLoader::GetHeight() const
2740 {
2741         return iHeight;
2742 }
2743  
2744 const unsigned char* TargaLoader::GetImg() const
2745 {
2746         return pImage;
2747 }
2748  
2749 const unsigned char* TargaLoader::GetPalette() const
2750 {
2751         return pPalette;
2752 }
2753
2754 //-----------------------------------------------------------------
2755 // OutputDebugString functions
2756 //-----------------------------------------------------------------
2757
2758 void OutputDebugString(const tstring& textRef)
2759 {
2760         OutputDebugString(textRef.c_str());
2761 }
2762
2763
2764 //---------------------------
2765 // HitRegion methods
2766 //---------------------------
2767 HitRegion::HitRegion() : m_HitRegion(0)
2768 {
2769         // nothing to create
2770 }
2771
2772 HitRegion::~HitRegion()
2773 {
2774         if (m_HitRegion)
2775                 DeleteObject(m_HitRegion);
2776 }
2777
2778
2779 bool HitRegion::Create(int type, int x, int y, int width, int height)
2780 {
2781         if (m_HitRegion) DeleteObject(m_HitRegion);
2782
2783         if (type == HitRegion::Ellipse)
2784                 m_HitRegion = CreateEllipticRgn(x, y, x + width, y + height);
2785         else
2786                 m_HitRegion = CreateRectRgn(x, y, x + width, y + height);
2787
2788         return true;
2789 }
2790
2791 bool HitRegion::Create(int type, const POINT* pointsArr, int numberOfPoints)
2792 {
2793         if (m_HitRegion) DeleteObject(m_HitRegion);
2794
2795         m_HitRegion = CreatePolygonRgn(pointsArr, numberOfPoints, WINDING);
2796
2797         return true;
2798 }       
2799
2800 bool HitRegion::Create(int type, const Bitmap* bmpPtr, COLORREF cTransparent, COLORREF cTolerance)
2801 {
2802         if (!bmpPtr->Exists()) return false;
2803
2804         HBITMAP hBitmap = bmpPtr->GetHandle();
2805
2806         if (!hBitmap) return false;
2807
2808         if (m_HitRegion) DeleteObject(m_HitRegion);
2809
2810         // for some reason, the BitmapToRegion function has R and B switched. Flipping the colors to get the right result.
2811         COLORREF flippedTransparent = RGB(GetBValue(cTransparent), GetGValue(cTransparent), GetRValue(cTransparent));
2812         COLORREF flippedTolerance = RGB(GetBValue(cTolerance), GetGValue(cTolerance), GetRValue(cTolerance));
2813
2814         m_HitRegion = BitmapToRegion(hBitmap, flippedTransparent, flippedTolerance);
2815
2816         return (m_HitRegion?true:false);
2817 }       
2818
2819 //      BitmapToRegion :        Create a region from the "non-transparent" pixels of a bitmap
2820 //      Author :                Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998
2821 //  Some modifications: Kevin Hoefman, Febr 2007
2822 HRGN HitRegion::BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor, COLORREF cTolerance) const
2823 {
2824         HRGN hRgn = NULL;
2825
2826         if (hBmp)
2827         {
2828                 // Create a memory DC inside which we will scan the bitmap content
2829                 HDC hMemDC = CreateCompatibleDC(NULL);
2830
2831                 if (hMemDC)
2832                 {
2833                         // Get bitmap siz
2834                         BITMAP bm;
2835                         GetObject(hBmp, sizeof(bm), &bm);
2836
2837                         // Create a 32 bits depth bitmap and select it into the memory DC
2838                         BITMAPINFOHEADER RGB32BITSBITMAPINFO = {
2839                                         sizeof(BITMAPINFOHEADER),       // biSize
2840                                         bm.bmWidth,                                     // biWidth;
2841                                         bm.bmHeight,                            // biHeight;
2842                                         1,                                                      // biPlanes;
2843                                         32,                                                     // biBitCount
2844                                         BI_RGB,                                         // biCompression;
2845                                         0,                                                      // biSizeImage;
2846                                         0,                                                      // biXPelsPerMeter;
2847                                         0,                                                      // biYPelsPerMeter;
2848                                         0,                                                      // biClrUsed;
2849                                         0                                                       // biClrImportant;
2850                         };
2851                         VOID * pbits32;
2852                         HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0);
2853
2854                         if (hbm32)
2855                         {
2856                                 HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);
2857
2858                                 // Create a DC just to copy the bitmap into the memory D
2859                                 HDC hDC = CreateCompatibleDC(hMemDC);
2860
2861                                 if (hDC)
2862                                 {
2863                                         // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits
2864                                         BITMAP bm32;
2865                                         GetObject(hbm32, sizeof(bm32), &bm32);
2866                                         while (bm32.bmWidthBytes % 4)
2867                                                 bm32.bmWidthBytes++;
2868
2869                                         // Copy the bitmap into the memory D
2870                                         HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
2871                                         BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);
2872
2873                                         // For better performances, we will use the ExtCreateRegion() function to create the
2874                                         // region. This function take a RGNDATA structure on entry. We will add rectangles b
2875                                         // amount of ALLOC_UNIT number in this structure
2876                                         #define ALLOC_UNIT      100
2877                                         DWORD maxRects = ALLOC_UNIT;
2878                                         HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
2879                                         RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
2880                                         pData->rdh.dwSize = sizeof(RGNDATAHEADER);
2881                                         pData->rdh.iType = RDH_RECTANGLES;
2882                                         pData->rdh.nCount = pData->rdh.nRgnSize = 0;
2883                                         SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
2884
2885                                         // Keep on hand highest and lowest values for the "transparent" pixel
2886                                         BYTE lr = GetRValue(cTransparentColor);
2887                                         BYTE lg = GetGValue(cTransparentColor);
2888                                         BYTE lb = GetBValue(cTransparentColor);
2889                                         BYTE hr = min(0xff, lr + GetRValue(cTolerance));
2890                                         BYTE hg = min(0xff, lg + GetGValue(cTolerance));
2891                                         BYTE hb = min(0xff, lb + GetBValue(cTolerance));
2892
2893                                         // Scan each bitmap row from bottom to top (the bitmap is inverted vertically
2894                                         BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
2895                                         for (int y = 0; y < bm.bmHeight; y++)
2896                                         {
2897                                                 // Scan each bitmap pixel from left to righ
2898                                                 for (int x = 0; x < bm.bmWidth; x++)
2899                                                 {
2900                                                         // Search for a continuous range of "non transparent pixels"
2901                                                         int x0 = x;
2902                                                         LONG *p = (LONG *)p32 + x;
2903                                                         while (x < bm.bmWidth)
2904                                                         {
2905                                                                 BYTE b = GetRValue(*p);
2906                                                                 if (b >= lr && b <= hr)
2907                                                                 {
2908                                                                         b = GetGValue(*p);
2909                                                                         if (b >= lg && b <= hg)
2910                                                                         {
2911                                                                                 b = GetBValue(*p);
2912                                                                                 if (b >= lb && b <= hb)
2913                                                                                         // This pixel is "transparent"
2914                                                                                         break;
2915                                                                         }
2916                                                                 }
2917                                                                 p++;
2918                                                                 x++;
2919                                                         }
2920
2921                                                         if (x > x0)
2922                                                         {
2923                                                                 // Add the pixels (x0, y) to (x, y+1) as a new rectangle in the regio
2924                                                                 if (pData->rdh.nCount >= maxRects)
2925                                                                 {
2926                                                                         GlobalUnlock(hData);
2927                                                                         maxRects += ALLOC_UNIT;
2928                                                                         hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
2929                                                                         pData = (RGNDATA *)GlobalLock(hData);
2930                                                                
2931                                                                 }
2932                                                                 RECT *pr = (RECT *)&pData->Buffer;
2933                                                                 SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
2934                                                                 if (x0 < pData->rdh.rcBound.left)
2935                                                                         pData->rdh.rcBound.left = x0;
2936                                                                 if (y < pData->rdh.rcBound.top)
2937                                                                         pData->rdh.rcBound.top = y;
2938                                                                 if (x > pData->rdh.rcBound.right)
2939                                                                         pData->rdh.rcBound.right = x;
2940                                                                 if (y+1 > pData->rdh.rcBound.bottom)
2941                                                                         pData->rdh.rcBound.bottom = y+1;
2942                                                                 pData->rdh.nCount++;
2943
2944                                                                 /*
2945                                                                 // On Windows98, ExtCreateRegion() may fail if the number of rectangles is to
2946                                                                 // large (ie: > 4000). Therefore, we have to create the region by multiple steps
2947                                                                 if (pData->rdh.nCount == 2000)
2948                                                                 {
2949                                                                         HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
2950                                                                         
2951                                                                         // Free the data
2952                                                                         GlobalFree(hData);
2953
2954                                                                         if (hRgn)
2955                                                                         {
2956                                                                                 CombineRgn(hRgn, hRgn, h, RGN_OR);
2957                                                                                 DeleteObject(h);
2958                                                                         }
2959                                                                         else
2960                                                                                 hRgn = h;
2961                                                                         pData->rdh.nCount = 0;
2962                                                                         SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
2963                                                                 }
2964                                                                 */
2965                                                         }
2966                                                 }
2967
2968                                                 // Go to next row (remember, the bitmap is inverted vertically
2969                                                 p32 -= bm32.bmWidthBytes;
2970                                         }
2971
2972                                         // Create or extend the region with the remaining rectangle
2973                                         HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
2974
2975                                         if (hRgn)
2976                                         {
2977                                                 CombineRgn(hRgn, hRgn, h, RGN_OR);
2978                                                 DeleteObject(h);
2979                                         }
2980                                         else
2981                                                 hRgn = h;
2982
2983                                         // Clean u
2984                                         SelectObject(hDC, holdBmp);
2985                                         DeleteDC(hDC);
2986                                 }
2987
2988                                 DeleteObject(SelectObject(hMemDC, holdBmp));
2989                         }
2990
2991                         DeleteDC(hMemDC);
2992                 }
2993         }
2994
2995         return hRgn;
2996 }
2997        
2998 HitRegion* HitRegion::Clone() const
2999 {
3000         HitRegion* temp = new HitRegion();
3001
3002         temp->m_HitRegion = CreateRectRgn(0, 0, 10, 10); // create dummy region
3003         CombineRgn(temp->m_HitRegion, m_HitRegion, 0, RGN_COPY);
3004
3005         return temp;
3006 }
3007        
3008 void HitRegion::Move(int x, int y)
3009 {
3010         OffsetRgn(m_HitRegion, x, y);
3011 }
3012        
3013 RECT HitRegion::GetDimension() const
3014 {
3015         RECT boundingbox;
3016         GetRgnBox(m_HitRegion, &boundingbox);
3017
3018         return boundingbox;
3019 }
3020
3021 HRGN HitRegion::GetHandle() const
3022 {
3023         return m_HitRegion;
3024 }
3025
3026 bool HitRegion::HitTest(HitRegion* regPtr) const
3027 {
3028         HRGN temp = CreateRectRgn(0, 0, 10, 10);                        // dummy region
3029         bool result = (CombineRgn(temp, m_HitRegion, regPtr->m_HitRegion, RGN_AND) != NULLREGION);
3030
3031         DeleteObject(temp);
3032         return result;
3033 }
3034        
3035 bool HitRegion::HitTest(int x, int y) const
3036 {
3037         return PtInRegion(m_HitRegion, x, y)?true:false;
3038 }
3039        
3040 POINT HitRegion::CollisionTest(HitRegion* regPtr) const
3041 {
3042         POINT result;
3043
3044         HRGN temp = CreateRectRgn(0, 0, 10, 10);                        // dummy region
3045         int overlap = CombineRgn(temp, m_HitRegion, regPtr->m_HitRegion, RGN_AND);
3046
3047         if (overlap == NULLREGION)
3048         {
3049                 result.x = -1000000;
3050                 result.y = -1000000;
3051         }
3052         else
3053         {
3054                 RECT boundingbox;
3055                 GetRgnBox(temp, &boundingbox);
3056                 result.x = boundingbox.left + (boundingbox.right - boundingbox.left)/2;
3057                 result.y = boundingbox.top + (boundingbox.bottom - boundingbox.top)/2;
3058         }
3059
3060         DeleteObject(temp);
3061        
3062         return result;
3063 }
Note: See TracBrowser for help on using the browser.