![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
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 00029 //#define _CRT_SECURE_NO_DEPRECATE 00030 #define VIDEO_WINMAIN_ARGS 00031 #include "../../common/gui/video.h" 00032 #include <cstdlib> 00033 #include <cstdio> 00034 #include <cstring> 00035 #include <cctype> 00036 #include <cassert> 00037 #include <math.h> 00038 #include "tbb/task_scheduler_init.h" 00039 #include "tbb/blocked_range.h" 00040 #include "tbb/parallel_for.h" 00041 #include "tbb/tick_count.h" 00042 00043 using namespace std; 00044 00045 #ifdef _MSC_VER 00046 // warning C4068: unknown pragma 00047 #pragma warning(disable: 4068) 00048 #endif 00049 00050 #define DEFAULT_NUMBER_OF_FRAMES 100 00051 int number_of_frames = -1; 00052 const size_t MAX_WIDTH = 1024; 00053 const size_t MAX_HEIGHT = 512; 00054 00055 int UniverseHeight=MAX_HEIGHT; 00056 int UniverseWidth=MAX_WIDTH; 00057 00058 typedef float value; 00059 00061 static value V[MAX_HEIGHT][MAX_WIDTH]; 00062 00064 static value S[MAX_HEIGHT][MAX_WIDTH]; 00065 00067 static value T[MAX_HEIGHT][MAX_WIDTH]; 00068 00070 static value M[MAX_HEIGHT][MAX_WIDTH]; 00071 00073 static value L[MAX_HEIGHT][MAX_WIDTH]; 00074 00076 static value D[MAX_HEIGHT][MAX_WIDTH]; 00077 00082 static tbb::affinity_partitioner Affinity; 00083 00084 enum MaterialType { 00085 WATER=0, 00086 SANDSTONE=1, 00087 SHALE=2 00088 }; 00089 00091 static unsigned char Material[MAX_HEIGHT][MAX_WIDTH]; 00092 00093 static const colorcomp_t MaterialColor[4][3] = { // BGR 00094 {96,0,0}, // WATER 00095 {0,48,48}, // SANDSTONE 00096 {32,32,23} // SHALE 00097 }; 00098 00099 static const int DamperSize = 32; 00100 00101 static const int ColorMapSize = 1024; 00102 static color_t ColorMap[4][ColorMapSize]; 00103 00104 static int PulseTime = 100; 00105 static int PulseCounter; 00106 static int PulseX = UniverseWidth/3; 00107 static int PulseY = UniverseHeight/4; 00108 00109 static bool InitIsParallel = true; 00110 const char *titles[2] = {"Seismic Simulation: Serial", "Seismic Simulation: Parallel"}; 00114 int threads_low = 0, threads_high = tbb::task_scheduler_init::automatic; 00115 00116 static void UpdatePulse() { 00117 if( PulseCounter>0 ) { 00118 value t = (PulseCounter-PulseTime/2)*0.05f; 00119 V[PulseY][PulseX] += 64*sqrt(M[PulseY][PulseX])*exp(-t*t); 00120 --PulseCounter; 00121 } 00122 } 00123 00124 static void SerialUpdateStress() { 00125 drawing_area drawing(0, 0, UniverseWidth, UniverseHeight); 00126 for( int i=1; i<UniverseHeight-1; ++i ) { 00127 drawing.set_pos(1, i); 00128 #pragma ivdep 00129 for( int j=1; j<UniverseWidth-1; ++j ) { 00130 S[i][j] += M[i][j]*(V[i][j+1]-V[i][j]); 00131 T[i][j] += M[i][j]*(V[i+1][j]-V[i][j]); 00132 int index = (int)(V[i][j]*(ColorMapSize/2)) + ColorMapSize/2; 00133 if( index<0 ) index = 0; 00134 if( index>=ColorMapSize ) index = ColorMapSize-1; 00135 color_t* c = ColorMap[Material[i][j]]; 00136 drawing.put_pixel(c[index]); 00137 } 00138 } 00139 } 00140 00141 struct UpdateStressBody { 00142 void operator()( const tbb::blocked_range<int>& range ) const { 00143 drawing_area drawing(0, range.begin(), UniverseWidth, range.end()-range.begin()); 00144 int i_end = range.end(); 00145 for( int y = 0, i=range.begin(); i!=i_end; ++i,y++ ) { 00146 drawing.set_pos(1, y); 00147 #pragma ivdep 00148 for( int j=1; j<UniverseWidth-1; ++j ) { 00149 S[i][j] += M[i][j]*(V[i][j+1]-V[i][j]); 00150 T[i][j] += M[i][j]*(V[i+1][j]-V[i][j]); 00151 int index = (int)(V[i][j]*(ColorMapSize/2)) + ColorMapSize/2; 00152 if( index<0 ) index = 0; 00153 if( index>=ColorMapSize ) index = ColorMapSize-1; 00154 color_t* c = ColorMap[Material[i][j]]; 00155 drawing.put_pixel(c[index]); 00156 } 00157 } 00158 } 00159 }; 00160 00161 static void ParallelUpdateStress() { 00162 tbb::parallel_for( tbb::blocked_range<int>( 1, UniverseHeight-1 ), // Index space for loop 00163 UpdateStressBody(), // Body of loop 00164 Affinity ); // Affinity hint 00165 } 00166 00167 static void SerialUpdateVelocity() { 00168 for( int i=1; i<UniverseHeight-1; ++i ) 00169 #pragma ivdep 00170 for( int j=1; j<UniverseWidth-1; ++j ) 00171 V[i][j] = D[i][j]*(V[i][j] + L[i][j]*(S[i][j] - S[i][j-1] + T[i][j] - T[i-1][j])); 00172 } 00173 00174 struct UpdateVelocityBody { 00175 void operator()( const tbb::blocked_range<int>& range ) const { 00176 int i_end = range.end(); 00177 for( int i=range.begin(); i!=i_end; ++i ) 00178 #pragma ivdep 00179 for( int j=1; j<UniverseWidth-1; ++j ) 00180 V[i][j] = D[i][j]*(V[i][j] + L[i][j]*(S[i][j] - S[i][j-1] + T[i][j] - T[i-1][j])); 00181 } 00182 }; 00183 00184 static void ParallelUpdateVelocity() { 00185 tbb::parallel_for( tbb::blocked_range<int>( 1, UniverseHeight-1 ), // Index space for loop 00186 UpdateVelocityBody(), // Body of loop 00187 Affinity ); // Affinity hint 00188 } 00189 00190 void SerialUpdateUniverse() { 00191 UpdatePulse(); 00192 SerialUpdateStress(); 00193 SerialUpdateVelocity(); 00194 } 00195 00196 void ParallelUpdateUniverse() { 00197 UpdatePulse(); 00198 ParallelUpdateStress(); 00199 ParallelUpdateVelocity(); 00200 } 00201 00202 class seismic_video : public video 00203 { 00204 void on_mouse(int x, int y, int key) { 00205 if(key == 1 && PulseCounter == 0) { 00206 PulseCounter = PulseTime; 00207 PulseX = x; PulseY = y; 00208 } 00209 } 00210 void on_key(int key) { 00211 key &= 0xff; 00212 if(char(key) == ' ') InitIsParallel = !InitIsParallel; 00213 else if(char(key) == 'p') InitIsParallel = true; 00214 else if(char(key) == 's') InitIsParallel = false; 00215 else if(char(key) == 'e') updating = true; 00216 else if(char(key) == 'd') updating = false; 00217 else if(key == 27) running = false; 00218 title = InitIsParallel?titles[1]:titles[0]; 00219 } 00220 void on_process() { 00221 tbb::task_scheduler_init Init(threads_high); 00222 do { 00223 if( InitIsParallel ) 00224 ParallelUpdateUniverse(); 00225 else 00226 SerialUpdateUniverse(); 00227 if( number_of_frames > 0 ) --number_of_frames; 00228 } while(next_frame() && number_of_frames); 00229 } 00230 } video; 00231 00232 void InitializeUniverse() { 00233 PulseCounter = PulseTime; 00234 // Initialize V, S, and T to slightly non-zero values, in order to avoid denormal waves. 00235 for( int i=0; i<UniverseHeight; ++i ) 00236 #pragma ivdep 00237 for( int j=0; j<UniverseWidth; ++j ) { 00238 T[i][j] = S[i][j] = V[i][j] = value(1.0E-6); 00239 } 00240 for( int i=1; i<UniverseHeight-1; ++i ) { 00241 for( int j=1; j<UniverseWidth-1; ++j ) { 00242 float x = float(j-UniverseWidth/2)/(UniverseWidth/2); 00243 value t = (value)i/UniverseHeight; 00244 MaterialType m; 00245 D[i][j] = 1.0; 00246 // Coefficient values are fictitious, and chosen to visually exaggerate 00247 // physical effects such as Rayleigh waves. The fabs/exp line generates 00248 // a shale layer with a gentle upwards slope and an anticline. 00249 if( t<0.3f ) { 00250 m = WATER; 00251 M[i][j] = 0.125; 00252 L[i][j] = 0.125; 00253 } else if( fabs(t-0.7+0.2*exp(-8*x*x)+0.025*x)<=0.1 ) { 00254 m = SHALE; 00255 M[i][j] = 0.5; 00256 L[i][j] = 0.6; 00257 } else { 00258 m = SANDSTONE; 00259 M[i][j] = 0.3; 00260 L[i][j] = 0.4; 00261 } 00262 Material[i][j] = m; 00263 } 00264 } 00265 value scale = 2.0f/ColorMapSize; 00266 for( int k=0; k<4; ++k ) { 00267 for( int i=0; i<ColorMapSize; ++i ) { 00268 colorcomp_t c[3]; 00269 value t = (i-ColorMapSize/2)*scale; 00270 value r = t>0 ? t : 0; 00271 value b = t<0 ? -t : 0; 00272 value g = 0.5f*fabs(t); 00273 memcpy(c, MaterialColor[k], sizeof(c)); 00274 c[2] = colorcomp_t(r*(255-c[2])+c[2]); 00275 c[1] = colorcomp_t(g*(255-c[1])+c[1]); 00276 c[0] = colorcomp_t(b*(255-c[0])+c[0]); 00277 ColorMap[k][i] = video.get_color(c[2], c[1], c[0]); 00278 } 00279 } 00280 // Set damping coefficients around border to reduce reflections from boundaries. 00281 value d = 1.0; 00282 for( int k=DamperSize-1; k>0; --k ) { 00283 d *= 1-1.0f/(DamperSize*DamperSize); 00284 for( int j=1; j<UniverseWidth-1; ++j ) { 00285 D[k][j] *= d; 00286 D[UniverseHeight-1-k][j] *= d; 00287 } 00288 for( int i=1; i<UniverseHeight-1; ++i ) { 00289 D[i][k] *= d; 00290 D[i][UniverseWidth-1-k] *= d; 00291 } 00292 } 00293 } 00294 00296 #ifdef _WINDOWS 00297 #include "msvs/resource.h" 00298 #endif 00299 00300 int main(int argc, char *argv[]) 00301 { 00302 // threads number init 00303 if(argc > 1 && isdigit(argv[1][0])) { 00304 char* end; threads_high = threads_low = (int)strtol(argv[1],&end,0); 00305 switch( *end ) { 00306 case ':': threads_high = (int)strtol(end+1,0,0); break; 00307 case '\0': break; 00308 default: printf("unexpected character = %c\n",*end); 00309 } 00310 } 00311 if (argc > 2 && isdigit(argv[2][0])){ 00312 number_of_frames = (int)strtol(argv[2],0,0); 00313 } 00314 // video layer init 00315 video.title = InitIsParallel?titles[1]:titles[0]; 00316 #ifdef _WINDOWS 00317 #define MAX_LOADSTRING 100 00318 TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 00319 LoadStringA(video::win_hInstance, IDC_SEISMICSIMULATION, szWindowClass, MAX_LOADSTRING); 00320 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 00321 WNDCLASSEX wcex; memset(&wcex, 0, sizeof(wcex)); 00322 wcex.lpfnWndProc = (WNDPROC)WndProc; 00323 wcex.hIcon = LoadIcon(video::win_hInstance, MAKEINTRESOURCE(IDI_SEISMICSIMULATION)); 00324 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 00325 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 00326 wcex.lpszMenuName = LPCTSTR(IDC_SEISMICSIMULATION); 00327 wcex.lpszClassName = szWindowClass; 00328 wcex.hIconSm = LoadIcon(video::win_hInstance, MAKEINTRESOURCE(IDI_SMALL)); 00329 video.win_set_class(wcex); // ascii convention here 00330 video.win_load_accelerators(IDC_SEISMICSIMULATION); 00331 #endif 00332 if(video.init_window(UniverseWidth, UniverseHeight)) { 00333 video.calc_fps = true; 00334 video.threaded = threads_low > 0; 00335 // video is ok, init universe 00336 InitializeUniverse(); 00337 // main loop 00338 video.main_loop(); 00339 } 00340 else if(video.init_console()) { 00341 // do console mode 00342 if(number_of_frames <= 0) number_of_frames = DEFAULT_NUMBER_OF_FRAMES; 00343 if(threads_high == tbb::task_scheduler_init::automatic) threads_high = 4; 00344 if(threads_high < threads_low) threads_high = threads_low; 00345 for( int p = threads_low; p <= threads_high; ++p ) { 00346 InitializeUniverse(); 00347 tbb::task_scheduler_init init(tbb::task_scheduler_init::deferred); 00348 if( p > 0 ) 00349 init.initialize( p ); 00350 tbb::tick_count t0 = tbb::tick_count::now(); 00351 if( p > 0 ) 00352 for( int i=0; i<number_of_frames; ++i ) 00353 ParallelUpdateUniverse(); 00354 else 00355 for( int i=0; i<number_of_frames; ++i ) 00356 SerialUpdateUniverse(); 00357 tbb::tick_count t1 = tbb::tick_count::now(); 00358 printf("%.1f frame per sec", number_of_frames/(t1-t0).seconds()); 00359 if( p > 0 ) 00360 printf(" with %d way parallelism\n",p); 00361 else 00362 printf(" with serial version\n"); 00363 } 00364 } 00365 video.terminate(); 00366 return 0; 00367 } 00368 00369 #ifdef _WINDOWS 00370 // 00371 // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) 00372 // 00373 // PURPOSE: Processes messages for the main window. 00374 // 00375 // WM_COMMAND - process the application menu 00376 // WM_PAINT - Paint the main window 00377 // WM_DESTROY - post a quit message and return 00378 // 00379 // 00380 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 00381 { 00382 switch (message) 00383 { 00384 case WM_INITDIALOG: return TRUE; 00385 case WM_COMMAND: 00386 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { 00387 EndDialog(hDlg, LOWORD(wParam)); 00388 return TRUE; 00389 } 00390 break; 00391 } 00392 return FALSE; 00393 } 00394 00395 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 00396 { 00397 int wmId, wmEvent; 00398 switch (message) { 00399 case WM_COMMAND: 00400 wmId = LOWORD(wParam); 00401 wmEvent = HIWORD(wParam); 00402 // Parse the menu selections: 00403 switch (wmId) 00404 { 00405 case IDM_ABOUT: 00406 DialogBox(video::win_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)About); 00407 break; 00408 case IDM_EXIT: 00409 PostQuitMessage(0); 00410 break; 00411 case ID_FILE_PARALLEL: 00412 if( !InitIsParallel ) { 00413 InitIsParallel = true; 00414 video.title = titles[1]; 00415 } 00416 break; 00417 case ID_FILE_SERIAL: 00418 if( InitIsParallel ) { 00419 InitIsParallel = false; 00420 video.title = titles[0]; 00421 } 00422 break; 00423 case ID_FILE_ENABLEGUI: 00424 video.updating = true; 00425 break; 00426 case ID_FILE_DISABLEGUI: 00427 video.updating = false; 00428 break; 00429 default: 00430 return DefWindowProc(hWnd, message, wParam, lParam); 00431 } 00432 break; 00433 default: 00434 return DefWindowProc(hWnd, message, wParam, lParam); 00435 } 00436 return 0; 00437 } 00438 00439 #endif
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.