#include "Graphics2.h" Graphics2 app; void Graphics2::CreateSceneGraph() { // Reset our variables for movement _boostMultiplier = _boostMin; _flySpeed = 1; _turnSpeed = 1; _invertPitch = -1; _currentController = GamePadController(); _currentPlayerObject = nullptr; // Check if the shift and ctrl keys are held to disable the clutter if (GetAsyncKeyState(VK_SHIFT) && GetAsyncKeyState(VK_CONTROL)) { _noClutter = true; } // Set the default camera position GetCamera()->SetCameraPosition(0.0f, 550.0f, -80.0f); // Get the main scene graph SceneGraphPointer sceneGraph = GetSceneGraph(); // This is where you add nodes to the scene graph //shared_ptr cube = make_shared(L"Body", L"Textures\\woodbox.bmp"); //cube->SetWorldTransform(XMMatrixScaling(5.0f, 8.0f, 2.5f) * XMMatrixTranslation(0, 23.0f, 0)); XMMatrixScaling(50.0f, 800.0f, 50.0f) * XMMatrixTranslation(-65.0f, 350.0f, -65.0f) //sceneGraph->Add(cube); // Set some global lighting variables for the ambient and directional lights, if i get time look into other lighting? DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetAmbientLight(XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f)); DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetDirectionalLight(XMVectorSet(0.5f, -1.0f, -1.0f, 0.0f), XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f)); // Add the skybox node shared_ptr skyDome = make_shared(L"SkyDome", L"Textures\\SkyWater.dds", 360.0f); sceneGraph->Add(skyDome); // Set the terrain node, we can use the heightmap or perlin noise nodes //shared_ptr terrainNode = make_shared(L"MainTerrain", L"Textures\\Example_HeightMap.raw", L"RandomWords"); //My height maps do not load with the given function, i have no idea what format its in then... //shared_ptr terrainNode = make_shared(L"MainTerrain", L"TerrainCache\\cache_LovelyCat_10_000000.raw", L"RandomWords"); shared_ptr terrainNode = make_shared(L"MainTerrain", L"LovelyCat", 10.0f); terrainNode->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight()); terrainNode->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor()); // Set the water color for tinting here terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x84), SharedMethods::RGBValueToIntensity(0xC1), SharedMethods::RGBValueToIntensity(0xF9), 1.0f)); // Rivers of blood mode //terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x66), 0.0f, 0.0f, 1.0f)); sceneGraph->Add(terrainNode); // Add the controlled plane model shared_ptr plane1Node = make_shared(L"Plane1", L"Models\\Plane\\Bonanza.3DS"); plane1Node->SetStartOrientation(XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), XM_PI) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), 0.5f * XM_PI)); plane1Node->SetNodePosition(0.0f, 550.0f, -50.0f); sceneGraph->Add(plane1Node); // Add the boat scene graph so i can scale and position the model shared_ptr boatGraph = make_shared(L"boatGraph"); boatGraph->SetWorldTransform(XMMatrixScaling(0.1f, 0.1f, 0.1f) * XMMatrixTranslation(-1880.0f, 290.0f, 610.0f)); // Added the moveable boat model shared_ptr boat1Node = make_shared(L"Boat1", L"Models\\Boat\\Boat.FBX"); boat1Node->SetStartOrientation(XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), (90.0f * XM_PI) / 180.0f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), (90.0f * XM_PI) / 180.0f)); boat1Node->SetNodePosition(0.0f, 0.0f, 0.0f); boatGraph->Add(boat1Node); sceneGraph->Add(boatGraph); // Set the current player object to the plane and turn on follow mode _currentPlayerObject = plane1Node; GetCamera()->SetFollowNode(plane1Node, XMFLOAT3(0.0f, 40.0f, -100.0f), false); // Set the background color although i assume this will be deprecated when the skybox is added SetBackgroundColour(XMFLOAT4(0.29f, 0.38f, 0.72f, 1.0f)); //SetBackgroundColour(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0, 1, 1)); _currentRotation = 0; _currentSideRotation = 0; _currentPropRotation = 0; } // Method for generating the random clutter on the terrain void Graphics2::GenerateClutter() { SceneGraphPointer sceneGraph = GetSceneGraph(); // Get the current terrain node so that we can access its methods shared_ptr mainTerrain = dynamic_pointer_cast(sceneGraph->Find(L"MainTerrain")); // Check if the terrain is actually loaded before trying to access it. if (!_initDone && mainTerrain != nullptr) { // Create the spawn object lists vector rngSpawnList; vector rngBushSpawnList; vector rngSnowSpawnList; vector rngDirtSpawnList; // Trees TerrainPopNode treeModelA = TerrainPopNode(); treeModelA.modelName = L"Models\\Tree\\Tree1.fbx"; treeModelA.nodeBaseName = L"treeA"; treeModelA.scaleFactor = 0.5f; TerrainPopNode treeModelB = TerrainPopNode(); treeModelB.modelName = L"Models\\Tree\\Tree2.fbx"; treeModelB.nodeBaseName = L"treeB"; treeModelB.scaleFactor = 0.5f; rngSpawnList.push_back(treeModelA); rngSpawnList.push_back(treeModelB); shared_ptr treeGroupA = make_shared(L"TreeGroupA"); // Populate the terrain and add the child scene graph to the main scenegraph mainTerrain->PopulateTerrain(treeGroupA, rngSpawnList, 20, 20, 500.0f, 650.0f, 0.9f, 1.0f); // Initialise the newly created models treeGroupA->Initialise(); sceneGraph->Add(treeGroupA); // Bushes TerrainPopNode bushModelA = TerrainPopNode(); bushModelA.modelName = L"Models\\Tree\\Bush1.fbx"; bushModelA.nodeBaseName = L"bushA"; bushModelA.scaleFactor = 0.05f; TerrainPopNode bushModelB = TerrainPopNode(); bushModelB.modelName = L"Models\\Tree\\Bush2.fbx"; bushModelB.nodeBaseName = L"bushB"; bushModelB.scaleFactor = 0.05f; TerrainPopNode grassModelA = TerrainPopNode(); grassModelA.modelName = L"Models\\Tree\\Grass1.fbx"; grassModelA.nodeBaseName = L"grassA"; grassModelA.scaleFactor = 0.005f; TerrainPopNode grassModelB = TerrainPopNode(); grassModelB.modelName = L"Models\\Tree\\Grass2.fbx"; grassModelB.nodeBaseName = L"grassB"; grassModelB.scaleFactor = 0.05f; TerrainPopNode grassModelC = TerrainPopNode(); grassModelC.modelName = L"Models\\Tree\\Grass3.fbx"; grassModelC.nodeBaseName = L"grassC"; grassModelC.scaleFactor = 0.05f; rngBushSpawnList.push_back(bushModelA); rngBushSpawnList.push_back(bushModelB); rngBushSpawnList.push_back(grassModelA); rngBushSpawnList.push_back(grassModelB); rngBushSpawnList.push_back(grassModelC); shared_ptr bushGroupA = make_shared(L"BushGroupA"); mainTerrain->PopulateTerrain(bushGroupA, rngBushSpawnList, 7, 7, 500.0f, 650.0f, 0.95f, 1.0f); bushGroupA->Initialise(); sceneGraph->Add(bushGroupA); // The Snow trees TerrainPopNode treeModelSA = TerrainPopNode(); treeModelSA.modelName = L"Models\\Tree\\Tree3.fbx"; treeModelSA.nodeBaseName = L"treeSA"; treeModelSA.scaleFactor = 0.1f; rngSnowSpawnList.push_back(treeModelSA); shared_ptr treeGroupSA = make_shared(L"TreeGroupSnowA"); mainTerrain->PopulateTerrain(treeGroupSA, rngSnowSpawnList, 50, 50, 750.0f, 1000.0f, 0.6f, 1.0f); treeGroupSA->Initialise(); sceneGraph->Add(treeGroupSA); // The Rocks and desert tree TerrainPopNode treeModelDA = TerrainPopNode(); treeModelDA.modelName = L"Models\\Tree\\Tree4.fbx"; treeModelDA.nodeBaseName = L"treeDA"; treeModelDA.scaleFactor = 0.05f; TerrainPopNode rockModelA = TerrainPopNode(); rockModelA.modelName = L"Models\\Tree\\Rock1.fbx"; rockModelA.nodeBaseName = L"rockA"; rockModelA.scaleFactor = 0.1f; TerrainPopNode rockModelB = TerrainPopNode(); rockModelB.modelName = L"Models\\Tree\\Rock2.fbx"; rockModelB.nodeBaseName = L"rockB"; rockModelB.scaleFactor = 0.1f; TerrainPopNode rockModelC = TerrainPopNode(); rockModelC.modelName = L"Models\\Tree\\Rock3.fbx"; rockModelC.nodeBaseName = L"rockC"; rockModelC.scaleFactor = 0.1f; rngDirtSpawnList.push_back(treeModelDA); rngDirtSpawnList.push_back(rockModelA); rngDirtSpawnList.push_back(rockModelB); rngDirtSpawnList.push_back(rockModelC); shared_ptr treeGroupDA = make_shared(L"TreeGroupDirtA"); mainTerrain->PopulateTerrain(treeGroupDA, rngDirtSpawnList, 10, 10, 310.0f, 410.0f, 0.9f, 1.0f); treeGroupDA->Initialise(); sceneGraph->Add(treeGroupDA); _initDone = true; } } void Graphics2::UpdateSceneGraph() { SceneGraphPointer sceneGraph = GetSceneGraph(); shared_ptr mainTerrain = dynamic_pointer_cast(sceneGraph->Find(L"MainTerrain")); // Check if the main terrain exists and runs the generate clutter method, we have to run it in the update because // the terrain hasnt actually been generated til now, and we need the heights and normals so we can check if something can fit in a place if (!_initDone && mainTerrain != nullptr && !_noClutter) { GenerateClutter(); } // This block gets the current inputs from either the keyboard of the gamepad, gamepad is a little iffy since the pitch is kind of wanky GetCurrentControlInputs(); XMVECTOR startCameraPos = GetCamera()->GetCameraPosition(); // If the current player object is set, then always move forward if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetForwardBack(_flySpeed * _boostMultiplier); startCameraPos = _currentPlayerObject->GetNodePosition(); } for (ControlInputs currentControl : _currentInputs) { switch (currentControl) { case ControlInputs::Forward: if (_currentPlayerObject == nullptr) { GetCamera()->SetForwardBack(_flySpeed * _boostMultiplier); } break; case ControlInputs::Back: if (_currentPlayerObject == nullptr) { GetCamera()->SetForwardBack(-_flySpeed * _boostMultiplier); } break; case ControlInputs::StrafeLeft: if (_currentPlayerObject != nullptr) { //_currentPlayerObject->SetLeftRight(-_flySpeed * _boostMultiplier); _currentPlayerObject->SetRoll(_turnSpeed * 0.5f); } else { GetCamera()->SetLeftRight(-_flySpeed * _boostMultiplier); } break; case ControlInputs::StrafeRight: if (_currentPlayerObject != nullptr) { //_currentPlayerObject->SetLeftRight(_flySpeed * _boostMultiplier); _currentPlayerObject->SetRoll(-_turnSpeed * 0.5f); } else { GetCamera()->SetLeftRight(_flySpeed * _boostMultiplier); } break; case ControlInputs::TurnLeft: if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetYaw(-_turnSpeed); } else { GetCamera()->SetYaw(-_turnSpeed); } break; case ControlInputs::TurnRight: if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetYaw(_turnSpeed); } else { GetCamera()->SetYaw(_turnSpeed); } break; case ControlInputs::Up: if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetPitch(_turnSpeed * _invertPitch); } else { GetCamera()->SetPitch(_turnSpeed * _invertPitch); } break; case ControlInputs::Down: if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetPitch(-_turnSpeed * _invertPitch); } else { GetCamera()->SetPitch(-_turnSpeed * _invertPitch); } break; } } // Fetch the plane and boat nodes so that we can move them shared_ptr plane1 = dynamic_pointer_cast(sceneGraph->Find(L"Plane1")); shared_ptr boat1 = dynamic_pointer_cast(sceneGraph->Find(L"Boat1")); // Move the plane if (plane1 != nullptr) { //plane1->SetWorldTransform(SharedMethods::RotateFromPoint(-60.0f, 0, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentRotation * XM_PI / 180.0f))); //plane1->AddToWorldTransform(XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), 90.0f * XM_PI / 180.0f)); //sceneGraph->Find(L"Plane1")->GetFirstChild()->GetFirstChild()->SetWorldTransform(XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, -1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f)); //sceneGraph->Find(L"Plane1")->Update((SharedMethods::RotateFromPoint(30.0f, -20.0f, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f))) * XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, 0.0f, 0.0f), _currentRotation * XM_PI / 180.0f)); // Spin the planes propeller, it goes faster if you are boosting plane1->Find(L"airscrew")->SetWorldTransform(SharedMethods::RotateFromPoint(0.0f, 15.471f, 14.5f, XMMatrixRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), _currentPropRotation * XM_PI / 180.0f))); } // Move the boat if (boat1 != nullptr) { boat1->SetForwardBack(-3.0f); boat1->SetYaw(-0.2f); } // Reset the rotation numbers when theyve done a full rotation so they just just increase forever if (_currentRotation == 360) { _currentRotation = 0; _currentSideRotation = 0; _currentPropRotation = 0; } else { _currentRotation += 1; _currentSideRotation += 1; _currentPropRotation += 10 * _boostMultiplier; } // Check the camera and our terrain boundaries XMVECTOR currentCameraPos = GetCamera()->GetCameraPosition(); if (_currentPlayerObject != nullptr) { currentCameraPos = _currentPlayerObject->GetNodePosition(); } GetCamera()->Update(); if (mainTerrain != nullptr) { // If a boundary is hit then move the object back bool boundaryHit = false; XMFLOAT4 cameraOffset = XMFLOAT4(XMVectorGetX(startCameraPos), XMVectorGetY(startCameraPos), XMVectorGetZ(startCameraPos), 0.0f); if (XMVectorGetY(currentCameraPos) < mainTerrain->GetHeightAtPoint(XMVectorGetX(currentCameraPos), XMVectorGetZ(currentCameraPos), true) + 4.0f) { cameraOffset.y = cameraOffset.y + 4.0f; boundaryHit = true; } float currentCameraXPos = XMVectorGetX(currentCameraPos); float xOffset = 150.0f; if (currentCameraXPos > 0) { xOffset = -xOffset; } float currentCameraZPos = XMVectorGetZ(currentCameraPos); float zOffset = 150.0f; if (currentCameraZPos > 0) { zOffset = -zOffset; } if (!mainTerrain->CheckXBoundary(currentCameraXPos + -xOffset)) { cameraOffset.x = cameraOffset.x + xOffset; boundaryHit = true; } if (!mainTerrain->CheckZBoundary(currentCameraZPos + -zOffset)) { cameraOffset.z = cameraOffset.z + zOffset; boundaryHit = true; } if (boundaryHit) { if (_currentPlayerObject != nullptr) { _currentPlayerObject->SetNodePosition(cameraOffset); } else { GetCamera()->SetCameraPosition(cameraOffset); } } } // Reset the control array ready for the next frames input ResetCurrentControlInputs(); } // Method for getting the current frames inputs void Graphics2::GetCurrentControlInputs() { // Check if the window has focus before accepting any keypresses if (GetForegroundWindow() == Framework::GetHWnd()) { // Check if any connected controllers have inputs bool boostHit = false; _currentController.ProcessGameController(_currentInputs, boostHit); if (GetAsyncKeyState(VK_SHIFT) || boostHit) { _currentInputs.insert(ControlInputs::Fire1); _boostMultiplier = SharedMethods::Clamp(_boostMultiplier + _boostStep, 1, _boostMax); } else { _boostMultiplier = SharedMethods::Clamp(_boostMultiplier - _boostStep, 1, _boostMax); } // Forward if (GetAsyncKeyState(0x57) || GetAsyncKeyState(VK_UP)) { _currentInputs.insert(ControlInputs::Forward); } // Back if (GetAsyncKeyState(0x53) || GetAsyncKeyState(VK_DOWN)) { _currentInputs.insert(ControlInputs::Back); } // Turn Left if (GetAsyncKeyState(0x41) || GetAsyncKeyState(VK_LEFT)) { _currentInputs.insert(ControlInputs::TurnLeft); } // Turn Right if (GetAsyncKeyState(0x44) || GetAsyncKeyState(VK_RIGHT)) { _currentInputs.insert(ControlInputs::TurnRight); } // Strafe Left if (GetAsyncKeyState(0x51)) { _currentInputs.insert(ControlInputs::StrafeLeft); } // Strafe Right if (GetAsyncKeyState(0x45)) { _currentInputs.insert(ControlInputs::StrafeRight); } // "Jump" if (GetAsyncKeyState(VK_SPACE)) { _currentInputs.insert(ControlInputs::Up); } // "Crouch" if (GetAsyncKeyState(VK_CONTROL)) { _currentInputs.insert(ControlInputs::Down); } } } // Method for clearing the current inputs ready for the next frame void Graphics2::ResetCurrentControlInputs() { _currentInputs.clear(); }