// EMERGENT GAME TECHNOLOGIES PROPRIETARY INFORMATION // // This software is supplied under the terms of a license agreement or // nondisclosure agreement with Emergent Game Technologies and may not // be copied or disclosed except in accordance with the terms of that // agreement. // // Copyright (c) 1996-2007 Emergent Game Technologies. // All Rights Reserved. // // Emergent Game Technologies, Chapel Hill, North Carolina 27517 // http://www.emergent.net #include "stdafx.h" #include #include #include #include #if defined(WIN32) #include #endif //#if defined(WIN32) #ifndef _PS3 #include #endif #include "SceneApp.h" #include "CameraController.h" #include "SceneAppAccum.h" #include "GamepadMappings.h" #include "ShaderHelper.h" #include "NiScreenText.h" #include "WStreamResource.h" SceneApp* g_Game = NULL; //--------------------------------------------------------------------------- NiApplication* NiApplication::Create() { return NiNew SceneApp; } //--------------------------------------------------------------------------- SceneApp::SceneApp() : NiApplication("SceneApp: View GSA/GSB files", DEFAULT_WIDTH, DEFAULT_HEIGHT, true), m_pkText(NULL), m_uiCurrentCamera(0), m_uiWalkableCamera(0), m_pkSceneView(NULL), m_pkDuplicateView(NULL) { char acExecutableDir[NI_MAX_PATH]; NiPath::GetExecutableDirectory(acExecutableDir, NI_MAX_PATH); #if defined(_XENON) SetMediaPath("D:\\Data\\"); #elif defined (WIN32) char acDataDirectory[NI_MAX_PATH + 32]; NiStrcpy(acDataDirectory, NI_MAX_PATH + 32, acExecutableDir); #ifndef NISHIPPING NiStrcat(acDataDirectory, NI_MAX_PATH + 32, "..\\..\\..\\Data\\Win32\\"); #else NiStrcat(acDataDirectory, NI_MAX_PATH + 32, "..\\..\\Data\\Win32\\"); #endif NiPath::RemoveDotDots(acDataDirectory); SetMediaPath(acDataDirectory); #elif defined (_PS3) SetMediaPath("../../../Data/Win32/"); #endif // Create Asset Manager and Error Handler m_spAssetManager = NiNew NiExternalAssetManager; m_spAssetManager->SetAssetFactory(NiFactories::GetAssetFactory()); m_spError = NiNew NiDefaultErrorHandler; m_pkCameraController = NULL; NiStrcpy(m_acFilename, NI_MAX_PATH, ""); m_bUseSplitScreen = true; m_pkShaderHelper = 0; m_bVisualTrackersCreated = false; m_bForceShadowsOff = false; m_kSceneRootPointerName = "Scene Root Pointer"; m_spCuller = NiNew NiOcclusionCuller; g_Game = this; m_bWebMode = FALSE; m_Loading = TRUE; } //--------------------------------------------------------------------------- SceneApp::~SceneApp() { g_Game = NULL; } //--------------------------------------------------------------------------- void SceneApp::Terminate() { m_spFullClick = NULL; m_spLeftClick = NULL; m_spRightClick = NULL; NiDelete m_pkText; m_spScreenQuad = NULL; m_spError = NULL; m_spAssetManager = NULL; m_spEntityScene = NULL; NiDelete m_pkCameraController; m_spAccum = NULL; m_spNewPipelineScreenElements = NULL; m_spOldPipelineScreenElements = NULL; m_spLogo = NULL; NiDelete m_pkShaderHelper; NiSmartPointerCast(NiOcclusionCuller, m_spCuller) ->RemoveAllOcclusionGeometry(); m_kSceneRootPointerName = NULL; unsigned int uiSize = m_kShaderPaths.GetSize(); for(unsigned int ui=0; uiGetWidth(); UINT H = m_pkAppWindow->GetHeight(); if (m_bD3D10Renderer) { ::MessageBox(NULL,"暂不考虑DX10渲染设备.","Sunyou Client",MB_OK); return false; } m_spRenderer = NiDX9Renderer::Create(W, H, NiDX9Renderer::USE_MULTITHREADED, GetWindowReference(), GetRenderWindowReference()); if (m_spRenderer == NULL) { NiMessageBox("Unable to create a renderer!", "Renderer Failure!"); QuitApplication(); return false; } return true; } //--------------------------------------------------------------------------- bool SceneApp::CreateScene() { CreateSplashScreen(); RenderSplashScreen(); if (NiShadowManager::GetShadowManager()) { NiShadowManager::SetMaxActiveShadowGenerators( m_bWebMode? 1 : 4); NiShadowManager::SetActive(!m_bForceShadowsOff); } // We use a NiAlphaAccumulator in order that our alpha gets sorted and // drawn correctly (just in case needed). NiMaterial* pkCurrentPipelineMaterial = m_spRenderer->GetInitialDefaultMaterial(); NiMaterial* pkLegacyPipelineMaterial = pkCurrentPipelineMaterial; #ifndef _PS3 m_spRenderer->UseLegacyPipelineAsDefaultMaterial(); pkLegacyPipelineMaterial = m_spRenderer->GetDefaultMaterial(); #endif m_spAccum = NiNew SceneAppAccum( pkLegacyPipelineMaterial, pkCurrentPipelineMaterial); m_spRenderer->SetSorter(m_spAccum); m_spRenderer->SetDefaultMaterial(pkCurrentPipelineMaterial); if (!m_bWebMode) { // Load Scenes from disk and store into an array.... NiEntityStreamingAscii kStream; m_pkText->SetString(m_acFilename); RenderSplashScreen(""); if (!kStream.Load(m_acFilename)) { char caOut[NI_MAX_PATH]; NiSprintf(caOut, NI_MAX_PATH, "Failed: Loading file name %s", m_acFilename); NiMessageBox(caOut, "Failed"); return false; } if (kStream.GetSceneCount() < 1) { NiMessageBox("Failed: Obtaining a Scene", "Failed"); return false; } m_spEntityScene = kStream.GetSceneAt(0); RenderSplashScreen("Updated Scene"); unsigned int uiCount = m_spEntityScene->GetEntityCount(); for(unsigned int uiEntity=0; uiEntity< uiCount; uiEntity++) { NiEntityInterface* pkEntity =m_spEntityScene->GetEntityAt(uiEntity); const char* pcName = pkEntity->GetName(); RenderSplashScreen(pcName); pkEntity->Update(NULL, 0.0, m_spError, m_spAssetManager); } #ifndef _PS3 ApplyMaterialToAllGeometry(pkLegacyPipelineMaterial); #endif ApplyMaterialToAllGeometry(pkCurrentPipelineMaterial); RenderSplashScreen("Loading pipeline_new.dds"); m_spNewPipelineScreenElements = CreateScreenElements("pipeline_new.dds"); RenderSplashScreen("Loading pipeline_old.dds"); m_spOldPipelineScreenElements = CreateScreenElements("pipeline_old.dds"); m_spNewPipelineScreenElements->SetRectangle(0, 0.0f, 0.0f, 0.5f, 1.0f); m_spOldPipelineScreenElements->SetRectangle(0, 0.5f, 0.0f, 0.5f, 1.0f); RenderSplashScreen("Loading Gamebryo_Logo_2C_PMS.tga"); // Create Logo NiTexturingPropertyPtr spText = NiNew NiTexturingProperty( ConvertMediaFilename("Gamebryo_Logo_2C_PMS.tga")); spText->SetApplyMode(NiTexturingProperty::APPLY_REPLACE); m_spLogo = m_spRenderer->CreateScreenElement(0, 0, spText->GetBaseTexture()->GetWidth(), spText->GetBaseTexture()->GetHeight(), NiRenderer::CORNER_BOTTOM_LEFT); m_spLogo->AttachProperty(spText); NiAlphaPropertyPtr spAlpha = NiNew NiAlphaProperty; spAlpha->SetAlphaBlending(true); spAlpha->SetSrcBlendMode(NiAlphaProperty::ALPHA_SRCALPHA); spAlpha->SetDestBlendMode(NiAlphaProperty::ALPHA_INVSRCALPHA); m_spLogo->AttachProperty(spAlpha); m_spLogo->UpdateProperties(); m_spLogo->Update(0.0f); RenderSplashScreen("Initializing Materials"); }else { WStreamResource::LoadScene(m_acFilename, &m_spEntityScene); } return true; } //--------------------------------------------------------------------------- void SceneApp::CreateSplashScreen() { if (m_bWebMode) { return; } // Create screen quad. m_spScreenQuad = NiNew NiScreenElements(NiNew NiScreenElementsData(false, false, 1)); int iPolygon = m_spScreenQuad->Insert(4); m_spScreenQuad->SetRectangle(iPolygon, 0.0f, 0.0f, 1.0f, 1.0f); m_spScreenQuad->UpdateBound(); m_spScreenQuad->SetTextures(iPolygon, 0, 0.0f, 0.0f, 1.0f, 1.0f); // Create and add texturing property. NiTexturingProperty* pkTexProp = NiNew NiTexturingProperty(); pkTexProp->SetApplyMode(NiTexturingProperty::APPLY_REPLACE); pkTexProp->SetBaseMap(NiNew NiTexturingProperty::Map()); pkTexProp->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); m_spScreenQuad->AttachProperty(pkTexProp); // Create and add z-buffer property. NiZBufferProperty* pkZBufferProp = NiNew NiZBufferProperty(); pkZBufferProp->SetZBufferTest(false); pkZBufferProp->SetZBufferWrite(false); m_spScreenQuad->AttachProperty(pkZBufferProp); // Perform initial update. m_spScreenQuad->Update(0.0f); m_spScreenQuad->UpdateNodeBound(); m_spScreenQuad->UpdateProperties(); m_spScreenQuad->UpdateEffects(); // Load splash screen texture. NiTexturePtr spSplashScreenTex = NiSourceTexture::Create( ConvertMediaFilename("SplashScreen.bmp")); NIASSERT(spSplashScreenTex); pkTexProp->SetBaseTexture(spSplashScreenTex); // Create the screen text object // Set initial string to match default LOD m_pkText = NiNew NiScreenText(512, &GetScreenTextures(), NiColorA::WHITE, "COURIER16.TGA", 11, 21, 23); unsigned int uiX, uiY; m_spRenderer->GetOnScreenCoord(0.0f, 0.0f, 0, 0, uiX, uiY, NiRenderer::CORNER_TOP_LEFT); m_pkText->SetTextOrigin(uiX, uiY); m_pkText->SetVisible(true); } //--------------------------------------------------------------------------- bool SceneApp::CreateFrame() { NiDefaultClickRenderStep* pkShadowRenderStep = NULL; if (NiShadowManager::GetShadowManager()) { // Initialize shadow click generator and active it. NiShadowManager::SetActiveShadowClickGenerator( "NiDefaultShadowClickGenerator"); // Initialize shadow manager parameters. NIASSERT(m_spCamera); NiShadowManager::SetSceneCamera(m_spCamera); // A different culling process is used here than the NiOcclusionCuller // used by the rest of the application. This is because, in general, // there will not be a lot of shadow casters for each light, making the // overhead of occlusion culling outweigh its benefits. If occlusion // culling for shadow maps is desired, m_spCuller should be passed into // NiShadowManager::SetCullingProcess below. NiShadowManager::SetCullingProcess( NiNew NiCullingProcess(&m_kVisible)); // Create shadow render step. pkShadowRenderStep = NiNew NiDefaultClickRenderStep; pkShadowRenderStep->SetName(m_kShadowRenderStepName); pkShadowRenderStep->SetPreProcessingCallbackFunc(ShadowRenderStepPre); } // Create scene render view. NIASSERT(m_spError && m_spCuller && m_spEntityScene); m_pkSceneView = NiNew NiSceneRenderView(m_spCamera, m_spCuller, m_spError); m_pkSceneView->AppendScene(m_spEntityScene); // Create second render view for use with split-screen. m_pkDuplicateView = NiNew NiSceneRenderView(m_spCamera, m_spCuller, m_spError); m_pkDuplicateView->AppendScene(m_spEntityScene); // Create accumulator processor. NiAccumulatorProcessor* pkProcessor = NiNew NiAccumulatorProcessor( m_spAccum); // Create full-screen render click. m_spFullClick = NiNew NiViewRenderClick; m_spFullClick->AppendRenderView(m_pkSceneView); m_spFullClick->SetClearAllBuffers(true); m_spFullClick->SetProcessor(pkProcessor); // Create left-half render click. m_spLeftClick = NiNew NiViewRenderClick; m_spLeftClick->AppendRenderView(m_pkSceneView); m_spLeftClick->SetClearAllBuffers(true); m_spLeftClick->SetProcessor(pkProcessor); m_spLeftClick->SetPreProcessingCallbackFunc(LeftClickPre, this); // Create right-half render click. m_spRightClick = NiNew NiViewRenderClick; m_spRightClick->AppendRenderView(m_pkDuplicateView); m_spRightClick->SetProcessor(pkProcessor); m_spRightClick->SetPreProcessingCallbackFunc(RightClickPre, this); m_spRightClick->SetPostProcessingCallbackFunc(RightClickPost, this); // Create screen element render click. NIASSERT(m_spScreenElementsRenderView); NiViewRenderClick* pkScreenElementsRenderClick = NiNew NiViewRenderClick; pkScreenElementsRenderClick->AppendRenderView( m_spScreenElementsRenderView); NIASSERT(m_spScreenTextureRenderClick && m_spVisualTrackerRenderClick); // Create render step that contains all the render clicks. NiDefaultClickRenderStep* pkRenderStep = NiNew NiDefaultClickRenderStep; pkRenderStep->AppendRenderClick(m_spFullClick); pkRenderStep->AppendRenderClick(m_spLeftClick); pkRenderStep->AppendRenderClick(m_spRightClick); pkRenderStep->AppendRenderClick(pkScreenElementsRenderClick); pkRenderStep->AppendRenderClick(m_spScreenTextureRenderClick); pkRenderStep->AppendRenderClick(m_spVisualTrackerRenderClick); // Create render frame that contains the single render step. m_spFrame = NiNew NiRenderFrame; if (pkShadowRenderStep) { m_spFrame->AppendRenderStep(pkShadowRenderStep); } m_spFrame->AppendRenderStep(pkRenderStep); m_spFrame->SetPreProcessingCallbackFunc(RenderFramePre, this); return true; } //--------------------------------------------------------------------------- bool SceneApp::RenderFramePre(NiRenderFrame* pkCurrentFrame, void* pvCallbackData) { SceneApp* pkThis = (SceneApp*) pvCallbackData; NIASSERT(pkThis); if (pkThis->GetUseSplitScreen()) { pkThis->m_spFullClick->SetActive(false); pkThis->m_spLeftClick->SetActive(true); pkThis->m_spRightClick->SetActive(true); } else { pkThis->m_spFullClick->SetActive(true); pkThis->m_spLeftClick->SetActive(false); pkThis->m_spRightClick->SetActive(false); } return true; } //--------------------------------------------------------------------------- bool SceneApp::LeftClickPre(NiRenderClick* pkCurrentRenderClick, void* pvCallbackData) { SceneApp* pkThis = (SceneApp*) pvCallbackData; NIASSERT(pkThis); pkThis->m_spCamera->SetViewPort(pkThis->m_kLeftPort); pkThis->m_spCamera->SetViewFrustum(pkThis->m_kLeftFrustum); return true; } //--------------------------------------------------------------------------- bool SceneApp::RightClickPre(NiRenderClick* pkCurrentRenderClick, void* pvCallbackData) { SceneApp* pkThis = (SceneApp*) pvCallbackData; NIASSERT(pkThis); pkThis->m_spCamera->SetViewPort(pkThis->m_kRightPort); pkThis->m_spCamera->SetViewFrustum(pkThis->m_kRightFrustum); pkThis->m_spAccum->SetUseNewSystem(!pkThis->m_spAccum->GetUseNewSystem()); return true; } //--------------------------------------------------------------------------- bool SceneApp::RightClickPost(NiRenderClick* pkCurrentRenderClick, void* pvCallbackData) { SceneApp* pkThis = (SceneApp*) pvCallbackData; NIASSERT(pkThis); pkThis->m_spAccum->SetUseNewSystem(!pkThis->m_spAccum->GetUseNewSystem()); return true; } //--------------------------------------------------------------------------- bool SceneApp::ProcessCommandLine() { if (!ms_pkCommand->Filename(&m_acFilename[0], NI_MAX_PATH)) { NiMessageBox("Failed: No file specified", "Failed"); return false; } bool bNoDefaultShaders = false; ms_pkCommand->Boolean("NoDefaultShaders", bNoDefaultShaders); if (!bNoDefaultShaders) { // If NoDefaultShaders is not specified, then default shaders are // used. char* pcShaderPath = NiAlloc(char, NI_MAX_PATH); char* pcShaderProgramPath = NiAlloc(char, NI_MAX_PATH); #if defined(WIN32) // Use the Default path. For win32, this can be taken from the // environmental variable EGB_SHADER_LIBRARY_PATH. pcShaderPath[0] = '\0'; #if _MSC_VER >= 1400 size_t stSize = 0; getenv_s(&stSize, pcShaderPath, NI_MAX_PATH, "EGB_SHADER_LIBRARY_PATH"); #else //#if _MSC_VER >= 1400 char* pcEnvPathTemp = getenv("EGB_SHADER_LIBRARY_PATH"); if (pcEnvPathTemp) NiStrcpy(pcShaderPath, NI_MAX_PATH, pcEnvPathTemp); #endif //#if _MSC_VER >= 1400 if (pcShaderPath[0] != '\0') { m_kShaderPaths.Add(pcShaderPath); // Also set-up a default Shader Program directory if (m_bD3D10Renderer) { NiSprintf(pcShaderProgramPath, NI_MAX_PATH, "%s\\Data\\D3D10\\", pcShaderPath); } else { NiSprintf(pcShaderProgramPath, NI_MAX_PATH, "%s\\Data\\DX9\\", pcShaderPath); } m_kShaderProgramPaths.Add(pcShaderProgramPath); } else { NiFree(pcShaderPath); NiFree(pcShaderProgramPath); pcShaderPath = pcShaderProgramPath = NULL; } #elif defined(_XENON) // For consoles, this is taken from the data directory const char* pcDataDir = GetMediaPath(); NiSprintf(pcShaderPath, NI_MAX_PATH, "%sShaders\\", pcDataDir); m_kShaderPaths.Add(pcShaderPath); NiSprintf(pcShaderProgramPath, NI_MAX_PATH, "%sData\\Xenon\\", pcShaderPath); m_kShaderProgramPaths.Add(pcShaderProgramPath); #elif defined (_PS3) NiStrcpy(pcShaderPath, NI_MAX_PATH, "../../../Data/PS3/Shaders/"); m_kShaderPaths.Add(pcShaderPath); NiStrcpy(pcShaderProgramPath, NI_MAX_PATH, pcShaderPath); m_kShaderProgramPaths.Add(pcShaderProgramPath); #endif } // Add shader paths while(1) { char acShaderPath[NI_MAX_PATH]; if (!ms_pkCommand->String("ShaderPath", acShaderPath, NI_MAX_PATH)) break; char* pcShaderPath = NiAlloc(char, NI_MAX_PATH); NiStrcpy(pcShaderPath, NI_MAX_PATH, acShaderPath); m_kShaderPaths.Add(pcShaderPath); } // Add program paths while(1) { char acShaderProgramPath[NI_MAX_PATH]; if (!ms_pkCommand->String("ShaderProgramPath", acShaderProgramPath, NI_MAX_PATH)) break; char* pcShaderProgramPath = NiAlloc(char, NI_MAX_PATH); NiStrcpy(pcShaderProgramPath, NI_MAX_PATH, acShaderProgramPath); m_kShaderProgramPaths.Add(pcShaderProgramPath); } ms_pkCommand->Boolean("VisualTrackers", m_bVisualTrackersCreated); float fFPS; if (ms_pkCommand->Float("FPS", fFPS) || ms_pkCommand->Float("fps", fFPS)) { if (fFPS > 0) SetMaxFrameRate(fFPS); } ms_pkCommand->Boolean("ShadowsOff", m_bForceShadowsOff); return true; } //--------------------------------------------------------------------------- bool SceneApp::CreateShaders() { // Shader directories must be passed in via command line unsigned int uiNumShaderPaths = m_kShaderPaths.GetSize(); if (uiNumShaderPaths == 0) return true; m_pkShaderHelper = NiNew ShaderHelper(); if (!m_pkShaderHelper) return false; char** ppcShaderDirectories = NiExternalNew char*[uiNumShaderPaths]; for(unsigned int ui=0; uiSetupShaderSystem(ppcProgramDirectories, uiNumProgramPaths, ppcShaderDirectories, uiNumShaderPaths); NiExternalDelete [] ppcProgramDirectories; NiExternalDelete [] ppcShaderDirectories; if (!bSuccess) { NiMessageBox("Failed: SetupShaderSystem", "Failed"); } return bSuccess; } //--------------------------------------------------------------------------- bool SceneApp::CreateCameraController() { // Create camera controller // The camera controller will find all walkables and defaults associated // with this scene NiDelete m_pkCameraController; m_pkCameraController = NiNew CameraController(m_spEntityScene); m_spCamera = m_pkCameraController->GetCamera(); m_pkCameraController->GetAllCameras(m_kAllCameras); m_uiCurrentCamera = m_kAllCameras.Find(m_spCamera); m_uiWalkableCamera = m_uiCurrentCamera; if (!m_spCamera || m_kAllCameras.GetSize()==0) { NiMessageBox("Failed: Couldn't find a camera", "Failed"); return false; } m_kOrigFrustum = m_spCamera->GetViewFrustum(); m_kOrigPort = m_spCamera->GetViewPort(); //m_kLeftFrustum(-0.5f, 0.0f, 0.5f, -0.5, 1.0f, 10000.0f); m_kLeftFrustum = NiFrustum(m_kOrigFrustum.m_fLeft, 0.0f, m_kOrigFrustum.m_fTop, m_kOrigFrustum.m_fBottom, m_kOrigFrustum.m_fNear, m_kOrigFrustum.m_fFar); //m_kRightFrustum(0.0f, 0.5f, 0.5f, -0.5, 1.0f, 10000.0f); m_kRightFrustum = NiFrustum( 0.0f,m_kOrigFrustum.m_fRight, m_kOrigFrustum.m_fTop, m_kOrigFrustum.m_fBottom, m_kOrigFrustum.m_fNear, m_kOrigFrustum.m_fFar); //NiRect kRectLeft(0.0f, 0.5f, 1.0f, 0.0f); // L,R,T,B m_kLeftPort = NiRect(m_kOrigPort.m_left, m_kOrigPort.m_right/2.0f, m_kOrigPort.m_top, m_kOrigPort.m_bottom); //NiRect kRectRight(0.5f, 1.0f, 1.0f, 0.0f); // L,R,T,B m_kRightPort = NiRect(m_kOrigPort.m_right/2.0f, m_kOrigPort.m_right, m_kOrigPort.m_top, m_kOrigPort.m_bottom); if (!m_bWebMode) { SetUseSplitScreen(false); } return true; } //--------------------------------------------------------------------------- NiScreenElements* SceneApp::CreateScreenElements(const char* pcFilename) { // Create screen elements NiScreenElements* pkScreenElements = NiNew NiScreenElements( NiNew NiScreenElementsData(false, false, 1)); // We know that the polygon handle is zero and will use it directly in // the vertex and texture coordinate assignments. pkScreenElements->Insert(4); pkScreenElements->SetTextures(0, 0, 0.0f, 0.0f, 1.0f, 1.0f); NiTexturingPropertyPtr spText = NiNew NiTexturingProperty( ConvertMediaFilename(pcFilename)); spText->SetApplyMode(NiTexturingProperty::APPLY_REPLACE); pkScreenElements->AttachProperty(spText); NiAlphaPropertyPtr spAlpha = NiNew NiAlphaProperty; spAlpha->SetAlphaBlending(true); spAlpha->SetSrcBlendMode(NiAlphaProperty::ALPHA_SRCALPHA); spAlpha->SetDestBlendMode(NiAlphaProperty::ALPHA_INVSRCALPHA); pkScreenElements->AttachProperty(spAlpha); pkScreenElements->SetDefaultMaterialNeedsUpdateFlag(false); pkScreenElements->UpdateProperties(); pkScreenElements->Update(0.0f); GetScreenElements().AddTail(pkScreenElements); pkScreenElements->SetDefaultMaterialNeedsUpdateFlag(false); return pkScreenElements; } //--------------------------------------------------------------------------- void SceneApp::ApplyMaterialToAllGeometry( NiMaterial* pkLegacyPipelineMaterial) { for (unsigned int ui = 0; ui < m_spEntityScene->GetEntityCount(); ui++) { RecursiveApplyMaterial(m_spEntityScene->GetEntityAt(ui), pkLegacyPipelineMaterial); } } //--------------------------------------------------------------------------- void SceneApp::ApplyMaterial(NiAVObject* pkObject, NiMaterial* pkLegacyPipelineMaterial) { const char* pcName = pkObject->GetName(); if (pcName) { if (NiStricmp(pcName, "walkable") == 0) return; if (strstr(pcName, "Occluder")) return; } if (NiIsKindOf(NiNode, pkObject)) { NiNode* pkNode = (NiNode*)pkObject; const unsigned int uiSize = pkNode->GetArrayCount(); for (unsigned int uiI = 0; uiI < uiSize; uiI++) { NiAVObject* pkChild = pkNode->GetAt(uiI); if (pkChild) { ApplyMaterial(pkChild, pkLegacyPipelineMaterial); } } } else if (NiIsKindOf(NiGeometry, pkObject) && !NiIsKindOf(NiParticleSystem, pkObject) && !NiIsKindOf(NiLines, pkObject)) { NiGeometry* pkGeom = (NiGeometry*)pkObject; //if (pkGeom->GetActiveMaterial()) // return; if (!pkGeom->IsMaterialApplied(pkLegacyPipelineMaterial)) { pkGeom->ApplyMaterial(pkLegacyPipelineMaterial); } } } HWND GetTopLevelParent(HWND hWnd) { if (hWnd == NULL) return NULL; HWND hWndParent = hWnd; HWND hWndT; do { hWndT = GetParent(hWndParent); if (hWndT != NULL) { hWndParent = hWndT; } } while(hWndT); if (hWndParent != NULL) { // check. BOOL bChildWnd = ::GetWindowLong(hWndParent, GWL_STYLE) & WS_CHILD; } return hWndParent; } NiInputSystem::CreateParams* SceneApp::GetInputSystemCreateParams() { if (m_bWebMode) { NiDI8InputSystem::DI8CreateParams* pkParams = NiNew NiDI8InputSystem::DI8CreateParams(); NIASSERT(pkParams); pkParams->SetRenderer(m_spRenderer); pkParams->SetKeyboardUsage( NiInputSystem::FOREGROUND | NiInputSystem::NONEXCLUSIVE); unsigned int uiMouseFlags = NiInputSystem::FOREGROUND | NiInputSystem::NONEXCLUSIVE; pkParams->SetMouseUsage(uiMouseFlags); pkParams->SetGamePadCount(0); pkParams->SetOwnerInstance(GetInstanceReference()); // dinput 需要和进程中的顶级窗口关联才有效,否则 SetCooperativeLevel 会返回E_HANDLE错误. // 在WEB 控件中,我们需要返回浏览器窗口句柄. HWND hViewportWnd = GetWindowReference(); HWND hTopLevel = GetTopLevelParent(hViewportWnd); NIASSERT(hTopLevel); pkParams->SetOwnerWindow(hTopLevel); return pkParams; }else { return NiApplication::GetInputSystemCreateParams(); } } bool SceneApp::CreateInputSystem() { // Create and initialize parameters for the input system NiInputSystem::CreateParams* pkParams = GetInputSystemCreateParams(); m_spInputSystem = NiInputSystem::Create(pkParams); NiDelete pkParams; if (!m_spInputSystem) { NiMessageBox("CreateInputSystem: Creation failed.", "NiApplication Error"); return false; } // The creation of the input system automatically starts an enumeration // of the devices. NiInputErr eErr = m_spInputSystem->CheckEnumerationStatus(); switch (eErr) { case NIIERR_ENUM_NOTRUNNING: NIASSERT(!"EnumerateDevices failed?"); return false; case NIIERR_ENUM_FAILED: NIASSERT(!"CheckEnumerationStatus> FAILED!"); return false; case NIIERR_ENUM_COMPLETE: case NIIERR_ENUM_NOTCOMPLETE: default: break; } // On Win32, assume there is a mouse and keyboard if (!m_spInputSystem->OpenMouse() || !m_spInputSystem->OpenKeyboard()) { NiMessageBox("CreateInputSystem: Mouse or keyboard failed to open.", "NiApplication Error"); return false; } return true; } //--------------------------------------------------------------------------- void SceneApp::ProcessInput() { // Call NiApplication::ProcessInput() // --- unless Q is pressed, as we don't want to accidentally quit. NiInputKeyboard* pkKeyboard = NiApplication::ms_pkApplication-> GetInputSystem()->GetKeyboard(); if (!m_bWebMode) { // 屏蔽 ESC 造成的进程终止. NiApplication::ProcessInput(); } bool bTogglePipeline = false; bool bToggleSplitscreen = false; bool bToggleWireframe = false; bool bToggleFly = false; bool bToggleShadows = false; bool bToggleCamera = false; if (!m_bWebMode) { for (unsigned int uiPort = 0; uiPort < NiInputSystem::MAX_GAMEPADS; uiPort++) { NiInputGamePad* pkGamePad = NiApplication::ms_pkApplication-> GetInputSystem()->GetGamePad(uiPort); if (!pkGamePad) continue; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_FULLSCREEN_BUTTON)) bTogglePipeline = true; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_PIPELINE_BUTTON)) bToggleSplitscreen = true; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_WIREFRAME_BUTTON)) bToggleWireframe = true; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_FLY_BUTTON)) bToggleFly = true; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_SHADOWS_BUTTON)) bToggleShadows = true; if (pkGamePad->ButtonWasPressed(SCENEAPP_TOGGLE_CAMERA_BUTTON)) bToggleCamera = true; } } if (pkKeyboard) { if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_M)) bTogglePipeline = true; if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_P)) bToggleSplitscreen = true; if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_F)) bToggleFly= true; if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_T)) SetShowAllTrackers(!m_bShowAllTrackers); if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_F1)) bToggleWireframe = true; if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_F4)) bToggleShadows = true; if (pkKeyboard->KeyWasPressed(NiInputKeyboard::KEY_SPACE)) bToggleCamera = true; } if (bToggleSplitscreen) { // Toggle whether to use split screen or full screen SetUseSplitScreen(!GetUseSplitScreen()); } if (bTogglePipeline) { #ifndef _PS3 // No "old" pipeline on PS3. // Toggle pipeline to use m_spAccum->SetUseNewSystem(!m_spAccum->GetUseNewSystem()); if (m_spAccum->GetUseNewSystem()) { // New system on left side of screen m_spNewPipelineScreenElements->SetRectangle(0, 0.0f, 0.0f, 0.5f, 1.0f); m_spOldPipelineScreenElements->SetRectangle(0, 0.5f, 0.0f, 0.5f, 1.0f); } else { // New system on right side of screen m_spOldPipelineScreenElements->SetRectangle(0, 0.0f, 0.0f, 0.5f, 1.0f); m_spNewPipelineScreenElements->SetRectangle(0, 0.5f, 0.0f, 0.5f, 1.0f); } #endif } if (bToggleWireframe) { for (unsigned int ui = 0; ui < m_spEntityScene->GetEntityCount(); ui++) { RecursiveToggleWireframe(m_spEntityScene->GetEntityAt(ui)); } } if (bToggleFly && m_uiCurrentCamera == m_uiWalkableCamera) { m_pkCameraController->SetFly(!m_pkCameraController->GetFly()); } if (bToggleShadows && NiShadowManager::GetShadowManager()) { m_bForceShadowsOff = !m_bForceShadowsOff; NiShadowManager::SetActive(!m_bForceShadowsOff); } if (bToggleCamera) { AdvanceCamera(); } } //--------------------------------------------------------------------------- void SceneApp::UpdateFrame() { NiApplication::UpdateFrame(); m_spError->ClearErrors(); if (m_pkCameraController) { // Update cameras. if (m_uiCurrentCamera == m_uiWalkableCamera) { m_pkCameraController->UpdateAllCameras(m_fAccumTime, m_spError, m_spAssetManager); } } // Update entities. for (unsigned int ui = 0; ui < m_kEntitiesToUpdate.GetSize(); ui++) { m_kEntitiesToUpdate.GetAt(ui)->Update(NULL, m_fAccumTime, m_spError, m_spAssetManager); } } //--------------------------------------------------------------------------- bool SceneApp::GetUseSplitScreen() { return m_bUseSplitScreen; } //--------------------------------------------------------------------------- void SceneApp::SetUseSplitScreen(bool bUseSplitScreen) { if (bUseSplitScreen == m_bUseSplitScreen) return; m_bUseSplitScreen = bUseSplitScreen; if (m_bUseSplitScreen) { GetScreenElements().AddTail(m_spNewPipelineScreenElements); GetScreenElements().AddTail(m_spOldPipelineScreenElements); GetScreenElements().Remove(m_spLogo); } else { GetScreenElements().Remove(m_spNewPipelineScreenElements); GetScreenElements().Remove(m_spOldPipelineScreenElements); GetScreenElements().AddTail(m_spLogo); //const NiFrustum& kCameraFrustum = m_spCamera->GetViewFrustum(); //NiRect kRect(0.0f, 1.0f, 1.0f, 0.0f); // L,R,T,B m_spCamera->SetViewFrustum(m_kOrigFrustum); m_spCamera->SetViewPort(m_kOrigPort); } m_spAccum->SetUseSplitScreen(bUseSplitScreen); } //--------------------------------------------------------------------------- void SceneApp::PrepareScene(NiScene* pkScene) { // These steps must be done SEQUENTIALLY in order // // 1) Update the scene first, so that it loads all the necessary assets. // 2) Find all the shadow lights, so we know where we're going to have // to attach rendered textures and attach them. // 3) Set the most complicated material that will be used per object // (shadow material) precache then, but only after any walkables // and the occluders that need to keep their geometry and indices are // marked in the PickController::Initialize and // NiOcclusionCuller::FindOccusionGeometry routines. // // If the scene isn't updated by the time we look for lights, then all // the shadow lights and affected entities may not have been loaded yet. // If the rendered textures aren't all attached by the time we precache, // then the wrong shader will be generated. m_spCamera->Update(0.0f); NiSmartPointerCast(NiOcclusionCuller, m_spCuller)->FindOcclusionGeometry( m_spEntityScene); pkScene->Update(m_fAccumTime, m_spError, m_spAssetManager); for (unsigned int ui = 0; ui < pkScene->GetEntityCount(); ui++) { RecursivePrecacheEntity(pkScene->GetEntityAt(ui)); } } //--------------------------------------------------------------------------- void SceneApp::RecursivePrecacheEntity(NiEntityInterface* pkEntity) { if (!pkEntity) { return; } unsigned int uiSceneRootCount; if (pkEntity->GetElementCount(m_kSceneRootPointerName, uiSceneRootCount)) { for (unsigned int ui = 0; ui < uiSceneRootCount; ui++) { NiObject* pkObject; NIVERIFY(pkEntity->GetPropertyData( m_kSceneRootPointerName, pkObject, ui)); NiAVObject* pkSceneRoot = NiDynamicCast(NiAVObject, pkObject); if (pkSceneRoot) { RecursivePrecacheScene(pkSceneRoot); pkSceneRoot->SetDefaultMaterialNeedsUpdateFlag(false); } } } if (pkEntity->IsAnimated()) { m_kEntitiesToUpdate.Add(pkEntity); } } //--------------------------------------------------------------------------- void SceneApp::RecursivePrecacheScene(NiAVObject* pkObject) { // Apply the "Scene" shader to the geometry if (NiIsKindOf(NiGeometry, pkObject)) { NiGeometry* pkGeometry = (NiGeometry*)pkObject; // Precache geometry with the shadowing shader, to ensure that // the depth map shader (with fewer vertex requirements) does // not dictate the packing of the geometry. m_spRenderer->PrecacheGeometry(pkGeometry, 0, 0); #if defined(WIN32) // With no geometry groups, it is still efficient to force the // precache now. if (NiIsKindOf(NiDX9Renderer, m_spRenderer)) { NiSmartPointerCast(NiDX9Renderer, m_spRenderer)-> PerformPrecache(); } #endif // #if defined(WIN32) // Pregenerate shader NiShader* pkShader = pkGeometry->GetShaderFromMaterial(); } else if (NiIsKindOf(NiNode, pkObject)) { // Recurse to children NiNode* pkNode = (NiNode*)pkObject; unsigned int uiChildCount = pkNode->GetArrayCount(); for (unsigned int i = 0; i < uiChildCount; i++) { NiAVObject* pkChild = pkNode->GetAt(i); if (pkChild) { RecursivePrecacheScene(pkChild); } } } } //--------------------------------------------------------------------------- void SceneApp::RecursiveApplyMaterial(NiEntityInterface* pkEntity, NiMaterial* pkLegacyPipelineMaterial) { if (!pkEntity) { return; } unsigned int uiSceneRootCount; if (pkEntity->GetElementCount(m_kSceneRootPointerName, uiSceneRootCount)) { for (unsigned int ui = 0; ui < uiSceneRootCount; ui++) { NiObject* pkObject; NIVERIFY(pkEntity->GetPropertyData( m_kSceneRootPointerName, pkObject, ui)); NiAVObject* pkSceneRoot = NiDynamicCast(NiAVObject, pkObject); if (pkSceneRoot) { // Add wireframe property. NiWireframeProperty* pkWireframeProp = (NiWireframeProperty*) pkSceneRoot->GetProperty(NiWireframeProperty::GetType()); if (!pkWireframeProp) { pkWireframeProp = NiNew NiWireframeProperty(); pkSceneRoot->AttachProperty(pkWireframeProp); pkSceneRoot->UpdateProperties(); } ApplyMaterial(pkSceneRoot, pkLegacyPipelineMaterial); } } } } //--------------------------------------------------------------------------- void SceneApp::RecursiveToggleWireframe(NiEntityInterface* pkEntity) { if (!pkEntity) { return; } unsigned int uiSceneRootCount; if (pkEntity->GetElementCount(m_kSceneRootPointerName, uiSceneRootCount)) { for (unsigned int ui = 0; ui < uiSceneRootCount; ui++) { NiObject* pkObject; NIVERIFY(pkEntity->GetPropertyData( m_kSceneRootPointerName, pkObject, ui)); NiAVObject* pkSceneRoot = NiDynamicCast(NiAVObject, pkObject); if (pkSceneRoot) { NiWireframeProperty* pkWireframeProp = (NiWireframeProperty*) pkSceneRoot->GetProperty(NiWireframeProperty::GetType()); if (pkWireframeProp) { pkWireframeProp->SetWireframe( !pkWireframeProp->GetWireframe()); } else { pkWireframeProp = NiNew NiWireframeProperty(); pkSceneRoot->AttachProperty(pkWireframeProp); pkSceneRoot->UpdateProperties(); } } } } } //--------------------------------------------------------------------------- void SceneApp::RenderSplashScreen(const char* pcMsg) { if (m_bWebMode) { return; } if (m_spScreenQuad && m_pkText) { if (pcMsg) m_pkText->SetString(pcMsg); else m_pkText->SetString(""); m_spRenderer->BeginFrame(); m_spRenderer->BeginUsingDefaultRenderTargetGroup( NiRenderer::CLEAR_ALL); m_spRenderer->SetScreenSpaceCameraData(); m_spScreenQuad->Draw(m_spRenderer); const NiTPointerList& kScreenTextures = GetScreenTextures(); NiTListIterator kIter = kScreenTextures.GetHeadPos(); while (kIter) { NiScreenTexture* pkTexture = kScreenTextures.GetNext(kIter); NIASSERT(pkTexture); pkTexture->Draw(m_spRenderer); } m_spRenderer->EndUsingRenderTargetGroup(); m_spRenderer->EndFrame(); m_spRenderer->DisplayFrame(); } } //--------------------------------------------------------------------------- void SceneApp::AdvanceCamera() { bool bSplitScreen = m_bUseSplitScreen; SetUseSplitScreen(false); // Advance camera m_uiCurrentCamera = (m_uiCurrentCamera + 1) % m_kAllCameras.GetSize(); m_spCamera = m_kAllCameras.GetAt(m_uiCurrentCamera); // Save splitscreen restore data m_kOrigFrustum = m_spCamera->GetViewFrustum(); m_kOrigPort = m_spCamera->GetViewPort(); // Restore splitscreen state SetUseSplitScreen(bSplitScreen); // Update active camera m_pkSceneView->SetCamera(m_spCamera); m_pkDuplicateView->SetCamera(m_spCamera); // NiShadowManager's camera will be updated by NiApplication::RenderFrame. } //---------------------------------------------------------------------------