Asynchronous streaming and memory management improvements in progress.
Note: This branch is unstable --HG-- branch : async_streaming
This commit is contained in:
@@ -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 = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
|
||||
E461A164152E56C000F2044A /* KRSpotLight.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRSpotLight.cpp; sourceTree = "<group>"; };
|
||||
E461A167152E570500F2044A /* KRSpotLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRSpotLight.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
E468447D17FFDF51001F1FA1 /* KRLocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRLocator.cpp; sourceTree = "<group>"; };
|
||||
E468447E17FFDF51001F1FA1 /* KRLocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRLocator.h; sourceTree = "<group>"; };
|
||||
E46A6B6C1559E97D000DBD37 /* KRResource+blend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "KRResource+blend.cpp"; sourceTree = "<group>"; };
|
||||
E46A6B6F1559EF0A000DBD37 /* KRResource+blend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KRResource+blend.h"; sourceTree = "<group>"; };
|
||||
E46C214115364BC8009CABF3 /* tinyxml2_readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tinyxml2_readme.txt; sourceTree = "<group>"; };
|
||||
@@ -971,6 +977,8 @@
|
||||
E480BE6B1671C653004EC8AD /* KRBone.cpp */,
|
||||
E4AE635B1704FB0A00B460CD /* KRLODGroup.cpp */,
|
||||
E4AE635C1704FB0A00B460CD /* KRLODGroup.h */,
|
||||
E468447D17FFDF51001F1FA1 /* KRLocator.cpp */,
|
||||
E468447E17FFDF51001F1FA1 /* KRLocator.h */,
|
||||
);
|
||||
name = "Scene Graph Nodes";
|
||||
sourceTree = "<group>";
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
35
KREngine/kraken/KRLocator.cpp
Normal file
35
KREngine/kraken/KRLocator.cpp
Normal file
@@ -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);
|
||||
}
|
||||
27
KREngine/kraken/KRLocator.h
Normal file
27
KREngine/kraken/KRLocator.h
Normal file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, const KRMat4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector<KRBone *> &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::vector<std:
|
||||
size_t vertex_count = mi.vertices.size();
|
||||
size_t bone_count = mi.bone_names.size();
|
||||
size_t new_file_size = sizeof(pack_header) + sizeof(pack_material) * submesh_count + sizeof(pack_bone) * bone_count + KRALIGN(2 * index_count) + KRALIGN(8 * index_base_count) + vertex_size * vertex_count;
|
||||
|
||||
m_pData->unlock();
|
||||
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<index_count; index_number++) {
|
||||
int prev_vertex_index = index_data_start[index_number];
|
||||
if(prev_vertex_index > 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<index_count; index_number++) {
|
||||
int prev_vertex_index = index_data_start[index_number];
|
||||
if(prev_vertex_index > 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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<KFbxNode>(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<boost::char_separator<char> > char_tokenizer;
|
||||
|
||||
int step = 0;
|
||||
|
||||
char_tokenizer name_components(name, boost::char_separator<char>("_"));
|
||||
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<float>(component);
|
||||
step++;
|
||||
} else if(step == 2) {
|
||||
max_distance = boost::lexical_cast<float>(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<int>& pIndex);
|
||||
// PoseList pose_list;
|
||||
// FbxArray<int> 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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user