Shadowrun: Awakened 29 September 2011 - Build 871
winvideo.h
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00031 
00032 #ifndef _CRT_SECURE_NO_DEPRECATE
00033 #define _CRT_SECURE_NO_DEPRECATE
00034 #endif
00035 // Check that the target Windows version has all API calls requried.
00036 #ifndef _WIN32_WINNT
00037 # define _WIN32_WINNT 0x0400
00038 #endif
00039 #if _WIN32_WINNT<0x0400
00040 # define YIELD_TO_THREAD() Sleep(0)
00041 #else
00042 # define YIELD_TO_THREAD() SwitchToThread()
00043 #endif
00044 #include "video.h"
00045 #include <fcntl.h>
00046 #include <io.h>
00047 #include <iostream>
00048 #include <fstream>
00049 
00050 #pragma comment(lib, "gdi32.lib")
00051 #pragma comment(lib, "user32.lib")
00052 
00053 // maximum mumber of lines the output console should have
00054 static const WORD MAX_CONSOLE_LINES = 500;
00055 const COLORREF              RGBKEY = RGB(8, 8, 16); // at least 8 for 16-bit palette
00056 HWND                        g_hAppWnd;           // The program's window handle
00057 HANDLE                      g_handles[2] = {0,0};// thread and wake up event
00058 unsigned int *              g_pImg = 0;          // drawing memory
00059 int                         g_sizex, g_sizey;
00060 static video *              g_video = 0;
00061 WNDPROC                     g_pUserProc = 0;
00062 HINSTANCE                   video::win_hInstance = 0;
00063 int                         video::win_iCmdShow = 0;
00064 static WNDCLASSEX *         gWndClass = 0;
00065 static HACCEL               hAccelTable = 0;
00066 static DWORD                g_msec = 0;
00067 static int g_fps = 0, g_updates = 0, g_skips = 0;
00068 
00069 bool DisplayError(LPSTR lpstrErr, HRESULT hres = 0); // always returns false
00070 LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
00071 
00073 bool WinInit(HINSTANCE hInstance, int nCmdShow, WNDCLASSEX *uwc, const char *title, bool fixedsize)
00074 {
00075     WNDCLASSEX wndclass;  // Our app's windows class
00076     if(uwc) {
00077         memcpy(&wndclass, uwc, sizeof(wndclass));
00078         g_pUserProc = uwc->lpfnWndProc;
00079     } else {
00080         memset(&wndclass, 0, sizeof(wndclass));
00081         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
00082         wndclass.lpszClassName = title;
00083     }
00084     wndclass.cbSize = sizeof(wndclass);
00085     wndclass.hInstance = hInstance;
00086     wndclass.lpfnWndProc = InternalWndProc;
00087     wndclass.style |= CS_HREDRAW | CS_VREDRAW;
00088     wndclass.hbrBackground = CreateSolidBrush(RGBKEY);
00089 
00090     if( !RegisterClassExA(&wndclass) ) return false;
00091     int xaddend = GetSystemMetrics(fixedsize?SM_CXFIXEDFRAME:SM_CXFRAME)*2;
00092     int yaddend = GetSystemMetrics(fixedsize?SM_CYFIXEDFRAME:SM_CYFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
00093     if(wndclass.lpszMenuName) yaddend += GetSystemMetrics(SM_CYMENU);
00094 
00095     // Setup the new window's physical parameters - and tell Windows to create it
00096     g_hAppWnd = CreateWindowA(wndclass.lpszClassName,  // Window class name
00097                              title,  // Window caption
00098                              !fixedsize ? WS_OVERLAPPEDWINDOW :  // Window style
00099                              WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
00100                              CW_USEDEFAULT,  // Initial x pos: use default placement
00101                              0,              // Initial y pos: not used here
00102                              g_sizex+xaddend,// Initial x size
00103                              g_sizey+yaddend,// Initial y size
00104                              NULL,      // parent window handle
00105                              NULL,      // window menu handle
00106                              hInstance, // program instance handle
00107                              NULL);     // Creation parameters
00108     return g_hAppWnd != NULL;
00109 }
00110 
00112 static bool RedirectIOToConsole(void)
00113 {
00114     int hConHandle; size_t lStdHandle;
00115     CONSOLE_SCREEN_BUFFER_INFO coninfo;
00116     FILE *fp;
00117     // allocate a console for this app
00118     AllocConsole();
00119 
00120     // set the screen buffer to be big enough to let us scroll text
00121     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
00122     coninfo.dwSize.Y = MAX_CONSOLE_LINES;
00123     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
00124 
00125     // redirect unbuffered STDOUT to the console
00126     lStdHandle = (size_t)GetStdHandle(STD_OUTPUT_HANDLE);
00127     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
00128     if(hConHandle <= 0) return false;
00129     fp = _fdopen( hConHandle, "w" );
00130     *stdout = *fp;
00131     setvbuf( stdout, NULL, _IONBF, 0 );
00132 
00133     // redirect unbuffered STDERR to the console
00134     lStdHandle = (size_t)GetStdHandle(STD_ERROR_HANDLE);
00135     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
00136     if(hConHandle > 0) {
00137         fp = _fdopen( hConHandle, "w" );
00138         *stderr = *fp;
00139         setvbuf( stderr, NULL, _IONBF, 0 );
00140     }
00141 
00142     // redirect unbuffered STDIN to the console
00143     lStdHandle = (size_t)GetStdHandle(STD_INPUT_HANDLE);
00144     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
00145     if(hConHandle > 0) {
00146         fp = _fdopen( hConHandle, "r" );
00147         *stdin = *fp;
00148         setvbuf( stdin, NULL, _IONBF, 0 );
00149     }
00150 
00151     // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
00152     // point to console as well
00153     std::ios::sync_with_stdio();
00154     return true;
00155 }
00156 
00157 
00158 video::video()
00159     : red_mask(0xff0000), red_shift(16), green_mask(0xff00),
00160       green_shift(8), blue_mask(0xff), blue_shift(0), depth(24)
00161 {
00162     assert(g_video == 0);
00163     g_video = this; title = "Video"; running = threaded = calc_fps = false; updating = true;
00164 }
00165 
00167 void video::win_set_class(WNDCLASSEX &wcex)
00168 {
00169     gWndClass = &wcex;
00170 }
00171 
00172 void video::win_load_accelerators(int idc)
00173 {
00174     hAccelTable = LoadAccelerators(win_hInstance, MAKEINTRESOURCE(idc));
00175 }
00176 
00177 bool video::init_console()
00178 {
00179     if(RedirectIOToConsole()) {
00180         if(!g_pImg && g_sizex && g_sizey)
00181             g_pImg = new unsigned int[g_sizex * g_sizey];
00182         if(g_pImg) running = true;
00183         return true;
00184     }
00185     return false;
00186 }
00187 
00188 video::~video()
00189 {
00190     if(g_video) terminate();
00191 }
00192 
00193 DWORD WINAPI thread_video(LPVOID lpParameter)
00194 {
00195     video *v = (video*)lpParameter;
00196     v->on_process();
00197     return 0;
00198 }
00199 
00200 static bool loop_once(video *v)
00201 {
00202     // screen update notify
00203     if(int updates = g_updates) {
00204         g_updates = 0;
00205         if(g_video->updating) { g_skips += updates-1; g_fps++; }
00206         else g_skips += updates;
00207         UpdateWindow(g_hAppWnd);
00208     }
00209     // update fps
00210     DWORD msec = GetTickCount();
00211     if(v->calc_fps && msec >= g_msec+1000) {
00212         double sec = (msec - g_msec)/1000.0;
00213         char buffer[256], n = _snprintf(buffer, 128, "%s: %d fps", v->title, int(double(g_fps + g_skips)/sec));
00214         if(g_skips) _snprintf(buffer+n, 128, " - %d skipped = %d updates", int(g_skips/sec), int(g_fps/sec));
00215         SetWindowTextA(g_hAppWnd, buffer);
00216         g_msec = msec; g_skips = g_fps = 0;
00217     }
00218     // event processing, including painting
00219     MSG msg;
00220     if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00221     {
00222         if( msg.message == WM_QUIT ) { v->running = false; return false; }
00223         if( !hAccelTable || !TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
00224         {
00225             TranslateMessage(&msg);
00226             DispatchMessage(&msg);
00227         }
00228         return true; // try again
00229     }
00230     return false;
00231 }
00232 
00234 void video::main_loop()
00235 {
00236     // let Windows draw and unroll the window
00237     InvalidateRect(g_hAppWnd, 0, false);
00238     g_msec = GetTickCount(); // let's stay for 0,5 sec
00239     while(g_msec + 500 > GetTickCount()) { loop_once(this); Sleep(1); }
00240     g_msec = GetTickCount();
00241     // now, start main process
00242     if(threaded) {
00243         g_handles[0] = CreateThread (
00244             NULL,             // LPSECURITY_ATTRIBUTES security_attrs
00245             0,                // SIZE_T stacksize
00246             (LPTHREAD_START_ROUTINE) thread_video,
00247             this,               // argument
00248             0, 0);
00249         if(!g_handles[0]) { DisplayError("Can't create thread"); return; }
00250         else // harmless race is possible here
00251             g_handles[1] = CreateEvent(NULL, false, false, NULL);
00252         while(running) {
00253             while(loop_once(this));
00254             YIELD_TO_THREAD(); // give time for processing when running on single CPU
00255             DWORD r = MsgWaitForMultipleObjects(2, g_handles, false, INFINITE, QS_ALLINPUT^QS_MOUSEMOVE);
00256             if(r == WAIT_OBJECT_0) break; // thread terminated
00257         }
00258         running = false;
00259         if(WaitForSingleObject(g_handles[0], 300) == WAIT_TIMEOUT)
00260             TerminateThread(g_handles[0], 0);
00261         if(g_handles[0]) CloseHandle(g_handles[0]);
00262         if(g_handles[1]) CloseHandle(g_handles[1]);
00263         g_handles[0] = g_handles[1] = 0;
00264     }
00265     else on_process();
00266 }
00267 
00269 bool video::next_frame()
00270 {
00271     if(!running) return false;
00272     g_updates++; // Fast but inaccurate counter. The data race here is benign.
00273     if(!threaded) while(loop_once(this));
00274     else if(g_handles[1]) {
00275         SetEvent(g_handles[1]);
00276         YIELD_TO_THREAD();
00277     }
00278     return true;
00279 }
00280 
00282 void video::show_title()
00283 {
00284     if(g_hAppWnd)
00285         SetWindowTextA(g_hAppWnd, title);
00286 }

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net