Files
directx-plane-game/Graphics2/Graphics2.cpp
iDunnoDev 616f68bf8b Added Comments
Added ability to hold shift and skip the terrain generation when loading
Added ability for the perlin terrain to save a raw image of the terrain to use as a cache
2022-06-13 16:41:25 +01:00

495 lines
16 KiB
C++

#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<TexturedCubeNode> cube = make_shared<TexturedCubeNode>(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<SkyNode> skyDome = make_shared<SkyNode>(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<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(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<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(L"MainTerrain", L"TerrainCache\\cache_LovelyCat_10_000000.raw", L"RandomWords");
shared_ptr<PerlinTerrainNode> terrainNode = make_shared<PerlinTerrainNode>(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<ControlledSplitMeshNode> plane1Node = make_shared<ControlledSplitMeshNode>(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<SceneGraph> boatGraph = make_shared<SceneGraph>(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<ControlledMeshNode> boat1Node = make_shared<ControlledMeshNode>(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<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(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<TerrainPopNode> rngSpawnList;
vector<TerrainPopNode> rngBushSpawnList;
vector<TerrainPopNode> rngSnowSpawnList;
vector<TerrainPopNode> 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<SceneGraph> treeGroupA = make_shared<SceneGraph>(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<SceneGraph> bushGroupA = make_shared<SceneGraph>(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<SceneGraph> treeGroupSA = make_shared<SceneGraph>(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<SceneGraph> treeGroupDA = make_shared<SceneGraph>(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<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(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<ControlledSplitMeshNode> plane1 = dynamic_pointer_cast<ControlledSplitMeshNode>(sceneGraph->Find(L"Plane1"));
shared_ptr<ControlledMeshNode> boat1 = dynamic_pointer_cast<ControlledMeshNode>(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<float>(_boostMultiplier + _boostStep, 1, _boostMax);
}
else
{
_boostMultiplier = SharedMethods::Clamp<float>(_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();
}