bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } DWORD sceneChangeStartTime; if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); sceneChangeStartTime = OSGetTime(); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); App->scaleItem = NULL; bChangingSources = true; ListView_DeleteAllItems(hwndSources); bool bSkipTransition = false; XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); String className = sourceElement->GetString(TEXT("class")); if(className == "DeviceCapture") { // There's a capture device in the next scene that isn't a global source, // so let's skip the transition since it won't work anyway. bSkipTransition = true; } } for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); // Do not add image sources yet in case we're skipping the transition. // This fixes the issue where capture devices sources that used the // same device as one in the previous scene would just go blank // after switching. if(bRunning && newScene && !bSkipTransition) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); UINT numSources; if (scene) { //shutdown previous scene, if any numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceLeaveScene(); } } } scene->EndScene(); } Scene *previousScene = scene; scene = newScene; if(newScene && bSkipTransition) { // If we're skipping the transition because of a non-global // DirectShow device, delete the scene here and add the // ImageSources at this point instead. delete previousScene; if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); if(newScene) newScene->AddImageSource(sourceElement); } } } scene->BeginScene(); numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } if(!bTransitioning && !bSkipTransition) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); if(!bSkipTransition) { // Do not delete the previous scene here, since it has already // been deleted. delete previousScene; } DWORD sceneChangeTime = OSGetTime() - sceneChangeStartTime; if (sceneChangeTime >= 500) Log(TEXT("PERFORMANCE WARNING: Scene change took %u ms, maybe some sources should be global sources?"), sceneChangeTime); } if(API != NULL) ReportSwitchScenes(lpScene); return true; }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(API != NULL) ReportSwitchScenes(lpScene); if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); bChangingSources = true; ListView_DeleteAllItems(hwndSources); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); if(bRunning && newScene) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); if(scene) scene->EndScene(); Scene *previousScene = scene; scene = newScene; scene->BeginScene(); if(!bTransitioning) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); delete previousScene; } return true; }