| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- //========================================================================
- // SceneNodes.cpp - defines the base class for the 3D graphics scene graph, and
- // derived classes like RootNode, Alpha scene nodes, Camera, Grids, etc.
- //
- // Part of the GameCode4 Application
- //
- // GameCode4 is the sample application that encapsulates much of the source code
- // discussed in "Game Coding Complete - 4th Edition" by Mike McShaffry and David
- // "Rez" Graham, published by Charles River Media.
- // ISBN-10: 1133776574 | ISBN-13: 978-1133776574
- //
- // If this source code has found it's way to you, and you think it has helped you
- // in any way, do the authors a favor and buy a new copy of the book - there are
- // detailed explanations in it that compliment this code well. Buy a copy at Amazon.com
- // by clicking here:
- // http://www.amazon.com/gp/product/1133776574/ref=olp_product_details?ie=UTF8&me=&seller=
- //
- // There's a companion web site at http://www.mcshaffry.com/GameCode/
- //
- // The source code is managed and maintained through Google Code:
- // http://code.google.com/p/gamecode4/
- //
- // (c) Copyright 2012 Michael L. McShaffry and David Graham
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Lesser GPL v3
- // as published by the Free Software Foundation.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- // http://www.gnu.org/licenses/lgpl-3.0.txt for more details.
- //
- // You should have received a copy of the GNU Lesser GPL v3
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- //
- //========================================================================
- #include "../Unix/GameCodeStd.h"
- #include "../Actors/RenderComponent.h"
- #include "../Actors/TransformComponent.h"
- #include "SceneNodes.h"
- #include "Scene.h"
- #include <glm/gtx/string_cast.hpp>
- ////////////////////////////////////////////////////
- // SceneNodeProperties Implementation
- ////////////////////////////////////////////////////
- SceneNodeProperties::SceneNodeProperties(void)
- {
- m_ActorId = INVALID_ACTOR_ID;
- m_Radius = 0;
- m_RenderPass = RenderPass_0;
- m_AlphaType = AlphaOpaque;
- }
- //
- // SceneNodeProperties::Transform - Chapter 16, page 528
- //
- void SceneNodeProperties::Transform(glm::mat4 *toWorld, glm::mat4 *fromWorld) const
- {
- if (toWorld)
- *toWorld = m_ToWorld;
-
- if (fromWorld)
- *fromWorld = m_FromWorld;
- }
- ////////////////////////////////////////////////////
- // SceneNode Implementation
- ////////////////////////////////////////////////////
- SceneNode::SceneNode(
- ActorId actorId,
- WeakBaseRenderComponentPtr renderComponent,
- RenderPass renderPass,
- const glm::mat4 to,
- std::optional<const glm::mat4> from
- ) {
- m_pParent= NULL;
- m_Props.m_ActorId = actorId;
- m_Props.m_Name = (renderComponent) ? renderComponent->VGetName() : "SceneNode";
- m_Props.m_RenderPass = renderPass;
- m_Props.m_AlphaType = AlphaOpaque;
- m_RenderComponent = renderComponent;
- VSetTransform(to, from);
- SetRadius(0);
- // [mrmike] - these lines were moved to VOnRestore() post press
- //Color color = (renderComponent) ? renderComponent->GetColor() : g_White;
- //m_Props.m_Material.SetDiffuse(color);
- }
- SceneNode::~SceneNode()
- {
- }
- //
- // SceneNode::VOnRestore - Chapter 16, page 532
- //
- int SceneNode::VOnRestore(Scene *pScene)
- {
- Color color = (m_RenderComponent) ? m_RenderComponent->GetColor() : g_White;
- m_Props.m_Material.SetDiffuse(color);
- // This is meant to be called from any class
- // that inherits from SceneNode and overloads
- // VOnRestore()
- SceneNodeList::iterator i = m_Children.begin();
- SceneNodeList::iterator end = m_Children.end();
- while (i != end)
- {
- (*i)->VOnRestore(pScene);
- ++i;
- }
- return 0;
- }
- //
- // SceneNode::VSetTransform - Chapter 16, page 531
- //
- void SceneNode::VSetTransform(
- const glm::mat4 toWorld,
- std::optional<const glm::mat4> fromWorld
- ) {
- m_Props.m_ToWorld = toWorld;
- if (!fromWorld)
- {
- m_Props.m_FromWorld = glm::inverse(m_Props.m_ToWorld);
- }
- else
- {
- m_Props.m_FromWorld = *fromWorld;
- }
- }
- //
- // SceneNode::VPostRender - Chapter 16, page 532
- //
- int SceneNode::VPreRender(Scene *pScene)
- {
- StrongActorPtr pActor = MakeStrongPtr(g_pApp->GetGameLogic()->VGetActor(m_Props.m_ActorId));
- if (pActor)
- {
- std::shared_ptr<TransformComponent> pTc = MakeStrongPtr(pActor->GetComponent<TransformComponent>(TransformComponent::g_Name));
- if (pTc)
- {
- m_Props.m_ToWorld = pTc->GetTransform();
- }
- }
- pScene->PushAndSetMatrix(m_Props.m_ToWorld);
- return 0;
- }
- //
- // SceneNode::VIsVisible - Chapter 16, page 533
- //
- bool SceneNode::VIsVisible(Scene *pScene) const
- {
- // transform the location of this node into the camera space
- // of the camera attached to the scene
- // glm::mat4 toWorld, fromWorld;
- // pScene->GetCamera()->VGet()->Transform(&toWorld, &fromWorld);
- // glm::vec3 pos = GetWorldPosition();
- // glm::vec3 fromWorldPos = fromWorld.Xform(pos);
- // Frustum const &frustum = pScene->GetCamera()->GetFrustum();
- // bool isVisible = frustum.Inside(fromWorldPos, VGet()->Radius());
- // return isVisible;
- return true;
- }
- //
- // SceneNode::VPostRender - Chapter 16, page 532
- //
- int SceneNode::VPostRender(Scene *pScene)
- {
- pScene->PopMatrix();
- return 0;
- }
- //
- // SceneNode::VOnUpdate - Chapter 16, page 532
- //
- int SceneNode::VOnUpdate(Scene *pScene, uint64_t const elapsedMs)
- {
- // This is meant to be called from any class
- // that inherits from SceneNode and overloads
- // VOnUpdate()
- SceneNodeList::iterator i = m_Children.begin();
- SceneNodeList::iterator end = m_Children.end();
- while (i != end)
- {
- (*i)->VOnUpdate(pScene, elapsedMs);
- ++i;
- }
- return 0;
- }
- //
- // SceneNode::VRenderChildren - Chapter 16, page 533
- //
- int SceneNode::VRenderChildren(Scene *pScene)
- {
- // Iterate through the children
- SceneNodeList::iterator i = m_Children.begin();
- SceneNodeList::iterator end = m_Children.end();
- while (i != end)
- {
- if ((*i)->VPreRender(pScene) == 0)
- {
- // You could short-circuit rendering
- // if an object returns E_FAIL from
- // VPreRender()
- // Don't render this node if you can't see it
- if ((*i)->VIsVisible(pScene))
- {
- float alpha = (*i)->VGet()->m_Material.GetAlpha();
- if (alpha==fOPAQUE)
- {
- (*i)->VRender(pScene);
- }
- // else if (alpha!=fTRANSPARENT)
- // {
- // // The object isn't totally transparent
- // AlphaSceneNode *asn = GCC_NEW AlphaSceneNode;
- // }
- (*i)->VRenderChildren(pScene);
- }
- // [mrmike] post-press fix - if the parent is not visible, the childrend
- // shouldn't be visible either.
- // (*i)->VRenderChildren(pScene);
- }
- (*i)->VPostRender(pScene);
- ++i;
- }
- return 0;
- }
- //
- // SceneNode::VAddChild - Chapter 16, page 535
- //
- bool SceneNode::VAddChild(std::shared_ptr<ISceneNode> ikid)
- {
- m_Children.push_back(ikid);
- std::shared_ptr<SceneNode> kid = static_pointer_cast<SceneNode>(ikid);
- kid->m_pParent = this; // [mrmike] Post-press fix - the parent was never set!
- // The radius of the sphere should be fixed right here
- glm::vec3 kidPos = geometry::GetPosition(kid->VGet()->ToWorld());
-
- // [mrmike] - Post-press fix. This was not correct! subtracting the parents's position from the kidPos
- // created a HUGE radius, depending on the location of the parent, which could be anywhere
- // in the game world.
- //Vec3 dir = kidPos - m_Props.ToWorld().GetPosition();
- //float newRadius = dir.Length() + kid->VGet()->Radius();
-
- float newRadius = glm::length(kidPos) + kid->VGet()->Radius();
- if (newRadius > m_Props.m_Radius)
- m_Props.m_Radius = newRadius;
- return true;
- }
- //
- // SceneNode::VRemoveChild - not in the book
- //
- // If an actor is destroyed it should be removed from the scene graph.
- // Generally the HumanView will recieve a message saying the actor has been
- // destroyed, and it will then call Scene::RemoveChild which will traverse
- // the scene graph to find the child that needs removing.
- //
- bool SceneNode::VRemoveChild(ActorId id)
- {
- for(SceneNodeList::iterator i=m_Children.begin(); i!=m_Children.end(); ++i)
- {
- const SceneNodeProperties* pProps = (*i)->VGet();
- if(pProps->GetActorId() != INVALID_ACTOR_ID && id == pProps->GetActorId())
- {
- i = m_Children.erase(i); //this can be expensive for vectors
- return true;
- }
- }
- return false;
- }
- ////////////////////////////////////////////////////
- // RootNode Implementation
- ////////////////////////////////////////////////////
- //
- // RootNode::RootNode - Chapter 16, page 545
- //
- RootNode::RootNode()
- : SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_0, glm::mat4(1.0f))
- {
- m_Children.reserve(RenderPass_Last);
- std::shared_ptr<SceneNode> staticGroup(GCC_NEW SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_Static, glm::mat4(1.0f)));
- m_Children.push_back(staticGroup); // RenderPass_Static = 0
- std::shared_ptr<SceneNode> actorGroup(GCC_NEW SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_Actor, glm::mat4(1.0f)));
- m_Children.push_back(actorGroup); // RenderPass_Actor = 1
- std::shared_ptr<SceneNode> skyGroup(GCC_NEW SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_Sky, glm::mat4(1.0f)));
- m_Children.push_back(skyGroup); // RenderPass_Sky = 2
- std::shared_ptr<SceneNode> invisibleGroup(GCC_NEW SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_NotRendered, glm::mat4(1.0f)));
- m_Children.push_back(invisibleGroup); // RenderPass_NotRendered = 3
- }
- //
- // RootNode::VAddChild - Chapter 16, page 546
- //
- bool RootNode::VAddChild(std::shared_ptr<ISceneNode> kid)
- {
- // The Root node has children that divide the scene graph into render passes.
- // Scene nodes will get added to these children based on the value of the
- // render pass member variable.
- RenderPass pass = kid->VGet()->GetRenderPass();
- if ((unsigned)pass >= m_Children.size() || !m_Children[pass])
- {
- GCC_ASSERT(0 && "There is no such render pass");
- return false;
- }
- return m_Children[pass]->VAddChild(kid);
- }
- //
- // RootNode::VRemoveChild - not described in the book
- //
- // Returns false if nothing was removed
- //
- bool RootNode::VRemoveChild(ActorId id)
- {
- bool anythingRemoved = false;
- for(int i=RenderPass_0; i<RenderPass_Last; ++i)
- {
- if(m_Children[i]->VRemoveChild(id))
- {
- anythingRemoved = true;
- }
- }
- return anythingRemoved;
- }
- //
- // RootNode::VRenderChildren - Chapter 16, page 547
- //
- int RootNode::VRenderChildren(Scene *pScene)
- {
- // This code creates fine control of the render passes.
- for (int pass = RenderPass_0; pass < RenderPass_Last; ++pass)
- {
- switch(pass)
- {
- case RenderPass_Static:
- case RenderPass_Actor:
- m_Children[pass]->VRenderChildren(pScene);
- break;
- case RenderPass_Sky:
- {
- std::shared_ptr<IRenderState> skyPass = pScene->GetRenderer()->VPrepareSkyBoxPass();
- m_Children[pass]->VRenderChildren(pScene);
- break;
- }
- }
- }
- return 0;
- }
- ////////////////////////////////////////////////////
- // CameraNode Implementation
- ////////////////////////////////////////////////////
- //
- // CameraNode::VRender - Chapter 16, page 550
- //
- int CameraNode::VRender(Scene *pScene)
- {
- if (m_DebugCamera)
- {
- // m_Frustum.Render();
- }
- return 1;
- }
- //
- // CameraNode::VOnRestore - Chapter 16, page 550
- //
- int CameraNode::VOnRestore(Scene *pScene)
- {
- Point p = g_pApp->GetScreenSize();
- m_Frustum.SetAspect((float) p.x / (float) p.y);
- m_Projection = glm::perspective(
- m_Frustum.m_Fov,
- m_Frustum.m_Aspect,
- m_Frustum.m_Near,
- m_Frustum.m_Far
- );
- // [munnellg] this isn't necessary, but we'll do it to
- // preserve book code
- pScene->GetRenderer()->VSetProjectionTransform(m_Projection);
- return 0;
- }
- //
- // CameraNode::SetView - Chapter 16, page 550
- //
- // Note: this is incorrectly called CameraNode::SetView in the book
- //
- int CameraNode::SetViewTransform(Scene *pScene)
- {
- // TODO(munnellg) - implement
- // If there is a target, make sure the camera is
- // rigidly attached right behind the target
- if(m_pTarget)
- {
- glm::mat4 mat = m_pTarget->VGet()->ToWorld();
- glm::vec4 at = m_CamOffsetVector;
- glm::vec4 atWorld = mat * at;
- glm::vec3 pos = geometry::GetPosition(mat) + glm::vec3(atWorld);
- geometry::SetPosition(mat, pos);
- VSetTransform(mat);
- }
- m_View = VGet()->FromWorld();
- // [munnellg] this isn't necessary, but we'll do it to
- // preserve book code
- pScene->GetRenderer()->VSetViewTransform(m_View);
- return 0;
- }
- //
- // CameraNode::GetWorldViewProjection - not described in the book
- //
- // Returns the concatenation of the world and view projection, which is generally sent into vertex shaders
- //
- glm::mat4 CameraNode::GetWorldViewProjection(Scene *pScene)
- {
- glm::mat4 world = pScene->GetTopMatrix();
- glm::mat4 view = VGet()->FromWorld();
- return m_Projection * view * world;
- }
- ////////////////////////////////////////////////////
- // D3DGrid9 Implementation
- //
- // D3D9 classes are not covered in the 4th edition. They are included here for those
- // people that don't have D3D11 compatible video cards.
- //
- // The code is somewhat similar to the D3DGrid11 class, which IS discussed in Chapter 16
- // of the 4th edition.
- //
- ////////////////////////////////////////////////////
- OpenGLGrid::OpenGLGrid(ActorId actorId, WeakBaseRenderComponentPtr renderComponent, const glm::mat4 pMatrix)
- : SceneNode(actorId, renderComponent, RenderPass_0, pMatrix)
- {
- m_bTextureHasAlpha = false;
- m_numIndices = 0;
- m_vbo = 0;
- m_vao = 0;
- m_ebo = 0;
- }
- OpenGLGrid::~OpenGLGrid()
- {
- glDeleteVertexArrays(1, &m_vao);
- glDeleteBuffers(1, &m_vbo);
- glDeleteBuffers(1, &m_ebo);
- }
- int OpenGLGrid::VOnRestore(Scene *pScene)
- {
- // clear out any existing buffers
- glDeleteVertexArrays(1, &m_vao);
- glDeleteBuffers(1, &m_vbo);
- glDeleteBuffers(1, &m_ebo);
- // TODO(munnellg) - these VOnRestore calls need to have their results checked
- SceneNode::VOnRestore(pScene);
- // TODO(munnellg) - release shaders if allocating before creating shader so we don't leak memory
- m_ShaderProgram.OnRestore(pScene);
- GridRenderComponent* grc = static_cast<GridRenderComponent*>(m_RenderComponent);
- int squares = grc->GetDivision();
- SetRadius(sqrt(squares * squares / 2.0f) );
- // Create the vertex buffer - we'll need enough verts
- // to populate the grid. If we want a 2x2 grid, we'll
- // need 3x3 set of verts.
- m_numVerts = (squares+1)*(squares+1); // Create vertex buffer
- // Fill the vertex buffer. We are setting the tu and tv texture
- // coordinates, which range from 0.0 to 1.0
- VertexUnlitTextured *pVerts = GCC_NEW VertexUnlitTextured[m_numVerts];
- GCC_ASSERT(pVerts && "Out of memory in OpenGLGrid::VOnRestore");
- if (!pVerts)
- return 1;
- for( int j=0; j<(squares+1); j++ )
- {
- for (int i=0; i<(squares+1); i++)
- {
- // Which vertex are we setting?
- int index = i + (j * (squares+1) );
- VertexUnlitTextured *vert = &pVerts[index];
- // Default position of the grid is centered on the origin flat on
- // the XZ plane
- float x = (float)i - (squares/2.0f);
- float y = (float)j - (squares/2.0f);
- vert->Pos = glm::vec3(x,0.f,y);
- vert->Normal = glm::vec3(0.0f, 1.0f, 0.0f);
- // The texture coordinates are set to x,y to make the
- // texture tile along with units - 1.0, 2.0, 3.0, etc
- vert->Uv.x = x;
- vert->Uv.y = y;
- }
- }
- // The number of indicies equals the number of polygons times 3
- // since there are 3 indicies per polygon. Each grid square contains
- // two polygons. The indicies are 16 bit, since our grids won't
- // be that big!
- m_numPolys = squares * squares * 2;
- m_numIndices = m_numPolys * 3;
- GLuint *pIndices = GCC_NEW GLuint[m_numIndices];
- GCC_ASSERT(pIndices && "Out of memory in OpenGLGrid::VOnRestore");
- if (!pIndices)
- {
- delete[] pVerts;
- return 1;
- }
- // Loop through the grid squares and calc the values
- // of each index. Each grid square has two triangles:
- //
- // A - B
- // | / |
- // C - D
-
- GLuint *current = pIndices;
- for( int j=0; j<squares; j++ )
- {
- for (int i=0; i<squares; i++)
- {
- // Triangle #1 ACB
- *(current) = GLuint(i + (j*(squares+1)));
- *(current+1) = GLuint(i + ((j+1)*(squares+1)));
- *(current+2) = GLuint((i+1) + (j*(squares+1)));
- *(current+3) = GLuint((i+1) + (j*(squares+1)));
- *(current+4) = GLuint(i + ((j+1)*(squares+1)));
- *(current+5) = GLuint((i+1) + ((j+1)*(squares+1)));
- current += 6;
- }
- }
- glCreateVertexArrays(1, &m_vao);
- glCreateBuffers(1, &m_vbo);
- glNamedBufferStorage(m_vbo, sizeof(VertexUnlitTextured) * m_numVerts, pVerts, 0);
- glVertexArrayVertexBuffer(m_vao, 0, m_vbo, 0, sizeof(VertexUnlitTextured));
- glEnableVertexArrayAttrib(m_vao, 0);
- glVertexArrayAttribFormat(m_vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
- glVertexArrayAttribBinding(m_vao, 0, 0);
- glEnableVertexArrayAttrib(m_vao, 1);
- glVertexArrayAttribFormat(m_vao, 1, 3, GL_FLOAT, GL_FALSE, offsetof(VertexUnlitTextured, Normal));
- glVertexArrayAttribBinding(m_vao, 1, 0);
- glEnableVertexArrayAttrib(m_vao, 2);
- glVertexArrayAttribFormat(m_vao, 2, 2, GL_FLOAT, GL_FALSE, offsetof(VertexUnlitTextured, Uv));
- glVertexArrayAttribBinding(m_vao, 2, 0);
-
- delete[] pVerts;
- glCreateBuffers(1, &m_ebo);
- glNamedBufferStorage(m_ebo, sizeof(GLuint) * m_numIndices, pIndices, 0);
- glVertexArrayElementBuffer(m_vao, m_ebo);
- delete[] pIndices;
- return 0;
- }
- int OpenGLGrid::VRender(Scene *pScene)
- {
- GridRenderComponent* grc = static_cast<GridRenderComponent*>(m_RenderComponent);
- m_ShaderProgram.SetTexture(grc->GetTextureResource());
- m_ShaderProgram.SetupRender(pScene, this);
- glBindVertexArray(m_vao);
- glDrawElements(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0);
- glBindVertexArray(0);
- return 0;
- }
|