svvitch
digital signage player
|
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 }