diff --git a/KREngine/Kraken.xcodeproj/project.pbxproj b/KREngine/Kraken.xcodeproj/project.pbxproj index c0036f0..cc753f5 100644 --- a/KREngine/Kraken.xcodeproj/project.pbxproj +++ b/KREngine/Kraken.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 104A335E1672D31C001C8BA6 /* KRCollider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 104A335C1672D31B001C8BA6 /* KRCollider.cpp */; }; 104A335F1672D31C001C8BA6 /* KRCollider.h in Headers */ = {isa = PBXBuildFile; fileRef = 104A335D1672D31C001C8BA6 /* KRCollider.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 10CC33A4168530A300BB9846 /* libPVRTexLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 10CC33A3168530A300BB9846 /* libPVRTexLib.a */; }; 10CC33A5168534F000BB9846 /* KRCamera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E48B3CBF14393E2F000C50E2 /* KRCamera.cpp */; }; E4030E4C160A3CF000592648 /* KRStockGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = E4030E4B160A3CF000592648 /* KRStockGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; E4030E4D160A3CF000592648 /* KRStockGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = E4030E4B160A3CF000592648 /* KRStockGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -197,6 +196,10 @@ E499BF2216AE760F007FCDBE /* krengine_osx.h in Headers */ = {isa = PBXBuildFile; fileRef = E4BBBB8C1512A40300F43B5B /* krengine_osx.h */; settings = {ATTRIBUTES = (Public, ); }; }; E499BF2316AE7636007FCDBE /* kraken-prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = E4BBBB8B1512A40300F43B5B /* kraken-prefix.pch */; }; E499BF2516AE8C20007FCDBE /* KREngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = E491016F13C99BDC0098455B /* KREngine.mm */; }; + E4AE635D1704FB0A00B460CD /* KRLODGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */; }; + E4AE635E1704FB0A00B460CD /* KRLODGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */; }; + E4AE635F1704FB0A00B460CD /* KRLODGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE635C1704FB0A00B460CD /* KRLODGroup.h */; }; + E4AE63601704FB0A00B460CD /* KRLODGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE635C1704FB0A00B460CD /* KRLODGroup.h */; }; E4AFC6B615F7C46800DDB4C8 /* KRAABB.cpp in Headers */ = {isa = PBXBuildFile; fileRef = E40BA45215EFF79500D7C3DD /* KRAABB.cpp */; settings = {ATTRIBUTES = (Public, ); }; }; E4AFC6B915F7C7B200DDB4C8 /* KROctree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4924C2415EE95E700B965C6 /* KROctree.cpp */; settings = {ATTRIBUTES = (Public, ); }; }; E4AFC6BB15F7C7D600DDB4C8 /* KROctreeNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4924C2915EE96AA00B965C6 /* KROctreeNode.cpp */; }; @@ -483,6 +486,8 @@ E497B952151BEDA600D3DC67 /* KRResource+fbx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "KRResource+fbx.cpp"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; E497B95C151BF05F00D3DC67 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = ../../../../MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; E497B95E151BF09600D3DC67 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = ../../../../MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRLODGroup.cpp; sourceTree = ""; }; + E4AE635C1704FB0A00B460CD /* KRLODGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRLODGroup.h; sourceTree = ""; }; E4B175AA161F5A1000B8FB80 /* KRTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRTexture.cpp; sourceTree = ""; }; E4B175AB161F5A1000B8FB80 /* KRTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRTexture.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E4B175B0161F5FAE00B8FB80 /* KRTextureCube.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRTextureCube.cpp; sourceTree = ""; }; @@ -624,7 +629,6 @@ E497B95D151BF05F00D3DC67 /* CoreServices.framework in Frameworks */, E497B95F151BF09600D3DC67 /* SystemConfiguration.framework in Frameworks */, E460292B16682BF700261BB9 /* libfbxsdk-2013.3-static.a in Frameworks */, - 10CC33A4168530A300BB9846 /* libPVRTexLib.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -802,7 +806,7 @@ E428C2EF166960ED00A16EDF /* Animation */, E48839AB15F930E200BD66D5 /* Bundle */, E48839AA15F9309E00BD66D5 /* Material */, - E48839A915F9307E00BD66D5 /* Model */, + E48839A915F9307E00BD66D5 /* Mesh */, E48839A815F9304C00BD66D5 /* Texture */, E48839A715F9302E00BD66D5 /* Shader */, E48839A615F92FC300BD66D5 /* Scene */, @@ -855,7 +859,7 @@ name = Texture; sourceTree = ""; }; - E48839A915F9307E00BD66D5 /* Model */ = { + E48839A915F9307E00BD66D5 /* Mesh */ = { isa = PBXGroup; children = ( E491018313C99BDC0098455B /* KRMeshManager.h */, @@ -867,7 +871,7 @@ E4C454B1167BC04B003586CD /* KRMeshSphere.h */, E4C454B4167BC05C003586CD /* KRMeshSphere.cpp */, ); - name = Model; + name = Mesh; sourceTree = ""; }; E48839AA15F9309E00BD66D5 /* Material */ = { @@ -942,6 +946,8 @@ E4F975351536221C00FD60B2 /* KRNode.cpp */, E480BE671671C641004EC8AD /* KRBone.h */, E480BE6B1671C653004EC8AD /* KRBone.cpp */, + E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */, + E4AE635C1704FB0A00B460CD /* KRLODGroup.h */, ); name = "Scene Graph Nodes"; sourceTree = ""; @@ -1212,6 +1218,7 @@ E499BF2116AE75A7007FCDBE /* KREngine-common.h in Headers */, E450273B16E0491D00FDEC5C /* KRReverbZone.h in Headers */, E4FE6AA816B21D660058B8CE /* forsyth.h in Headers */, + E4AE635F1704FB0A00B460CD /* KRLODGroup.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1287,6 +1294,7 @@ E499BF1D16AE74FF007FCDBE /* KRTextureAnimated.h in Headers */, E499BF1F16AE753E007FCDBE /* KRCollider.h in Headers */, E499BF2316AE7636007FCDBE /* kraken-prefix.pch in Headers */, + E4AE63601704FB0A00B460CD /* KRLODGroup.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1548,6 +1556,7 @@ E4943231169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, E4FE6AAB16B21D7E0058B8CE /* forsyth.cpp in Sources */, E450273916E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, + E4AE635D1704FB0A00B460CD /* KRLODGroup.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1619,6 +1628,7 @@ E4F027DF1697BFFF00D4427D /* KRAudioBuffer.cpp in Sources */, E4943232169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, E450273A16E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, + E4AE635E1704FB0A00B460CD /* KRLODGroup.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1748,6 +1758,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LIBRARY = "libstdc++"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1780,8 +1791,9 @@ "\"$(SYSTEM_APPS_DIR)/Autodesk/FBX SDK/2013.3/lib/gcc4/ub\"", "\"$(SYSTEM_APPS_DIR)/Imagination/PowerVR/GraphicsSDK/PVRTexTool/Library/OSX_x86/Static\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = kraken; SDKROOT = macosx; SHARED_PRECOMPS_DIR = "$(CACHE_ROOT)/SharedPrecompiledHeaders_osx"; @@ -1794,6 +1806,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LIBRARY = "libstdc++"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1822,7 +1835,8 @@ "\"$(SYSTEM_APPS_DIR)/Autodesk/FBX SDK/2013.3/lib/gcc4/ub\"", "\"$(SYSTEM_APPS_DIR)/Imagination/PowerVR/GraphicsSDK/PVRTexTool/Library/OSX_x86/Static\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = kraken; SDKROOT = macosx; SHARED_PRECOMPS_DIR = "$(CACHE_ROOT)/SharedPrecompiledHeaders_osx"; diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index fbbafdd..015e796 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -83,6 +83,7 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) m_reverb_impulse_responses[i] = NULL; m_reverb_impulse_responses_weight[i] = 0.0f; } + m_output_accumulation = NULL; } void KRAudioManager::initAudio() diff --git a/KREngine/kraken/KRCamera.cpp b/KREngine/kraken/KRCamera.cpp index d9ed5a1..c5a95cd 100644 --- a/KREngine/kraken/KRCamera.cpp +++ b/KREngine/kraken/KRCamera.cpp @@ -95,6 +95,9 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende KRVector3 vecCameraDirection = m_viewport.getCameraDirection(); + + scene.updateOctree(m_viewport); + if(settings.bEnableDeferredLighting) { // ----====---- Opaque Geometry, Deferred rendering Pass 1 ----====---- diff --git a/KREngine/kraken/KRLODGroup.cpp b/KREngine/kraken/KRLODGroup.cpp new file mode 100644 index 0000000..a892aa7 --- /dev/null +++ b/KREngine/kraken/KRLODGroup.cpp @@ -0,0 +1,91 @@ +// +// KRLODGroup.cpp +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#include "KRLODGroup.h" +#include "KRContext.h" + +KRLODGroup::KRLODGroup(KRScene &scene, std::string name) : KRNode(scene, name) +{ + m_min_distance = 0.0f; + m_max_distance = 0.0f; +} + +KRLODGroup::~KRLODGroup() +{ +} + +std::string KRLODGroup::getElementName() { + return "lod_group"; +} + +tinyxml2::XMLElement *KRLODGroup::saveXML( tinyxml2::XMLNode *parent) +{ + tinyxml2::XMLElement *e = KRNode::saveXML(parent); + e->SetAttribute("min_distance", m_min_distance); + e->SetAttribute("max_distance", m_max_distance); + return e; +} + +void KRLODGroup::loadXML(tinyxml2::XMLElement *e) +{ + KRNode::loadXML(e); + + m_min_distance = 0.0f; + if(e->QueryFloatAttribute("min_distance", &m_min_distance) != tinyxml2::XML_SUCCESS) { + m_min_distance = 0.0f; + } + + m_max_distance = 0.0f; + if(e->QueryFloatAttribute("max_distance", &m_max_distance) != tinyxml2::XML_SUCCESS) { + m_max_distance = 0.0f; + } +} + +bool KRLODGroup::getLODVisibility(const KRViewport &viewport) +{ + // Compare square distances as sqrt is expensive + float sqr_distance = (viewport.getCameraPosition() - getWorldTranslation()).sqrMagnitude(); + return ((sqr_distance >= m_min_distance * m_min_distance || m_min_distance == 0) && (sqr_distance < m_max_distance * m_max_distance || m_max_distance == 0)); +} + +void KRLODGroup::updateLODVisibility(const KRViewport &viewport) +{ + bool new_visibility = getLODVisibility(viewport); + if(!new_visibility) { + hideLOD(); + } else { + if(!m_lod_visible) { + getScene().notify_sceneGraphCreate(this); + m_lod_visible = true; + } + for(std::vector::iterator itr=m_childNodes.begin(); itr < m_childNodes.end(); ++itr) { + (*itr)->updateLODVisibility(viewport); + } + } +} + +float KRLODGroup::getMinDistance() +{ + return m_min_distance; +} + +float KRLODGroup::getMaxDistance() +{ + return m_max_distance; +} + +void KRLODGroup::setMinDistance(float min_distance) +{ + m_min_distance = min_distance; +} + +void KRLODGroup::setMaxDistance(float max_distance) +{ + m_max_distance = max_distance; +} + diff --git a/KREngine/kraken/KRLODGroup.h b/KREngine/kraken/KRLODGroup.h new file mode 100644 index 0000000..f27395b --- /dev/null +++ b/KREngine/kraken/KRLODGroup.h @@ -0,0 +1,38 @@ +// +// KRLODGroup.h +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#ifndef KRLODGROUP_H +#define KRLODGROUP_H + +#include "KRResource.h" +#include "KRNode.h" +#include "KRTexture.h" + +class KRLODGroup : public KRNode { +public: + KRLODGroup(KRScene &scene, std::string name); + virtual ~KRLODGroup(); + virtual std::string getElementName(); + virtual tinyxml2::XMLElement *saveXML( tinyxml2::XMLNode *parent); + virtual void loadXML(tinyxml2::XMLElement *e); + + virtual void updateLODVisibility(const KRViewport &viewport); + + float getMinDistance(); + float getMaxDistance(); + void setMinDistance(float min_distance); + void setMaxDistance(float max_distance); + +private: + bool getLODVisibility(const KRViewport &viewport); + float m_min_distance; + float m_max_distance; +}; + + +#endif diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 9d90351..f7d51f3 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -9,6 +9,7 @@ #include "KREngine-common.h" #include "KRNode.h" +#include "KRLODGroup.h" #include "KRPointLight.h" #include "KRSpotLight.h" #include "KRDirectionalLight.h" @@ -37,6 +38,7 @@ KRNode::KRNode(KRScene &scene, std::string name) : KRContextObject(scene.getCont m_inverseBindPoseMatrixValid = false; m_modelMatrix = KRMat4(); m_bindPoseMatrix = KRMat4(); + m_lod_visible = false; } KRNode::~KRNode() { @@ -51,7 +53,10 @@ void KRNode::addChild(KRNode *child) { assert(child->m_parentNode == NULL); child->m_parentNode = this; m_childNodes.push_back(child); - getScene().notify_sceneGraphCreate(child); + if(m_lod_visible) { + // Child node inherits LOD visibility status from parent + child->showLOD(); + } } tinyxml2::XMLElement *KRNode::saveXML(tinyxml2::XMLNode *parent) { @@ -213,6 +218,8 @@ KRNode *KRNode::LoadXML(KRScene &scene, tinyxml2::XMLElement *e) { const char *szName = e->Attribute("name"); if(strcmp(szElementName, "node") == 0) { new_node = new KRNode(scene, szName); + } if(strcmp(szElementName, "lod_group") == 0) { + new_node = new KRLODGroup(scene, szName); } else if(strcmp(szElementName, "point_light") == 0) { new_node = new KRPointLight(scene, szName); } else if(strcmp(szElementName, "directional_light") == 0) { @@ -434,3 +441,37 @@ void KRNode::addToOctreeNode(KROctreeNode *octree_node) { m_octree_nodes.insert(octree_node); } + +void KRNode::updateLODVisibility(const KRViewport &viewport) +{ + // If we aren't an LOD group node, then we just add ourselves and all our children to the octree + showLOD(); +} + +void KRNode::hideLOD() +{ + if(m_lod_visible) { + m_lod_visible = false; + getScene().notify_sceneGraphDelete(this); + for(std::vector::iterator itr=m_childNodes.begin(); itr < m_childNodes.end(); ++itr) { + (*itr)->hideLOD(); + } + } +} + +void KRNode::showLOD() +{ + if(!m_lod_visible) { + getScene().notify_sceneGraphCreate(this); + m_lod_visible = true; + for(std::vector::iterator itr=m_childNodes.begin(); itr < m_childNodes.end(); ++itr) { + (*itr)->showLOD(); + } + } +} + + +bool KRNode::lodIsVisible() +{ + return m_lod_visible; +} diff --git a/KREngine/kraken/KRNode.h b/KREngine/kraken/KRNode.h index 2c7546d..de40593 100644 --- a/KREngine/kraken/KRNode.h +++ b/KREngine/kraken/KRNode.h @@ -103,6 +103,9 @@ public: virtual void physicsUpdate(float deltaTime); virtual bool hasPhysics(); + virtual void updateLODVisibility(const KRViewport &viewport); + bool lodIsVisible(); + protected: KRVector3 m_localTranslation; KRVector3 m_localScale; @@ -112,7 +115,16 @@ protected: KRVector3 m_initialLocalScale; KRVector3 m_initialLocalRotation; + + + bool m_lod_visible; + void hideLOD(); + void showLOD(); + float m_lod_min_coverage; + float m_lod_max_coverage; + KRNode *m_parentNode; + std::vector m_childNodes; private: void invalidateModelMatrix(); @@ -128,7 +140,7 @@ private: std::string m_name; - std::vector m_childNodes; + KRScene *m_pScene; diff --git a/KREngine/kraken/KROctree.cpp b/KREngine/kraken/KROctree.cpp index ffc22f4..00e0849 100644 --- a/KREngine/kraken/KROctree.cpp +++ b/KREngine/kraken/KROctree.cpp @@ -79,6 +79,7 @@ void KROctree::shrink() KROctreeNode *newRoot = m_pRootNode->stripChild(); delete m_pRootNode; m_pRootNode = newRoot; + if(m_pRootNode == NULL) return; } } } diff --git a/KREngine/kraken/KRResource+fbx.cpp b/KREngine/kraken/KRResource+fbx.cpp index b19a96b..94fcbbd 100644 --- a/KREngine/kraken/KRResource+fbx.cpp +++ b/KREngine/kraken/KRResource+fbx.cpp @@ -7,7 +7,8 @@ // #include "KREngine-common.h" - +#include +#include #include @@ -24,6 +25,7 @@ #include "KRBone.h" #include "KRBundle.h" #include "KRModel.h" +#include "KRLODGroup.h" #include "KRCollider.h" #ifdef IOS_REF @@ -45,6 +47,7 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector &resources, FbxG KRNode *LoadLight(KRNode *parent_node, std::vector &resources, KFbxNode* pNode); KRNode *LoadSkeleton(KRNode *parent_node, std::vector &resources, KFbxNode* pNode); KRNode *LoadCamera(KRNode *parent_node, std::vector &resources, KFbxNode* pNode); +void LoadLOD(KRContext &context, std::vector &resources, FbxGeometryConverter *pGeometryConverter, FbxLODGroup* pSourceLodGroup); std::string GetFbxObjectName(FbxObject *obj); const float KRAKEN_FBX_ANIMATION_FRAMERATE = 30.0f; // FINDME - This should be configurable @@ -724,46 +727,157 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorGetNodeAttribute()->GetAttributeType()); - switch(attribute_type) { - case KFbxNodeAttribute::eMesh: - new_node = LoadMesh(parent_node, resources, pGeometryConverter, pNode); - break; - case KFbxNodeAttribute::eLight: - new_node = LoadLight(parent_node, resources, pNode); - break; - case KFbxNodeAttribute::eSkeleton: - new_node = LoadSkeleton(parent_node, resources, pNode); - break; - case KFbxNodeAttribute::eCamera: - new_node = LoadCamera(parent_node, resources, pNode); - break; - default: - { - if(pNode->GetChildCount() > 0) { - // Create an empty node, for inheritence of transforms - new_node = new KRNode(parent_node->getScene(), GetFbxObjectName(pNode)); + if(attribute_type == KFbxNodeAttribute::eLODGroup) { + std::string name = GetFbxObjectName(pNode); + FbxLODGroup *fbx_lod_group = (FbxLODGroup*) pNode->GetNodeAttribute(); // FbxCast(pNode); + if(!fbx_lod_group->WorldSpace.Get()) { + printf("WARNING - LOD Groups only supported with world space distance thresholds.\n"); + } + float group_min_distance = 0.0f; + float group_max_distance = 0.0f; + if(fbx_lod_group->MinMaxDistance.Get()) { + group_min_distance = fbx_lod_group->MinDistance.Get(); + group_max_distance = fbx_lod_group->MinDistance.Get(); + } + // Create a lod_group node for each fbx child node + int child_count = pNode->GetChildCount(); + for(int i = 0; i < child_count; i++) + { + float min_distance = 0; + float max_distance = 0; // 0 for max_distance means infinity + FbxLODGroup::EDisplayLevel display_level; + fbx_lod_group->GetDisplayLevel(i, display_level); + switch(display_level) { + case FbxLODGroup::eUseLOD: + if(i > 0 ) { + FbxDistance d; + fbx_lod_group->GetThreshold(i - 1, d); + min_distance = d.value(); + } + if(i < child_count - 1) { + FbxDistance d; + fbx_lod_group->GetThreshold(i, d); + max_distance = d.value(); + } + break; + case FbxLODGroup::eShow: + // We leave min_distance and max_distance as 0's, which effectively makes the LOD group always visible + break; + case FbxLODGroup::eHide: + min_distance = -1; + max_distance = -1; + // LOD Groups with -1 for both min_distance and max_distance will never be displayed; import in case that the distance values are to be modified by scripting at runtime + break; + } + + if(group_min_distance != 0.0f && min_distance != -1) { + if(min_distance < group_min_distance) min_distance = group_min_distance; + } + if(group_max_distance != 0.0f && max_distance != -1) { + if(max_distance == 0.0f) { + max_distance = group_max_distance; + } else if(max_distance > group_max_distance) { + max_distance = group_max_distance; } } - break; - } - - - if(new_node != NULL) { - new_node->setLocalRotation(node_rotation); - new_node->setLocalTranslation(node_translation); - new_node->setLocalScale(node_scale); - parent_node->addChild(new_node); - - // Load child nodes - for(int i = 0; i < pNode->GetChildCount(); i++) - { + + KRLODGroup *new_node = new KRLODGroup(parent_node->getScene(), name + "_lodlevel" + boost::lexical_cast(i + 1)); + new_node->setMinDistance(min_distance); + new_node->setMaxDistance(max_distance); + new_node->setLocalRotation(node_rotation); + new_node->setLocalTranslation(node_translation); + new_node->setLocalScale(node_scale); + parent_node->addChild(new_node); + LoadNode(pFbxScene, new_node, resources, pGeometryConverter, pNode->GetChild(i)); } + } else { + KRNode *new_node = NULL; + switch(attribute_type) { + case KFbxNodeAttribute::eMesh: + new_node = LoadMesh(parent_node, resources, pGeometryConverter, pNode); + break; + case KFbxNodeAttribute::eLight: + new_node = LoadLight(parent_node, resources, pNode); + break; + case KFbxNodeAttribute::eSkeleton: + new_node = LoadSkeleton(parent_node, resources, pNode); + break; + case KFbxNodeAttribute::eCamera: + new_node = LoadCamera(parent_node, resources, pNode); + break; + default: + { + if(pNode->GetChildCount() > 0) { + // Create an empty node, for inheritence of transforms + std::string name = GetFbxObjectName(pNode); + + float min_distance = 0.0f; + float max_distance = 0.0f; + + typedef boost::tokenizer > char_tokenizer; + + int step = 0; + + char_tokenizer name_components(name, boost::char_separator("_")); + for(char_tokenizer::iterator itr=name_components.begin(); itr != name_components.end(); itr++) { + std::string component = *itr; + std::transform(component.begin(), component.end(), + component.begin(), ::tolower); + if(component.compare("lod") == 0) { + step = 1; + } else if(step == 1) { + min_distance = boost::lexical_cast(component); + step++; + } else if(step == 2) { + max_distance = boost::lexical_cast(component); + step++; + } + } + + /* + if(min_distance == 0.0f && max_distance == 0.0f) { + // Regular node for grouping children together under one transform + new_node = new KRNode(parent_node->getScene(), name); + } else { + */ + // LOD Enabled group node + KRLODGroup *lod_group = new KRLODGroup(parent_node->getScene(), name); + lod_group->setMinDistance(min_distance); + lod_group->setMaxDistance(max_distance); + new_node = lod_group; + /* + } + */ + + + } + } + break; + } + + + if(new_node != NULL) { + new_node->setLocalRotation(node_rotation); + new_node->setLocalTranslation(node_translation); + new_node->setLocalScale(node_scale); + parent_node->addChild(new_node); + + // Load child nodes + for(int i = 0; i < pNode->GetChildCount(); i++) + { + LoadNode(pFbxScene, new_node, resources, pGeometryConverter, pNode->GetChild(i)); + } + } } } +void LoadLOD(KRContext &context, std::vector &resources, FbxLODGroup* pSourceLodGroup) { + +} + void LoadMaterial(KRContext &context, std::vector &resources, FbxSurfaceMaterial *pMaterial) { //printf(" %s: %i - %i\n", pMaterial->GetName(), mat_vertex_start, mat_vertex_count + mat_vertex_start - 1); diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index ed91a2a..87aec87 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -38,6 +38,7 @@ #include "KRScene.h" #include "KRNode.h" +#include "KRLODGroup.h" #include "KRStockGeometry.h" #include "KRDirectionalLight.h" #include "KRSpotLight.h" @@ -48,7 +49,7 @@ const long KRENGINE_OCCLUSION_TEST_EXPIRY = 60; KRScene::KRScene(KRContext &context, std::string name) : KRResource(context, name) { m_pFirstLight = NULL; - m_pRootNode = new KRNode(*this, "scene_root"); + m_pRootNode = new KRLODGroup(*this, "scene_root"); notify_sceneGraphCreate(m_pRootNode); m_skyBoxName = name + "_skybox"; @@ -85,9 +86,6 @@ std::set &KRScene::getReverbZones() } void KRScene::render(KRCamera *pCamera, std::map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame) { - updateOctree(); - - if(new_frame) { // Expire cached occlusion test results. // Cached "failed" results are expired on the next frame (marked with .second of -1) @@ -425,8 +423,10 @@ void KRScene::notify_sceneGraphDelete(KRNode *pNode) } } -void KRScene::updateOctree() +void KRScene::updateOctree(const KRViewport &viewport) { + m_pRootNode->updateLODVisibility(viewport); + std::set newNodes = m_newNodes; std::set modifiedNodes = m_modifiedNodes; m_newNodes.clear(); @@ -449,7 +449,9 @@ void KRScene::updateOctree() } for(std::set::iterator itr=modifiedNodes.begin(); itr != modifiedNodes.end(); itr++) { KRNode *node = *itr; - m_nodeTree.update(node); + if(node->lodIsVisible()) { + m_nodeTree.update(node); + } } } diff --git a/KREngine/kraken/KRScene.h b/KREngine/kraken/KRScene.h index 6684ff4..dbc80ff 100644 --- a/KREngine/kraken/KRScene.h +++ b/KREngine/kraken/KRScene.h @@ -71,6 +71,7 @@ public: void render(KROctreeNode *pOctreeNode, std::map &visibleBounds, KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly); + void updateOctree(const KRViewport &viewport); void notify_sceneGraphCreate(KRNode *pNode); void notify_sceneGraphDelete(KRNode *pNode); @@ -99,7 +100,6 @@ private: std::set m_reverbZoneNodes; KROctree m_nodeTree; - void updateOctree(); std::string m_skyBoxName;