#include #include #include #include #include #include #include "Rune Engine/Rune/Rune.h" #include "Rune Engine/Rune/Rune Engine NULL.h" #include "Rune Engine/Rune/Core/DataStore/RuDataStore_Disk.h" #include "Rune Engine/Rune/Helper/RuHelper_Math.h" #include "Rune Engine/Rune/Scene/Terrain/RuWorld_EntitySystem.h" #include "Rune Engine/Rune/Scene/Terrain/RuWorld_ZoneDescriptorContainer.h" namespace { std::string JsonEscape(const char *value) { std::string out; for(const char *p = value ? value : ""; *p; ++p) { if(*p == '\\' || *p == '"') { out += '\\'; out += *p; } else if(*p == '\n') out += "\\n"; else if(*p == '\r') out += "\\r"; else if(*p == '\t') out += "\\t"; else out += *p; } return out; } void WriteColor(std::ostream &out, DWORD color) { out << "{\"argb\":\"0x" << std::uppercase << std::hex << std::setw(8) << std::setfill('0') << color << std::dec << std::setfill(' ') << "\",\"rgba\":[" << ((color >> 16) & 0xFF) / 255.0 << ',' << ((color >> 8) & 0xFF) / 255.0 << ',' << (color & 0xFF) / 255.0 << ',' << ((color >> 24) & 0xFF) / 255.0 << "]}"; } void WriteVector(std::ostream &out, const CRuVector3 &vector) { out << '[' << vector.x << ',' << vector.y << ',' << vector.z << ']'; } } int main(int argc, char **argv) { if(argc != 3 && argc != 6) { std::cerr << "Usage: runewaker_zone_lighting_exporter [probe-x probe-y probe-z]\n"; return 2; } if(RuInitialize_Core() == FALSE || RuInitialize_NULL() == FALSE) { std::cerr << "Rune engine initialization failed.\n"; return 3; } CRuDataStore_Disk *dataStore = ruNEW CRuDataStore_Disk(); if(dataStore->Open(argv[1], TRUE) == FALSE) { std::cerr << "Unable to open WDB: " << argv[1] << "\n"; ruSAFE_RELEASE(dataStore); RuShutdown(); return 4; } CRuWorld_ZoneDescriptorContainer *container = ruNEW CRuWorld_ZoneDescriptorContainer(); if(container->Attach(dataStore) == FALSE) { std::cerr << "Unable to attach world-zone descriptor table.\n"; ruSAFE_RELEASE(container); ruSAFE_RELEASE(dataStore); RuShutdown(); return 5; } CRuWorld_ObjectContainer *objectContainer = ruNEW CRuWorld_ObjectContainer( CRuAABB(CRuVector3(-100000.0f, -100000.0f, -100000.0f), CRuVector3(100000.0f, 100000.0f, 100000.0f)), 1000.0f); if(objectContainer->Attach(dataStore) == FALSE) { std::cerr << "Unable to attach world object table.\n"; ruSAFE_RELEASE(objectContainer); ruSAFE_RELEASE(container); ruSAFE_RELEASE(dataStore); RuShutdown(); return 7; } CRuArrayList triggers; objectContainer->EnumerateAllObjectsByType(CRuWorld_Trigger::Type(), triggers); CRuWorld_Trigger *entryZoneTrigger = NULL; INT32 entryZoneTriggerIndex = -1; INT32 entryZonePriority = 0xFFFFFFFF; REAL entryZoneDistance = FLT_MAX; CRuVector3 entryProbe; const BOOL hasEntryProbe = argc == 6; if(hasEntryProbe) { entryProbe.Set(static_cast(atof(argv[3])), static_cast(atof(argv[4])), static_cast(atof(argv[5]))); CRuCollisionQuery_Segment_Nearest query; CRuMatrix4x4 identityMatrix; query.m_worldTransform = &identityMatrix; query.m_invWorldTransform = &identityMatrix; query.m_ignoreCollisionFlag = TRUE; CRuSegment3 segments[2] = { CRuSegment3(entryProbe, entryProbe + CRuVector3(0.0f, -10000.0f, 0.0f)), CRuSegment3(entryProbe, entryProbe + CRuVector3(0.0f, 10000.0f, 0.0f)) }; for(INT32 ti = 0; ti < triggers.Count(); ++ti) { CRuWorld_Trigger *trigger = static_cast(triggers[ti]); if(trigger->GetTriggerType() != RuWorld::ruTRIGGERTYPE_ZONE) continue; RuPropertyType propertyValue; const INT32 priority = trigger->GetProperty("CRuWorld_Trigger:Priority", propertyValue) ? boost::get(propertyValue) : 0; for(INT32 si = 0; si < 2; ++si) { query.m_positiveHit = FALSE; query.m_collisionT = FLT_MAX; query.m_colSegment = segments[si]; trigger->QueryCollision(&query); if(!query.m_positiveHit) continue; const REAL distance = query.m_collisionT; BOOL prefer = priority > entryZonePriority || (priority == entryZonePriority && distance < entryZoneDistance); if(!prefer && priority == entryZonePriority && distance == entryZoneDistance && entryZoneTrigger) { INT32 parentID = trigger->GetZoneID(); CRuWorld_ZoneDescriptor *parent = container->GetZoneDescriptor(parentID); while(parent) { if(parent->GetZoneID() == entryZoneTrigger->GetZoneID()) { prefer = TRUE; break; } parent = container->GetZoneDescriptor(parent->GetParentZoneID()); } } if(prefer) { entryZoneTrigger = trigger; entryZoneTriggerIndex = ti; entryZonePriority = priority; entryZoneDistance = distance; } } } } std::ofstream out(argv[2], std::ios::out | std::ios::trunc); if(!out) { std::cerr << "Unable to write JSON: " << argv[2] << "\n"; ruSAFE_RELEASE(container); ruSAFE_RELEASE(dataStore); RuShutdown(); return 6; } out << std::setprecision(9) << "{\n \"sourceWdb\": \"" << JsonEscape(argv[1]) << "\",\n \"zoneDescriptorCount\": " << container->GetNumZoneDescriptors() << ",\n \"zones\": [\n"; for(INT32 zi = 0; zi < container->GetNumZoneDescriptors(); ++zi) { CRuWorld_ZoneDescriptor *zone = container->GetZoneDescriptorByIndex(zi); out << " {\"id\":" << zone->GetZoneID() << ",\"parentId\":" << zone->GetParentZoneID() << ",\"name\":\"" << JsonEscape(zone->GetName()) << "\",\"zoneType\":" << static_cast(zone->GetZoneType()) << ",\"settings\":["; for(INT32 si = 0; si < zone->GetNumZoneSettings(); ++si) { CRuWorld_ZoneSettings *s = zone->GetZoneSettingsByIndex(si); if(si) out << ','; out << "{\"timeGroup\":" << s->m_timeGroup << ",\"weatherGroup\":" << s->m_weatherGroup << ",\"primary\":"; WriteColor(out, s->m_color_Primary); out << ",\"secondary\":"; WriteColor(out, s->m_color_Secondary); out << ",\"ambient\":"; WriteColor(out, s->m_color_Ambient); out << ",\"specular\":"; WriteColor(out, s->m_color_Specular); out << ",\"fogColor\":"; WriteColor(out, s->m_color_Fog); out << ",\"fog\":{\"constant\":" << s->m_fog_Constant << ",\"start\":" << s->m_fog_Start << ",\"end\":" << s->m_fog_End << "},\"standardAnglesRadians\":[" << s->m_theta_Standard << ',' << s->m_phi_Standard << "],\"specularAnglesRadians\":[" << s->m_theta_Specular << ',' << s->m_phi_Specular << "],\"nativeDirectionsLeftHandedYUp\":{\"primary\":"; WriteVector(out, RuMathHelper_GenerateLightingVector(s->m_theta_Standard, s->m_phi_Standard)); out << ",\"secondary0\":"; WriteVector(out, RuMathHelper_GenerateLightingVector(s->m_theta_Standard + ruPI * 2.0f / 3.0f, 0.0f)); out << ",\"secondary1\":"; WriteVector(out, RuMathHelper_GenerateLightingVector(s->m_theta_Standard + ruPI * 4.0f / 3.0f, 0.0f)); out << ",\"specular\":"; WriteVector(out, RuMathHelper_GenerateLightingVector(s->m_theta_Specular, s->m_phi_Specular) * -1.0f); out << "},\"weatherSystem\":\"" << JsonEscape(s->m_weatherSystem) << "\",\"skyGradientTexture\":\"" << JsonEscape(s->m_skyGradientTextureName) << "\",\"customSkyBox\":\"" << JsonEscape(s->m_customSkyBoxName) << "\",\"cloudCover\":" << s->m_cloudCover << ",\"cloudSharpness\":" << s->m_cloudSharpness << ",\"cloudColors\":["; WriteColor(out, s->m_cloudColor0); out << ','; WriteColor(out, s->m_cloudColor1); out << "]}"; } out << "]}" << (zi + 1 < container->GetNumZoneDescriptors() ? "," : "") << "\n"; } INT32 zoneTriggerCount = 0; for(INT32 ti = 0; ti < triggers.Count(); ++ti) { if(static_cast(triggers[ti])->GetTriggerType() == RuWorld::ruTRIGGERTYPE_ZONE) { ++zoneTriggerCount; } } out << " ],\n \"zoneTriggerCount\": " << zoneTriggerCount << ",\n \"zoneTriggers\": [\n"; INT32 writtenZoneTriggers = 0; for(INT32 ti = 0; ti < triggers.Count(); ++ti) { CRuWorld_Trigger *trigger = static_cast(triggers[ti]); if(trigger->GetTriggerType() != RuWorld::ruTRIGGERTYPE_ZONE) continue; CRuOBB bounds = trigger->GetTriggerBounds(); const CRuVector3 ¢er = bounds.Center(); const CRuVector3 *axes = bounds.Axis(); const float *extents = bounds.Extents(); RuPropertyType propertyValue; const INT32 priority = trigger->GetProperty("CRuWorld_Trigger:Priority", propertyValue) ? boost::get(propertyValue) : 0; out << " {\"triggerType\":" << static_cast(trigger->GetTriggerType()) << ",\"zoneId\":" << trigger->GetZoneID() << ",\"zoneType\":" << static_cast(trigger->GetZoneType()) << ",\"priority\":" << priority << ",\"command\":\"" << JsonEscape(trigger->GetCommandString()) << "\",\"obb\":{\"center\":[" << center.x << ',' << center.y << ',' << center.z << "],\"axes\":[" << '[' << axes[0].x << ',' << axes[0].y << ',' << axes[0].z << "]," << '[' << axes[1].x << ',' << axes[1].y << ',' << axes[1].z << "]," << '[' << axes[2].x << ',' << axes[2].y << ',' << axes[2].z << "]],\"halfExtents\":[" << extents[0] << ',' << extents[1] << ',' << extents[2] << "]}}" << (++writtenZoneTriggers < zoneTriggerCount ? "," : "") << "\n"; } out << " ],\n \"entryZoneSelection\":"; if(!hasEntryProbe) { out << "null\n"; } else { out << "{\"probe\":[" << entryProbe.x << ',' << entryProbe.y << ',' << entryProbe.z << "],\"triggerIndex\":" << entryZoneTriggerIndex << ",\"triggerZoneId\":"; if(entryZoneTrigger) out << entryZoneTrigger->GetZoneID(); else out << "null"; out << ",\"triggerPriority\":"; if(entryZoneTrigger) out << entryZonePriority; else out << "null"; out << ",\"boundaryDistance\":"; if(entryZoneTrigger) out << entryZoneDistance; else out << "null"; out << ",\"settingsZoneId\":"; INT32 settingsZoneID = -1; CRuWorld_ZoneSettings *entrySettings = NULL; CRuWorld_ZoneDescriptor *selectedZone = entryZoneTrigger ? container->GetZoneDescriptor(entryZoneTrigger->GetZoneID()) : NULL; while(selectedZone) { entrySettings = selectedZone->GetZoneSettings(0, 0); if(entrySettings) { settingsZoneID = selectedZone->GetZoneID(); break; } selectedZone = container->GetZoneDescriptor(selectedZone->GetParentZoneID()); } if(entrySettings) out << settingsZoneID; else out << "null"; out << ",\"timeGroup\":0,\"weatherGroup\":0,\"selectedTimeGroup\":"; if(entrySettings) out << entrySettings->m_timeGroup; else out << "null"; out << ",\"selectedWeatherGroup\":"; if(entrySettings) out << entrySettings->m_weatherGroup; else out << "null"; out << "}\n"; } out << "}\n"; out.close(); std::cout << "Wrote " << container->GetNumZoneDescriptors() << " source zone descriptors.\n"; for(INT32 ti = 0; ti < triggers.Count(); ++ti) ruSAFE_RELEASE(triggers[ti]); ruSAFE_RELEASE(objectContainer); ruSAFE_RELEASE(container); ruSAFE_RELEASE(dataStore); RuShutdown(); return 0; }