From 4dddec7f8509c850a1bcd5df4ddc2137ffd558ee Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Sun, 6 Oct 2013 18:56:23 -0700 Subject: [PATCH] Asynchronous streaming and memory management improvements in progress. Note: This branch is unstable --HG-- branch : async_streaming --- KREngine/Kraken.xcodeproj/project.pbxproj | 12 ++ KREngine/kraken/KRAnimation.cpp | 5 +- KREngine/kraken/KRAnimationCurve.cpp | 54 +++++-- KREngine/kraken/KRAudioManager.cpp | 8 +- KREngine/kraken/KRAudioSample.cpp | 7 +- KREngine/kraken/KRBundle.cpp | 45 +++--- KREngine/kraken/KRDataBlock.cpp | 149 ++++++++++++++--- KREngine/kraken/KRDataBlock.h | 30 +++- KREngine/kraken/KREngine-common.h | 2 + KREngine/kraken/KRLocator.cpp | 35 ++++ KREngine/kraken/KRLocator.h | 27 ++++ KREngine/kraken/KRMaterialManager.cpp | 4 +- KREngine/kraken/KRMesh.cpp | 186 ++++++++++++---------- KREngine/kraken/KRNode.cpp | 3 + KREngine/kraken/KRResource+fbx.cpp | 103 +++++++----- KREngine/kraken/KRScene.cpp | 2 + KREngine/kraken/KRShaderManager.cpp | 4 +- KREngine/kraken/KRTexture2D.cpp | 2 + KREngine/kraken/KRTexturePVR.cpp | 5 +- KREngine/kraken/KRTextureTGA.cpp | 4 +- 20 files changed, 488 insertions(+), 199 deletions(-) create mode 100644 KREngine/kraken/KRLocator.cpp create mode 100644 KREngine/kraken/KRLocator.h diff --git a/KREngine/Kraken.xcodeproj/project.pbxproj b/KREngine/Kraken.xcodeproj/project.pbxproj index d44fbbe..a306cac 100644 --- a/KREngine/Kraken.xcodeproj/project.pbxproj +++ b/KREngine/Kraken.xcodeproj/project.pbxproj @@ -109,6 +109,10 @@ E461A176152E5C5600F2044A /* KRPointLight.h in Headers */ = {isa = PBXBuildFile; fileRef = E461A157152E555400F2044A /* KRPointLight.h */; settings = {ATTRIBUTES = (Public, ); }; }; E461A177152E5C6600F2044A /* KRMat4.h in Headers */ = {isa = PBXBuildFile; fileRef = E491017613C99BDC0098455B /* KRMat4.h */; settings = {ATTRIBUTES = (Public, ); }; }; E461A17A152E5C9100F2044A /* KRMat4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E491017713C99BDC0098455B /* KRMat4.cpp */; }; + E468447F17FFDF51001F1FA1 /* KRLocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E468447D17FFDF51001F1FA1 /* KRLocator.cpp */; }; + E468448017FFDF51001F1FA1 /* KRLocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E468447D17FFDF51001F1FA1 /* KRLocator.cpp */; }; + E468448117FFDF51001F1FA1 /* KRLocator.h in Headers */ = {isa = PBXBuildFile; fileRef = E468447E17FFDF51001F1FA1 /* KRLocator.h */; }; + E468448217FFDF51001F1FA1 /* KRLocator.h in Headers */ = {isa = PBXBuildFile; fileRef = E468447E17FFDF51001F1FA1 /* KRLocator.h */; }; E46A6B6D1559E97D000DBD37 /* KRResource+blend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46A6B6C1559E97D000DBD37 /* KRResource+blend.cpp */; }; E46A6B701559EF0A000DBD37 /* KRResource+blend.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A6B6F1559EF0A000DBD37 /* KRResource+blend.h */; settings = {ATTRIBUTES = (Public, ); }; }; E46C214515364BC8009CABF3 /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46C214215364BC8009CABF3 /* tinyxml2.cpp */; }; @@ -438,6 +442,8 @@ E461A15E152E565700F2044A /* KRDirectionalLight.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRDirectionalLight.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; E461A164152E56C000F2044A /* KRSpotLight.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRSpotLight.cpp; sourceTree = ""; }; E461A167152E570500F2044A /* KRSpotLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRSpotLight.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + E468447D17FFDF51001F1FA1 /* KRLocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRLocator.cpp; sourceTree = ""; }; + E468447E17FFDF51001F1FA1 /* KRLocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRLocator.h; sourceTree = ""; }; E46A6B6C1559E97D000DBD37 /* KRResource+blend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "KRResource+blend.cpp"; sourceTree = ""; }; E46A6B6F1559EF0A000DBD37 /* KRResource+blend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KRResource+blend.h"; sourceTree = ""; }; E46C214115364BC8009CABF3 /* tinyxml2_readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tinyxml2_readme.txt; sourceTree = ""; }; @@ -971,6 +977,8 @@ E480BE6B1671C653004EC8AD /* KRBone.cpp */, E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */, E4AE635C1704FB0A00B460CD /* KRLODGroup.h */, + E468447D17FFDF51001F1FA1 /* KRLocator.cpp */, + E468447E17FFDF51001F1FA1 /* KRLocator.h */, ); name = "Scene Graph Nodes"; sourceTree = ""; @@ -1198,6 +1206,7 @@ E461A152152E54B500F2044A /* KRLight.h in Headers */, E461A15C152E563100F2044A /* KRDirectionalLight.h in Headers */, E461A168152E570700F2044A /* KRSpotLight.h in Headers */, + E468448117FFDF51001F1FA1 /* KRLocator.h in Headers */, E4F975321536220900FD60B2 /* KRNode.h in Headers */, E46C214715364BC8009CABF3 /* tinyxml2.h in Headers */, E48C696F15374F5B00232E28 /* KRContext.h in Headers */, @@ -1257,6 +1266,7 @@ E497B948151BB89D00D3DC67 /* KRVector2.h in Headers */, E4D0683F1512A790005FFBEB /* KRVector3.h in Headers */, E461A177152E5C6600F2044A /* KRMat4.h in Headers */, + E468448217FFDF51001F1FA1 /* KRLocator.h in Headers */, E4F975461536327C00FD60B2 /* KRMeshManager.h in Headers */, E497B94B151BCEE900D3DC67 /* KRResource.h in Headers */, E43B0AD915DDCA0F00A5CB9F /* KRContextObject.h in Headers */, @@ -1544,6 +1554,7 @@ E497B950151BD2CE00D3DC67 /* KRResource+obj.cpp in Sources */, E461A156152E54F800F2044A /* KRLight.cpp in Sources */, E461A159152E557E00F2044A /* KRPointLight.cpp in Sources */, + E468447F17FFDF51001F1FA1 /* KRLocator.cpp in Sources */, E461A15F152E565700F2044A /* KRDirectionalLight.cpp in Sources */, E461A165152E56C000F2044A /* KRSpotLight.cpp in Sources */, E4F975361536221C00FD60B2 /* KRNode.cpp in Sources */, @@ -1607,6 +1618,7 @@ E4BBBBA71512A6DC00F43B5B /* KRVector3.cpp in Sources */, E4B2A43B1523B02E004CB0EC /* KRMaterial.cpp in Sources */, E4BBBB8E1512A40300F43B5B /* krengine_osx.mm in Sources */, + E468448017FFDF51001F1FA1 /* KRLocator.cpp in Sources */, E497B947151BA99500D3DC67 /* KRVector2.cpp in Sources */, E497B94E151BCF2500D3DC67 /* KRResource.cpp in Sources */, E497B951151BD2CE00D3DC67 /* KRResource+obj.cpp in Sources */, diff --git a/KREngine/kraken/KRAnimation.cpp b/KREngine/kraken/KRAnimation.cpp index 02b99a8..f5db97b 100644 --- a/KREngine/kraken/KRAnimation.cpp +++ b/KREngine/kraken/KRAnimation.cpp @@ -85,9 +85,10 @@ bool KRAnimation::save(KRDataBlock &data) { KRAnimation *KRAnimation::Load(KRContext &context, const std::string &name, KRDataBlock *data) { - data->append((void *)"\0", 1); // Ensure data is null terminated, to read as a string safely + std::string xml_string = data->getString(); + tinyxml2::XMLDocument doc; - doc.Parse((char *)data->getStart()); + doc.Parse(xml_string.c_str()); KRAnimation *new_animation = new KRAnimation(context, name); tinyxml2::XMLElement *animation_node = doc.RootElement(); diff --git a/KREngine/kraken/KRAnimationCurve.cpp b/KREngine/kraken/KRAnimationCurve.cpp index 48077e9..a99138e 100644 --- a/KREngine/kraken/KRAnimationCurve.cpp +++ b/KREngine/kraken/KRAnimationCurve.cpp @@ -37,11 +37,13 @@ KRAnimationCurve::KRAnimationCurve(KRContext &context, const std::string &name) { m_pData = new KRDataBlock(); m_pData->expand(sizeof(animation_curve_header)); + m_pData->lock(); animation_curve_header *header = (animation_curve_header *)m_pData->getStart(); strcpy(header->szTag, "KRCURVE1.0 "); header->frame_rate = 30.0f; header->frame_start = 0; header->frame_count = 0; + m_pData->unlock(); } KRAnimationCurve::~KRAnimationCurve() @@ -84,11 +86,16 @@ KRAnimationCurve *KRAnimationCurve::Load(KRContext &context, const std::string & int KRAnimationCurve::getFrameCount() { - return ((animation_curve_header *)m_pData->getStart())->frame_count; + m_pData->lock(); + int frame_count = ((animation_curve_header *)m_pData->getStart())->frame_count; + m_pData->unlock(); + + return frame_count; } void KRAnimationCurve::setFrameCount(int frame_count) { + m_pData->lock(); int prev_frame_count = getFrameCount(); if(frame_count != prev_frame_count) { float fill_value = 0.0f; @@ -102,30 +109,42 @@ void KRAnimationCurve::setFrameCount(int frame_count) } ((animation_curve_header *)m_pData->getStart())->frame_count = frame_count; } + m_pData->unlock(); } float KRAnimationCurve::getFrameRate() { - return ((animation_curve_header *)m_pData->getStart())->frame_rate; + m_pData->lock(); + float frame_rate =((animation_curve_header *)m_pData->getStart())->frame_rate; + m_pData->unlock(); + return frame_rate; } void KRAnimationCurve::setFrameRate(float frame_rate) { + m_pData->lock(); ((animation_curve_header *)m_pData->getStart())->frame_rate = frame_rate; + m_pData->unlock(); } int KRAnimationCurve::getFrameStart() { - return ((animation_curve_header *)m_pData->getStart())->frame_start; + m_pData->lock(); + int frame_start = ((animation_curve_header *)m_pData->getStart())->frame_start; + m_pData->unlock(); + return frame_start; } void KRAnimationCurve::setFrameStart(int frame_number) { + m_pData->lock(); ((animation_curve_header *)m_pData->getStart())->frame_start = frame_number; + m_pData->unlock(); } float KRAnimationCurve::getValue(int frame_number) { + m_pData->lock(); //printf("frame_number: %i\n", frame_number); int clamped_frame = frame_number - getFrameStart(); if(clamped_frame < 0) { @@ -134,43 +153,56 @@ float KRAnimationCurve::getValue(int frame_number) clamped_frame = getFrameCount()-1; } float *frame_data = (float *)((char *)m_pData->getStart() + sizeof(animation_curve_header)); - return frame_data[clamped_frame]; + float v = frame_data[clamped_frame]; + m_pData->unlock(); + return v; } void KRAnimationCurve::setValue(int frame_number, float value) { + m_pData->lock(); int clamped_frame = frame_number - getFrameStart(); if(clamped_frame >= 0 && clamped_frame < getFrameCount()) { float *frame_data = (float *)((char *)m_pData->getStart() + sizeof(animation_curve_header)); frame_data[clamped_frame] = value; } + m_pData->unlock(); } float KRAnimationCurve::getValue(float local_time) { // TODO - Need to add interpolation for time values between frames. // Must consider looping animations when determining which two frames to interpolate between. - return getValue((int)(local_time * getFrameRate())); + m_pData->lock(); + float v = getValue((int)(local_time * getFrameRate())); + m_pData->unlock(); + return v; } bool KRAnimationCurve::valueChanges(float start_time, float duration) { - return valueChanges((int)(start_time * getFrameRate()), (int)(duration * getFrameRate())); + m_pData->lock(); + bool c = valueChanges((int)(start_time * getFrameRate()), (int)(duration * getFrameRate())); + m_pData->unlock(); + return c; } bool KRAnimationCurve::valueChanges(int start_frame, int frame_count) { - + m_pData->lock(); float first_value = getValue(start_frame); + bool change_found = false; + // Range of frames is not inclusive of last frame - for(int frame_number = start_frame + 1; frame_number < start_frame + frame_count; frame_number++) { + for(int frame_number = start_frame + 1; frame_number < start_frame + frame_count && !change_found; frame_number++) { if(getValue(frame_number) != first_value) { - return true; + change_found = true; } } - return false; + m_pData->unlock(); + return change_found; } KRAnimationCurve *KRAnimationCurve::split(const std::string &name, float start_time, float duration) @@ -185,11 +217,13 @@ KRAnimationCurve *KRAnimationCurve::split(const std::string &name, int start_fra new_curve->setFrameRate(getFrameRate()); new_curve->setFrameStart(start_frame); new_curve->setFrameCount(frame_count); + new_curve->m_pData->lock(); // Range of frames is not inclusive of last frame for(int frame_number = start_frame; frame_number < start_frame + frame_count; frame_number++) { new_curve->setValue(frame_number, getValue(frame_number)); // TODO - MEMCPY here? } + new_curve->m_pData->unlock(); getContext().getAnimationCurveManager()->addAnimationCurve(new_curve); return new_curve; diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index 428cb2b..4d8158f 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -214,8 +214,8 @@ void KRAudioManager::renderAudio(UInt32 inNumberFrames, AudioBufferList *ioData) uint64_t end_time = mach_absolute_time(); - uint64_t duration = (end_time - start_time) * m_timebase_info.numer / m_timebase_info.denom; // Nanoseconds - uint64_t max_duration = (uint64_t)inNumberFrames * 1000000000 / 44100; +// uint64_t duration = (end_time - start_time) * m_timebase_info.numer / m_timebase_info.denom; // Nanoseconds +// uint64_t max_duration = (uint64_t)inNumberFrames * 1000000000 / 44100; // fprintf(stderr, "audio load: %5.1f%% hrtf channels: %li\n", (float)(duration * 1000 / max_duration) / 10.0f, m_mapped_sources.size()); } @@ -1364,14 +1364,14 @@ KRDataBlock *KRAudioManager::getBufferData(int size) data = new KRDataBlock(); data->expand(size); } - + data->lock(); return data; - } void KRAudioManager::recycleBufferData(KRDataBlock *data) { if(data != NULL) { + data->unlock(); if(data->getSize() == KRENGINE_AUDIO_MAX_BUFFER_SIZE && m_bufferPoolIdle.size() < KRENGINE_AUDIO_MAX_POOL_SIZE) { m_bufferPoolIdle.push_back(data); } else { diff --git a/KREngine/kraken/KRAudioSample.cpp b/KREngine/kraken/KRAudioSample.cpp index 793729f..b9bd250 100644 --- a/KREngine/kraken/KRAudioSample.cpp +++ b/KREngine/kraken/KRAudioSample.cpp @@ -40,6 +40,7 @@ KRAudioSample::KRAudioSample(KRContext &context, std::string name, std::string extension) : KRResource(context, name) { m_pData = new KRDataBlock(); + m_pData->lock(); m_extension = extension; m_audio_file_id = 0; @@ -55,6 +56,7 @@ KRAudioSample::KRAudioSample(KRContext &context, std::string name, std::string e KRAudioSample::KRAudioSample(KRContext &context, std::string name, std::string extension, KRDataBlock *data) : KRResource(context, name) { m_pData = data; + m_pData->lock(); m_extension = extension; m_audio_file_id = 0; @@ -71,6 +73,7 @@ KRAudioSample::KRAudioSample(KRContext &context, std::string name, std::string e KRAudioSample::~KRAudioSample() { closeFile(); + m_pData->unlock(); delete m_pData; } @@ -198,7 +201,8 @@ OSStatus KRAudioSample::ReadProc( // AudioFile_ReadProc KRAudioSample *sound = (KRAudioSample *)inClientData; UInt32 max_count = sound->m_pData->getSize() - inPosition; *actualCount = requestCount < max_count ? requestCount : max_count; - memcpy(buffer, (unsigned char *)sound->m_pData->getStart() + inPosition, *actualCount); + sound->m_pData->copy(buffer, inPosition, *actualCount); + //memcpy(buffer, (unsigned char *)sound->m_pData->getStart() + inPosition, *actualCount); return noErr; } @@ -231,6 +235,7 @@ void KRAudioSample::openFile() { // AudioFileInitializeWithCallbacks if(m_fileRef == NULL) { + // Temp variables UInt32 propertySize; diff --git a/KREngine/kraken/KRBundle.cpp b/KREngine/kraken/KRBundle.cpp index 5173695..d152d77 100644 --- a/KREngine/kraken/KRBundle.cpp +++ b/KREngine/kraken/KRBundle.cpp @@ -53,35 +53,18 @@ KRBundle::KRBundle(KRContext &context, std::string name, KRDataBlock *pData) : K { m_pData = pData; - unsigned char *pFile = (unsigned char *)m_pData->getStart(); - while(pFile < m_pData->getEnd() ) { - tar_header_type *file_header = (tar_header_type *)pFile; - size_t file_size = strtol(file_header->file_size, NULL, 8); - pFile += 512; // Skip past the header to the file contents - - if(file_header->file_name[0] != '\0' && file_header->file_name[0] != '.') { + __int64_t file_pos = 0; + while(file_pos < m_pData->getSize()) { + tar_header_type file_header; + m_pData->copy(&file_header, file_pos, sizeof(file_header)); + size_t file_size = strtol(file_header.file_size, NULL, 8); + file_pos += 512; // Skip past the header to the file contents + if(file_header.file_name[0] != '\0' && file_header.file_name[0] != '.') { // We ignore the last two records in the tar file, which are zero'ed out tar_header structures - KRDataBlock *pFileData = new KRDataBlock(); - if(pFileData->load(pFile, file_size)) { - context.loadResource(file_header->file_name, pFileData); - } else { - delete pFileData; - assert(false); - } + KRDataBlock *pFileData = pData->getSubBlock(file_pos, file_size); + context.loadResource(file_header.file_name, pFileData); } - - // Advance past the end of the file - /* - if((file_size & 0x01ff) == 0) { - // file size is a multiple of 512 bytes, we can just add it - pFile += file_size; - } else { - // We would not be on a 512 byte boundary, round up to the next one - pFile += (file_size + 0x0200) - (file_size & 0x1ff); - } - */ - pFile += RoundUpSize(file_size); - + file_pos += RoundUpSize(file_size); } } @@ -90,7 +73,9 @@ KRBundle::KRBundle(KRContext &context, std::string name) : KRResource(context, n // Create an empty krbundle (tar) file, initialized with two zero-ed out file headers, which terminate it. m_pData = new KRDataBlock(); m_pData->expand(KRENGINE_KRBUNDLE_HEADER_SIZE * 2); + m_pData->lock(); memset(m_pData->getStart(), 0, m_pData->getSize()); + m_pData->unlock(); } size_t KRBundle::RoundUpSize(size_t s) @@ -142,6 +127,8 @@ void KRBundle::append(KRResource &resource) m_pData->expand(KRENGINE_KRBUNDLE_HEADER_SIZE + resource_data.getSize() + padding_size - KRENGINE_KRBUNDLE_HEADER_SIZE * 2); // We will overwrite the existing zero-ed out file headers that marked the end of the archive, so we don't have to include their size here + m_pData->lock(); + // Get location of file header tar_header_type *file_header = (tar_header_type *)((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize() - KRENGINE_KRBUNDLE_HEADER_SIZE); @@ -149,7 +136,9 @@ void KRBundle::append(KRResource &resource) memset(file_header, 0, KRENGINE_KRBUNDLE_HEADER_SIZE); // Copy resource data + resource_data.lock(); memcpy((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize(), resource_data.getStart(), resource_data.getSize()); + resource_data.unlock(); // Zero out alignment padding and terminating set of file header blocks memset((unsigned char *)m_pData->getEnd() - padding_size, 0, padding_size); @@ -172,4 +161,6 @@ void KRBundle::append(KRResource &resource) check_sum += byte_ptr[i]; } sprintf(file_header->checksum, "%07o", check_sum); + + m_pData->unlock(); } diff --git a/KREngine/kraken/KRDataBlock.cpp b/KREngine/kraken/KRDataBlock.cpp index b60ad37..05a9e94 100644 --- a/KREngine/kraken/KRDataBlock.cpp +++ b/KREngine/kraken/KRDataBlock.cpp @@ -30,12 +30,18 @@ // #include "KRDataBlock.h" +#include "KREngine-common.h" KRDataBlock::KRDataBlock() { m_data = NULL; m_data_size = 0; + m_data_offset = 0; m_fdPackFile = 0; + m_mmapData = NULL; + m_fileOwnerDataBlock = NULL; m_bMalloced = false; + m_lockCount = 0; + m_bReadOnly = false; } KRDataBlock::~KRDataBlock() { @@ -45,10 +51,13 @@ KRDataBlock::~KRDataBlock() { // Unload a file, releasing any mmap'ed file handles or malloc'ed ram that was in use void KRDataBlock::unload() { + assert(m_lockCount == 0); + if(m_fdPackFile) { // Memory mapped file - munmap(m_data, m_data_size); - close(m_fdPackFile); + if(m_fileOwnerDataBlock == this) { + close(m_fdPackFile); + } } else if(m_data != NULL && m_bMalloced) { // Malloc'ed data free(m_data); @@ -57,7 +66,11 @@ void KRDataBlock::unload() m_bMalloced = false; m_data = NULL; m_data_size = 0; + m_data_offset = 0; m_fdPackFile = 0; + m_mmapData = NULL; + m_fileOwnerDataBlock = NULL; + m_bReadOnly = false; } // Encapsulate a pointer. Note - The pointer will not be free'ed @@ -66,6 +79,8 @@ bool KRDataBlock::load(void *data, size_t size) unload(); m_data = data; m_data_size = size; + m_data_offset = 0; + m_bReadOnly = false; return true; } @@ -76,14 +91,14 @@ bool KRDataBlock::load(const std::string &path) unload(); struct stat statbuf; + m_bReadOnly = true; m_fdPackFile = open(path.c_str(), O_RDONLY); if(m_fdPackFile >= 0) { + m_fileOwnerDataBlock = this; if(fstat(m_fdPackFile, &statbuf) >= 0) { - if ((m_data = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, m_fdPackFile, 0)) == (caddr_t) -1) { - } else { - m_data_size = statbuf.st_size; - success = true; - } + m_data_size = statbuf.st_size; + m_data_offset = 0; + success = true; } } if(!success) { @@ -93,13 +108,32 @@ bool KRDataBlock::load(const std::string &path) return success; } +// Create a KRDataBlock encapsulating a sub-region of this block. The caller is responsible to free the object. +KRDataBlock *KRDataBlock::getSubBlock(int start, int length) +{ + KRDataBlock *new_block = new KRDataBlock(); + + new_block->m_data_size = length; + if(m_fdPackFile) { + new_block->m_fdPackFile = m_fdPackFile; + new_block->m_fileOwnerDataBlock = m_fileOwnerDataBlock; + new_block->m_data_offset = start; + } else if(m_bMalloced) { + new_block->m_data = (unsigned char *)m_data + start; + } + new_block->m_bReadOnly = true; + return new_block; +} + // Return a pointer to the start of the data block void *KRDataBlock::getStart() { + assertLocked(); return m_data; } // Return a pointer to the byte after the end of the data block void *KRDataBlock::getEnd() { + assertLocked(); return (unsigned char *)m_data + m_data_size; } @@ -111,28 +145,33 @@ size_t KRDataBlock::getSize() const { // Expand the data block, and switch it to read-write mode. Note - this may result in a mmap'ed file being copied to malloc'ed ram and then closed void KRDataBlock::expand(size_t size) { - if(m_data == NULL) { + if(m_data == NULL && m_fdPackFile == 0) { // Starting with an empty data block; allocate memory on the heap m_data = malloc(size); assert(m_data != NULL); m_data_size = size; + m_data_offset = 0; m_bMalloced = true; } else if(m_bMalloced) { // Starting with a malloc'ed data block; realloc it expand m_data = realloc(m_data, m_data_size + size); m_data_size += size; } else { - // Starting with a mmap'ed data block; copy it to ram before expanding to avoid updating the original file until save() is called + // Starting with a mmap'ed data block, an encapsulated pointer, or a sub-block; copy it to ram before expanding to avoid updating the original file until save() is called // ... Or starting with a pointer reference, we must make our own copy and must not free the pointer void *pNewData = malloc(m_data_size + size); assert(pNewData != NULL); - memcpy((unsigned char *)pNewData, m_data, m_data_size); // Copy exising data + + // Copy exising data + copy(pNewData); + // Unload existing data allocation, which is now redundant size_t new_size = m_data_size + size; // We need to store this before unload() as unload() will reset it unload(); m_bMalloced = true; m_data = pNewData; m_data_size = new_size; + m_data_offset = 0; } } @@ -142,12 +181,31 @@ void KRDataBlock::append(void *data, size_t size) { expand(size); // Fill the new space with the data to append + lock(); memcpy((unsigned char *)m_data + m_data_size - size, data, size); + unlock(); +} + + +// Copy the entire data block to the destination pointer +void KRDataBlock::copy(void *dest) { + lock(); + memcpy((unsigned char *)dest, m_data, m_data_size); + unlock(); +} + +// Copy a range of data to the destination pointer +void KRDataBlock::copy(void *dest, int start, int count) { + lock(); + memcpy((unsigned char *)dest, (unsigned char *)m_data + start, count); + unlock(); } // Append data to the end of the block, increasing the size of the block and making it read-write. void KRDataBlock::append(KRDataBlock &data) { + data.lock(); append(data.getStart(), data.getSize()); + data.unlock(); } // Append string to the end of the block, increasing the size of the block and making it read-write. The null terminating character is included @@ -157,7 +215,7 @@ void KRDataBlock::append(const std::string &s) append((void *)szText, strlen(szText)+1); } -// Save the data to a file, and switch to read-only mode. The data pointer will be replaced with a mmap'ed address of the file; the malloc'ed data will be freed +// Save the data to a file. bool KRDataBlock::save(const std::string& path) { int fdNewFile = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); if(fdNewFile == -1) { @@ -173,20 +231,16 @@ bool KRDataBlock::save(const std::string& path) { close(fdNewFile); return false; } else if(m_data != NULL) { + + // Copy data to new file - memcpy(pNewData, m_data, m_data_size); + copy(pNewData); - // Unload existing data allocation, which is now redundant - size_t new_size = m_data_size; // We need to store this, as unload() will reset it - unload(); - - // Protect new mmap'ed memory - mprotect(pNewData, m_data_size, PROT_READ); + // Unmap the new file + munmap(pNewData, m_data_size); - // Switch pointer to use new mmap'ed memory - m_data_size = new_size; - m_fdPackFile = fdNewFile; - m_data = pNewData; + // Close the new file + close(fdNewFile); } return true; } @@ -195,8 +249,57 @@ bool KRDataBlock::save(const std::string& path) { // Get contents as a string std::string KRDataBlock::getString() { + lock(); KRDataBlock b; b.append(*this); b.append((void *)"\0", 1); // Ensure data is null terminated, to read as a string safely - return std::string((char *)b.getStart()); + b.lock(); + std::string ret = std::string((char *)b.getStart()); + b.unlock(); + unlock(); + return ret; +} + +// Lock the memory, forcing it to be loaded into a contiguous block of address space +void KRDataBlock::lock() +{ + m_lockCount++; + if(m_lockCount == 1) { + + // Memory mapped file; ensure data is mapped to ram + if(m_fdPackFile) { + // Round m_data_offset down to the next memory page, as required by mmap + size_t alignment_offset = m_data_offset & (KRAKEN_MEM_PAGE_SIZE - 1); + if ((m_mmapData = mmap(0, m_data_size + alignment_offset, m_bReadOnly ? PROT_READ : PROT_WRITE, MAP_SHARED, m_fdPackFile, m_data_offset - alignment_offset)) == (caddr_t) -1) { + assert(false); // mmap() failed. + } + m_data = (unsigned char *)m_mmapData + alignment_offset; + } + + } +} + +// Unlock the memory, releasing the address space for use by other allocations +void KRDataBlock::unlock() +{ + // We expect that the data block was previously locked + assertLocked(); + + m_lockCount--; + if(m_lockCount == 0) { + + // Memory mapped file; ensure data is unmapped from ram + if(m_fdPackFile) { + munmap(m_mmapData, m_data_size); + m_data = NULL; + m_mmapData = NULL; + } + + } +} + +// Assert if not locked +void KRDataBlock::assertLocked() +{ + assert(m_lockCount > 0); } diff --git a/KREngine/kraken/KRDataBlock.h b/KREngine/kraken/KRDataBlock.h index b67dba8..13caed0 100644 --- a/KREngine/kraken/KRDataBlock.h +++ b/KREngine/kraken/KRDataBlock.h @@ -45,9 +45,12 @@ public: // Load a file into memory using mmap. The data pointer will be protected as read-only until append() or expand() is called bool load(const std::string &path); - // Save the data to a file, and switch to read-only mode. The data pointer will be replaced with a mmap'ed address of the file; the malloc'ed data will be freed + // Save the data to a file. bool save(const std::string& path); + // Create a KRDataBlock encapsulating a sub-region of this block. The caller is responsible to free the object. + KRDataBlock *getSubBlock(int start, int length); + // Append data to the end of the block, increasing the size of the block and making it read-write. void append(void *data, size_t size); @@ -74,15 +77,40 @@ public: // Get the contents as a string std::string getString(); + + // Copy the entire data block to the destination pointer + void copy(void *dest); + + // Copy a range of data to the destination pointer + void copy(void *dest, int start, int count); + + // Lock the memory, forcing it to be loaded into a contiguous block of address space + void lock(); + + // Unlock the memory, releasing the address space for use by other allocations + void unlock(); + private: void *m_data; size_t m_data_size; + size_t m_data_offset; // For memory mapped objects: int m_fdPackFile; + KRDataBlock *m_fileOwnerDataBlock; + void *m_mmapData; // For malloc'ed objects: bool m_bMalloced; + + // Lock refcount + int m_lockCount; + + // Read-only allocation + bool m_bReadOnly; + + // Assert if not locked + void assertLocked(); }; #endif diff --git a/KREngine/kraken/KREngine-common.h b/KREngine/kraken/KREngine-common.h index d80a414..700adba 100644 --- a/KREngine/kraken/KREngine-common.h +++ b/KREngine/kraken/KREngine-common.h @@ -11,6 +11,8 @@ #ifndef KRENGINE_COMMON_H #define KRENGINE_COMMON_H +#define KRAKEN_MEM_PAGE_SIZE 4096 +#define KRAKEN_MEM_ROUND_DOWN_PAGE(x) (x & ~(KRAKEN_MEM_PAGE_SIZE - 1)) #define KRENGINE_MAX_TEXTURE_UNITS 8 float const PI = 3.141592653589793f; diff --git a/KREngine/kraken/KRLocator.cpp b/KREngine/kraken/KRLocator.cpp new file mode 100644 index 0000000..13d8878 --- /dev/null +++ b/KREngine/kraken/KRLocator.cpp @@ -0,0 +1,35 @@ +// +// KRLocator.cpp +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#include "KRLocator.h" +#include "KRContext.h" + +KRLocator::KRLocator(KRScene &scene, std::string name) : KRNode(scene, name) +{ + setScaleCompensation(true); +} + +KRLocator::~KRLocator() +{ +} + +std::string KRLocator::getElementName() { + return "locator"; +} + +tinyxml2::XMLElement *KRLocator::saveXML( tinyxml2::XMLNode *parent) +{ + tinyxml2::XMLElement *e = KRNode::saveXML(parent); + + return e; +} + +void KRLocator::loadXML(tinyxml2::XMLElement *e) +{ + KRNode::loadXML(e); +} diff --git a/KREngine/kraken/KRLocator.h b/KREngine/kraken/KRLocator.h new file mode 100644 index 0000000..19e6f22 --- /dev/null +++ b/KREngine/kraken/KRLocator.h @@ -0,0 +1,27 @@ +// +// KRLocator +// KREngine +// +// Created by Kearwood Gilbert on 2012-12-06. +// Copyright (c) 2012 Kearwood Software. All rights reserved. +// + +#ifndef KRLOCATOR_H +#define KRLOCATOR_H + +#include "KRResource.h" +#include "KRNode.h" +#include "KRTexture.h" + +class KRLocator : public KRNode { +public: + KRLocator(KRScene &scene, std::string name); + virtual ~KRLocator(); + virtual std::string getElementName(); + virtual tinyxml2::XMLElement *saveXML( tinyxml2::XMLNode *parent); + virtual void loadXML(tinyxml2::XMLElement *e); + +}; + + +#endif diff --git a/KREngine/kraken/KRMaterialManager.cpp b/KREngine/kraken/KRMaterialManager.cpp index 5f9d568..8b7deaa 100644 --- a/KREngine/kraken/KRMaterialManager.cpp +++ b/KREngine/kraken/KRMaterialManager.cpp @@ -100,7 +100,7 @@ void KRMaterialManager::add(KRMaterial *new_material) { bool KRMaterialManager::load(const char *szName, KRDataBlock *data) { KRMaterial *pMaterial = NULL; char szSymbol[16][256]; - + data->lock(); char *pScan = (char *)data->getStart(); char *pEnd = (char *)data->getEnd(); @@ -282,7 +282,7 @@ bool KRMaterialManager::load(const char *szName, KRDataBlock *data) { } } - + data->unlock(); delete data; return true; } diff --git a/KREngine/kraken/KRMesh.cpp b/KREngine/kraken/KRMesh.cpp index 1afe334..a044244 100644 --- a/KREngine/kraken/KRMesh.cpp +++ b/KREngine/kraken/KRMesh.cpp @@ -46,6 +46,7 @@ KRMesh::KRMesh(KRContext &context, std::string name) : KRResource(context, name) m_materials.clear(); m_uniqueMaterials.clear(); m_pData = new KRDataBlock(); + m_pData->lock(); setName(name); } @@ -54,6 +55,7 @@ KRMesh::KRMesh(KRContext &context, std::string name, KRDataBlock *data) : KRReso m_materials.clear(); m_uniqueMaterials.clear(); m_pData = new KRDataBlock(); + m_pData->lock(); setName(name); loadPack(data); @@ -104,6 +106,7 @@ int KRMesh::GetLODCoverage(const std::string &name) KRMesh::~KRMesh() { clearData(); + m_pData->unlock(); if(m_pData) delete m_pData; } @@ -124,8 +127,10 @@ bool KRMesh::save(KRDataBlock &data) { void KRMesh::loadPack(KRDataBlock *data) { clearData(); + m_pData->unlock(); delete m_pData; m_pData = data; + m_pData->lock(); updateAttributeOffsets(); pack_header *pHeader = getHeader(); m_minPoint = KRVector3(pHeader->minx, pHeader->miny, pHeader->minz); @@ -134,6 +139,8 @@ void KRMesh::loadPack(KRDataBlock *data) { void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector &bones) { + m_pData->lock(); + //fprintf(stderr, "Rendering model: %s\n", m_name.c_str()); if(renderPass != KRNode::RENDER_PASS_ADDITIVE_PARTICLES && renderPass != KRNode::RENDER_PASS_PARTICLE_OCCLUSION && renderPass != KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE) { getSubmeshes(); @@ -214,6 +221,8 @@ void KRMesh::render(const std::string &object_name, KRCamera *pCamera, std::vect } } } + + m_pData->unlock(); } GLfloat KRMesh::getMaxDimension() { @@ -429,8 +438,9 @@ void KRMesh::LoadData(/*std::vector<__uint16_t> vertex_indexes, std::vectorunlock(); m_pData->expand(new_file_size); + m_pData->lock(); pack_header *pHeader = getHeader(); memset(pHeader, 0, sizeof(pack_header)); @@ -586,7 +596,9 @@ KRVector3 KRMesh::getMaxPoint() const { } void KRMesh::clearData() { + m_pData->unlock(); m_pData->unload(); + m_pData->lock(); } void KRMesh::clearBuffers() { @@ -892,8 +904,11 @@ size_t KRMesh::AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_ int KRMesh::getBoneCount() { + m_pData->lock(); pack_header *header = getHeader(); - return header->bone_count; + int bone_count = header->bone_count; + m_pData->unlock(); + return bone_count; } char *KRMesh::getBoneName(int bone_index) @@ -908,7 +923,10 @@ KRMat4 KRMesh::getBoneBindPose(int bone_index) KRMesh::model_format_t KRMesh::getModelFormat() const { - return (model_format_t)getHeader()->model_format; + m_pData->lock(); + model_format_t f = (model_format_t)getHeader()->model_format; + m_pData->unlock(); + return f; } bool KRMesh::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo) @@ -1055,7 +1073,7 @@ bool KRMesh::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitin void KRMesh::convertToIndexed() { - + m_pData->lock(); char *szKey = new char[m_vertex_size * 2 + 1]; // Convert model to indexed vertices, identying vertexes with identical attributes and optimizing order of trianges for best usage post-vertex-transform cache on GPU @@ -1230,6 +1248,8 @@ void KRMesh::convertToIndexed() mi.format = KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES; + + m_pData->unlock(); LoadData(mi, false, false); } @@ -1284,85 +1304,89 @@ int KRMesh::getTriangleVertexIndex(int submesh, int index) const void KRMesh::optimizeIndexes() { - if(getModelFormat() != KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES) return; - - __uint16_t *new_indices = (__uint16_t *)malloc(0x10000 * sizeof(__uint16_t)); - __uint16_t *vertex_mapping = (__uint16_t *)malloc(0x10000 * sizeof(__uint16_t)); - unsigned char *new_vertex_data = (unsigned char *)malloc(m_vertex_size * 0x10000); - - // FINDME, TODO, HACK - This will segfault if the KRData object is still mmap'ed to a read-only file. Need to detach from the file before calling this function. Currently, this function is only being used during the import process, so it isn't going to cause any problems for now. - - pack_header *header = getHeader(); - - __uint16_t *index_data = getIndexData(); - unsigned char *vertex_data = getVertexData(); - - for(int submesh_index=0; submesh_index < header->submesh_count; submesh_index++) { - pack_material *submesh = getSubmesh(submesh_index); - int vertexes_remaining = submesh->vertex_count; - int index_group = getSubmesh(submesh_index)->index_group; - int index_group_offset = getSubmesh(submesh_index)->index_group_offset; - while(vertexes_remaining > 0) { - int start_index_offset, start_vertex_offset, index_count, vertex_count; - getIndexedRange(index_group++, start_index_offset, start_vertex_offset, index_count, vertex_count); - - int vertexes_to_process = vertexes_remaining; - if(vertexes_to_process + index_group_offset > 0xffff) { - vertexes_to_process = 0xffff - index_group_offset; - } - - __uint16_t *index_data_start = index_data + start_index_offset + index_group_offset; - - - // ----====---- Step 1: Optimize triangle drawing order to maximize use of the GPU's post-transform vertex cache ----====---- - Forsyth::OptimizeFaces(index_data_start, vertexes_to_process, vertex_count, new_indices, 16); // FINDME, TODO - GPU post-transform vertex cache size of 16 should be configureable - memcpy(index_data_start, new_indices, vertexes_to_process * sizeof(__uint16_t)); - vertexes_remaining -= vertexes_to_process; - - /* - - unsigned char * vertex_data_start = vertex_data + start_vertex_offset; - - // ----====---- Step 2: Re-order the vertex data to maintain cache coherency ----====---- - for(int i=0; i < vertex_count; i++) { - vertex_mapping[i] = i; - } - int new_vertex_index=0; - for(int index_number=0; index_number new_vertex_index) { - // Swap prev_vertex_index and new_vertex_index - - for(int i=0; i < index_count; i++) { - if(index_data_start[i] == prev_vertex_index) { - index_data_start[i] = new_vertex_index; - } else if(index_data_start[i] == new_vertex_index) { - index_data_start[i] = prev_vertex_index; - } - } - - int tmp = vertex_mapping[prev_vertex_index]; - vertex_mapping[prev_vertex_index] = vertex_mapping[new_vertex_index]; - vertex_mapping[new_vertex_index] = tmp; - - - new_vertex_index++; + m_pData->lock(); + if(getModelFormat() == KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES) { + + __uint16_t *new_indices = (__uint16_t *)malloc(0x10000 * sizeof(__uint16_t)); + __uint16_t *vertex_mapping = (__uint16_t *)malloc(0x10000 * sizeof(__uint16_t)); + unsigned char *new_vertex_data = (unsigned char *)malloc(m_vertex_size * 0x10000); + + // FINDME, TODO, HACK - This will segfault if the KRData object is still mmap'ed to a read-only file. Need to detach from the file before calling this function. Currently, this function is only being used during the import process, so it isn't going to cause any problems for now. + + pack_header *header = getHeader(); + + __uint16_t *index_data = getIndexData(); + unsigned char *vertex_data = getVertexData(); + + for(int submesh_index=0; submesh_index < header->submesh_count; submesh_index++) { + pack_material *submesh = getSubmesh(submesh_index); + int vertexes_remaining = submesh->vertex_count; + int index_group = getSubmesh(submesh_index)->index_group; + int index_group_offset = getSubmesh(submesh_index)->index_group_offset; + while(vertexes_remaining > 0) { + int start_index_offset, start_vertex_offset, index_count, vertex_count; + getIndexedRange(index_group++, start_index_offset, start_vertex_offset, index_count, vertex_count); + + int vertexes_to_process = vertexes_remaining; + if(vertexes_to_process + index_group_offset > 0xffff) { + vertexes_to_process = 0xffff - index_group_offset; } + + __uint16_t *index_data_start = index_data + start_index_offset + index_group_offset; + + + // ----====---- Step 1: Optimize triangle drawing order to maximize use of the GPU's post-transform vertex cache ----====---- + Forsyth::OptimizeFaces(index_data_start, vertexes_to_process, vertex_count, new_indices, 16); // FINDME, TODO - GPU post-transform vertex cache size of 16 should be configureable + memcpy(index_data_start, new_indices, vertexes_to_process * sizeof(__uint16_t)); + vertexes_remaining -= vertexes_to_process; + + /* + + unsigned char * vertex_data_start = vertex_data + start_vertex_offset; + + // ----====---- Step 2: Re-order the vertex data to maintain cache coherency ----====---- + for(int i=0; i < vertex_count; i++) { + vertex_mapping[i] = i; + } + int new_vertex_index=0; + for(int index_number=0; index_number new_vertex_index) { + // Swap prev_vertex_index and new_vertex_index + + for(int i=0; i < index_count; i++) { + if(index_data_start[i] == prev_vertex_index) { + index_data_start[i] = new_vertex_index; + } else if(index_data_start[i] == new_vertex_index) { + index_data_start[i] = prev_vertex_index; + } + } + + int tmp = vertex_mapping[prev_vertex_index]; + vertex_mapping[prev_vertex_index] = vertex_mapping[new_vertex_index]; + vertex_mapping[new_vertex_index] = tmp; + + + new_vertex_index++; + } + } + + for(int i=0; i < vertex_count; i++) { + memcpy(new_vertex_data + vertex_mapping[i] * m_vertex_size, vertex_data_start + i * m_vertex_size, m_vertex_size); + } + memcpy(vertex_data_start, new_vertex_data, vertex_count * m_vertex_size); + */ + + + + index_group_offset = 0; } - - for(int i=0; i < vertex_count; i++) { - memcpy(new_vertex_data + vertex_mapping[i] * m_vertex_size, vertex_data_start + i * m_vertex_size, m_vertex_size); - } - memcpy(vertex_data_start, new_vertex_data, vertex_count * m_vertex_size); - */ - - - - index_group_offset = 0; } - } + + free(new_indices); + free(vertex_mapping); + free(new_vertex_data); + } // if(getModelFormat() == KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES) - free(new_indices); - free(vertex_mapping); - free(new_vertex_data); + m_pData->unlock(); } diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 56d8093..70e5ae1 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -20,6 +20,7 @@ #include "KRAABB.h" #include "KRQuaternion.h" #include "KRBone.h" +#include "KRLocator.h" #include "KRAudioSource.h" #include "KRAmbientZone.h" #include "KRReverbZone.h" @@ -421,6 +422,8 @@ KRNode *KRNode::LoadXML(KRScene &scene, tinyxml2::XMLElement *e) { new_node = new KRCollider(scene, szName, e->Attribute("mesh"), 65535, 1.0f); } else if(strcmp(szElementName, "bone") == 0) { new_node = new KRBone(scene, szName); + } else if(strcmp(szElementName, "locator") == 0) { + new_node = new KRLocator(scene, szName); } else if(strcmp(szElementName, "audio_source") == 0) { new_node = new KRAudioSource(scene, szName); } else if(strcmp(szElementName, "ambient_zone") == 0) { diff --git a/KREngine/kraken/KRResource+fbx.cpp b/KREngine/kraken/KRResource+fbx.cpp index 360f002..c5ee30d 100644 --- a/KREngine/kraken/KRResource+fbx.cpp +++ b/KREngine/kraken/KRResource+fbx.cpp @@ -23,6 +23,7 @@ #include "KRScene.h" #include "KRQuaternion.h" #include "KRBone.h" +#include "KRLocator.h" #include "KRBundle.h" #include "KRModel.h" #include "KRLODGroup.h" @@ -46,6 +47,7 @@ void LoadMesh(KRContext &context, KFbxScene* pFbxScene, FbxGeometryConverter *pG KRNode *LoadMesh(KRNode *parent_node, KFbxScene* pFbxScene, FbxGeometryConverter *pGeometryConverter, KFbxNode* pNode); KRNode *LoadLight(KRNode *parent_node, KFbxNode* pNode); KRNode *LoadSkeleton(KRNode *parent_node, FbxScene* pScene, KFbxNode* pNode); +KRNode *LoadLocator(KRNode *parent_node, FbxScene* pScene, KFbxNode* pNode); KRNode *LoadCamera(KRNode *parent_node, KFbxNode* pNode); std::string GetFbxObjectName(FbxObject *obj); @@ -54,9 +56,25 @@ const float KRAKEN_FBX_ANIMATION_FRAMERATE = 30.0f; // FINDME - This should be c std::string GetFbxObjectName(FbxObject *obj) { + bool is_locator = false; + KFbxNode *node = FbxCast(obj); + if(node) { + KFbxNodeAttribute::EType attribute_type = (node->GetNodeAttribute()->GetAttributeType()); + if(attribute_type == KFbxNodeAttribute::eNull) { + KFbxNull* pSourceNull = (KFbxNull*) node->GetNodeAttribute(); + if(pSourceNull->Look.Get() == KFbxNull::eCross ) { + is_locator = true; + } + } + } + + // Object names from FBX files are now concatenated with the FBX numerical ID to ensure that they are unique // TODO - This should be updated to only add a prefix or suffix if needed to make the name unique - if(strcmp(obj->GetName(), "default_camera") == 0) { + if(is_locator) { + // We do not rename locators + return std::string(obj->GetName()); + } else if(strcmp(obj->GetName(), "default_camera") == 0) { // There is currently support for rendering from only one camera, "default_camera". We don't translate this node's name, so that animations can drive the camera return "default_camera"; } else { @@ -955,54 +973,40 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, FbxGeometryConverter *p case KFbxNodeAttribute::eSkeleton: new_node = LoadSkeleton(parent_node, pFbxScene, pNode); break; + case KFbxNodeAttribute::eCamera: new_node = LoadCamera(parent_node, 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++; - } + bool is_locator = false; + if(attribute_type == KFbxNodeAttribute::eNull) { + KFbxNull* pSourceNull = (KFbxNull*) pNode->GetNodeAttribute(); + if(pSourceNull->Look.Get() == KFbxNull::eCross ) { + is_locator = true; } - - /* - 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; - /* + } + + if(is_locator) { + new_node = LoadLocator(parent_node, pFbxScene, pNode); + } else { + if(pNode->GetChildCount() > 0) { + // Create an empty node, for inheritence of transforms + std::string name = GetFbxObjectName(pNode); + + + /* + 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(0.0f); + lod_group->setMaxDistance(0.0f); + new_node = lod_group; } - */ - - } } break; @@ -1526,6 +1530,21 @@ KRNode *LoadSkeleton(KRNode *parent_node, FbxScene* pFbxScene, KFbxNode* pNode) return new_bone; } +KRNode *LoadLocator(KRNode *parent_node, FbxScene* pFbxScene, KFbxNode* pNode) { + std::string name = GetFbxObjectName(pNode); + + KRLocator *new_locator = new KRLocator(parent_node->getScene(), name.c_str()); + + //static bool GetBindPoseContaining(FbxScene* pScene, FbxNode* pNode, PoseList& pPoseList, FbxArray& pIndex); + // PoseList pose_list; + // FbxArray pose_indices; + // if(FbxPose::GetBindPoseContaining(pFbxScene, pNode, pose_list, pose_indices)) { + // fprintf(stderr, "Found bind pose(s)!\n"); + // } + + return new_locator; +} + KRNode *LoadCamera(KRNode *parent_node, KFbxNode* pNode) { FbxCamera *camera = (FbxCamera *)pNode->GetNodeAttribute(); const char *szName = pNode->GetName(); diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index 2a1f2f5..2e9c36c 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -406,7 +406,9 @@ KRScene *KRScene::Load(KRContext &context, const std::string &name, KRDataBlock { data->append((void *)"\0", 1); // Ensure data is null terminated, to read as a string safely tinyxml2::XMLDocument doc; + data->lock(); doc.Parse((char *)data->getStart()); + data->unlock(); KRScene *new_scene = new KRScene(context, name); tinyxml2::XMLElement *scene_element = doc.RootElement(); diff --git a/KREngine/kraken/KRShaderManager.cpp b/KREngine/kraken/KRShaderManager.cpp index a591ea8..570f5ed 100644 --- a/KREngine/kraken/KRShaderManager.cpp +++ b/KREngine/kraken/KRShaderManager.cpp @@ -254,12 +254,12 @@ bool KRShaderManager::selectShader(KRCamera &camera, KRShader *pShader, const KR } void KRShaderManager::loadFragmentShader(const std::string &name, KRDataBlock *data) { - m_fragShaderSource[name] = string((char *)data->getStart(), data->getSize()); + m_fragShaderSource[name] = data->getString(); delete data; } void KRShaderManager::loadVertexShader(const std::string &name, KRDataBlock *data) { - m_vertShaderSource[name] = string((char *)data->getStart(), data->getSize()); + m_vertShaderSource[name] = data->getString(); delete data; } diff --git a/KREngine/kraken/KRTexture2D.cpp b/KREngine/kraken/KRTexture2D.cpp index da79d62..ea2a922 100644 --- a/KREngine/kraken/KRTexture2D.cpp +++ b/KREngine/kraken/KRTexture2D.cpp @@ -36,9 +36,11 @@ KRTexture2D::KRTexture2D(KRContext &context, KRDataBlock *data, std::string name) : KRTexture(context, name) { m_current_lod_max_dim = 0; m_pData = data; + m_pData->lock(); } KRTexture2D::~KRTexture2D() { + m_pData->unlock(); delete m_pData; } diff --git a/KREngine/kraken/KRTexturePVR.cpp b/KREngine/kraken/KRTexturePVR.cpp index 97addbf..63d6f4f 100644 --- a/KREngine/kraken/KRTexturePVR.cpp +++ b/KREngine/kraken/KRTexturePVR.cpp @@ -64,6 +64,7 @@ typedef struct _PVRTexHeader KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string name) : KRTexture2D(context, data, name) { #if TARGET_OS_IPHONE + m_pData->lock(); PVRTexHeader *header = (PVRTexHeader *)m_pData->getStart(); uint32_t formatFlags = header->flags & PVR_TEXTURE_FLAG_TYPE_MASK; if (formatFlags == kPVRTextureFlagTypePVRTC_4) { @@ -134,7 +135,7 @@ KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string na m_max_lod_max_dim = m_iWidth > m_iHeight ? m_iWidth : m_iHeight; m_min_lod_max_dim = width > height ? width : height; - + m_pData->unlock(); #endif } @@ -176,8 +177,6 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo int target_dim = lod_max_dim; if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim; - GLenum err; - if(m_blocks.size() == 0) { return false; } diff --git a/KREngine/kraken/KRTextureTGA.cpp b/KREngine/kraken/KRTextureTGA.cpp index 5c6bb71..294c17b 100644 --- a/KREngine/kraken/KRTextureTGA.cpp +++ b/KREngine/kraken/KRTextureTGA.cpp @@ -28,10 +28,12 @@ typedef struct { KRTextureTGA::KRTextureTGA(KRContext &context, KRDataBlock *data, std::string name) : KRTexture2D(context, data, name) { + data->lock(); TGA_HEADER *pHeader = (TGA_HEADER *)data->getStart(); m_max_lod_max_dim = pHeader->width > pHeader->height ? pHeader->width : pHeader->height; m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images + data->unlock(); } KRTextureTGA::~KRTextureTGA() @@ -73,7 +75,7 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo } //#endif glTexImage2D(target, 0, GL_RGBA, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image); - delete converted_image; + free(converted_image); err = glGetError(); if (err != GL_NO_ERROR) { return false;