svvitch
digital signage player
D:/vs_workspace/switch_sf/src/svvitch/Renderer.cpp
Go to the documentation of this file.
00001 //=============================================================
00002 // Renderer.cpp
00003 // レンダラークラスの実装
00004 //=============================================================
00005 #define _WIN32_DCOM
00006 
00007 #include <Poco/Net/NetworkInterface.h>
00008 #include "Renderer.h"
00009 #include "Scene.h"
00010 #include "Utils.h"
00011 #include <Poco/File.h>
00012 #include <Poco/string.h>
00013 #include <Poco/format.h>
00014 #include <Poco/UnicodeConverter.h>
00015 #include <psapi.h>
00016 #include <errors.h>
00017 #include <winioctl.h>
00018 
00019 
00020 Renderer::Renderer():
00021     _log(Poco::Logger::get("")),
00022     _postedQuit(false), _d3d(NULL), _device(NULL), _backBuffer(NULL), _captureTexture(NULL), _sound(NULL), _fontTexture(NULL),
00023     _current(0), _lastDeviceChanged(0)
00024 {
00025 }
00026 
00027 Renderer::‾Renderer() {
00028     finalize();
00029 }
00030 
00034 HRESULT Renderer::initialize(HINSTANCE hInstance, HWND hWnd) {
00035     // COMの初期化
00036     HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
00037 //  hr = CoInitialize(NULL);
00038     if (FAILED(hr)) {   
00039         vector<WCHAR> err(1024);
00040         DWORD res = AMGetErrorText(hr, &err[0], 1024);
00041         string utf8;
00042         Poco::UnicodeConverter::toUTF8(wstring(&err[0]), utf8);
00043         _log.warning(Poco::format("failed com initialize: %s", utf8));
00044     }
00045 
00046     GdiplusStartup(&_gdiToken, &_gdiSI, NULL);
00047     // Direct3D9オブジェクトの作成
00048     if ((_d3d = Direct3DCreate9(D3D_SDK_VERSION)) == 0) return E_FAIL;
00049 
00050     //利用できるアダプタ数を数える
00051     D3DCAPS9 caps;
00052     _d3d->GetDeviceCaps(0, D3DDEVTYPE_HAL, &caps);
00053     _displayAdpters = caps.NumberOfAdaptersInGroup;
00054     _maxTextureW = caps.MaxTextureWidth;
00055     _maxTextureH = caps.MaxTextureHeight;
00056     if (config().imageSplitWidth <= 0) {
00057         config().imageSplitWidth = _maxTextureW;
00058     }
00059     _log.information(Poco::format("display adapters: %u texture-max: %ux%u", _displayAdpters, _maxTextureW, _maxTextureH));
00060     string usePsize = (caps.FVFCaps & D3DFVFCAPS_PSIZE)?"true":"false";
00061     _log.information(Poco::format("set point size: %s", usePsize));
00062 
00063     // 現在のディスプレイモードを取得
00064     D3DDISPLAYMODE d3ddm;
00065     if (FAILED(_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) {
00066         _log.warning("failed GetAdapterDisplayMode");
00067         return E_FAIL;
00068     }
00069 
00070     // デバイスのプレゼンテーションパラメータを初期化
00071     _presentParams = new D3DPRESENT_PARAMETERS[_displayAdpters];
00072     ZeroMemory(&_presentParams[0], sizeof(D3DPRESENT_PARAMETERS));
00073     if (config().fullsceen) {
00074         _presentParams[0].Windowed = FALSE;
00075         _presentParams[0].FullScreen_RefreshRateInHz = (config().mainRate == 0)?D3DPRESENT_RATE_DEFAULT:config().mainRate;
00076 //      _presentParams[0].FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
00077         _presentParams[0].BackBufferFormat = d3ddm.Format;
00078     } else {
00079         _presentParams[0].Windowed = TRUE;
00080         _presentParams[0].FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
00081         _presentParams[0].BackBufferFormat = D3DFMT_UNKNOWN;
00082     }
00083     _presentParams[0].BackBufferWidth = config().mainRect.right;
00084     _presentParams[0].BackBufferHeight = config().mainRect.bottom;
00085     _presentParams[0].BackBufferCount = 1;
00086     _presentParams[0].SwapEffect = D3DSWAPEFFECT_DISCARD;
00087     //_presentParams[0].SwapEffect = D3DSWAPEFFECT_FLIP;
00088     //_presentParams[0].SwapEffect = D3DSWAPEFFECT_COPY;
00089     _presentParams[0].MultiSampleType = D3DMULTISAMPLE_NONE;
00090     _presentParams[0].MultiSampleQuality = 0;
00091     _presentParams[0].hDeviceWindow = hWnd;
00092     _presentParams[0].EnableAutoDepthStencil = FALSE;
00093     _presentParams[0].AutoDepthStencilFormat = D3DFMT_D16;
00094     _presentParams[0].Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
00095     _presentParams[0].PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
00096     //_presentParams[0].PresentationInterval = D3DPRESENT_INTERVAL_ONE;
00097 
00098     if (config().fullsceen) {
00099         HWND hWnd2 = hWnd;
00100         for (int i = 1; i < _displayAdpters; i++) {
00101             //アダプタが2以上あればマルチヘッド用のD3DPRESENT_PARAMETERのデータを入力
00102             _presentParams[i] = _presentParams[0];
00103             WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WindowProc, 0, 0, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"multihead", NULL};
00104             RegisterClassEx(&wc);
00105             std::wstring wtitle;
00106             Poco::UnicodeConverter::toUTF16(config().windowTitle, wtitle);
00107             if (SUCCEEDED(_d3d->GetAdapterDisplayMode(i, &d3ddm))) {
00108                 hWnd2 = CreateWindow(wc.lpszClassName, wtitle.c_str(), WS_POPUP, 0, 0, d3ddm.Width, d3ddm.Height, NULL, NULL, wc.hInstance, NULL);
00109                 _presentParams[i].BackBufferWidth = d3ddm.Width;
00110                 _presentParams[i].BackBufferHeight = d3ddm.Height;
00111                 _presentParams[i].FullScreen_RefreshRateInHz = d3ddm.RefreshRate;
00112                 Configuration& conf = (Configuration)config();
00113                 conf.subRect.right = d3ddm.Width;
00114                 conf.subRect.bottom = d3ddm.Height;
00115             } else {
00116                 hWnd2 = CreateWindow(wc.lpszClassName, wtitle.c_str(), WS_POPUP, 0, 0, config().subRect.right, config().subRect.bottom, NULL, NULL, wc.hInstance, NULL);
00117                 _presentParams[i].FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
00118             }
00119             _presentParams[i].hDeviceWindow = hWnd2;
00120         }
00121     }
00122 
00123     // ディスプレイアダプタを表すためのデバイスを作成
00124     DWORD flag = D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE;
00125     if (config().fullsceen && _displayAdpters > 1) flag  |= D3DCREATE_ADAPTERGROUP_DEVICE;
00126     if (FAILED(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flag | D3DCREATE_HARDWARE_VERTEXPROCESSING, &_presentParams[0], &_device))) {
00127         // 上記の設定が失敗したら
00128         // 描画をハードウェアで行い、頂点処理はCPUで行なう
00129         if (FAILED(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flag | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &_presentParams[0], &_device))) {
00130             // 上記の設定が失敗したら
00131             // 描画と頂点処理をCPUで行なう
00132             if (FAILED(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, flag | D3DCREATE_SOFTWARE_VERTEXPROCESSING,& _presentParams[0], &_device))) {
00133                 // 初期化失敗
00134                 _log.warning("failed not create Direct3D device");
00135                 return E_FAIL;
00136             } else {
00137                 _log.information("device: REF/SOFTWARE_VERTEXPROCESSING");
00138             }
00139         } else {
00140             _log.information("device: HAL/SOFTWARE_VERTEXPROCESSING");
00141         }
00142     } else {
00143         _log.information("device: HAL/HARDWARE_VERTEXPROCESSING");
00144     }
00145     _textureMem = _device->GetAvailableTextureMem() / 1024 / 1024;
00146 
00147     // レンダリングターゲットの取得
00148     //  D3DSURFACE_DESC desc;
00149     //  HRESULT hr = _renderTarget->GetDesc(&desc);
00150     //  if (SUCCEEDED(hr)) _log.information(Poco::format("render target: %ux%u %d", desc.Width, desc.Height, (int)desc.Format));
00151     int w = config().stageRect.right;
00152     int h = config().stageRect.bottom;
00153     switch(config().splitType) {
00154     case 1:
00155         {
00156             int dw = config().splitSize.cx * config().splitCycles;
00157             w = (config().stageRect.right + dw) / dw * config().splitSize.cx;
00158             h = config().stageRect.bottom * config().splitCycles;
00159         }
00160         break;
00161     case 2:
00162         w = config().mainRect.right;
00163         h = config().mainRect.bottom;
00164         ;
00165     }
00166     int cw = w * config().captureQuality;
00167     int ch = h * config().captureQuality;
00168     _captureTexture = createRenderTarget(cw, ch);
00169     if (_captureTexture) {
00170         D3DSURFACE_DESC desc;
00171         _captureTexture->GetLevelDesc(0, &desc);
00172         _log.information(Poco::format("capture: %ux%u %d", desc.Width, desc.Height, (int)desc.Format));
00173     }
00174 
00175     // サウンドデバイスの生成
00176     hr = DirectSoundCreate(NULL, &_sound, NULL);
00177     if (FAILED(hr)) {
00178         _log.warning("failed not initialize direct sound");
00179         // return E_FAIL;
00180     } else {
00181         hr = _sound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
00182         if (FAILED(hr)) {
00183             _log.warning("failed not set cooperative level");
00184             return E_FAIL;
00185         }
00186     }
00187 
00188     // MediaFoundation向けのデバイスマネージャ生成
00189     hr = DXVA2CreateDirect3DDeviceManager9(&_deviceResetToken, &_devManager);
00190     if FAILED(hr) {
00191         _log.warning("failed DXVA2CreateDirect3DDeviceManager9");
00192     } else {
00193         hr = _devManager->ResetDevice(_device, _deviceResetToken);
00194         if SUCCEEDED(hr) _log.warning("initialized Direct3DDeviceManager9");
00195     }
00196 
00197     // フォント読込み
00198     _fc = new Gdiplus::PrivateFontCollection();
00199     Poco::File dir("fonts");
00200     if (dir.exists()) {
00201         vector<Poco::File> files;
00202         dir.list(files);
00203         for (vector<Poco::File>::iterator it = files.begin(); it != files.end(); it++) {
00204             Poco::File f = *it;
00205             int find = Poco::toLower(f.path()).find(".ttf");
00206             if (find >= 0 && find == f.path().length() - 4) {
00207                 addPrivateFontFile(f.path());
00208             } else {
00209                 find = Poco::toLower(f.path()).find(".ttc");
00210                 if (find >= 0 && find == f.path().length() - 4) {
00211                     addPrivateFontFile(f.path());
00212                 }
00213             }
00214         }
00215     } else {
00216         _log.warning("not found 'fonts' directory");
00217     }
00218 
00219     int count = 0;
00220     Gdiplus::FontFamily ff[32];
00221     _fc->GetFamilies(32, ff, &count);
00222     for (int i = 0; i < 32 && i < count; i++) {
00223         WCHAR s[64] = L"";
00224         ff[i].GetFamilyName(s);
00225         string name;
00226         Poco::UnicodeConverter::toUTF8(s, name);
00227         _log.information(Poco::format("private font family: %s", name));
00228         if (name == config().asciiFont) createFontTexture(&ff[i], 32);
00229 //      if (name == _conf->multiByteFont) _multiByteFont = ff[i].Clone();
00230     }
00231 
00232     Poco::Net::NetworkInterface::NetworkInterfaceList interfaces = Poco::Net::NetworkInterface::list();
00233     if (!interfaces.empty()) {
00234         for (Poco::Net::NetworkInterface::NetworkInterfaceList::const_iterator it = interfaces.begin(); it != interfaces.end(); it++) {
00235             Poco::Net::NetworkInterface netIF = *it;
00236             if (!netIF.address().isLoopback() && netIF.address().toString() != "0.1.0.4") {
00237                 _addresses.push_back(netIF.address().toString());
00238             }
00239         }
00240     }
00241 
00242     _keycode = 0;
00243     _shift = false;
00244     _ctrl = false;
00245     PROCESS_MEMORY_COUNTERS pmc = {0};
00246     GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(PROCESS_MEMORY_COUNTERS));
00247     _mem = pmc.WorkingSetSize / 1024;
00248     if (config().mainRate == 0) config().mainRate = 60;
00249 
00250     return S_OK;
00251 }
00252 
00253 const HWND Renderer::getWindowHandle() const {
00254     return _hwnd;
00255 }
00256 
00257 bool Renderer::peekMessage() {
00258     MSG msg;
00259     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
00260         if (msg.message == WM_QUIT) {
00261             // PostQuitMessage()が呼ばれた
00262             _postedQuit = true;
00263             _exitCode = (int)msg.wParam;
00264             //break;
00265         } else {
00266             // メッセージの翻訳とディスパッチ
00267             TranslateMessage(&msg);
00268             DispatchMessage(&msg);
00269         }
00270     }
00271     return !_postedQuit;
00272 }
00273 
00274 int Renderer::getExitCode() {
00275     return _exitCode;
00276 }
00277 
00278 void Renderer::finalize() {
00279     // DXUTShutdown();
00280     // Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00281     _sceneMap.clear();
00282     for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00283         SAFE_DELETE(*it);
00284     }
00285     _scenes.clear();
00286     for (Poco::HashMap<string, LPDIRECT3DTEXTURE9>::Iterator it = _cachedTextures.begin(); it != _cachedTextures.end(); it++) {
00287         SAFE_RELEASE(it->second);
00288     }
00289     _cachedTextures.clear();
00290 
00291     SAFE_RELEASE(_fontTexture);
00292     SAFE_RELEASE(_captureTexture);
00293     SAFE_RELEASE(_backBuffer);
00294     SAFE_RELEASE(_devManager);
00295     SAFE_RELEASE(_device);
00296     SAFE_RELEASE(_d3d);
00297     SAFE_DELETE(_presentParams);
00298     SAFE_DELETE(_fc);
00299     Gdiplus::GdiplusShutdown(_gdiToken);
00300 }
00301 
00302 
00306 void Renderer::drawText(const Gdiplus::FontFamily* ff, const int fontSize, const DWORD c1, const DWORD c2, const int w1, const DWORD c3, const int w2, const DWORD c4, const string& text, Gdiplus::Bitmap* bitmap, Gdiplus::Rect& rect) const {
00307     int x = 0;
00308     int y = 0;
00309     if (rect.Width - rect.X != 0) {
00310         x = -rect.X;
00311     }
00312     if (rect.Height - rect.Y != 0) {
00313         y = -rect.Y;
00314     }
00315 
00316     Gdiplus::Graphics g(bitmap);
00317     g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
00318     g.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
00319     Gdiplus::GraphicsPath path;
00320     std::wstring wtext;
00321     Poco::UnicodeConverter::toUTF16(text, wtext);
00322     path.AddString(wtext.c_str(), wcslen(wtext.c_str()), ff, Gdiplus::FontStyleRegular, fontSize, Gdiplus::Point(x, y), Gdiplus::StringFormat::GenericDefault());
00323     Gdiplus::Brush* foreBrush = NULL;
00324     if (c1 == c2) {
00325         foreBrush = new Gdiplus::SolidBrush(Gdiplus::Color(c1));
00326     } else {
00327         foreBrush = new Gdiplus::LinearGradientBrush(Gdiplus::Rect(0, 0, 1, rect.Height), Gdiplus::Color(c1), Gdiplus::Color(c2), Gdiplus::LinearGradientModeVertical);
00328     }
00329     Gdiplus::Pen* pen1 = NULL;
00330     if (w1 > 0) {
00331         Gdiplus::Color c1(c3);
00332         Gdiplus::SolidBrush brush(c1);
00333         pen1 = new Gdiplus::Pen(&brush, w1);
00334         pen1->SetLineJoin(Gdiplus::LineJoinRound);
00335         g.DrawPath(pen1, &path);
00336     }
00337     Gdiplus::Pen* pen2 = NULL;
00338     if (w2 > 0) {
00339         Gdiplus::Color c2(c4);
00340         Gdiplus::SolidBrush brush(c2);
00341         pen2 = new Gdiplus::Pen(&brush, w2);
00342         pen2->SetLineJoin(Gdiplus::LineJoinRound);
00343         g.DrawPath(pen2, &path);
00344     }
00345     g.FillPath(foreBrush, &path);
00346 
00347     // 描画領域を取得
00348     if (pen1) {
00349         // pen1のサイズでrectを取得
00350         path.Widen(pen1);
00351         path.GetBounds(&rect);
00352     } else if (pen2) {
00353         // pen2のサイズでrectを取得
00354         path.Widen(pen2);
00355         path.GetBounds(&rect);
00356     } else {
00357         path.GetBounds(&rect);
00358     }
00359     delete foreBrush;
00360     SAFE_DELETE(pen1);
00361     SAFE_DELETE(pen2);
00362     g.Flush();
00363 
00364 //  {
00365 //      UINT num;        // number of image encoders
00366 //      UINT size;       // size, in bytes, of the image encoder array
00367 //      ImageCodecInfo* pImageCodecInfo;
00368 //      GetImageEncodersSize(&num, &size);
00369 //      pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
00370 //      GetImageEncoders(num, size, pImageCodecInfo);
00371 //      for (int i = 0; i < num ; i ++) {
00372 //          if (!wcscmp(pImageCodecInfo[i].MimeType, L"image/png")) {
00373 //              bitmap.Save(L"test.png", &pImageCodecInfo[i].Clsid);
00374 //              break;
00375 //          }
00376 //      }
00377 //      free(pImageCodecInfo);
00378 //  }
00379 }
00380 
00384 void Renderer::createFontTexture(const Gdiplus::FontFamily* fontFamily, const int fontSize) {
00385     _fontTexture = createTexture(512, 512, D3DFMT_A8R8G8B8);
00386     if (_fontTexture) {
00387         colorFill(_fontTexture, 0);
00388         D3DLOCKED_RECT lockRect;
00389         HRESULT hr = _fontTexture->LockRect(0, &lockRect, NULL, 0);
00390         if (FAILED(hr)) {
00391             SAFE_RELEASE(_fontTexture);
00392         } else {
00393             Gdiplus::Bitmap bitmap(512, 512, lockRect.Pitch, PixelFormat32bppARGB, (BYTE*)lockRect.pBits);
00394             Gdiplus::Graphics g(&bitmap);
00395             g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
00396             g.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
00397             Gdiplus::Font font(fontFamily, fontSize, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel);
00398             Gdiplus::StringFormat format;
00399             format.SetAlignment(Gdiplus::StringAlignmentCenter);
00400             Gdiplus::SolidBrush brush(Gdiplus::Color::White);
00401             WCHAR ascii[2] = L"";
00402             for (int i = 0x20; i <= 0xff; i++) {
00403                 int x = (i % 16) * 32;
00404                 int y = (i / 16) * 32;
00405                 ascii[0] = i;
00406                 g.DrawString(ascii, 1, &font, Gdiplus::RectF(x, y - 3, 32, 32 + 3), &format, &brush);
00407             }
00408             g.Flush();
00409             _fontTexture->UnlockRect(0);
00410             _log.information("create font texture");
00411         }
00412     } else {
00413         _log.warning("failed create font texture");
00414     }
00415 }
00416 
00417 
00421 bool Renderer::deliveryMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
00422     switch (msg) {
00423     case WM_CREATE:
00424         break;
00425     case WM_MOUSEMOVE:
00426         break;
00427     case WM_LBUTTONDOWN:
00428         //押す
00429         break;
00430     case WM_LBUTTONUP:
00431         //離す
00432         break;
00433     case WM_LBUTTONDBLCLK:
00434         //ダブルクリック
00435         break;
00436     case WM_RBUTTONDOWN:
00437         break;
00438     case WM_RBUTTONUP:
00439         break;
00440     case WM_RBUTTONDBLCLK:
00441         break;
00442     }
00443     return false;
00444 }
00445 
00449 const LPDIRECT3DDEVICE9 Renderer::get3DDevice() const {
00450     return _device;
00451 }
00452 
00456 const LPDIRECTSOUND Renderer::getSoundDevice() const {
00457     return _sound;
00458 }
00459 
00463 void Renderer::notifyKeyDown(const int keycode, const bool shift, const bool ctrl) {
00464     _keycode = keycode;
00465     _shift = shift;
00466     _ctrl = ctrl;
00467     _keyUpdated = true;
00468 }
00469 
00470 void Renderer::notifyKeyUp(const int keycode, const bool shift,const  bool ctrl) {
00471 }
00472 
00473 const int Renderer::getSceneCount() {
00474     Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00475     return _scenes.size();
00476 }
00477 
00478 void Renderer::insertScene(const int i, const string name, Scene* scene) {
00479     Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00480     int j = 0;
00481     for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00482         if (i <= j) {
00483             _scenes.insert(it, scene);
00484             _sceneMap[name] = scene;
00485             return;
00486         }
00487         j++;
00488     }
00489     addScene(name, scene);
00490 }
00491 
00492 void Renderer::addScene(const string name, Scene* scene) {
00493     Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00494     _scenes.push_back(scene);
00495     _sceneMap[name] = scene;
00496 }
00497 
00498 Scene* Renderer::getScene(const string& name) {
00499     Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00500     Poco::HashMap<string, Scene*>::Iterator it = _sceneMap.find(name);
00501     if (it != _sceneMap.end()) {
00502         return it->second;
00503     }
00504     return NULL;
00505 }
00506 
00507 void Renderer::removeScene(const string& name) {
00508     Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00509     Poco::HashMap<string, Scene*>::Iterator i = _sceneMap.find(name);
00510     if (i != _sceneMap.end()) {
00511         for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00512             if (i->second == *it) {
00513                 _sceneMap.erase(name);
00514                 _scenes.erase(it);
00515                 _log.information(Poco::format("*remove scene: %s", name));
00516                 break;
00517             }
00518         }
00519     }
00520 }
00521 
00522 bool Renderer::tryDrawLock() {
00523     return _drawLock.tryLock();
00524 }
00525 
00526 void Renderer::drawUnlock() {
00527     _drawLock.unlock();
00528 }
00529 
00533 void Renderer::renderScene(const bool visibled, const LONGLONG current) {
00534     MEMORYSTATUS ms;
00535     ms.dwLength = sizeof(MEMORYSTATUS);
00536     GlobalMemoryStatus(&ms);
00537     int availMem = ms.dwAvailPhys / 1024 / 1024;
00538 
00539     PROCESS_MEMORY_COUNTERS pmc = {0};
00540     GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(PROCESS_MEMORY_COUNTERS));
00541     int mem = pmc.WorkingSetSize / 1024;
00542     Uint32 fps = _fpsCounter.getFPS();
00543     _fpsCounter.count();
00544 
00545     //PerformanceTimer timer;
00546     //timer.start();
00547     _current = current;
00548     if (hasAddDrives() && _current - _lastDeviceChanged > 45000) {
00549         // 最後のデバイス変化から規定時間経過
00550         {
00551             Poco::ScopedLock<Poco::FastMutex> lock(_deviceLock);
00552             for (vector<string>::iterator it = _addDrives.begin(); it != _addDrives.end(); it++) {
00553                 _readyDrives.push(*it);
00554             }
00555             _addDrives.clear();
00556         }
00557     }
00558     if (!visibled) {
00559         Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00560         for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00561             Scene* scene = (*it);
00562             scene->processAlways();
00563         }
00564         return;
00565     }
00566 
00567     int keycode = 0;
00568     bool shift = false;
00569     bool ctrl = false;
00570     if (_keyUpdated) {
00571         _keyUpdated = false;
00572         keycode = _keycode;
00573         shift = _shift;
00574         ctrl = _ctrl;
00575     }
00576     {
00577         Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00578         switch (keycode) {
00579             case 'S':
00580             case 's':
00581                 config().viewStatus = !(config().viewStatus);
00582                 break;
00583         }
00584 
00585         for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00586             Scene* scene = (*it);
00587             scene->notifyKey(keycode, shift, ctrl);
00588             scene->process();
00589             scene->processAlways();
00590         }
00591     }
00592 
00593     _device->SetFVF(VERTEX_FVF);
00594     _device->SetRenderState(D3DRS_ZENABLE, false);
00595     _device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
00596 
00597     _drawLock.lock();
00598     LPDIRECT3DSWAPCHAIN9 swapChain1 = NULL;
00599     LPDIRECT3DSWAPCHAIN9 swapChain2 = NULL;
00600     HRESULT hr = _device->GetSwapChain(0, &swapChain1);
00601     if (SUCCEEDED(hr)) {
00602         LPDIRECT3DSURFACE9 backBuffer = NULL; //バックバッファ
00603         hr = swapChain1->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
00604         hr = _device->SetRenderTarget(0, backBuffer);
00605         SAFE_RELEASE(backBuffer);
00606     }
00607 
00608     if (FAILED(_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f),  1.0f, 0))) {
00609         return;
00610     }
00611 
00612     // 描画1
00613     if (SUCCEEDED(_device->BeginScene())) {
00614         Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00615         for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00616             (*it)->draw1();
00617         }
00618         _device->EndScene();
00619     }
00620     _drawLock.unlock();
00621 
00622     D3DTEXTUREFILTERTYPE filter = D3DTEXF_NONE;
00623     if (config().captureFilter == "point") {
00624         filter = D3DTEXF_POINT;
00625     } else if (config().captureFilter == "linear") {
00626         filter = D3DTEXF_ANISOTROPIC;
00627     } else if (config().captureFilter == "anisotropic") {
00628         filter = D3DTEXF_ANISOTROPIC;
00629     } else if (config().captureFilter == "pyramidalquad") {
00630         filter = D3DTEXF_PYRAMIDALQUAD;
00631     } else if (config().captureFilter == "gaussianquad") {
00632         filter = D3DTEXF_GAUSSIANQUAD;
00633     }
00634     if (config().fullsceen && _displayAdpters > 1) {
00635         swapChain1->Present(NULL, NULL, NULL, NULL, 0);
00636 
00637         if (_captureTexture) {
00638             LPDIRECT3DSURFACE9 backBuffer = NULL;
00639             hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
00640             if (SUCCEEDED(hr)) {
00641                 LPDIRECT3DSURFACE9 dst = NULL;
00642                 hr = _captureTexture->GetSurfaceLevel(0, &dst);
00643                 if (SUCCEEDED(hr)) {
00644                     if (config().splitType == 0) {
00645                         int x = config().stageRect.left;
00646                         int y = config().stageRect.top;
00647                         int w = config().stageRect.right;
00648                         int h = config().stageRect.bottom;
00649                         RECT rect;
00650                         ::SetRect(&rect, x, y, x + w, y + h);
00651                         _device->StretchRect(backBuffer, &rect, dst, NULL, filter);
00652                     } else {
00653                         _device->StretchRect(backBuffer, &(config().mainRect), dst, NULL, filter);
00654                     }
00655                     SAFE_RELEASE(dst);
00656                 } else {
00657                     _log.warning("failed get capture surface");
00658                 }
00659                 SAFE_RELEASE(backBuffer);
00660             } else {
00661                 _log.warning("failed get back buffer 1");
00662             }
00663         }
00664 
00665         hr = _device->GetSwapChain(1, &swapChain2);
00666         if SUCCEEDED(hr) {
00667             LPDIRECT3DSURFACE9 backBuffer = NULL; //バックバッファ
00668             hr = swapChain2->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
00669             hr = _device->SetRenderTarget(0, backBuffer);
00670             SAFE_RELEASE(backBuffer);
00671 
00672             if FAILED(_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f),  1.0f, 0)) {
00673                 _log.warning("failed device clear");
00674             }
00675         }
00676     }
00677 
00678     // 描画2
00679     hr = _device->GetRenderTarget(0, &_backBuffer);
00680     if FAILED(hr) {
00681         _log.warning("failed get back buffer 2");
00682     }
00683 
00684     _drawLock.lock();
00685     if (!config().fullsceen || _displayAdpters == 1) {
00686         LPDIRECT3DSURFACE9 backBuffer = NULL; //バックバッファ
00687         hr = swapChain1->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
00688         hr = _device->SetRenderTarget(0, backBuffer);
00689         SAFE_RELEASE(backBuffer);
00690     }
00691     if SUCCEEDED(_device->BeginScene()) {
00692         Poco::ScopedLock<Poco::FastMutex> lock(_sceneLock);
00693         for (vector<Scene*>::iterator it = _scenes.begin(); it != _scenes.end(); it++) {
00694             (*it)->draw2();
00695         }
00696 
00697         if (config().viewStatus) {
00698             _availableTextureMem = _device->GetAvailableTextureMem() / 1024 / 1024;
00699             string address = svvitch::join(_addresses, "/");
00700             string memory;
00701             if (availMem > 1024) {
00702                 memory = Poco::format("ram>%03dMB(%0.1hfGB)", (mem / 1024), availMem / F(1024));
00703             } else {
00704                 memory = Poco::format("ram>%03dMB(%03dMB)", (mem / 1024), availMem);
00705             }
00706             if (_availableTextureMem > 1024) {
00707                 memory += Poco::format(" vram>%0.1hfGB", _availableTextureMem / F(1024));
00708             } else {
00709                 memory += Poco::format(" vram>%03uMB", _availableTextureMem);
00710             }
00711 
00712             // string mouse = Poco::format("mouse: %04ld,%03ld,%03ld", _dims.lX, _dims.lY, _dims.lZ);
00713             DWORD time = current / 1000;
00714             string runTime = Poco::format("%lud%02lu:%02lu:%02lu", time / 86400, time / 3600 % 24, time / 60 % 60, time % 60);
00715             string s = Poco::format("ver%s %02lufps run>%s %s ip>%s", svvitch::version(), fps, runTime, memory, address);
00716             if (s.size() * 12 > config().mainRect.right) {
00717                 drawFontTextureText(0, config().subRect.bottom - 16, config().mainRect.right / s.size(), 16, 0x99669966, s);
00718             } else {
00719                 drawFontTextureText(0, config().subRect.bottom - 16, 12, 16, 0x99669966, s);
00720             }
00721         }
00722         _device->EndScene();
00723     }
00724     _drawLock.unlock();
00725 
00726     if (config().fullsceen && _displayAdpters > 1) {
00727         if (swapChain2) swapChain2->Present(NULL, NULL, NULL, NULL, 0);
00728 
00729     } else {
00730         if (_device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) {
00731             _log.warning("failed device lost");
00732             if (_device->TestCooperativeLevel() == D3DERR_DEVICELOST) {
00733                 return;
00734             }
00735             hr = _device->Reset(&_presentParams[0]);
00736             if FAILED(hr) {
00737                 _log.warning("failed reset device");
00738             }
00739 
00740         } else {
00741             if (_captureTexture) {
00742                 LPDIRECT3DSURFACE9 backBuffer = NULL;
00743                 HRESULT hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
00744                 if SUCCEEDED(hr) {
00745                     LPDIRECT3DSURFACE9 dst = NULL;
00746                     hr = _captureTexture->GetSurfaceLevel(0, &dst);
00747                     if (SUCCEEDED(hr)) {
00748                         RECT rect;
00749                         rect.left = config().stageRect.left;
00750                         rect.top = config().stageRect.top;
00751                         rect.right = config().stageRect.left + config().stageRect.right;
00752                         rect.bottom = config().stageRect.top + config().stageRect.bottom;
00753                         switch(config().splitType) {
00754                         case 1:
00755                         case 2:
00756                             {
00757                                 int dw = config().splitSize.cx * config().splitCycles;
00758                                 rect.left = config().mainRect.left;
00759                                 rect.top = config().mainRect.top;
00760                                 rect.right = config().mainRect.left + config().stageRect.right / dw * config().splitSize.cx;
00761                                 rect.bottom = config().mainRect.top + config().stageRect.bottom * config().splitCycles;
00762                             }
00763                             break;
00764                         default:
00765                             break;
00766                         }
00767                         _device->StretchRect(backBuffer, &rect, dst, NULL, filter);
00768                         SAFE_RELEASE(dst);
00769                     } else {
00770                         _log.warning("failed get capture surface");
00771                     }
00772                     SAFE_RELEASE(backBuffer);
00773                 } else {
00774                     _log.warning("failed get back buffer 3");
00775                 }
00776             }
00777         }
00778     }
00779     SAFE_RELEASE(_backBuffer);
00780 
00781     SAFE_RELEASE(swapChain1);
00782     SAFE_RELEASE(swapChain2);
00783 }
00784 
00785 const UINT Renderer::getTextureMem() const {
00786     return _textureMem;
00787 }
00788 
00789 const UINT Renderer::getAvailableTextureMem() const {
00790     return _availableTextureMem;
00791 }
00792 
00793 const UINT Renderer::getDisplayAdapters() const {
00794     return _displayAdpters;
00795 }
00796 
00797 const UINT Renderer::getMaxTextureW() const {
00798     return _maxTextureW;
00799 }
00800 
00801 const UINT Renderer::getMaxTextureH() const {
00802     return _maxTextureH;
00803 }
00804 
00808 const LPDIRECT3DTEXTURE9 Renderer::createTexture(const int w, const int h, const D3DFORMAT format) const {
00809     LPDIRECT3DTEXTURE9 texture = NULL;
00810     HRESULT hr = _device->CreateTexture(w, h, 1, 0, format, D3DPOOL_MANAGED, &texture, NULL);
00811     if (SUCCEEDED(hr)) {
00812     // D3DSURFACE_DESC desc;
00813     // hr = texture->GetLevelDesc(0, &desc);        
00814     // if (SUCCEEDED(hr)) _log.information(Poco::format("create texture: %ux%u", desc.Width, desc.Height));
00815     } else if (D3DERR_INVALIDCALL == hr) {
00816         _log.warning(Poco::format("failed create texture: %dx%d", w, h));
00817     } else if (D3DERR_OUTOFVIDEOMEMORY == hr) {
00818         _log.warning(Poco::format("failed create texture(out of videomemory): %dx%d", w, h));
00819     } else if (E_OUTOFMEMORY == hr) {
00820         _log.warning(Poco::format("failed create texture(out of memory): %dx%d", w, h));
00821     }
00822     return texture;
00823 }
00824 
00828 const LPDIRECT3DTEXTURE9 Renderer::createTexture(const string file) const {
00829     LPDIRECT3DTEXTURE9 texture = NULL;
00830     wstring wfile;
00831     Poco::UnicodeConverter::toUTF16(file, wfile);
00832     D3DXIMAGE_INFO info = {0};
00833     HRESULT hr = D3DXGetImageInfoFromFile(wfile.c_str(), &info);
00834     if (SUCCEEDED(hr) && info.Width > 0 && info.Height > 0) {
00835         hr = D3DXCreateTextureFromFileEx(_device, wfile.c_str(), info.Width, info.Height, 1, 0, info.Format, D3DPOOL_DEFAULT, D3DX_FILTER_NONE, D3DX_DEFAULT, 0, NULL, NULL, &texture);
00836         if FAILED(hr) {
00837             _log.warning(Poco::format("failed create texture: %s", file));
00838         }
00839     }
00840     return texture;
00841 }
00842 
00846 const LPDIRECT3DTEXTURE9 Renderer::createRenderTarget(const int w, const int h, const D3DFORMAT format) const {
00847     LPDIRECT3DTEXTURE9 texture = NULL;
00848     HRESULT hr = _device->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
00849     if (SUCCEEDED(hr)) {
00850         D3DSURFACE_DESC desc;
00851         hr = texture->GetLevelDesc(0, &desc);
00852 //      if (SUCCEEDED(hr)) _log.information(Poco::format("create render target texture: %ux%u", desc.Width, desc.Height));
00853     } else if (D3DERR_INVALIDCALL == hr) {
00854         _log.warning(Poco::format("failed create texture: %dx%d", w, h));
00855     } else if (D3DERR_OUTOFVIDEOMEMORY == hr) {
00856         _log.warning(Poco::format("failed create texture(out of videomemory): %dx%d", w, h));
00857     } else if (E_OUTOFMEMORY == hr) {
00858         _log.warning(Poco::format("failed create texture(out of memory): %dx%d", w, h));
00859     }
00860     return texture;
00861 }
00862 
00863 const LPDIRECT3DSURFACE9 Renderer::createLockableSurface(const int w, const int h, const D3DFORMAT format) const {
00864     LPDIRECT3DSURFACE9 surface = NULL;
00865     HRESULT hr = _device->CreateOffscreenPlainSurface(w, h, format, D3DPOOL_SYSTEMMEM, &surface, NULL);
00866     return surface;
00867 }
00868 
00869 const bool Renderer::getRenderTargetData(LPDIRECT3DTEXTURE9 texture, LPDIRECT3DSURFACE9 surface) const {
00870     if (texture) {
00871         LPDIRECT3DSURFACE9 target;
00872         HRESULT hr = texture->GetSurfaceLevel(0, &target);
00873         if (SUCCEEDED(hr)) {
00874             hr = _device->GetRenderTargetData(target, surface);
00875             SAFE_RELEASE(target);
00876             return SUCCEEDED(hr);
00877         }
00878     }
00879     return false;
00880 }
00881 
00882 const bool Renderer::updateRenderTargetData(LPDIRECT3DTEXTURE9 texture, LPDIRECT3DSURFACE9 surface) const {
00883     if (texture) {
00884         LPDIRECT3DSURFACE9 target;
00885         HRESULT hr = texture->GetSurfaceLevel(0, &target);
00886         if (SUCCEEDED(hr)) {
00887             hr = _device->UpdateSurface(surface, NULL, target, NULL);
00888             SAFE_RELEASE(target);
00889             return SUCCEEDED(hr);
00890         }
00891     }
00892     return false;
00893 }
00894 
00895 const bool Renderer::colorFill(const LPDIRECT3DTEXTURE9 texture, const DWORD col) const {
00896     LPDIRECT3DSURFACE9 dst = NULL;
00897     HRESULT hr = texture->GetSurfaceLevel(0, &dst);
00898     if (SUCCEEDED(hr)) {
00899         hr = _device->ColorFill(dst, NULL, col);
00900         SAFE_RELEASE(dst);
00901     }
00902     return SUCCEEDED(hr);
00903 }
00904 
00908 const LPDIRECT3DTEXTURE9 Renderer::getCaptureTexture() const {
00909     return _captureTexture;
00910 }
00911 
00912 
00913 void Renderer::drawLine(const int x1, const int y1, const DWORD c1, const int x2, const int y2, const DWORD c2) {
00914     VERTEX v[] = {
00915         {F(x1), F(y1), F(0), F(1), c1, F(0), F(0)},
00916         {F(x2), F(y2), F(0), F(1), c2, F(0), F(0)}
00917     };
00918     _device->DrawPrimitiveUP(D3DPT_LINELIST, 1, v, sizeof(VERTEX));
00919 }
00920 
00924 void Renderer::drawTexture(const int x, const int y, const LPDIRECT3DTEXTURE9 texture, const int flipMode, const D3DCOLOR c1, const D3DCOLOR c2, const D3DCOLOR c3, const D3DCOLOR c4) const {
00925     Uint32 tw = 0, th = 0;
00926     if (texture) {
00927         D3DSURFACE_DESC desc;
00928         HRESULT hr = texture->GetLevelDesc(0, &desc);
00929         tw = desc.Width;
00930         th = desc.Height;
00931     }
00932     drawTexture(x, y, tw, th, texture, flipMode, c1, c2, c3, c4);
00933 }
00934 
00938 void Renderer::drawTexture(const int x, const int y, const int w, const int h, const LPDIRECT3DTEXTURE9 texture, const int flipMode, const D3DCOLOR c1, const D3DCOLOR c2, const D3DCOLOR c3, const D3DCOLOR c4) const {
00939     float u1, u2, v1, v2;
00940     switch (flipMode) {
00941     case 1:
00942         u1 = F(1); u2 = F(0);
00943         v1 = F(0); v2 = F(1);
00944         break;
00945     default:
00946         u1 = F(0); u2 = F(1);
00947         v1 = F(0); v2 = F(1);
00948     }
00949     _device->SetTexture(0, texture);
00950 
00951     float x1, y1, x2, y2;
00952     x1 = F(x     - 0.5);
00953     y1 = F(y     - 0.5);
00954     x2 = F(x + w - 0.5);
00955     y2 = F(y + h - 0.5);
00956     VERTEX dst[] =
00957         {
00958             {x1, y1, 0.0f, 1.0f, c1, u1, v1},
00959             {x2, y1, 0.0f, 1.0f, c2, u2, v1},
00960             {x1, y2, 0.0f, 1.0f, c3, u1, v2},
00961             {x2, y2, 0.0f, 1.0f, c4, u2, v2}
00962         };
00963     _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, VERTEX_SIZE);
00964     _device->SetTexture(0, NULL);
00965 }
00966 
00970 void Renderer::drawTextureWithAngle(const int x, const int y, const int w, const int h, const int angle, const int cx, const int cy, const LPDIRECT3DTEXTURE9 texture, const int flipMode, const D3DCOLOR c1, const D3DCOLOR c2, const D3DCOLOR c3, const D3DCOLOR c4) const {
00971     float u1, u2, v1, v2;
00972     switch (flipMode) {
00973     case 1:
00974         u1 = F(1); u2 = F(0);
00975         v1 = F(0); v2 = F(1);
00976         break;
00977     default:
00978         u1 = F(0); u2 = F(1);
00979         v1 = F(0); v2 = F(1);
00980     }
00981 
00982     float x1 = F(x     - 0.5) - cx;
00983     float y1 = F(y     - 0.5) - cy;
00984     float x2 = F(x + w - 0.5) - cx;
00985     float y2 = F(y + h - 0.5) - cy;
00986 
00987     float rad = (angle % 360) * PI / 180;
00988     float sin = ::sinf(rad);
00989     float cos = ::cos(rad);
00990 
00991     float ax1 = (cos * x1) - (sin * y1) + cx;
00992     float ay1 = (sin * x1) + (cos * y1) + cy;
00993     float ax2 = (cos * x2) - (sin * y1) + cx;
00994     float ay2 = (sin * x2) + (cos * y1) + cy;
00995     float ax3 = (cos * x1) - (sin * y2) + cx;
00996     float ay3 = (sin * x1) + (cos * y2) + cy;
00997     float ax4 = (cos * x2) - (sin * y2) + cx;
00998     float ay4 = (sin * x2) + (cos * y2) + cy;
00999 
01000     VERTEX dst[] =
01001         {
01002             {ax1, ay1, 0.0f, 1.0f, c1, u1, v1},
01003             {ax2, ay2, 0.0f, 1.0f, c2, u2, v1},
01004             {ax3, ay3, 0.0f, 1.0f, c3, u1, v2},
01005             {ax4, ay4, 0.0f, 1.0f, c4, u2, v2}
01006         };
01007     _device->SetTexture(0, texture);
01008     _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, VERTEX_SIZE);
01009     _device->SetTexture(0, NULL);
01010 }
01011 
01012 void Renderer::drawTexture(const float dx, const float dy, const float dw, const float dh, const float sx, const float sy, const float sw, const float sh, const LPDIRECT3DTEXTURE9 texture, const int flipMode, const D3DCOLOR c1, const D3DCOLOR c2, const D3DCOLOR c3, const D3DCOLOR c4) const {
01013     float u1, u2, v1, v2;
01014     if (texture) {
01015         D3DSURFACE_DESC desc;
01016         HRESULT hr = texture->GetLevelDesc(0, &desc);
01017         u1 = sx / desc.Width;
01018         v1 = sy / desc.Height;
01019         u2 = (sx + sw) / desc.Width;
01020         v2 = (sy + sh) / desc.Height;
01021     }
01022     float tmp;
01023     switch (flipMode) {
01024     case 1:
01025         tmp = u1; u1 = u2; u2 = tmp;
01026         break;
01027     case 2:
01028         tmp = v1; v1 = v2; v2 = tmp;
01029         break;
01030     case 3:
01031         tmp = u1; u1 = u2; u2 = tmp;
01032         tmp = v1; v1 = v2; v2 = tmp;
01033         break;
01034     }
01035 
01036     VERTEX dst[] =
01037         {
01038             {dx      - 0.5, dy      - 0.5, 0.0f, 1.0f, c1, u1, v1},
01039             {dx + dw - 0.5, dy      - 0.5, 0.0f, 1.0f, c2, u2, v1},
01040             {dx      - 0.5, dy + dh - 0.5, 0.0f, 1.0f, c3, u1, v2},
01041             {dx + dw - 0.5, dy + dh - 0.5, 0.0f, 1.0f, c4, u2, v2}
01042         };
01043     _device->SetTexture(0, texture);
01044     _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, VERTEX_SIZE);
01045     _device->SetTexture(0, NULL);
01046 }
01047 
01048 void Renderer::drawTextureWithAngle(const float dx, const float dy, const float dw, const float dh, const float sx, const float sy, const float sw, const float sh, const int angle, const int cx, const int cy, const LPDIRECT3DTEXTURE9 texture, const D3DCOLOR c1, const D3DCOLOR c2, const D3DCOLOR c3, const D3DCOLOR c4) const {
01049     float u1, v1, u2, v2;
01050     if (texture) {
01051         D3DSURFACE_DESC desc;
01052         HRESULT hr = texture->GetLevelDesc(0, &desc);
01053         u1 = sx / desc.Width;
01054         v1 = sy / desc.Height;
01055         u2 = (sx + sw) / desc.Width;
01056         v2 = (sy + sh) / desc.Height;
01057     }
01058 
01059     float x1 = F(dx      - 0.5) - cx;
01060     float y1 = F(dy      - 0.5) - cy;
01061     float x2 = F(dx + dw - 0.5) - cx;
01062     float y2 = F(dy + dh - 0.5) - cy;
01063 
01064     float rad = (angle % 360) * PI / 180;
01065     float sin = ::sinf(rad);
01066     float cos = ::cos(rad);
01067 
01068     float ax1 = (cos * x1) - (sin * y1) + cx;
01069     float ay1 = (sin * x1) + (cos * y1) + cy;
01070     float ax2 = (cos * x2) - (sin * y1) + cx;
01071     float ay2 = (sin * x2) + (cos * y1) + cy;
01072     float ax3 = (cos * x1) - (sin * y2) + cx;
01073     float ay3 = (sin * x1) + (cos * y2) + cy;
01074     float ax4 = (cos * x2) - (sin * y2) + cx;
01075     float ay4 = (sin * x2) + (cos * y2) + cy;
01076 
01077     VERTEX dst[] =
01078         {
01079             {ax1, ay1, 0.0f, 1.0f, c1, u1, v1},
01080             {ax2, ay2, 0.0f, 1.0f, c2, u2, v1},
01081             {ax3, ay3, 0.0f, 1.0f, c3, u1, v2},
01082             {ax4, ay4, 0.0f, 1.0f, c4, u2, v2}
01083         };
01084     _device->SetTexture(0, texture);
01085     _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, VERTEX_SIZE);
01086     _device->SetTexture(0, NULL);
01087 }
01088 
01089 LPD3DXEFFECT Renderer::createEffect(const string path) {
01090     std::wstring wfile;
01091     Poco::UnicodeConverter::toUTF16(path, wfile);
01092     LPD3DXBUFFER errors = NULL;
01093     LPD3DXEFFECT fx = NULL;
01094     HRESULT hr = D3DXCreateEffectFromFile(_device, wfile.c_str(), 0, 0, D3DXSHADER_DEBUG, 0, &fx, &errors);
01095     if (errors) {
01096         std::vector<char> text(errors->GetBufferSize());
01097         memcpy(&text[0], errors->GetBufferPointer(), errors->GetBufferSize());
01098         text.push_back('¥0');
01099         _log.warning(Poco::format("shader compile error: %s", string(&text[0])));
01100         SAFE_RELEASE(errors);
01101         return NULL;
01102     } else if (FAILED(hr)) {
01103         _log.warning(Poco::format("failed shader: %s", string("")));
01104         return NULL;
01105     }
01106     return fx;
01107 }
01108 
01109 void Renderer::getPrivateFontFamily(string fontName, Gdiplus::FontFamily** result) {
01110     std::wstring wfontName;
01111     Poco::UnicodeConverter::toUTF16(fontName, wfontName);
01112     //int count = _fc->GetFamilyCount();
01113     int count = 0;
01114     Gdiplus::FontFamily ff[32];
01115     _fc->GetFamilies(32, ff, &count);
01116     for (int i = 0; i < 32 && i < count; i++) {
01117         WCHAR name[64] = L"";
01118         ff[i].GetFamilyName(name);
01119         if (wfontName == name) {
01120             string ffName;
01121             Poco::UnicodeConverter::toUTF8(name, ffName);
01122             _log.information(Poco::format("%d:[%s]", i, ffName));
01123             *result = ff[i].Clone();
01124             return;
01125         }
01126     }
01127 }
01128 
01129 void Renderer::getPrivateFontFamilies(vector<string>& fonts) {
01130     fonts.clear();
01131     int count = 0;
01132     Gdiplus::FontFamily ff[32];
01133     _fc->GetFamilies(32, ff, &count);
01134     for (int i = 0; i < 32 && i < count; i++) {
01135         WCHAR name[64] = L"";
01136         ff[i].GetFamilyName(name);
01137         string utf8;
01138         Poco::UnicodeConverter::toUTF8(name, utf8);
01139         fonts.push_back(utf8);
01140     }
01141 }
01142 
01143 bool Renderer::addPrivateFontFile(string file) {
01144     wstring wfile;
01145     Poco::UnicodeConverter::toUTF16(file, wfile);
01146     Gdiplus::Status status = _fc->AddFontFile(wfile.c_str());
01147     if (status != Gdiplus::Ok) {
01148         _log.warning(Poco::format("failed add private font: %s", file));
01149         return false;
01150     }
01151     return true;
01152 }
01153 
01157 bool Renderer::beginFont(const wstring& fontFace, const Sint32 size) {
01158     if (_backBuffer) {
01159         HRESULT hr = _backBuffer->GetDC(&_hdc);
01160         if (FAILED(hr)) {
01161             _log.warning("failed get backbuffer HDC");
01162             return false;
01163         }
01164 
01165         _hfont = CreateFont(
01166             size,                       // フォント高さ
01167             0,                          // 文字幅
01168             0,                          // テキストの角度    
01169             0,                          // ベースラインとx軸との角度
01170             FW_BOLD,                    // フォントの重さ(太さ)
01171             false,                      // イタリック体
01172             false,                      // アンダーライン
01173             false,                      // 打ち消し線
01174             SHIFTJIS_CHARSET,           // 文字セット
01175             OUT_TT_PRECIS,              // 出力精度
01176             CLIP_DEFAULT_PRECIS,        // クリッピング精度
01177             PROOF_QUALITY,              // 出力品質
01178             FIXED_PITCH | FF_MODERN,    // ピッチとファミリー
01179             fontFace.c_str());          // 書体名
01180         if (!_hfont) {
01181             _log.warning("failed create HFONT");
01182             return false;
01183         }
01184         // フォント設定
01185         _hfontOLD = (HFONT)SelectObject(_hdc, _hfont);
01186 
01187         return true;
01188     }
01189     return false;
01190 }
01191 
01192 void Renderer::drawFont(const Sint32 x, const Sint32 y, const COLORREF fontColor, const COLORREF backColor, const string& text) const {
01193     if (!_hdc) return;
01194     SetBkColor(_hdc, backColor);    // 背景色
01195     SetBkMode(_hdc, OPAQUE);
01196     SetTextColor(_hdc, fontColor);  // フォント色
01197 
01198     // フォント描画
01199     wstring wtext;
01200     Poco::UnicodeConverter::toUTF16(text, wtext);
01201     TextOut(_hdc, x, y, wtext.c_str(), wtext.length());
01202 }
01203 
01204 void Renderer::endFont() {
01205     if (!_hdc) return;
01206     SelectObject(_hdc, _hfontOLD);
01207     DeleteObject(_hfont);
01208     if (_backBuffer) {
01209         HRESULT hr = _backBuffer->ReleaseDC(_hdc);
01210     }
01211     _hdc = NULL;
01212     _hfont = NULL;
01213     _hfontOLD = NULL;
01214 }
01215 
01216 bool Renderer::copyTexture(LPDIRECT3DTEXTURE9 src, LPDIRECT3DTEXTURE9 dst) {
01217     LPDIRECT3DSURFACE9 ss = NULL;
01218     src->GetSurfaceLevel(0, &ss);
01219     LPDIRECT3DSURFACE9 ds = NULL;
01220     dst->GetSurfaceLevel(0, &ds);
01221     HRESULT hr = _device->StretchRect(ss, NULL, ds, NULL, D3DTEXF_POINT);
01222     SAFE_RELEASE(ss);
01223     SAFE_RELEASE(ds);
01224     return SUCCEEDED(hr);
01225 }
01226 
01227 const LPDIRECT3DTEXTURE9 Renderer::createTexturedText(const wstring& fontFamily, const int fontSize, const DWORD c1, const DWORD c2, const int w1, const DWORD c3, const int w2, const DWORD c4, const string& text, int clipH) const {
01228     WCHAR s[32] = L"";
01229     Gdiplus::FontFamily* ff = NULL;
01230     if (fontFamily.empty()) {
01231         // フォント指定が無い場合はデフォルトのフォントを検索
01232         Gdiplus::FontFamily temp[16];
01233         int num = 0;
01234         _fc->GetFamilies(16, temp, &num);
01235         for (int i = 0; i < num; i++) {
01236             temp[i].GetFamilyName(s);
01237             string name;
01238             Poco::UnicodeConverter::toUTF8(s, name);
01239             if (config().multiByteFont == name) ff = temp[i].Clone();
01240         }
01241     }
01242 
01243     if (!ff) {
01244         wstring fontName = fontFamily;
01245         if (fontName.empty()) fontName = config().defaultFont;
01246         Gdiplus::Font f(fontName.c_str(), fontSize);
01247         Gdiplus::FontFamily temp;
01248         f.GetFamily(&temp);
01249         ff = temp.Clone();
01250         ff->GetFamilyName(s);
01251         string name;
01252         Poco::UnicodeConverter::toUTF8(s, name);
01253 //      _log.information(Poco::format("use font: %s", name));
01254     }
01255 
01256     // 文字列レンダリング後サイズの確認
01257     Gdiplus::Rect rect(0, 0, 0, 0);
01258     {
01259         Gdiplus::Bitmap bitmap(1, 1, PixelFormat32bppARGB);
01260         drawText(ff, fontSize, c1, c2, w1, c3, w2, c4, text, &bitmap, rect);
01261     }
01262 
01263     // 最終的な描画処理
01264     LPDIRECT3DTEXTURE9 texture = NULL;
01265     {
01266         int x = rect.X;
01267         int y = rect.Y;
01268         int w = rect.Width;
01269         int h = rect.Height;
01270         rect.Width = w - x;     // rectの領域をx/y=0で作り直す
01271         rect.Height = h - y;    // ただしx/yはクリアせずそのまま引き渡すことで、biasとして使用する
01272 //      _log.information(Poco::format("bitmap(%d,%d %dx%d): %s", x, y, w, h, text));
01273         if (clipH < 0) clipH = h;
01274         texture = createTexture(w, clipH, D3DFMT_A8R8G8B8);
01275         if (!texture) {
01276             // テクスチャが生成できない
01277             SAFE_DELETE(ff);
01278             return NULL;
01279         }
01280         D3DSURFACE_DESC desc;
01281         HRESULT hr = texture->GetLevelDesc(0, &desc);
01282         Uint32 tw = desc.Width;
01283         Uint32 th = desc.Height;
01284 //      _log.information(Poco::format("textured text: %lux%lu %s", tw, th, text));
01285         if (w > tw) {
01286             // テクスチャの幅の方が小さい場合、テクスチャを折返しで作る
01287             SAFE_RELEASE(texture);
01288             Gdiplus::Bitmap bitmap(w, h, PixelFormat32bppARGB);
01289             drawText(ff, fontSize, c1, c2, w1, c3, w2, c4, text, &bitmap, rect);
01290             texture = createTexture(tw, th * ((w + tw - 1) / tw), D3DFMT_A8R8G8B8);
01291             colorFill(texture, D3DCOLOR_ARGB(0, 0, 0, 0));
01292             HRESULT hr = texture->GetLevelDesc(0, &desc);
01293             tw = desc.Width;
01294             th = desc.Height;
01295             _log.debug(Poco::format("texture: %lux%lu", tw, th));
01296             D3DLOCKED_RECT lockRect;
01297             hr = texture->LockRect(0, &lockRect,NULL, 0);
01298             if (SUCCEEDED(hr)) {
01299                 Gdiplus::Bitmap dst(tw, th, lockRect.Pitch, PixelFormat32bppARGB, (BYTE*)lockRect.pBits);
01300                 Gdiplus::Graphics g(&dst);
01301                 int y = 0;
01302                 for (int x = 0; x < w; x+=tw) {
01303                     Gdiplus::Rect rect(0, y, tw, 32);
01304                     g.SetClip(rect);
01305                     g.DrawImage(&bitmap, -x, y);
01306                     y += 32;
01307                 }
01308                 g.Flush();
01309                 texture->UnlockRect(0);
01310                 _log.debug(Poco::format("draw texture(with turns): %lux%lu", tw, th));
01311 //              _w = 1024;
01312             }
01313 
01314         } else {
01315             // 折返し無し
01316             colorFill(texture, D3DCOLOR_ARGB(0, 0, 0, 0));
01317             D3DLOCKED_RECT lockRect;
01318             HRESULT hr = texture->LockRect(0, &lockRect,NULL, 0);
01319             if (SUCCEEDED(hr)) {
01320                 Gdiplus::Bitmap bitmap(tw, th, lockRect.Pitch, PixelFormat32bppARGB, (BYTE*)lockRect.pBits);
01321                 drawText(ff, fontSize, c1, c2, w1, c3, w2, c4, text, &bitmap, rect);
01322                 texture->UnlockRect(0);
01323                 _log.debug(Poco::format("draw text texture: %lux%lu", tw, th));
01324 //              _w = rect.Width;
01325             }
01326         }
01327     }
01328     SAFE_DELETE(ff);
01329     return texture;
01330 }
01331 
01332 void Renderer::drawFontTextureText(const int x, const int y, const int w, const int h, const D3DCOLOR col, const string s) const {
01333     if (_fontTexture) {
01334         D3DSURFACE_DESC desc;
01335         HRESULT hr = _fontTexture->GetLevelDesc(0, &desc);
01336         UINT tw = desc.Width;
01337         UINT th = desc.Height;
01338         _device->SetTexture(0, _fontTexture);
01339         for (int i = 0; i < s.length(); i++) {
01340             int dx = x + i * w;
01341             int a = s[i];
01342             float u1 = F((a % 16) * 32) / tw;
01343             float v1 = F((a / 16) * 32) / th;
01344             float u2 = F((a % 16) * 32 + 31) / tw;
01345             float v2 = F((a / 16) * 32 + 31) / th;
01346 
01347             {
01348                 VERTEX dst[] =
01349                     {
01350                         {F(dx     + 2), F(y     + 2), 0.0f, 1.0f, 0x66000000, u1, v1},
01351                         {F(dx + w + 2), F(y     + 2), 0.0f, 1.0f, 0x66000000, u2, v1},
01352                         {F(dx     + 2), F(y + h + 2), 0.0f, 1.0f, 0x66000000, u1, v2},
01353                         {F(dx + w + 2), F(y + h + 2), 0.0f, 1.0f, 0x66000000, u2, v2}
01354                     };
01355                 hr = _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, sizeof(VERTEX));
01356             }
01357             VERTEX dst[] =
01358                 {
01359                     {F(dx     - 0.5), F(y     - 0.5), 0.0f, 1.0f, col, u1, v1},
01360                     {F(dx + w - 0.5), F(y     - 0.5), 0.0f, 1.0f, col, u2, v1},
01361                     {F(dx     - 0.5), F(y + h - 0.5), 0.0f, 1.0f, col, u1, v2},
01362                     {F(dx + w - 0.5), F(y + h - 0.5), 0.0f, 1.0f, col, u2, v2}
01363                 };
01364             hr = _device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, sizeof(VERTEX));
01365         }
01366         _device->SetTexture(0, NULL);
01367 
01368     } else {
01369 //      beginFont(L"MS ゴシック", h);
01370 //      drawFont(x, y, col & 0xffffff, 0x333333, s);
01371 //      endFont();
01372     }
01373 }
01374 
01375 void Renderer::addCachedTexture(const string& name, const LPDIRECT3DTEXTURE9 texture) {
01376     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01377     Poco::HashMap<string, LPDIRECT3DTEXTURE9>::Iterator it = _cachedTextures.find(name);
01378     if (it != _cachedTextures.end()) {
01379         _log.information(Poco::format("texture already registed: %s", name));
01380         SAFE_RELEASE(it->second);
01381         _cachedTextures.erase(name);
01382     }
01383     _cachedTextures[name] = texture;
01384 }
01385 
01386 void Renderer::removeCachedTexture(const string& name) {
01387     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01388     Poco::HashMap<string, LPDIRECT3DTEXTURE9>::Iterator it = _cachedTextures.find(name);
01389     if (it != _cachedTextures.end()) {
01390         SAFE_RELEASE(it->second);
01391         _cachedTextures.erase(name);
01392     }
01393 }
01394 
01395 const LPDIRECT3DTEXTURE9 Renderer::getCachedTexture(const string& name) const {
01396 //  Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01397     Poco::HashMap<string, LPDIRECT3DTEXTURE9>::ConstIterator it = _cachedTextures.find(name);
01398     if (it != _cachedTextures.end()) {
01399         return it->second;
01400     }
01401     return NULL;
01402 }
01403 
01404 //
01405 // この関数は以下のURLよりコピー&改変
01406 // http://support.microsoft.com/kb/163503/ja
01407 //
01408 const string Renderer::firstDriveFromMask(ULONG unitmask) {
01409 //  _log.information(Poco::format("firstDriveFromMask: %lu", unitmask));
01410     CHAR i;
01411     for (i = 0; i < 26; ++i)
01412     {
01413         if (unitmask & 0x1) break;
01414         unitmask = unitmask >> 1;
01415     }
01416     vector<CHAR> s;
01417     s.push_back(i + 'A');
01418     s.push_back('¥0');
01419 //  _log.information(Poco::format("drive: %s", string(&s[0])));
01420     return &s[0];
01421 }
01422 
01423 HANDLE Renderer::openVolume(const string& driveLetter) {
01424     UINT driveType = GetDriveTypeA(Poco::format("%s:¥¥", driveLetter).c_str());
01425     DWORD accessFlags;
01426     switch (driveType) {
01427     case DRIVE_REMOVABLE:
01428     case DRIVE_FIXED: // USB-HDDはこれになる?
01429         accessFlags = GENERIC_READ | GENERIC_WRITE;
01430         break;
01431     case DRIVE_CDROM:
01432         accessFlags = GENERIC_READ;
01433         break;
01434     default:
01435         _log.warning(Poco::format("cannot eject.  Drive type is incorrect: %s=%?d", driveLetter, driveType));
01436         return INVALID_HANDLE_VALUE;
01437     }
01438 
01439     HANDLE volume = CreateFileA(Poco::format("¥¥¥¥.¥¥%s:", driveLetter).c_str(), accessFlags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
01440     if (volume == INVALID_HANDLE_VALUE) {
01441         _log.warning(Poco::format("failed open handle: %s", driveLetter));
01442     }
01443     return volume;
01444 }
01445 
01446 BOOL Renderer::closeVolume(HANDLE volume) {
01447     return CloseHandle(volume);
01448 }
01449 
01450 #define LOCK_TIMEOUT        10000       // 10 Seconds
01451 #define LOCK_RETRIES        20
01452 
01453 BOOL Renderer::lockVolume(HANDLE volume) {
01454     DWORD retBytes;
01455     DWORD sleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
01456     // Do this in a loop until a timeout period has expired
01457     for (int nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
01458         if (DeviceIoControl(volume, FSCTL_LOCK_VOLUME, NULL, 0,  NULL, 0, &retBytes, NULL)) {
01459             return TRUE;
01460         }
01461         Sleep(sleepAmount);
01462     }
01463 
01464     return FALSE;
01465 }
01466 
01467 BOOL Renderer::dismountVolume(HANDLE volume) {
01468     DWORD retBytes;
01469     return DeviceIoControl(volume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &retBytes, NULL);
01470 }
01471 
01472 BOOL Renderer::preventRemovalOfVolume(HANDLE volume, BOOL preventRemoval) {
01473     DWORD retBytes;
01474     PREVENT_MEDIA_REMOVAL pmr;
01475     pmr.PreventMediaRemoval = preventRemoval;
01476     return DeviceIoControl(volume, IOCTL_STORAGE_MEDIA_REMOVAL, &pmr, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &retBytes,  NULL);
01477 }
01478 
01479 BOOL Renderer::autoEjectVolume(HANDLE volume) {
01480     DWORD retBytes;
01481     return DeviceIoControl(volume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &retBytes, NULL);
01482 }
01483 
01484 BOOL Renderer::ejectVolume(const string& driveLetter) {
01485     // Open the volume.
01486     HANDLE volume = openVolume(driveLetter);
01487     if (volume == INVALID_HANDLE_VALUE)
01488     return FALSE;
01489 
01490     BOOL removeSafely = FALSE;
01491     BOOL autoEject = FALSE;
01492     // Lock and dismount the volume.
01493     if (lockVolume(volume) && dismountVolume(volume)) {
01494         removeSafely = TRUE;
01495 
01496         // Set prevent removal to false and eject the volume.
01497         if (preventRemovalOfVolume(volume, FALSE) && autoEjectVolume(volume)) autoEject = TRUE;
01498     }
01499     if (!closeVolume(volume)) return FALSE;
01500 
01501     if (autoEject) {
01502         _log.warning(Poco::format("media in drive %s has been ejected safely.", driveLetter));
01503     } else if (removeSafely) {
01504         _log.information(Poco::format("media in drive %s can be safely removed.", driveLetter));
01505     }
01506 
01507     return TRUE;
01508 }
01509 
01510 void Renderer::addDrive(ULONG unitmask) {
01511     Poco::ScopedLock<Poco::FastMutex> lock(_deviceLock);
01512     string drive = firstDriveFromMask(unitmask);
01513     _addDrives.push_back(drive);
01514     _log.information(Poco::format("add drive %s", drive));
01515 }
01516 
01517 void Renderer::removeDrive(ULONG unitmask) {
01518     Poco::ScopedLock<Poco::FastMutex> lock(_deviceLock);
01519     string drive = firstDriveFromMask(unitmask);
01520     for (vector<string>::iterator it = _addDrives.begin(); it != _addDrives.end(); ) {
01521         if ((*it) == drive) {
01522             it = _addDrives.erase(it);
01523         } else {
01524             it++;
01525         }
01526     }
01527     _log.information(Poco::format("remove drive %s", drive));
01528 }
01529 
01530 bool Renderer::hasAddDrives() {
01531     Poco::ScopedLock<Poco::FastMutex> lock(_deviceLock);
01532     return !_addDrives.empty();
01533 }
01534 
01535 void Renderer::deviceChanged() {
01536     _lastDeviceChanged = _current;
01537 }
01538 
01539 string Renderer::popReadyDrive() {
01540     Poco::ScopedLock<Poco::FastMutex> lock(_deviceLock);
01541     if (!_readyDrives.empty()) {
01542         string drive = _readyDrives.front();
01543         _readyDrives.pop();
01544         return drive;
01545     }
01546     return string();
01547 }
01548 
01549 void Renderer::setStatus(const string& key, const string& value) {
01550     _status[key] = value;
01551 }
01552 
01553 const string Renderer::getStatus(const string& key) {
01554     map<string, string>::const_iterator it = _status.find(key);
01555     if (it != _status.end()) {
01556         return it->second;
01557     }
01558     return string("");
01559 }
01560 
01561 void Renderer::removeStatus(const string& key) {
01562     map<string, string>::const_iterator it = _status.find(key);
01563     if (it != _status.end()) _status.erase(it);
01564 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines