Matrix4::Matrix4(const Any& any) { any.verifyName("Matrix4"); any.verifyType(Any::ARRAY); const std::string& name = toLower(any.name()); if (name == "matrix4") { any.verifySize(16); for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { elt[r][c] = any[r * 4 + c]; } } } else if (name == "matrix4::scale") { if (any.size() == 1) { *this = scale(any[0].number()); } else if (any.size() == 3) { *this = scale(any[0], any[1], any[2]); } else { any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments"); } } else if (name == "matrix4::translation") { if (any.size() == 3) { *this = translation(any[0], any[1], any[2]); } else { any.verify(false, "Matrix4::translation() takes either 1 or 3 arguments"); } } else { any.verify(false, "Expected Matrix4 constructor"); } }
static void testParse() { { const String& src = "name[ \"foo\", b4r, { a = b, c = d}]"; Any a = Any::parse(src); a.verifyType(Any::ARRAY); a[0].verifyType(Any::STRING); testAssert(a[0].string() == "foo"); testAssert(a[1].string() == "b4r"); testAssert(a[2]["a"].string() == "b"); } { const String& src = "[v = 1,\r\n/*\r\n*/\r\nx = 1]"; Any a = Any::parse(src); testAssert(a.type() == Any::TABLE); testAssert(a.size() == 2); Any val1 = a["v"]; testAssert(val1.type() == Any::NUMBER); testAssert(val1.number() == 1); } { const String& src = "{\n\ val0 : (1);\n\ \n\ // Comment 1\n\ val1 : 3;\n\ \ // Comment 2\n\ // Comment 3\n\ val2 : None;\n\ val3 : none;\n\ val4 : NIL;\n\ }"; Any a = Any::parse(src); testAssert(a.type() == Any::TABLE); testAssert(a.size() == 5); Any val1 = a["val1"]; testAssert(val1.type() == Any::NUMBER); testAssert(val1.number() == 3); testAssert(val1.comment() == "Comment 1"); testAssert(a["val2"].isNil()); testAssert(a["val3"].string() == "none"); testAssert(a["val4"].isNil()); }
bool Any::operator==(const Any & other) const { if(type != other.type)return false; try{ switch(type){ case UNDEFINED: return true; case BOOL: return boolValue==other.boolValue; case INTEGER: return integerValue==other.integerValue; case DOUBLE: return doubleValue==other.doubleValue; case STRING: return stringValue==other.stringValue; case ARRAY: { if(size()!=other.size())return false; for(size_t i=0;i<size();i++){ if(arrayValue[i]!=other.arrayValue.at(i))return false; } return true; } case OBJECT:{ for(auto & kv : objectValue){ if(kv.second != other.objectValue.at(kv.first)){ return false; } } return true; } default: return false; } }catch(...){ return false; } }
Matrix4::Matrix4(const Any& any) { any.verifyNameBeginsWith("Matrix4", "CFrame", "CoordinateFrame"); any.verifyType(Any::ARRAY); const std::string& name = any.name(); if (name == "Matrix4") { any.verifySize(16); for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { elt[r][c] = any[r * 4 + c]; } } } else if (name == "Matrix4::scale") { if (any.size() == 1) { *this = scale(any[0].floatValue()); } else if (any.size() == 3) { *this = scale(any[0], any[1], any[2]); } else { any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments"); } } else if (name == "Matrix4::rollDegrees") { any.verifySize(1); *this = rollDegrees(any[0].floatValue()); } else if (name == "Matrix4::yawDegrees") { any.verifySize(1); *this = yawDegrees(any[0].floatValue()); } else if (name == "Matrix4::pitchDegrees") { any.verifySize(1); *this = pitchDegrees(any[0].floatValue()); } else if (name == "Matrix4::translation") { if (any.size() == 3) { *this = translation(any[0], any[1], any[2]); } else { any.verify(false, "Matrix4::translation() requires 3 arguments"); } } else if (name == "Matrix4::diagonal") { any.verifySize(4); *this = diagonal(any[0], any[1], any[2], any[3]); } else if (name == "Matrix4::identity") { *this = identity(); } else if (beginsWith(name, "CFrame") || beginsWith(name, "CoordinateFrame")) { *this = CFrame(any); } else { any.verify(false, "Expected Matrix4 constructor"); } }
CoordinateFrame::CoordinateFrame(const Any& any) { *this = CFrame(); const std::string& n = toUpper(any.name()); if (beginsWith(n, "VECTOR3")) { translation = any; } else if (beginsWith(n, "MATRIX3")) { rotation = any; } else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) { any.verifyType(Any::TABLE, Any::ARRAY); if (any.type() == Any::ARRAY) { any.verifySize(2); rotation = any[0]; translation = any[1]; } else { for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) { const std::string& n = toLower(it->key); if (n == "translation") { translation = Vector3(it->value); } else if (n == "rotation") { rotation = Matrix3(it->value); } else { any.verify(false, "Illegal table key: " + it->key); } } } } else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) { *this = PhysicsFrame(any); } else { any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees"); any.verifyType(Any::ARRAY); any.verifySize(3, 6); int s = any.size(); *this = fromXYZYPRDegrees(any[0], any[1], any[2], (s > 3) ? any[3].number() : 0.0f, (s > 4) ? any[4].number() : 0.0f, (s > 5) ? any[5].number() : 0.0f); } }
CoordinateFrame::CoordinateFrame(const Any& any) { *this = CFrame(); const String& n = toUpper(any.name()); if (beginsWith(n, "VECTOR3") || beginsWith(n, "POINT3")) { translation = Point3(any); } else if (beginsWith(n, "MATRIX3")) { rotation = Matrix3(any); } else if (beginsWith(n, "MATRIX4")) { *this = Matrix4(any).approxCoordinateFrame(); } else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) { any.verifyType(Any::TABLE, Any::ARRAY); if (any.type() == Any::ARRAY) { any.verifySize(2); rotation = any[0]; translation = any[1]; } else { AnyTableReader r(any); r.getIfPresent("translation", translation); r.getIfPresent("rotation", rotation); r.verifyDone(); } } else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) { *this = PhysicsFrame(any); // } else if (beginsWith(n, "UPRIGHTFRAME") || beginsWith(n, "UFRAME")) { // *this = UprightFrame(any); } else { any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees"); any.verifyType(Any::ARRAY); any.verifySize(3, 6); int s = any.size(); *this = fromXYZYPRDegrees(any[0], any[1], any[2], (s > 3) ? (float)any[3].number() : 0.0f, (s > 4) ? (float)any[4].number() : 0.0f, (s > 5) ? (float)any[5].number() : 0.0f); } }
shared_ptr<Entity::Track> Entity::Track::create(Entity* entity, Scene* scene, const Any& a, const VariableTable& variableTable) { if (a.type() == Any::STRING) { // This must be an id const shared_ptr<Entity::Track>& c = variableTable[a.string()]; if (isNull(c)) { a.verify(false, ""); } return c; } if ((beginsWith(a.name(), "PhysicsFrameSpline")) || (beginsWith(a.name(), "PFrameSpline")) || (beginsWith(a.name(), "Point3")) || (beginsWith(a.name(), "Vector3")) || (beginsWith(a.name(), "Matrix3")) || (beginsWith(a.name(), "Matrix4")) || (beginsWith(a.name(), "CFrame")) || (beginsWith(a.name(), "PFrame")) || (beginsWith(a.name(), "UprightSpline")) || (beginsWith(a.name(), "CoordinateFrame")) || (beginsWith(a.name(), "PhysicsFrame"))) { return Entity::SplineTrack::create(a); } else if (a.name() == "entity") { // Name of an Entity const std::string& targetName = a[0].string(); alwaysAssertM(notNull(scene) && notNull(entity), "entity() Track requires non-NULL Scene and Entity"); debugAssert(targetName != ""); scene->setOrder(entity->name(), targetName); return shared_ptr<Entity::Track>(new TrackEntityTrack(targetName, scene)); } else if (a.name() == "transform") { return shared_ptr<Entity::Track> (new TransformTrack(create(entity, scene, a[0], variableTable), create(entity, scene, a[1], variableTable))); } else if (a.name() == "follow") { a.verify(false, "follow Tracks are unimplemented"); return shared_ptr<Entity::Track>(); // return shared_ptr<Entity::Track>(new TransformTrack(create(a[0]), create(a[1]))); } else if (a.name() == "orbit") { return shared_ptr<Entity::Track>(new OrbitTrack(a[0], a[1])); } else if (a.name() == "combine") { return shared_ptr<Entity::Track> (new CombineTrack(create(entity, scene, a[0], variableTable), create(entity, scene, a[1], variableTable))); } else if (a.name() == "lookAt") { return shared_ptr<Entity::Track> (new LookAtTrack(create(entity, scene, a[0], variableTable), create(entity, scene, a[1], variableTable), (a.size() > 2) ? Vector3(a[2]) : Vector3::unitY())); } else if (a.name() == "timeShift") { shared_ptr<Track> p = create(entity, scene, a[0], variableTable); a.verify(notNull(dynamic_pointer_cast<SplineTrack>(p)) || notNull(dynamic_pointer_cast<OrbitTrack>(p)), "timeShift() requires a PhysicsFrameSpline or orbit"); return shared_ptr<Entity::Track>(new TimeShiftTrack(p, a[1].number())); } else if (a.name() == "with") { // Create a new variable table and recurse VariableTable extendedTable(&variableTable); const Any& vars = a[0]; for (Table<std::string, Any>::Iterator it = vars.table().begin(); it.isValid(); ++it) { // Note that if Any allowed iteration through its table in definition order, then // we could implement Scheme LET* instead of LET here. extendedTable.set(it->key, create(entity, scene, it->value, variableTable)); } return create(entity, scene, a[1], extendedTable); } else { // Some failure a.verify(false, "Unrecognized Entity::Track type"); return shared_ptr<Entity::Track>(); } }
ArticulatedModel::Instruction::Instruction(const Any& any) { any.verifyType(Any::ARRAY); source = any; part = Identifier(); mesh = Identifier(); arg = Any(); const std::string& instructionName = any.name(); if (instructionName == "scale") { type = SCALE; any.verifySize(1); arg = any[0]; } else if (instructionName == "moveCenterToOrigin") { type = MOVE_CENTER_TO_ORIGIN; any.verifySize(0); } else if (instructionName == "moveBaseToOrigin") { type = MOVE_BASE_TO_ORIGIN; any.verifySize(0); } else if (instructionName == "setCFrame") { type = SET_CFRAME; any.verifySize(2); part = any[0]; arg = any[1]; } else if (instructionName == "transformCFrame") { type = TRANSFORM_CFRAME; any.verifySize(2); part = any[0]; arg = any[1]; } else if (instructionName == "transformGeometry") { type = TRANSFORM_GEOMETRY; any.verifySize(2); part = any[0]; arg = any[1]; } else if (instructionName == "deleteMesh") { type = DELETE_MESH; any.verifySize(2); part = any[0]; mesh = any[1]; } else if (instructionName == "deletePart") { type = DELETE_PART; any.verifySize(1); part = any[0]; } else if (instructionName == "setMaterial") { type = SET_MATERIAL; any.verifySize(3); part = any[0]; mesh = any[1]; arg = any[2]; } else if (instructionName == "setTwoSided") { type = SET_TWO_SIDED; any.verifySize(3); part = any[0]; mesh = any[1]; arg = any[2]; } else if (instructionName == "mergeAll") { type = MERGE_ALL; any.verifySize(0); } else if (instructionName == "renamePart") { type = RENAME_PART; any.verifySize(2); part = any[0]; arg = any[1]; } else if (instructionName == "renameMesh") { type = RENAME_MESH; any.verifySize(3); part = any[0]; mesh = any[1]; arg = any[2]; } else if (instructionName == "add") { type = ADD; mesh = Identifier::none(); if (any.size() == 2) { any.verifySize(2); part = any[0]; arg = any[1]; } else { any.verifySize(1); part = Identifier::none(); arg = any[0]; } } else { any.verify(false, std::string("Unknown instruction: \"") + instructionName + "\""); } }
bool Any::operator==(const Any& x) const { beforeRead(); x.beforeRead(); if (m_type != x.m_type) { return false; } switch (m_type) { case NONE: return true; case BOOLEAN: return (m_simpleValue.b == x.m_simpleValue.b); case NUMBER: return (m_simpleValue.n == x.m_simpleValue.n); case STRING: debugAssert(m_data != NULL); return (*(m_data->value.s) == *(x.m_data->value.s)); case TABLE: { if (size() != x.size()) { return false; } debugAssert(m_data != NULL); if (m_data->name != x.m_data->name) { return false; } Table<std::string, Any>& cmptable = *(m_data->value.t); Table<std::string, Any>& xcmptable = *(x.m_data->value.t); for (Table<std::string, Any>::Iterator it1 = cmptable.begin(), it2 = xcmptable.begin(); it1 != cmptable.end() && it2 != xcmptable.end(); ++it1, ++it2) { if (*it1 != *it2) { return false; } } return true; } case ARRAY: { if (size() != x.size()) { return false; } debugAssert(m_data != NULL); if (m_data->name != x.m_data->name) { return false; } Array<Any>& cmparray = *(m_data->value.a); Array<Any>& xcmparray = *(x.m_data->value.a); for (int ii = 0; ii < size(); ++ii) { if (cmparray[ii] != xcmparray[ii]) { return false; } } return true; } default: alwaysAssertM(false, "Unknown type."); return false; } // switch (m_type) }
Any Scene::load(const std::string& scene) { std::string filename; clear(); m_modelTable.clear(); m_name = scene; bool isFilename = endsWith(toLower(scene), ".scn.any") || endsWith(toLower(scene), ".Scene.Any"); if (isFilename) { filename = scene; } else { const std::string* f = filenameTable().getPointer(scene); if (f == NULL) { throw "No scene with name '" + scene + "' found in (" + stringJoin(filenameTable().getKeys(), ", ") + ")"; } filename = *f; } Any any; any.load(filename); { const std::string& n = any.get("name", filename); // Ensure that this name appears in the filename table if it does not already, // so that it can be loaded by name in the future. if (! filenameTable().containsKey(n)) { filenameTable().set(n, filename); } } m_sourceAny = any; // Load the lighting environment (do this before loading entities, since some of them may // be lights that will enter this array) bool hasEnvironmentMap = false; if (any.containsKey("localLightingEnvironment")) { m_localLightingEnvironment = any["localLightingEnvironment"]; hasEnvironmentMap = any["localLightingEnvironment"].containsKey("environmentMap"); } // Load the models if (any.containsKey("models")) { Any models = any["models"]; if (models.size() > 0) { for (Any::AnyTable::Iterator it = models.table().begin(); it.isValid(); ++it) { const std::string name = it->key; Any v = it->value; createModel(v, name); } } } // Instance the models if (any.containsKey("entities")) { Any entities = any["entities"]; if (entities.size() > 0) { for (Table<std::string, Any>::Iterator it = entities.table().begin(); it.isValid(); ++it) { const std::string& name = it->key; const std::string& entityType = it->value.name(); createEntity(entityType, name, it->value); } } } shared_ptr<Texture> skyboxTexture = Texture::whiteCube(); Any skyAny; // Use the environment map as a skybox if there isn't one already, and vice versa Array<shared_ptr<Skybox> > skyboxes; getTypedEntityArray<Skybox>(skyboxes); if ( skyboxes.size() == 0 ) { if (any.containsKey("skybox")) { createEntity("Skybox", "skybox", any["skybox"]); m_skybox = typedEntity<Skybox>("skybox"); } else if (hasEnvironmentMap) { m_skybox = Skybox::create("skybox", this, Array<ScaledTexture>(m_localLightingEnvironment.environmentMapArray[0]), Array<SimTime>(0.0), 0, SplineExtrapolationMode::CLAMP, false, false); insert(m_skybox); } else { m_skybox = Skybox::create("skybox", this, Array<ScaledTexture>(ScaledTexture(Texture::whiteCube(), 1.0f)), Array<SimTime>(0.0), 0, SplineExtrapolationMode::CLAMP, false, false); insert(m_skybox); } } if (any.containsKey("environmentMap")) { throw std::string("environmentMap field has been replaced with localLightingEnvironment"); } // Default to using the skybox as an environment map if none is specified. if (! hasEnvironmentMap) { m_localLightingEnvironment.environmentMapArray.append(ScaledTexture(m_skybox->keyframeArray()[0].texture, m_skybox->keyframeArray()[0].constant)); } ////////////////////////////////////////////////////// if (m_cameraArray.size() == 0) { // Create a default camera, back it up from the origin m_cameraArray.append(Camera::create("camera")); m_cameraArray.last()->setFrame(CFrame::fromXYZYPRDegrees(0,1,-5,0,-5)); } setTime(any.get("time", 0.0)); m_lastVisibleChangeTime = m_lastLightChangeTime = m_lastStructuralChangeTime = System::time(); m_defaultCameraName = (std::string)any.get("defaultCamera", ""); // Set the initial positions, repeating a few times to allow // objects defined relative to others to reach a fixed point for (int i = 0; i < 3; ++i) { for (int e = 0; e < m_entityArray.size(); ++e) { m_entityArray[e]->onSimulation(m_time, nan()); } } // Pose objects so that they have bounds. { Array< shared_ptr<Surface> > ignore; onPose(ignore); } return any; }
GLight::GLight(const Any& any) { any.verifyName("GLight"); if (any.type() == Any::TABLE) { *this = GLight(); Vector3 spotTarget; bool hasSpotTarget = false; for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) { const std::string& key = toLower(it->key); if (key == "position") { position = it->value; } else if (key == "rightdirection") { rightDirection = it->value; } else if (key == "spotdirection") { spotDirection = Vector3(it->value).directionOrZero(); } else if (key == "spottarget") { spotTarget = it->value; hasSpotTarget = true; } else if (key == "spotcutoff") { spotCutoff = it->value.number(); } else if (key == "spotsquare") { spotSquare = it->value.boolean(); } else if (key == "attenuation") { attenuation[0] = it->value[0].number(); attenuation[1] = it->value[1].number(); attenuation[2] = it->value[2].number(); } else if (key == "color") { color = it->value; } else if (key == "enabled") { enabled = it->value.boolean(); } else if (key == "specular") { specular = it->value.boolean(); } else if (key == "diffuse") { diffuse = it->value.boolean(); } else { any.verify(false, "Illegal key: " + it->key); } } if (hasSpotTarget) { spotDirection = (spotTarget - position.xyz()).direction(); } } else if (toLower(any.name()) == "glight::directional") { *this = directional(any[0], any[1], (any.size() > 2) ? any[2] : Any(true), (any.size() > 3) ? any[3] : Any(true)); } else if (toLower(any.name()) == "glight::point") { *this = point(any[0], any[1], (any.size() > 2) ? any[2] : Any(1), (any.size() > 3) ? any[3] : Any(0), (any.size() > 4) ? any[4] : Any(0.5f), (any.size() > 5) ? any[5] : Any(true), (any.size() > 6) ? any[6] : Any(true)); } else if (toLower(any.name()) == "glight::spot") { *this = spot(any[0], any[1], any[2], any[3], (any.size() > 4) ? any[4] : Any(1), (any.size() > 5) ? any[5] : Any(0), (any.size() > 6) ? any[6] : Any(0), (any.size() > 7) ? any[7] : Any(true), (any.size() > 8) ? any[8] : Any(true)); } else { any.verify(false, "Unrecognized name"); } }