1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #include "language/resource.h" 26 #include "NstResourceString.hpp" 27 #include "NstIoLog.hpp" 28 #include "NstApplicationException.hpp" 29 #include "NstDirect2D.hpp" 30 #include "NstIoScreen.hpp" 31 32 #if NST_MSVC 33 #pragma comment(lib,"d3d9") 34 #pragma comment(lib,"d3dx9") 35 #endif 36 37 namespace Nestopia 38 { 39 namespace DirectX 40 { 41 #ifdef NST_MSVC_OPTIMIZE 42 #pragma optimize("t", on) 43 #endif 44 operator IDirect3D9&() const45 inline Direct2D::Base::operator IDirect3D9& () const 46 { 47 return com; 48 } 49 operator IDirect3DDevice9&() const50 inline Direct2D::Device::operator IDirect3DDevice9& () const 51 { 52 return **com; 53 } 54 CanDraw() const55 inline bool Direct2D::Device::Fonts::Font::CanDraw() const 56 { 57 return length && com; 58 } 59 NumVertices() const60 inline uint Direct2D::VertexBuffer::NumVertices() const 61 { 62 return numVertices; 63 } 64 NumStrips() const65 inline uint Direct2D::IndexBuffer::NumStrips() const 66 { 67 return numStrips; 68 } 69 GetLeftU(uint x) const70 inline double Direct2D::Textures::ScreenTexture::GetLeftU(uint x) const 71 { 72 return double(NST_MIN(size.x,x)) / desc.Width; 73 } 74 GetRightU(uint x) const75 inline double Direct2D::Textures::ScreenTexture::GetRightU(uint x) const 76 { 77 return double(NST_MIN(size.x,x)) / desc.Width; 78 } 79 GetTopV(uint y) const80 inline double Direct2D::Textures::ScreenTexture::GetTopV(uint y) const 81 { 82 return double(NST_MIN(size.y,y)) / desc.Height; 83 } 84 GetBottomV(uint y) const85 inline double Direct2D::Textures::ScreenTexture::GetBottomV(uint y) const 86 { 87 return double(NST_MIN(size.y,y)) / desc.Height; 88 } 89 GetLeftU(uint) const90 inline double Direct2D::Textures::EffectTexture::GetLeftU(uint) const 91 { 92 return 0.0; 93 } 94 GetRightU(uint) const95 inline double Direct2D::Textures::EffectTexture::GetRightU(uint) const 96 { 97 return 1.0; 98 } 99 GetTopV(uint y) const100 inline double Direct2D::Textures::EffectTexture::GetTopV(uint y) const 101 { 102 return double(NST_MIN(size.y,y)) / desc.Height * 2; 103 } 104 GetBottomV(uint y) const105 inline double Direct2D::Textures::EffectTexture::GetBottomV(uint y) const 106 { 107 return double(NST_MIN(size.y,y)) / desc.Height * 2; 108 } 109 GetScreenLeftU(uint x) const110 inline double Direct2D::Textures::GetScreenLeftU(uint x) const 111 { 112 return screenTexture.GetLeftU(x); 113 } 114 GetScreenRightU(uint x) const115 inline double Direct2D::Textures::GetScreenRightU(uint x) const 116 { 117 return screenTexture.GetRightU(x); 118 } 119 GetScreenTopV(uint y) const120 inline double Direct2D::Textures::GetScreenTopV(uint y) const 121 { 122 return screenTexture.GetTopV(y); 123 } 124 GetScreenBottomV(uint y) const125 inline double Direct2D::Textures::GetScreenBottomV(uint y) const 126 { 127 return screenTexture.GetBottomV(y); 128 } 129 GetEffectLeftU(uint x) const130 inline double Direct2D::Textures::GetEffectLeftU(uint x) const 131 { 132 return effectTexture.GetLeftU(x); 133 } 134 GetEffectRightU(uint x) const135 inline double Direct2D::Textures::GetEffectRightU(uint x) const 136 { 137 return effectTexture.GetRightU(x); 138 } 139 GetEffectTopV(uint y) const140 inline double Direct2D::Textures::GetEffectTopV(uint y) const 141 { 142 return effectTexture.GetTopV(y); 143 } 144 GetEffectBottomV(uint y) const145 inline double Direct2D::Textures::GetEffectBottomV(uint y) const 146 { 147 return effectTexture.GetBottomV(y); 148 } 149 Draw(const D3DCOLOR color,const DWORD flags,Rect rect) const150 inline void Direct2D::Device::Fonts::Font::Draw(const D3DCOLOR color,const DWORD flags,Rect rect) const 151 { 152 com->DrawText( NULL, string.Ptr(), length, &rect, flags, color ); 153 } 154 Render(const D3DPRESENT_PARAMETERS & presentation,const uint state) const155 NST_SINGLE_CALL void Direct2D::Device::Fonts::Render(const D3DPRESENT_PARAMETERS& presentation,const uint state) const 156 { 157 const uint width = presentation.BackBufferWidth; 158 const uint height = presentation.BackBufferHeight; 159 160 if (!presentation.Windowed) 161 { 162 if ((state & RENDER_FPS) && fps.CanDraw()) 163 { 164 for (uint i=0; i < 2; ++i) 165 { 166 fps.Draw 167 ( 168 i ? D3DCOLOR_ARGB(0xFF,0xA5,0xB5,0x40) : D3DCOLOR_ARGB(0xFF,0x2A,0x35,0x10), 169 DT_SINGLELINE|TA_BOTTOM|TA_RIGHT|DT_NOCLIP, 170 Rect(width-31,height-31,width-i-3,height-i-3) 171 ); 172 } 173 } 174 175 if ((state & RENDER_MSG) && msg.CanDraw()) 176 { 177 for (uint i=0; i < 2; ++i) 178 { 179 msg.Draw 180 ( 181 i ? D3DCOLOR_ARGB(0xFF,0xFF,0x20,0x20) : D3DCOLOR_ARGB(0xFF,0x20,0x20,0xA0), 182 DT_SINGLELINE|TA_BOTTOM|TA_LEFT|DT_NOCLIP, 183 Rect(4-i,height-31,width,height-i-3) 184 ); 185 } 186 } 187 } 188 189 if ((state & RENDER_NFO) && nfo.CanDraw()) 190 { 191 for (uint i=0; i < 2; ++i) 192 { 193 nfo.Draw 194 ( 195 i ? D3DCOLOR_ARGB(0xFF,0x20,0xFF,0x20) : D3DCOLOR_ARGB(0xFF,0x20,0x60,0x20), 196 TA_TOP|TA_LEFT|DT_NOCLIP, 197 Rect(16-i,16-i,width,height) 198 ); 199 } 200 } 201 } 202 RenderScreen(const uint state,const uint numIndexedStrips,const uint numVertices) const203 NST_SINGLE_CALL HRESULT Direct2D::Device::RenderScreen(const uint state,const uint numIndexedStrips,const uint numVertices) const 204 { 205 HRESULT hResult = com->BeginScene(); 206 207 if (SUCCEEDED(hResult)) 208 { 209 if (state & RENDER_PICTURE) 210 { 211 if (numIndexedStrips) 212 hResult = com->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, 0, numVertices, 0, numIndexedStrips ); 213 else 214 hResult = com->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); 215 } 216 217 fonts.Render( presentation, state ); 218 com->EndScene(); 219 } 220 221 return hResult; 222 } 223 224 #ifdef NST_MSVC_OPTIMIZE 225 #pragma optimize("", on) 226 #endif 227 Direct2D(HWND hWnd)228 Direct2D::Direct2D(HWND hWnd) 229 : 230 device ( hWnd, base ), 231 textures ( device.GetPresentation().BackBufferFormat ), 232 lastResult ( D3D_OK ) 233 { 234 ValidateObjects(); 235 } 236 ~Direct2D()237 Direct2D::~Direct2D() 238 { 239 } 240 241 #ifdef NST_MSVC_OPTIMIZE 242 #pragma optimize("t", on) 243 #endif 244 InvalidateObjects()245 void Direct2D::InvalidateObjects() 246 { 247 indexBuffer.Invalidate(); 248 vertexBuffer.Invalidate(); 249 textures.Invalidate(); 250 } 251 FlushObjects()252 void Direct2D::FlushObjects() 253 { 254 textures.Flush(); 255 } 256 ValidateObjects()257 void Direct2D::ValidateObjects() 258 { 259 if (SUCCEEDED(lastResult)) 260 { 261 lastResult = textures.Validate( device, GetAdapter(), device.GetPresentation().BackBufferFormat ); 262 263 if (SUCCEEDED(lastResult)) 264 { 265 lastResult = indexBuffer.Validate( device ); 266 267 if (SUCCEEDED(lastResult)) 268 lastResult = vertexBuffer.Validate( device, textures ); 269 } 270 } 271 } 272 RenderScreen(uint state)273 void Direct2D::RenderScreen(uint state) 274 { 275 if (SUCCEEDED(lastResult)) 276 lastResult = device.RenderScreen( state, indexBuffer.NumStrips(), vertexBuffer.NumVertices() ); 277 } 278 279 /** 280 * Selects a video adapter and creates a new video device. Selection is ignored if the adapter is already selected. 281 * 282 * @param adapter The video adapter to select. 283 * @throws Application::Exception If an error occured creating or resetting the new video device. 284 * @see Application::Exception 285 */ SelectAdapter(const Adapters::const_iterator adapter)286 void Direct2D::SelectAdapter(const Adapters::const_iterator adapter) 287 { 288 if (device.GetOrdinal() != adapter->ordinal) 289 { 290 InvalidateObjects(); 291 292 device.Create( base, *adapter ); 293 if (FAILED(device.Reset())) 294 throw Application::Exception( L"Couldn't reset the new video device!" ); 295 296 ValidateObjects(); 297 lastResult = D3D_OK; 298 //lastResult = INVALID_RECT; //removed when implementing support for multiple monitor adapters 299 } 300 else 301 { 302 Io::Log() << "Selection of video adapter with ordinal \"" << adapter->ordinal << "\" was ignored as it is already selected.\r\n"; 303 } 304 } 305 306 /** 307 * Verifies if a switch to a fullscreen mode can be made or if the mode is already set to fullscreen. 308 * 309 * @param mode The video mode to set to fullscreen. 310 * @return True if switched to the fullscreen mode can be made. False if the mode is already set to fullscreen. 311 */ CanSwitchFullscreen(const Adapter::Modes::const_iterator mode) const312 bool Direct2D::CanSwitchFullscreen(const Adapter::Modes::const_iterator mode) const 313 { 314 return device.CanSwitchFullscreen( *mode ); 315 } 316 317 /** 318 * Switches to a fullscreen mode. Switch is ignored if the specific mode is already set to fullscreen. 319 * 320 * @param mode The video mode to set to fullscreen. 321 * @return True if switched to fullscreen. False if the mode is already set in fullscreen. 322 */ SwitchFullscreen(const Adapter::Modes::const_iterator mode)323 bool Direct2D::SwitchFullscreen(const Adapter::Modes::const_iterator mode) 324 { 325 if (CanSwitchFullscreen( mode )) 326 { 327 FlushObjects(); 328 device.SwitchFullscreen( *mode ); 329 lastResult = D3D_OK; 330 ValidateObjects(); 331 return true; 332 } 333 334 return false; 335 } 336 337 /** 338 * Switches to window mode. Switch is ignored if already in window mode. 339 * 340 * @return True if switched to window mode. False if the mode is already in window mode. 341 */ SwitchWindowed()342 bool Direct2D::SwitchWindowed() 343 { 344 if (!device.GetPresentation().Windowed) 345 { 346 FlushObjects(); 347 device.SwitchWindowed(); 348 lastResult = D3D_OK; 349 ValidateObjects(); 350 return true; 351 } 352 353 return false; 354 } 355 EnableDialogBoxMode(const bool enable)356 void Direct2D::EnableDialogBoxMode(const bool enable) 357 { 358 if (device.CanToggleDialogBoxMode( enable )) 359 { 360 FlushObjects(); 361 lastResult = device.ToggleDialogBoxMode(); 362 ValidateObjects(); 363 } 364 } 365 Repair()366 bool Direct2D::Repair() 367 { 368 if (FAILED(lastResult) && lastResult != INVALID_RECT) 369 { 370 FlushObjects(); 371 lastResult = device.Repair( lastResult ); 372 ValidateObjects(); 373 } 374 375 return SUCCEEDED(lastResult); 376 } 377 UpdateWindowView()378 void Direct2D::UpdateWindowView() 379 { 380 const Point::Picture picture( device.GetPresentation().hDeviceWindow ); 381 382 if (picture.x > 0 && picture.y > 0) 383 { 384 const Point::Client client( device.GetPresentation().hDeviceWindow ); 385 NST_ASSERT( client.x >= picture.x && client.y >= picture.y ); 386 387 if 388 ( 389 client.x != device.GetPresentation().BackBufferWidth || 390 client.y != device.GetPresentation().BackBufferHeight || 391 lastResult == INVALID_RECT 392 ) 393 { 394 FlushObjects(); 395 lastResult = device.ResetWindowClient( client, lastResult ); 396 } 397 398 ValidateObjects(); 399 } 400 else 401 { 402 lastResult = INVALID_RECT; 403 } 404 } 405 UpdateWindowView(const Point & screen,const Rect & clipping,const uint scanlines,const int screenCurvature,const Adapter::Filter filter,const bool useVidMem)406 void Direct2D::UpdateWindowView 407 ( 408 const Point& screen, 409 const Rect& clipping, 410 const uint scanlines, 411 const int screenCurvature, 412 const Adapter::Filter filter, 413 const bool useVidMem 414 ) 415 { 416 const Point::Picture picture( device.GetPresentation().hDeviceWindow ); 417 418 if (picture.x > 0 && picture.y > 0) 419 { 420 textures.Update( base.GetAdapter(device.GetOrdinal()), screen, scanlines, filter, useVidMem ); 421 vertexBuffer.Update( picture, clipping, screenCurvature ); 422 indexBuffer.Update( screenCurvature ); 423 424 const Point::Client client( device.GetPresentation().hDeviceWindow ); 425 NST_ASSERT( client.x >= picture.x && client.y >= picture.y ); 426 427 if 428 ( 429 client.x != device.GetPresentation().BackBufferWidth || 430 client.y != device.GetPresentation().BackBufferHeight || 431 lastResult == INVALID_RECT 432 ) 433 { 434 FlushObjects(); 435 lastResult = device.ResetWindowClient( client, lastResult ); 436 } 437 438 ValidateObjects(); 439 } 440 else 441 { 442 lastResult = INVALID_RECT; 443 } 444 } 445 UpdateFullscreenView(const Rect & picture,const Point & screen,const Rect & clipping,const uint scanlines,const int screenCurvature,const Adapter::Filter filter,const bool useVidMem)446 void Direct2D::UpdateFullscreenView 447 ( 448 const Rect& picture, 449 const Point& screen, 450 const Rect& clipping, 451 const uint scanlines, 452 const int screenCurvature, 453 const Adapter::Filter filter, 454 const bool useVidMem 455 ) 456 { 457 NST_ASSERT( picture.Width() && picture.Height() ); 458 459 textures.Update( base.GetAdapter(device.GetOrdinal()), screen, scanlines, filter, useVidMem ); 460 vertexBuffer.Update( picture, clipping, screenCurvature ); 461 indexBuffer.Update( screenCurvature ); 462 ValidateObjects(); 463 } 464 UpdateFrameRate(const uint frameRate,const bool vsync,const bool tripleBuffering)465 void Direct2D::UpdateFrameRate(const uint frameRate,const bool vsync,const bool tripleBuffering) 466 { 467 if (device.ResetFrameRate( frameRate, vsync, tripleBuffering, base )) 468 { 469 FlushObjects(); 470 471 if (SUCCEEDED(lastResult)) 472 { 473 lastResult = device.Reset(); 474 ValidateObjects(); 475 } 476 } 477 } 478 SaveScreenShot(wcstring const file,const uint ext) const479 Direct2D::ScreenShotResult Direct2D::SaveScreenShot(wcstring const file,const uint ext) const 480 { 481 NST_ASSERT( file && *file ); 482 483 if (SUCCEEDED(lastResult)) 484 { 485 D3DXIMAGE_FILEFORMAT format; 486 487 switch (ext) 488 { 489 case MAKEFOURCC('p','n','g','\0'): format = D3DXIFF_PNG; break; 490 case MAKEFOURCC('j','p','g','\0'): format = D3DXIFF_JPG; break; 491 case MAKEFOURCC('b','m','p','\0'): format = D3DXIFF_BMP; break; 492 default: return SCREENSHOT_UNSUPPORTED; 493 } 494 495 if (textures.SaveToFile( file, format )) 496 return SCREENSHOT_OK; 497 } 498 499 return SCREENSHOT_ERROR; 500 } 501 Mode(uint w,uint h,uint b)502 Direct2D::Mode::Mode(uint w,uint h,uint b) 503 : width(w), height(h), bpp(b) {} 504 operator ==(const Mode & mode) const505 bool Direct2D::Mode::operator == (const Mode& mode) const 506 { 507 return width == mode.width && height == mode.height && bpp == mode.bpp; 508 } 509 operator <(const Mode & mode) const510 bool Direct2D::Mode::operator < (const Mode& mode) const 511 { 512 if ( width < mode.width ) return true; 513 if ( width > mode.width ) return false; 514 if ( height < mode.height ) return true; 515 if ( height > mode.height ) return false; 516 if ( bpp < mode.bpp ) return true; 517 if ( bpp > mode.bpp ) return false; 518 519 return false; 520 } 521 522 #ifdef NST_MSVC_OPTIMIZE 523 #pragma optimize("", on) 524 #endif 525 Base()526 Direct2D::Base::Base() 527 : com(Create()), adapters(EnumerateAdapters(com)) {} 528 ~Base()529 Direct2D::Base::~Base() 530 { 531 com.Release(); 532 } 533 Create()534 IDirect3D9& Direct2D::Base::Create() 535 { 536 IDirect3D9* com; 537 538 if (NULL != (com = ::Direct3DCreate9( D3D_SDK_VERSION ))) 539 { 540 return *com; 541 } 542 else if (NULL != (com = ::Direct3DCreate9( D3D9b_SDK_VERSION ))) // unofficial, it may work, it may not work 543 { 544 return *com; 545 } 546 else 547 { 548 throw Application::Exception( IDS_ERR_D3D_FAILED ); 549 } 550 } 551 552 /** 553 * Lists all video adapters and stores their information and properties. 554 * 555 * @param d3d The Direct3D9 object to fetch video adapters from. 556 */ EnumerateAdapters(IDirect3D9 & d3d)557 const Direct2D::Adapters Direct2D::Base::EnumerateAdapters(IDirect3D9& d3d) 558 { 559 NST_COMPILE_ASSERT( D3DADAPTER_DEFAULT == 0 ); 560 561 Io::Log() << "Direct3D: initializing..\r\n"; 562 563 Adapters adapters; 564 for (uint ordinal=0, numAdapters=d3d.GetAdapterCount(); ordinal < NST_MIN(numAdapters,255); ++ordinal) 565 { 566 D3DADAPTER_IDENTIFIER9 identifier; 567 568 if (SUCCEEDED(d3d.GetAdapterIdentifier( ordinal, 0, &identifier ))) 569 { 570 uint guidIndex = 1; //the index of adapters of the same GUID 571 if (!adapters.empty()) 572 { 573 for (Adapters::iterator adapterIterator = adapters.begin(); adapterIterator != adapters.end(); adapterIterator++) //for each previous found adapter 574 { 575 if (adapterIterator->guid == identifier.DeviceIdentifier) //if the adapter is of the same GUID 576 { 577 guidIndex++; 578 } 579 } 580 } 581 582 Io::Log() << "Direct3D: enumerating device - name: " 583 << (*identifier.Description ? identifier.Description : "unknown") 584 << ", GUID: " 585 << System::Guid( identifier.DeviceIdentifier ).GetString() 586 << ", index: " 587 << guidIndex 588 << "\r\n"; 589 590 Adapter::Modes modes; 591 592 for (uint format=0; format < 2; ++format) 593 { 594 const D3DFORMAT type = (format ? D3DFMT_X8R8G8B8 : D3DFMT_R5G6B5); 595 596 for (uint mode=0, numModes=d3d.GetAdapterModeCount( ordinal, type ); mode < numModes; ++mode) 597 { 598 D3DDISPLAYMODE display; 599 600 if (FAILED(d3d.EnumAdapterModes( ordinal, type, mode, &display ))) 601 continue; 602 603 if (display.Width < Mode::MIN_WIDTH || display.Height < Mode::MIN_HEIGHT || display.RefreshRate > Mode::MAX_RATE) 604 continue; 605 606 // C++ standard vagueness, sometimes set::iterator == set::const_iterator 607 const_cast<Mode::Rates&>(modes.insert(Mode( display.Width, display.Height, format ? 32 : 16 )).first->rates).insert( display.RefreshRate ); 608 } 609 } 610 611 if (modes.empty()) 612 { 613 Io::Log() << "Direct3D: found no valid display mode, continuing enumeration..\r\n"; 614 } 615 else 616 { 617 D3DCAPS9 caps; 618 619 if (FAILED(d3d.GetDeviceCaps( ordinal, D3DDEVTYPE_HAL, &caps ))) 620 { 621 if (FAILED(d3d.GetDeviceCaps( ordinal, D3DDEVTYPE_REF, &caps ))) 622 { 623 Io::Log() << "Direct3D: warning, bogus device, continuing enumeration..\r\n"; 624 continue; 625 } 626 else 627 { 628 Io::Log() << "Direct3D: performance warning, this is a REF device only!\r\n"; 629 } 630 } 631 632 adapters.push_back( Adapter() ); 633 Adapter& adapter = adapters.back(); 634 635 adapter.guid = identifier.DeviceIdentifier; 636 adapter.guidIndex = guidIndex; 637 adapter.name = (*identifier.Description ? identifier.Description : "Unknown"); 638 adapter.name.Trim(); 639 adapter.name << Resource::String( IDS_DIALOG_VIDEO_ADAPTER_INDEX_SUFFIX ).Invoke( ValueString(guidIndex) ); //appends the GUID index suffix 640 adapter.ordinal = ordinal; 641 adapter.deviceType = (caps.DeviceType != D3DDEVTYPE_REF ? Adapter::DEVICE_HAL : Adapter::DEVICE_HEL); 642 adapter.maxScreenSize = Point(caps.MaxTextureWidth,caps.MaxTextureHeight); 643 adapter.videoMemScreen = caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES; 644 adapter.anyTextureSize = (caps.TextureCaps & (D3DPTEXTURECAPS_SQUAREONLY|D3DPTEXTURECAPS_POW2|D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) == 0; 645 adapter.canDoScanlineEffect = (caps.MaxSimultaneousTextures >= 2) && (caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE) && (caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP); 646 adapter.intervalTwo = caps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO; 647 adapter.intervalThree = caps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE; 648 adapter.intervalFour = caps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR; 649 adapter.filters = 0; 650 adapter.modern = (caps.PixelShaderVersion >= D3DPS_VERSION(2,0)); 651 adapter.modes = modes; 652 653 if ((caps.TextureFilterCaps & (D3DPTFILTERCAPS_MINFLINEAR|D3DPTFILTERCAPS_MAGFLINEAR)) == (D3DPTFILTERCAPS_MINFLINEAR|D3DPTFILTERCAPS_MAGFLINEAR)) 654 adapter.filters |= Adapter::FILTER_BILINEAR; 655 656 Io::Log log; 657 658 log << "Direct3D: dynamic textures: " << (adapter.videoMemScreen ? "supported\r\n" : "unsupported\r\n") 659 << "Direct3D: texture bilinear filtering: " << ((adapter.filters & Adapter::FILTER_BILINEAR) ? "supported\r\n" : "unsupported\r\n") 660 << "Direct3D: max texture dimensions: " << caps.MaxTextureWidth << 'x' << caps.MaxTextureHeight 661 << "\r\nDirect3D: scanline effect: " << (adapter.canDoScanlineEffect ? "supported\r\n" : "unsupported\r\n") 662 << "Direct3D: vsync on every second refresh: " << (adapter.intervalTwo ? "supported\r\n" : "unsupported\r\n") 663 << "Direct3D: vsync on every third refresh: " << (adapter.intervalThree ? "supported\r\n" : "unsupported\r\n") 664 << "Direct3D: found " << modes.size() << " display modes\r\n" 665 << "Direct3D: supported monitor frequencies: "; 666 667 Mode::Rates rates; 668 669 for (Adapter::Modes::const_iterator it(modes.begin()), end(modes.end()); it != end; ++it) 670 rates.insert( it->rates.begin(), it->rates.end() ); 671 672 for (Mode::Rates::const_iterator it(rates.begin()), end(rates.end());; ) 673 { 674 log << uint(*it); 675 676 if (++it != end) 677 { 678 log << "hz, "; 679 } 680 else 681 { 682 log << "hz\r\n"; 683 break; 684 } 685 } 686 } 687 } 688 } 689 690 if (adapters.empty()) 691 throw Application::Exception( L"Found no valid display adapter!" ); 692 693 return adapters; 694 } 695 696 #ifdef NST_MSVC_OPTIMIZE 697 #pragma optimize("t", on) 698 #endif 699 FormatToBpp(const D3DFORMAT format)700 uint Direct2D::Base::FormatToBpp(const D3DFORMAT format) 701 { 702 switch (format) 703 { 704 case D3DFMT_X8R8G8B8: 705 case D3DFMT_X8B8G8R8: 706 case D3DFMT_A8R8G8B8: 707 case D3DFMT_A8B8G8R8: 708 case D3DFMT_A2R10G10B10: 709 case D3DFMT_A2B10G10R10: 710 return 32; 711 712 case D3DFMT_R5G6B5: 713 case D3DFMT_X1R5G5B5: 714 case D3DFMT_X4R4G4B4: 715 case D3DFMT_A1R5G5B5: 716 case D3DFMT_A4R4G4B4: 717 case D3DFMT_A8R3G3B2: 718 return 16; 719 } 720 721 return 0; 722 } 723 FormatToMask(const D3DFORMAT format,ulong & r,ulong & g,ulong & b)724 void Direct2D::Base::FormatToMask(const D3DFORMAT format,ulong& r,ulong& g,ulong& b) 725 { 726 switch (format) 727 { 728 case D3DFMT_X8R8G8B8: 729 case D3DFMT_A8R8G8B8: r = 0x00FF0000; g = 0x0000FF00; b = 0x000000FF; break; 730 case D3DFMT_X8B8G8R8: 731 case D3DFMT_A8B8G8R8: r = 0x000000FF; g = 0x0000FF00; b = 0x00FF0000; break; 732 case D3DFMT_A2R10G10B10: r = 0x3FF00000; g = 0x000FFC00; b = 0x000003FF; break; 733 case D3DFMT_A2B10G10R10: r = 0x000003FF; g = 0x000FFC00; b = 0x3FF00000; break; 734 case D3DFMT_R5G6B5: r = 0xF800; g = 0x07E0; b = 0x001F; break; 735 case D3DFMT_X1R5G5B5: 736 case D3DFMT_A1R5G5B5: r = 0x7C00; g = 0x03E0; b = 0x001F; break; 737 case D3DFMT_X4R4G4B4: 738 case D3DFMT_A4R4G4B4: r = 0x0F00; g = 0x00F0; b = 0x000F; break; 739 case D3DFMT_A8R3G3B2: r = 0x00E0; g = 0x001C; b = 0x0003; break; 740 default: r = 0; g = 0; b = 0; break; 741 } 742 } 743 744 #ifdef NST_MSVC_OPTIMIZE 745 #pragma optimize("", on) 746 #endif 747 Device(HWND const hWnd,const Base & base)748 Direct2D::Device::Device(HWND const hWnd,const Base& base) 749 { 750 NST_ASSERT( hWnd ); 751 752 presentation.BackBufferWidth = 0; 753 presentation.BackBufferHeight = 0; 754 presentation.BackBufferFormat = D3DFMT_UNKNOWN; 755 presentation.BackBufferCount = 1; 756 presentation.MultiSampleType = D3DMULTISAMPLE_NONE; 757 presentation.MultiSampleQuality = 0; 758 presentation.SwapEffect = D3DSWAPEFFECT_DISCARD; 759 presentation.hDeviceWindow = hWnd; 760 presentation.Windowed = true; 761 presentation.EnableAutoDepthStencil = false; 762 presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; 763 presentation.Flags = 0; 764 presentation.FullScreen_RefreshRateInHz = 0; 765 presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 766 767 dialogBoxMode = false; 768 769 Create( base, base.GetAdapter(0) ); //always connects to first video device at start up 770 } 771 Create(IDirect3D9 & d3d,const Adapter & adapter)772 void Direct2D::Device::Create(IDirect3D9& d3d,const Adapter& adapter) 773 { 774 ordinal = adapter.ordinal; 775 intervalTwo = adapter.intervalTwo; 776 intervalThree = adapter.intervalThree; 777 intervalFour = adapter.intervalFour; 778 779 fonts.Destroy( true ); 780 com.Release(); 781 782 NST_VERIFY( !!Point::Client(presentation.hDeviceWindow) ); 783 784 uint buffers = (timing.tripleBuffering ? 2 : 1); 785 presentation.BackBufferCount = buffers; 786 presentation.Flags = GetPresentationFlags(); 787 presentation.SwapEffect = GetSwapEffect(); 788 DWORD flags = D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING; 789 790 for (;;) 791 { 792 const HRESULT hResult = d3d.CreateDevice 793 ( 794 adapter.ordinal, 795 adapter.deviceType == Adapter::DEVICE_HAL ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF, 796 presentation.hDeviceWindow, 797 flags, 798 &presentation, 799 &com 800 ); 801 802 if (SUCCEEDED(hResult)) 803 { 804 break; 805 } 806 else if (hResult == D3DERR_DEVICELOST) 807 { 808 throw Application::Exception( L"Can't start! Direct3D is busy!" ); 809 } 810 else if (buffers != presentation.BackBufferCount) 811 { 812 buffers = presentation.BackBufferCount; 813 Io::Log() << "Direct3D: Warning! IDirect3D9::CreateDevice() failed, retrying with one back-buffer only..\r\n"; 814 } 815 else if (flags == (D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING)) 816 { 817 flags = D3DCREATE_HARDWARE_VERTEXPROCESSING; 818 Io::Log() << "Direct3D: Warning! IDirect3D9::CreateDevice() failed, retrying without a pure device..\r\n"; 819 } 820 else if (flags == D3DCREATE_HARDWARE_VERTEXPROCESSING) 821 { 822 flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; 823 Io::Log() << "Direct3D: Warning! IDirect3D9::CreateDevice() failed, retrying with software vertex processing mode..\r\n"; 824 } 825 else 826 { 827 if (HDC const hdc = ::GetDC( NULL )) 828 { 829 const int bits = ::GetDeviceCaps( hdc, BITSPIXEL ); 830 ::ReleaseDC( NULL, hdc ); 831 832 if (bits && bits != 16 && bits != 32) 833 throw Application::Exception( IDS_ERR_BAD_BPP ); 834 } 835 836 throw Application::Exception( IDS_ERR_D3D_DEVICE_FAILED ); 837 } 838 } 839 840 Prepare(); 841 fonts.Create( *this ); 842 843 Io::Log() << "Direct3D: creating " 844 << (adapter.deviceType == Adapter::DEVICE_HAL ? "HAL device #" : "REF device #") 845 << adapter.ordinal 846 << "\r\n"; 847 848 LogDisplaySwitch(); 849 } 850 GetDisplayMode(D3DDISPLAYMODE & displayMode) const851 bool Direct2D::Device::GetDisplayMode(D3DDISPLAYMODE& displayMode) const 852 { 853 IDirect3D9* base; 854 855 if (SUCCEEDED(com->GetDirect3D( &base ))) 856 { 857 const HRESULT hResult = base->GetAdapterDisplayMode( ordinal, &displayMode ); 858 base->Release(); 859 860 if (SUCCEEDED(hResult)) 861 return true; 862 } 863 864 displayMode.Width = presentation.BackBufferWidth; 865 displayMode.Height = presentation.BackBufferHeight; 866 867 return false; 868 } 869 870 #ifdef NST_MSVC_OPTIMIZE 871 #pragma optimize("t", on) 872 #endif 873 GetPresentationFlags() const874 DWORD Direct2D::Device::GetPresentationFlags() const 875 { 876 return (dialogBoxMode && !presentation.Windowed) ? D3DPRESENTFLAG_LOCKABLE_BACKBUFFER : 0; 877 } 878 GetSwapEffect() const879 D3DSWAPEFFECT Direct2D::Device::GetSwapEffect() const 880 { 881 return (dialogBoxMode && !presentation.Windowed) || (presentation.BackBufferCount > 1) ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY; 882 } 883 GetDesiredPresentationRate(const Mode & mode) const884 uint Direct2D::Device::GetDesiredPresentationRate(const Mode& mode) const 885 { 886 if (presentation.Windowed) 887 { 888 return 0; 889 } 890 else if (timing.autoHz) 891 { 892 int match = INT_MAX; 893 Mode::Rates::const_iterator close(mode.rates.begin()); 894 895 for (Mode::Rates::const_iterator it(mode.rates.end()), begin(mode.rates.begin());; ) 896 { 897 --it; 898 899 for (uint i=5; --i; ) 900 { 901 int diff = int(timing.frameRate * i) - int(*it); 902 903 if (diff == 0) 904 return *it; 905 906 if (diff < 0) 907 diff = int(*it) - int(timing.frameRate * i); 908 909 if (match > diff) 910 { 911 match = diff; 912 close = it; 913 } 914 } 915 916 if (it == begin) 917 break; 918 } 919 920 return *close; 921 } 922 else for (Mode::Rates::const_iterator it(mode.rates.begin()), end(mode.rates.end()); it != end; ++it) 923 { 924 if (*it == Mode::DEFAULT_RATE) 925 return Mode::DEFAULT_RATE; 926 } 927 928 return 0; 929 } 930 GetDesiredPresentationInterval(const uint rate) const931 DWORD Direct2D::Device::GetDesiredPresentationInterval(const uint rate) const 932 { 933 if (!timing.vsync || rate % timing.frameRate) 934 { 935 return D3DPRESENT_INTERVAL_IMMEDIATE; 936 } 937 else if (!presentation.Windowed) 938 { 939 if (timing.frameRate * 4 == rate && intervalFour) 940 { 941 return D3DPRESENT_INTERVAL_FOUR; 942 } 943 else if (timing.frameRate * 3 == rate && intervalThree) 944 { 945 return D3DPRESENT_INTERVAL_THREE; 946 } 947 else if (timing.frameRate * 2 == rate && intervalTwo) 948 { 949 return D3DPRESENT_INTERVAL_TWO; 950 } 951 } 952 953 return timing.frameRate == rate ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; 954 } 955 GetRefreshRate() const956 uint Direct2D::Device::GetRefreshRate() const 957 { 958 if (presentation.Windowed) 959 { 960 D3DDISPLAYMODE mode; 961 return GetDisplayMode( mode ) ? mode.RefreshRate : 0; 962 } 963 else 964 { 965 return presentation.FullScreen_RefreshRateInHz; 966 } 967 } 968 GetDesiredPresentationInterval() const969 DWORD Direct2D::Device::GetDesiredPresentationInterval() const 970 { 971 return GetDesiredPresentationInterval( GetRefreshRate() ); 972 } 973 Reset()974 HRESULT Direct2D::Device::Reset() 975 { 976 fonts.OnLost(); 977 978 const uint oldInterval = presentation.PresentationInterval; 979 presentation.PresentationInterval = GetDesiredPresentationInterval(); 980 uint buffers = timing.tripleBuffering ? 2 : 1; 981 presentation.BackBufferCount = buffers; 982 presentation.Flags = GetPresentationFlags(); 983 presentation.SwapEffect = GetSwapEffect(); 984 985 for (;;) 986 { 987 const HRESULT hResult = com->Reset( &presentation ); 988 989 if (SUCCEEDED(hResult)) 990 { 991 break; 992 } 993 else if (hResult == D3DERR_DEVICELOST) 994 { 995 return D3DERR_DEVICELOST; 996 } 997 else if (buffers != presentation.BackBufferCount) 998 { 999 buffers = presentation.BackBufferCount; 1000 Io::Log() << "Direct3D: Warning! IDirect3DDevice9::Reset() failed, retrying with one back-buffer only..\r\n"; 1001 } 1002 else throw Application::Exception 1003 ( 1004 IDS_ERR_FAILED, 1005 hResult == D3DERR_INVALIDCALL ? L"IDirect3DDevice9::Reset() (code: D3DERR_INVALIDCALL)" : 1006 hResult == D3DERR_OUTOFVIDEOMEMORY ? L"IDirect3DDevice9::Reset() (code: D3DERR_OUTOFVIDEOMEMORY)" : 1007 hResult == D3DERR_DRIVERINTERNALERROR ? L"IDirect3DDevice9::Reset() (code: D3DERR_DRIVERINTERNALERROR)" : 1008 hResult == E_OUTOFMEMORY ? L"IDirect3DDevice9::Reset() (code: E_OUTOFMEMORY)" : 1009 L"IDirect3DDevice9::Reset()" 1010 ); 1011 } 1012 1013 if (!presentation.Windowed && dialogBoxMode && FAILED(com->SetDialogBoxMode( true ))) 1014 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetDialogBoxMode()" ); 1015 1016 Prepare(); 1017 fonts.OnReset(); 1018 1019 if (presentation.PresentationInterval != oldInterval) 1020 { 1021 Io::Log() << 1022 ( 1023 presentation.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE ? "Direct3D: disabling VSYNC\r\n" : 1024 presentation.PresentationInterval == D3DPRESENT_INTERVAL_TWO ? "Direct3D: enabling VSYNC on second refresh\r\n" : 1025 presentation.PresentationInterval == D3DPRESENT_INTERVAL_THREE ? "Direct3D: enabling VSYNC on third refresh\r\n" : 1026 "Direct3D: enabling VSYNC\r\n" 1027 ); 1028 } 1029 1030 if (!presentation.Windowed && ::GetMenu( presentation.hDeviceWindow )) 1031 ::DrawMenuBar( presentation.hDeviceWindow ); 1032 1033 return D3D_OK; 1034 } 1035 Prepare() const1036 void Direct2D::Device::Prepare() const 1037 { 1038 com->SetRenderState( D3DRS_ZWRITEENABLE, false ); 1039 com->SetRenderState( D3DRS_COLORVERTEX, false ); 1040 com->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); 1041 com->SetRenderState( D3DRS_LIGHTING, false ); 1042 } 1043 LogDisplaySwitch() const1044 void Direct2D::Device::LogDisplaySwitch() const 1045 { 1046 Io::Log log; 1047 log << "Direct3D: entering "; 1048 1049 D3DDISPLAYMODE mode; 1050 1051 if (GetDisplayMode( mode )) 1052 { 1053 log << mode.Width 1054 << 'x' 1055 << mode.Height 1056 << 'x' 1057 << Base::FormatToBpp(mode.Format) 1058 << ' ' 1059 << mode.RefreshRate 1060 << "hz "; 1061 } 1062 1063 log << (presentation.Windowed ? "window mode\r\n" : "full-screen mode\r\n"); 1064 } 1065 GetMaxMessageLength() const1066 uint Direct2D::Device::GetMaxMessageLength() const 1067 { 1068 return fonts.Width() ? (presentation.BackBufferWidth - fonts.Width() * 7) / fonts.Width() : 64; 1069 } 1070 1071 #ifdef NST_MSVC_OPTIMIZE 1072 #pragma optimize("", on) 1073 #endif 1074 Repair(const HRESULT lastError)1075 HRESULT Direct2D::Device::Repair(const HRESULT lastError) 1076 { 1077 NST_ASSERT( FAILED(lastError) ); 1078 1079 uint id = 0; 1080 wcstring msg; 1081 1082 switch (lastError) 1083 { 1084 case D3DERR_DEVICELOST: 1085 case D3DERR_DEVICENOTRESET: 1086 1087 switch (com->TestCooperativeLevel()) 1088 { 1089 case D3DERR_DEVICELOST: 1090 1091 return D3DERR_DEVICELOST; 1092 1093 case D3DERR_DEVICENOTRESET: 1094 1095 return Reset(); 1096 1097 case D3DERR_DRIVERINTERNALERROR: 1098 1099 msg = L"Internal video driver error! Try upgrading it!"; 1100 break; 1101 1102 default: 1103 1104 id = IDS_ERR_FAILED; 1105 msg = L"IDirect3DDevice9::TestCooperativeLevel()"; 1106 break; 1107 } 1108 1109 case D3DERR_DRIVERINTERNALERROR: 1110 1111 msg = L"Internal video driver error! Try upgrading it!"; 1112 break; 1113 1114 case E_OUTOFMEMORY: 1115 1116 msg = L"Out of memory!"; 1117 break; 1118 1119 case D3DERR_OUTOFVIDEOMEMORY: 1120 1121 msg = L"Out of video memory!"; 1122 break; 1123 1124 default: 1125 1126 msg = L"Unknown Direct3D error!"; 1127 break; 1128 } 1129 1130 throw Application::Exception( id, msg ); 1131 } 1132 1133 #ifdef NST_MSVC_OPTIMIZE 1134 #pragma optimize("t", on) 1135 #endif 1136 CanToggleDialogBoxMode(bool enable) const1137 bool Direct2D::Device::CanToggleDialogBoxMode(bool enable) const 1138 { 1139 return !presentation.Windowed && dialogBoxMode != enable; 1140 } 1141 1142 /** 1143 * Verifies if a switch to a fullscreen mode can be made or if the mode is already set to fullscreen. 1144 * 1145 * @param mode The video mode to set to fullscreen. 1146 * @return True if switched to the fullscreen mode can be made. False if the mode is already set to fullscreen. 1147 */ CanSwitchFullscreen(const Mode & mode) const1148 bool Direct2D::Device::CanSwitchFullscreen(const Mode& mode) const 1149 { 1150 return 1151 ( 1152 presentation.Windowed || 1153 presentation.BackBufferWidth != mode.width || 1154 presentation.BackBufferHeight != mode.height || 1155 presentation.BackBufferFormat != (mode.bpp == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8) || 1156 presentation.FullScreen_RefreshRateInHz != GetDesiredPresentationRate( mode ) 1157 ); 1158 } 1159 1160 /** 1161 * Switches to fullscreen mode. Creates fonts to be displayed in fullscreen. 1162 * 1163 * @param mode The video mode to set to fullscreen. 1164 * @throws Application::Exception If failed switch to fullscreen. 1165 * @see Application::Exception 1166 */ SwitchFullscreen(const Mode & mode)1167 void Direct2D::Device::SwitchFullscreen(const Mode& mode) 1168 { 1169 presentation.Windowed = false; 1170 presentation.BackBufferWidth = mode.width; 1171 presentation.BackBufferHeight = mode.height; 1172 presentation.BackBufferFormat = (mode.bpp == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8); 1173 presentation.FullScreen_RefreshRateInHz = GetDesiredPresentationRate( mode ); 1174 1175 if (FAILED(Reset())) 1176 throw Application::Exception( L"Couldn't switch display mode!" ); 1177 1178 fonts.Create( *this ); 1179 LogDisplaySwitch(); 1180 } 1181 ToggleDialogBoxMode()1182 HRESULT Direct2D::Device::ToggleDialogBoxMode() 1183 { 1184 NST_ASSERT( !presentation.Windowed ); 1185 1186 if (dialogBoxMode) 1187 { 1188 dialogBoxMode = false; 1189 com->SetDialogBoxMode( false ); 1190 } 1191 else 1192 { 1193 dialogBoxMode = true; 1194 } 1195 1196 return Reset(); 1197 } 1198 1199 /** 1200 * Switches to window mode. Destroys any fullscreen fonts and creates fonts to be displayed in status bar. 1201 * 1202 * @throws Application::Exception If failed switch to window mode. 1203 * @see Application::Exception 1204 */ SwitchWindowed()1205 void Direct2D::Device::SwitchWindowed() 1206 { 1207 fonts.Destroy( false ); 1208 1209 presentation.Windowed = true; 1210 presentation.BackBufferWidth = 0; 1211 presentation.BackBufferHeight = 0; 1212 presentation.BackBufferFormat = D3DFMT_UNKNOWN; 1213 presentation.FullScreen_RefreshRateInHz = 0; 1214 1215 if (dialogBoxMode) 1216 { 1217 dialogBoxMode = false; 1218 com->SetDialogBoxMode( false ); 1219 } 1220 1221 if (FAILED(Reset())) 1222 throw Application::Exception( L"Couldn't switch display mode!" ); 1223 1224 fonts.Create( *this ); 1225 LogDisplaySwitch(); 1226 } 1227 ResetWindowClient(const Point & client,HRESULT hResult)1228 HRESULT Direct2D::Device::ResetWindowClient(const Point& client,HRESULT hResult) 1229 { 1230 NST_ASSERT( presentation.Windowed && client.x > 0 && client.y > 0 ); 1231 1232 presentation.BackBufferWidth = client.x; 1233 presentation.BackBufferHeight = client.y; 1234 1235 if (SUCCEEDED(hResult) || hResult == INVALID_RECT) 1236 hResult = Reset(); 1237 1238 return hResult; 1239 } 1240 ResetFrameRate(uint frameRate,bool vsync,bool tripleBuffering,const Base & base)1241 bool Direct2D::Device::ResetFrameRate(uint frameRate,bool vsync,bool tripleBuffering,const Base& base) 1242 { 1243 timing.frameRate = frameRate; 1244 timing.vsync = vsync; 1245 1246 bool update = false; 1247 1248 if (timing.tripleBuffering != tripleBuffering) 1249 { 1250 timing.tripleBuffering = tripleBuffering; 1251 update = true; 1252 } 1253 1254 if (!presentation.Windowed) 1255 { 1256 const Mode mode 1257 ( 1258 presentation.BackBufferWidth, 1259 presentation.BackBufferHeight, 1260 presentation.BackBufferFormat == D3DFMT_X8R8G8B8 ? 32 : 16 1261 ); 1262 1263 frameRate = GetDesiredPresentationRate( *base.GetAdapter(ordinal).modes.find(mode) ); 1264 1265 if (presentation.FullScreen_RefreshRateInHz != frameRate) 1266 { 1267 presentation.FullScreen_RefreshRateInHz = frameRate; 1268 update = true; 1269 } 1270 } 1271 1272 return update || presentation.PresentationInterval != GetDesiredPresentationInterval(); 1273 } 1274 Fonts()1275 Direct2D::Device::Fonts::Fonts() 1276 : width(0) {} 1277 Create(const Device & device)1278 void Direct2D::Device::Fonts::Font::Create(const Device& device) 1279 { 1280 wcstring fontName = L"System"; 1281 uint fontHeight = 12; 1282 1283 D3DDISPLAYMODE mode; 1284 device.GetDisplayMode( mode ); 1285 1286 if (mode.Width > 320 && mode.Height > 240) 1287 { 1288 fontHeight = mode.Height / (device.presentation.Windowed ? 32 : 16); 1289 1290 switch (PRIMARYLANGID(::GetUserDefaultLangID())) 1291 { 1292 case LANG_JAPANESE: fontName = L"MS Gothic"; break; 1293 case LANG_CHINESE: fontName = L"MS Hei"; break; 1294 case LANG_KOREAN: fontName = L"GulimChe"; break; 1295 default: fontName = L"Arial"; break; 1296 } 1297 } 1298 1299 if (com) 1300 { 1301 Object::Pod<D3DXFONT_DESC> desc; 1302 com->GetDesc( &desc ); 1303 1304 if (desc.Height == int(fontHeight) && bool(desc.Width > 320 && desc.Height > 240) == bool(mode.Width > 320 && mode.Height > 240)) 1305 return; 1306 1307 com.Release(); 1308 } 1309 1310 ::D3DXCreateFont 1311 ( 1312 *device.com, 1313 fontHeight, 1314 0, 1315 FW_NORMAL, 1316 1, 1317 false, 1318 DEFAULT_CHARSET, 1319 OUT_DEFAULT_PRECIS, 1320 DEFAULT_QUALITY, 1321 DEFAULT_PITCH|FF_DONTCARE, 1322 fontName, 1323 &com 1324 ); 1325 } 1326 Width() const1327 uint Direct2D::Device::Fonts::Font::Width() const 1328 { 1329 TEXTMETRIC metric; 1330 1331 if (com && SUCCEEDED(com->GetTextMetrics( &metric ))) 1332 return metric.tmAveCharWidth; 1333 else 1334 return 0; 1335 } 1336 Destroy()1337 void Direct2D::Device::Fonts::Font::Destroy() 1338 { 1339 length = 0; 1340 com.Release(); 1341 } 1342 OnReset() const1343 void Direct2D::Device::Fonts::Font::OnReset() const 1344 { 1345 if (com) 1346 com->OnResetDevice(); 1347 } 1348 OnLost() const1349 void Direct2D::Device::Fonts::Font::OnLost() const 1350 { 1351 if (com) 1352 com->OnLostDevice(); 1353 } 1354 Update(const GenericString & newstring)1355 void Direct2D::Device::Fonts::Font::Update(const GenericString& newstring) 1356 { 1357 string = newstring; 1358 length = newstring.Length(); 1359 1360 if (length && com) 1361 com->PreloadText( string.Ptr(), string.Length() ); 1362 } 1363 Create(const Device & device)1364 void Direct2D::Device::Fonts::Create(const Device& device) 1365 { 1366 nfo.Create( device ); 1367 1368 if (!device.presentation.Windowed) 1369 { 1370 fps.Create( device ); 1371 msg.Create( device ); 1372 } 1373 1374 width = nfo.Width(); 1375 } 1376 Destroy(const bool newDevice)1377 void Direct2D::Device::Fonts::Destroy(const bool newDevice) 1378 { 1379 width = 0; 1380 1381 fps.Destroy(); 1382 msg.Destroy(); 1383 1384 if (newDevice) 1385 nfo.Destroy(); 1386 else 1387 nfo.OnReset(); 1388 } 1389 OnReset() const1390 void Direct2D::Device::Fonts::OnReset() const 1391 { 1392 fps.OnReset(); 1393 msg.OnReset(); 1394 nfo.OnReset(); 1395 } 1396 OnLost() const1397 void Direct2D::Device::Fonts::OnLost() const 1398 { 1399 fps.OnLost(); 1400 msg.OnLost(); 1401 nfo.OnLost(); 1402 } 1403 Timing()1404 Direct2D::Device::Timing::Timing() 1405 : 1406 autoHz (false), 1407 vsync (false), 1408 tripleBuffering (false), 1409 frameRate (Mode::DEFAULT_RATE) 1410 { 1411 } 1412 VertexBuffer()1413 Direct2D::VertexBuffer::VertexBuffer() 1414 : numVertices(4), screenCurvature(0), dirty(false) {} 1415 ~VertexBuffer()1416 Direct2D::VertexBuffer::~VertexBuffer() 1417 { 1418 Invalidate(); 1419 } 1420 Update(const Rect & picture,const Rect & c,const int s)1421 void Direct2D::VertexBuffer::Update(const Rect& picture,const Rect& c,const int s) 1422 { 1423 NST_ASSERT( picture.Width() > 0 && picture.Height() > 0 && c.Width() > 0 && c.Height() > 0 ); 1424 1425 dirty = true; 1426 1427 rect = picture; 1428 clip = c; 1429 screenCurvature = s; 1430 1431 const uint n = (s ? (TSL_PATCHES+1) * (TSL_PATCHES+1) : 4); 1432 1433 if (numVertices != n) 1434 { 1435 numVertices = n; 1436 Invalidate(); 1437 } 1438 } 1439 Invalidate()1440 void Direct2D::VertexBuffer::Invalidate() 1441 { 1442 if (com) 1443 { 1444 IDirect3DDevice9* device; 1445 1446 if (SUCCEEDED(com->GetDevice( &device ))) 1447 { 1448 device->SetStreamSource( 0, NULL, 0, 0 ); 1449 device->Release(); 1450 } 1451 1452 com.Release(); 1453 } 1454 } 1455 Validate(IDirect3DDevice9 & device,const Textures & textures)1456 HRESULT Direct2D::VertexBuffer::Validate(IDirect3DDevice9& device,const Textures& textures) 1457 { 1458 if (!com) 1459 { 1460 const HRESULT hResult = device.CreateVertexBuffer 1461 ( 1462 numVertices * sizeof(Vertex), 1463 D3DUSAGE_WRITEONLY, 1464 FVF, 1465 D3DPOOL_MANAGED, 1466 &com, 1467 NULL 1468 ); 1469 1470 if (FAILED(hResult)) 1471 { 1472 if (hResult == D3DERR_DEVICELOST) 1473 return D3DERR_DEVICELOST; 1474 else 1475 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::CreateVertexBuffer()" ); 1476 } 1477 1478 dirty = true; 1479 } 1480 1481 if (dirty) 1482 { 1483 dirty = false; 1484 1485 void* ptr; 1486 const HRESULT hResult = com->Lock( 0, 0, &ptr, D3DLOCK_NOSYSLOCK ); 1487 1488 if (SUCCEEDED(hResult)) 1489 { 1490 Vertex* NST_RESTRICT v = static_cast<Vertex*>(ptr); 1491 1492 dirty = true; 1493 1494 if (screenCurvature) 1495 { 1496 const float z = 1.f - screenCurvature / 40.f; 1497 const D3DXVECTOR2 p0( rect.left - 0.499f, rect.top - 0.499f ); 1498 const D3DXVECTOR2 p1( rect.right - 0.499f, rect.bottom - 0.499f ); 1499 const D3DXVECTOR2 t( rect.Width() * z, rect.Height() * z ); 1500 1501 for (uint y=0; y <= TSL_PATCHES; ++y) 1502 { 1503 D3DXVECTOR2 vy; 1504 1505 float weight = y / float(TSL_PATCHES); 1506 ::D3DXVec2Hermite( &vy, &p0, &t, &p1, &t, weight ); 1507 1508 vy.x = textures.GetScreenBottomV(clip.top + clip.Height() * weight); 1509 float x1 = textures.GetEffectBottomV(clip.top + clip.Height() * weight); 1510 1511 for (uint x=0; x <= TSL_PATCHES; ++x, ++v) 1512 { 1513 D3DXVECTOR2 vx; 1514 1515 weight = x / float(TSL_PATCHES); 1516 ::D3DXVec2Hermite( &vx, &p0, &t, &p1, &t, weight ); 1517 1518 v->x = vx.x; 1519 v->y = vy.y; 1520 v->z = 0.f; 1521 v->rhw = 1.f; 1522 v->u0 = textures.GetScreenLeftU(clip.left + clip.Width() * weight); 1523 v->u1 = textures.GetEffectLeftU(clip.left + clip.Width() * weight); 1524 v->v0 = vy.x; 1525 v->v1 = x1; 1526 } 1527 } 1528 } 1529 else 1530 { 1531 v[0].x = rect.left - 0.499f; 1532 v[0].y = rect.top - 0.499f; 1533 v[0].z = 0.f; 1534 v[0].rhw = 1.f; 1535 v[0].u0 = textures.GetScreenLeftU( clip.left ); 1536 v[0].u1 = textures.GetEffectLeftU( clip.left ); 1537 v[0].v0 = textures.GetScreenTopV( clip.top ); 1538 v[0].v1 = textures.GetEffectTopV( clip.top ); 1539 v[1].x = rect.left - 0.499f; 1540 v[1].y = rect.bottom - 0.499f; 1541 v[1].z = 0.f; 1542 v[1].rhw = 1.f; 1543 v[1].u0 = textures.GetScreenLeftU( clip.left ); 1544 v[1].u1 = textures.GetEffectLeftU( clip.left ); 1545 v[1].v0 = textures.GetScreenBottomV( clip.bottom ); 1546 v[1].v1 = textures.GetEffectBottomV( clip.bottom ); 1547 v[2].x = rect.right - 0.499f; 1548 v[2].y = rect.top - 0.499f; 1549 v[2].z = 0.f; 1550 v[2].rhw = 1.f; 1551 v[2].u0 = textures.GetScreenRightU( clip.right ); 1552 v[2].u1 = textures.GetEffectRightU( clip.right ); 1553 v[2].v0 = textures.GetScreenTopV( clip.top ); 1554 v[2].v1 = textures.GetEffectTopV( clip.top ); 1555 v[3].x = rect.right - 0.499f; 1556 v[3].y = rect.bottom - 0.499f; 1557 v[3].z = 0.f; 1558 v[3].rhw = 1.f; 1559 v[3].u0 = textures.GetScreenRightU( clip.right ); 1560 v[3].u1 = textures.GetEffectRightU( clip.right ); 1561 v[3].v0 = textures.GetScreenBottomV( clip.bottom ); 1562 v[3].v1 = textures.GetEffectBottomV( clip.bottom ); 1563 } 1564 1565 com->Unlock(); 1566 } 1567 else if (hResult == D3DERR_DEVICELOST) 1568 { 1569 return D3DERR_DEVICELOST; 1570 } 1571 else 1572 { 1573 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DVertexBuffer9::Lock()" ); 1574 } 1575 1576 com->PreLoad(); 1577 } 1578 1579 if (FAILED(device.SetFVF( FVF ))) 1580 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetFVF()" ); 1581 1582 if (FAILED(device.SetStreamSource( 0, *com, 0, sizeof(Vertex) ))) 1583 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetStreamSource()" ); 1584 1585 return D3D_OK; 1586 } 1587 IndexBuffer()1588 Direct2D::IndexBuffer::IndexBuffer() 1589 : numStrips(0) {} 1590 ~IndexBuffer()1591 Direct2D::IndexBuffer::~IndexBuffer() 1592 { 1593 Invalidate(); 1594 } 1595 Update(bool s)1596 void Direct2D::IndexBuffer::Update(bool s) 1597 { 1598 if (bool(numStrips) != s) 1599 { 1600 numStrips = (s ? (TSL_PATCHES * 2 + 1) * TSL_PATCHES - 1 : 0); 1601 Invalidate(); 1602 } 1603 } 1604 Invalidate()1605 void Direct2D::IndexBuffer::Invalidate() 1606 { 1607 if (com) 1608 { 1609 IDirect3DDevice9* device; 1610 1611 if (SUCCEEDED(com->GetDevice( &device ))) 1612 { 1613 device->SetIndices( NULL ); 1614 device->Release(); 1615 } 1616 1617 com.Release(); 1618 } 1619 } 1620 Validate(IDirect3DDevice9 & device)1621 HRESULT Direct2D::IndexBuffer::Validate(IDirect3DDevice9& device) 1622 { 1623 NST_ASSERT( !com || numStrips ); 1624 1625 if (numStrips) 1626 { 1627 if (!com) 1628 { 1629 const HRESULT hResult = device.CreateIndexBuffer 1630 ( 1631 (((TSL_PATCHES * 2 + 1) * TSL_PATCHES) + 1) * sizeof(WORD), 1632 D3DUSAGE_WRITEONLY, 1633 D3DFMT_INDEX16, 1634 D3DPOOL_MANAGED, 1635 &com, 1636 NULL 1637 ); 1638 1639 if (SUCCEEDED(hResult)) 1640 { 1641 void* ptr; 1642 const HRESULT hResult = com->Lock( 0, 0, &ptr, D3DLOCK_NOSYSLOCK ); 1643 1644 if (SUCCEEDED(hResult)) 1645 { 1646 WORD* NST_RESTRICT data = static_cast<WORD*>(ptr); 1647 1648 for (uint p=0, i=0, n=TSL_PATCHES+1;;) 1649 { 1650 uint j = i + n; 1651 1652 do 1653 { 1654 *data++ = i; 1655 *data++ = i++ + n; 1656 } 1657 while (i < j); 1658 1659 i += n-1; 1660 1661 do 1662 { 1663 *data++ = i-- + n; 1664 *data++ = i; 1665 } 1666 while (i > j); 1667 1668 i += n; 1669 p += 2; 1670 1671 if (p == n-1) 1672 { 1673 *data++ = i; 1674 break; 1675 } 1676 } 1677 1678 com->Unlock(); 1679 } 1680 else if (hResult == D3DERR_DEVICELOST) 1681 { 1682 return D3DERR_DEVICELOST; 1683 } 1684 else 1685 { 1686 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DIndexBuffer9::Lock()" ); 1687 } 1688 } 1689 else if (hResult == D3DERR_DEVICELOST) 1690 { 1691 return D3DERR_DEVICELOST; 1692 } 1693 else 1694 { 1695 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::CreateIndexBuffer()" ); 1696 } 1697 } 1698 1699 com->PreLoad(); 1700 1701 if (FAILED(device.SetIndices( *com ))) 1702 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetIndices()" ); 1703 } 1704 1705 return D3D_OK; 1706 } 1707 Textures(D3DFORMAT backBufferFormat)1708 Direct2D::Textures::Textures(D3DFORMAT backBufferFormat) 1709 : 1710 screenTexture (backBufferFormat), 1711 effectTexture (backBufferFormat), 1712 filter (Adapter::FILTER_NONE) 1713 {} 1714 Update(const Adapter & adapter,const Point & screen,const uint scanlines,const Adapter::Filter f,const bool useVidMem)1715 void Direct2D::Textures::Update(const Adapter& adapter,const Point& screen,const uint scanlines,const Adapter::Filter f,const bool useVidMem) 1716 { 1717 NST_ASSERT( screen.x > 0 && screen.y > 0 ); 1718 1719 filter = f; 1720 1721 effectTexture.Update( adapter, screen, scanlines ); 1722 screenTexture.Update( adapter, screen, useVidMem ); 1723 } 1724 Flush()1725 void Direct2D::Textures::Flush() 1726 { 1727 screenTexture.Flush(); 1728 } 1729 Invalidate()1730 void Direct2D::Textures::Invalidate() 1731 { 1732 effectTexture.Invalidate(); 1733 screenTexture.Invalidate(); 1734 } 1735 Validate(IDirect3DDevice9 & device,const Adapter & adapter,const D3DFORMAT backBufferFormat)1736 HRESULT Direct2D::Textures::Validate(IDirect3DDevice9& device,const Adapter& adapter,const D3DFORMAT backBufferFormat) 1737 { 1738 if (screenTexture.Validate( device, backBufferFormat, adapter ) && effectTexture.Validate( device, backBufferFormat )) 1739 { 1740 const D3DTEXTUREFILTERTYPE type = (filter == Adapter::FILTER_NONE ? D3DTEXF_POINT : D3DTEXF_LINEAR); 1741 1742 for (uint i=0, n = (effectTexture ? 2 : 1); i < n; ++i) 1743 { 1744 device.SetSamplerState( i, D3DSAMP_MINFILTER, type ); 1745 device.SetSamplerState( i, D3DSAMP_MAGFILTER, type ); 1746 } 1747 1748 return D3D_OK; 1749 } 1750 1751 return D3DERR_DEVICELOST; 1752 } 1753 SaveToFile(wcstring const file,const D3DXIMAGE_FILEFORMAT type) const1754 bool Direct2D::Textures::SaveToFile(wcstring const file,const D3DXIMAGE_FILEFORMAT type) const 1755 { 1756 return screenTexture.SaveToFile( file, type ); 1757 } 1758 Texture(uint s,D3DFORMAT f)1759 Direct2D::Textures::Texture::Texture(uint s,D3DFORMAT f) 1760 : size(256,256), stage(s) 1761 { 1762 desc.Width = size.x; 1763 desc.Height = size.y; 1764 desc.Format = f; 1765 } 1766 ~Texture()1767 Direct2D::Textures::Texture::~Texture() 1768 { 1769 Invalidate(); 1770 } 1771 GetSquared(const Point & p)1772 uint Direct2D::Textures::Texture::GetSquared(const Point& p) 1773 { 1774 uint squared = NST_MAX(p.x,p.y); 1775 1776 squared--; 1777 squared |= squared >> 1; 1778 squared |= squared >> 2; 1779 squared |= squared >> 4; 1780 squared |= squared >> 8; 1781 squared |= squared >> 16; 1782 squared++; 1783 1784 return squared; 1785 } 1786 Invalidate()1787 void Direct2D::Textures::Texture::Invalidate() 1788 { 1789 if (com) 1790 { 1791 IDirect3DDevice9* device; 1792 1793 if (SUCCEEDED(com->GetDevice( &device ))) 1794 { 1795 device->SetTextureStageState( stage, D3DTSS_COLOROP, D3DTOP_DISABLE ); 1796 device->SetTexture( stage, NULL ); 1797 device->Release(); 1798 } 1799 1800 com.Release(); 1801 } 1802 } 1803 Validate(IDirect3DDevice9 & device,const D3DFORMAT desiredFormat,const bool dynamicUsage)1804 bool Direct2D::Textures::Texture::Validate(IDirect3DDevice9& device,const D3DFORMAT desiredFormat,const bool dynamicUsage) 1805 { 1806 if (!com) 1807 { 1808 const HRESULT hResult = ::D3DXCreateTexture 1809 ( 1810 &device, 1811 desc.Width, 1812 desc.Height, 1813 1, 1814 dynamicUsage ? D3DUSAGE_DYNAMIC : 0, 1815 desiredFormat, 1816 dynamicUsage ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, 1817 &com 1818 ); 1819 1820 if (SUCCEEDED(hResult)) 1821 { 1822 if (FAILED(com->GetLevelDesc( 0, &desc ))) 1823 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::GetLevelDesc()" ); 1824 1825 if (desc.Width >= size.x && desc.Height >= size.y) 1826 { 1827 if (!GetBitsPerPixel()) 1828 throw Application::Exception( L"Unsupported bits-per-pixel format!" ); 1829 1830 return true; 1831 } 1832 else 1833 { 1834 throw Application::Exception( L"Maximum texture dimension too small!" ); 1835 } 1836 } 1837 else if (hResult == D3DERR_DEVICELOST) 1838 { 1839 return false; 1840 } 1841 else 1842 { 1843 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::CreateTexture()" ); 1844 } 1845 } 1846 1847 return false; 1848 } 1849 ScreenTexture(D3DFORMAT f)1850 Direct2D::Textures::ScreenTexture::ScreenTexture(D3DFORMAT f) 1851 : Texture(0,f), useVidMem(false) {} 1852 Update(const Adapter & adapter,Point newSize,const bool wantVidMem)1853 void Direct2D::Textures::ScreenTexture::Update(const Adapter& adapter,Point newSize,const bool wantVidMem) 1854 { 1855 size = newSize; 1856 1857 if (!adapter.anyTextureSize) 1858 newSize = GetSquared(newSize); 1859 1860 if (desc.Width != newSize.x || desc.Height != newSize.y) 1861 { 1862 desc.Width = newSize.x; 1863 desc.Height = newSize.y; 1864 Invalidate(); 1865 } 1866 1867 if (useVidMem != wantVidMem) 1868 { 1869 useVidMem = wantVidMem; 1870 Invalidate(); 1871 } 1872 } 1873 Flush()1874 void Direct2D::Textures::ScreenTexture::Flush() 1875 { 1876 if (desc.Pool == D3DPOOL_DEFAULT) 1877 Invalidate(); 1878 } 1879 Validate(IDirect3DDevice9 & device,const D3DFORMAT desiredFormat,const Adapter & adapter)1880 bool Direct2D::Textures::ScreenTexture::Validate(IDirect3DDevice9& device,const D3DFORMAT desiredFormat,const Adapter& adapter) 1881 { 1882 if (!Texture::Validate( device, desiredFormat, useVidMem && adapter.videoMemScreen ) && !com) 1883 return false; 1884 1885 device.SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); 1886 device.SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 1887 device.SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); 1888 1889 device.SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); 1890 device.SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); 1891 1892 if (FAILED(device.SetTexture( 0, *com ))) 1893 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetTexture()" ); 1894 1895 return true; 1896 } 1897 SaveToFile(wcstring const file,const D3DXIMAGE_FILEFORMAT type) const1898 bool Direct2D::Textures::ScreenTexture::SaveToFile(wcstring const file,const D3DXIMAGE_FILEFORMAT type) const 1899 { 1900 NST_ASSERT( file && *file && size.x && size.y ); 1901 1902 if (!com) 1903 return false; 1904 1905 ComInterface<IDirect3DSurface9> surface; 1906 1907 { 1908 ComInterface<IDirect3DDevice9> device; 1909 1910 if (FAILED(com->GetDevice( &device ))) 1911 return false; 1912 1913 if (FAILED(device->CreateOffscreenPlainSurface( size.x, size.y, D3DFMT_R8G8B8, D3DPOOL_SCRATCH, &surface, NULL ))) 1914 return false; 1915 } 1916 1917 ulong masks[3]; 1918 GetBitMask(masks[0],masks[1],masks[2]); 1919 1920 uint shifts[3]; 1921 1922 for (uint i=0; i < 3; ++i) 1923 { 1924 NST_ASSERT( masks[i] ); 1925 1926 for (shifts[i]=0; !(masks[i] & 0x1); ++shifts[i]) 1927 masks[i] >>= 1; 1928 } 1929 1930 D3DLOCKED_RECT dstLock; 1931 1932 if (FAILED(surface->LockRect( &dstLock, NULL, D3DLOCK_NOSYSLOCK ))) 1933 return false; 1934 1935 D3DLOCKED_RECT srcLock; 1936 const RECT rect = {0,0,size.x,size.y}; 1937 1938 if (FAILED(com->LockRect( 0, &srcLock, &rect, D3DLOCK_READONLY|D3DLOCK_NOSYSLOCK ))) 1939 { 1940 surface->UnlockRect(); 1941 return false; 1942 } 1943 1944 BYTE* NST_RESTRICT dst = static_cast<BYTE*>(dstLock.pBits); 1945 const uint dstPitch = dstLock.Pitch - size.x * 3; 1946 1947 if (GetBitsPerPixel() == 16) 1948 { 1949 const WORD* NST_RESTRICT src = static_cast<WORD*>(srcLock.pBits); 1950 const uint srcPitch = srcLock.Pitch - size.x * sizeof(WORD); 1951 1952 for (uint y=size.y; y; --y) 1953 { 1954 for (const BYTE* const end=dst+size.x*3; dst != end; dst += 3) 1955 { 1956 const uint pixel = *src++; 1957 1958 dst[2] = ((pixel >> shifts[0] & masks[0]) * 0xFF + masks[0] / 2) / masks[0]; 1959 dst[1] = ((pixel >> shifts[1] & masks[1]) * 0xFF + masks[1] / 2) / masks[1]; 1960 dst[0] = ((pixel >> shifts[2] & masks[2]) * 0xFF + masks[2] / 2) / masks[2]; 1961 } 1962 1963 src = reinterpret_cast<const WORD*>(reinterpret_cast<const BYTE*>(src) + srcPitch); 1964 dst += dstPitch; 1965 } 1966 } 1967 else 1968 { 1969 const DWORD* NST_RESTRICT src = static_cast<DWORD*>(srcLock.pBits); 1970 const uint srcPitch = srcLock.Pitch - size.x * sizeof(DWORD); 1971 1972 for (uint y=size.y; y; --y) 1973 { 1974 for (const BYTE* const end=dst+size.x*3; dst != end; dst += 3) 1975 { 1976 const uint pixel = *src++; 1977 1978 dst[2] = ((pixel >> shifts[0] & masks[0]) * 0xFF + masks[0] / 2) / masks[0]; 1979 dst[1] = ((pixel >> shifts[1] & masks[1]) * 0xFF + masks[1] / 2) / masks[1]; 1980 dst[0] = ((pixel >> shifts[2] & masks[2]) * 0xFF + masks[2] / 2) / masks[2]; 1981 } 1982 1983 src = reinterpret_cast<const DWORD*>(reinterpret_cast<const BYTE*>(src) + srcPitch); 1984 dst += dstPitch; 1985 } 1986 } 1987 1988 com->UnlockRect( 0 ); 1989 surface->UnlockRect(); 1990 1991 return SUCCEEDED(::D3DXSaveSurfaceToFile( file, type, *surface, NULL, &rect )); 1992 } 1993 EffectTexture(D3DFORMAT f)1994 Direct2D::Textures::EffectTexture::EffectTexture(D3DFORMAT f) 1995 : Texture(1,f), scanlines(0), dirty(false) {} 1996 Update(const Adapter & adapter,Point newSize,const uint newScanlines)1997 void Direct2D::Textures::EffectTexture::Update(const Adapter& adapter,Point newSize,const uint newScanlines) 1998 { 1999 NST_ASSERT( newScanlines <= MAX_SCANLINES ); 2000 2001 newSize.x = 1; 2002 size = newSize; 2003 2004 if (!adapter.anyTextureSize) 2005 newSize = GetSquared(newSize); 2006 2007 if (desc.Width != newSize.x || desc.Height != newSize.y) 2008 { 2009 desc.Width = newSize.x; 2010 desc.Height = newSize.y; 2011 Invalidate(); 2012 } 2013 2014 if (scanlines != newScanlines) 2015 { 2016 dirty = true; 2017 2018 if ((scanlines > 0) != (newScanlines > 0)) 2019 Invalidate(); 2020 2021 scanlines = newScanlines; 2022 } 2023 } 2024 Validate(IDirect3DDevice9 & device,const D3DFORMAT desiredFormat)2025 bool Direct2D::Textures::EffectTexture::Validate(IDirect3DDevice9& device,const D3DFORMAT desiredFormat) 2026 { 2027 NST_ASSERT( !com || scanlines ); 2028 2029 if (scanlines) 2030 { 2031 if (Texture::Validate( device, desiredFormat, false )) 2032 { 2033 dirty = true; 2034 } 2035 else if (!com) 2036 { 2037 return false; 2038 } 2039 2040 if (dirty) 2041 { 2042 dirty = false; 2043 2044 ulong mask[3]; 2045 GetBitMask(mask[0],mask[1],mask[2]); 2046 2047 const uint intensity[2] = 2048 { 2049 mask[0] | mask[1] | mask[2], 2050 ((mask[0] * (100 - scanlines) / 100) & mask[0]) | 2051 ((mask[1] * (100 - scanlines) / 100) & mask[1]) | 2052 ((mask[2] * (100 - scanlines) / 100) & mask[2]) 2053 }; 2054 2055 D3DLOCKED_RECT lockedRect; 2056 const RECT rect = {0,0,desc.Width,desc.Height}; 2057 const HRESULT hResult = com->LockRect( 0, &lockedRect, &rect, D3DLOCK_NOSYSLOCK ); 2058 2059 if (SUCCEEDED(hResult)) 2060 { 2061 if (GetBitsPerPixel() == 32) 2062 { 2063 DWORD* NST_RESTRICT dst = static_cast<DWORD*>(lockedRect.pBits); 2064 const uint pitch = lockedRect.Pitch - desc.Width * sizeof(DWORD); 2065 2066 for (uint y=desc.Height/2; y; --y) 2067 { 2068 for (uint i=0; i < 2; ++i) 2069 { 2070 for (uint x=desc.Width; x; --x) 2071 *dst++ = intensity[i]; 2072 2073 dst = reinterpret_cast<DWORD*>(reinterpret_cast<BYTE*>(dst) + pitch); 2074 } 2075 } 2076 } 2077 else 2078 { 2079 WORD* NST_RESTRICT dst = static_cast<WORD*>(lockedRect.pBits); 2080 const uint pitch = lockedRect.Pitch - desc.Width * sizeof(WORD); 2081 2082 for (uint y=desc.Height/2; y; --y) 2083 { 2084 for (uint i=0; i < 2; ++i) 2085 { 2086 for (uint x=desc.Width; x; --x) 2087 *dst++ = intensity[i]; 2088 2089 dst = reinterpret_cast<WORD*>(reinterpret_cast<BYTE*>(dst) + pitch); 2090 } 2091 } 2092 } 2093 2094 com->UnlockRect(0); 2095 } 2096 else if (hResult == D3DERR_DEVICELOST) 2097 { 2098 return false; 2099 } 2100 else 2101 { 2102 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DTexture9::LockRect()" ); 2103 } 2104 2105 com->PreLoad(); 2106 } 2107 2108 device.SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); 2109 device.SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 2110 device.SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); 2111 2112 device.SetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP ); 2113 device.SetSamplerState( 1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP ); 2114 2115 if (FAILED(device.SetTexture( 1, *com ))) 2116 throw Application::Exception( IDS_ERR_FAILED, L"IDirect3DDevice9::SetTexture()" ); 2117 } 2118 2119 return true; 2120 } 2121 2122 #ifdef NST_MSVC_OPTIMIZE 2123 #pragma optimize("", on) 2124 #endif 2125 } 2126 } 2127