void NascentModelCommandStream::SkinControllerInstance::Serialize(Serialization::NascentBlockSerializer& serializer) const { ::Serialize(serializer, _id); ::Serialize(serializer, _localToWorldId); serializer.SerializeSubBlock(AsPointer(_materials.begin()), AsPointer(_materials.end())); ::Serialize(serializer, _materials.size()); ::Serialize(serializer, _levelOfDetail); }
std::vector<uint64> NascentModelCommandStream::GetInputInterface() const { std::vector<uint64> inputInterface(_transformationMachineOutputs.size()); unsigned c=0; for (auto i=_transformationMachineOutputs.begin(); i!=_transformationMachineOutputs.end(); ++i, ++c) inputInterface[c] = Hash64(AsPointer(i->_name.begin()), AsPointer(i->_name.end())); return std::move(inputInterface); }
void NascentAnimationSet::Serialize(Serialization::NascentBlockSerializer& serializer) const { serializer.SerializeSubBlock(AsPointer(_animationDrivers.begin()), AsPointer(_animationDrivers.end())); serializer.SerializeValue(_animationDrivers.size()); serializer.SerializeSubBlock(AsPointer(_constantDrivers.begin()), AsPointer(_constantDrivers.end())); serializer.SerializeValue(_constantDrivers.size()); serializer.SerializeSubBlock(AsPointer(_constantData.begin()), AsPointer(_constantData.end())); // List of animations... auto outputAnimations = std::make_unique<AnimationDesc[]>(_animations.size()); for (size_t c=0; c<_animations.size(); ++c) { AnimationDesc&o = outputAnimations[c]; const Animation&i = _animations[c]; o._name = Hash64(AsPointer(i._name.begin()), AsPointer(i._name.end())); o._beginDriver = i._begin; o._endDriver = i._end; o._beginConstantDriver = i._constantBegin; o._endConstantDriver = i._constantEnd; o._beginTime = i._startTime; o._endTime = i._endTime; } std::sort(outputAnimations.get(), &outputAnimations[_animations.size()], CompareAnimationName()); serializer.SerializeSubBlock(outputAnimations.get(), &outputAnimations[_animations.size()]); serializer.SerializeValue(_animations.size()); // Output interface... ConsoleRig::DebuggerOnlyWarning("Animation set output interface:\n"); auto parameterNameHashes = std::make_unique<uint64[]>(_parameterInterfaceDefinition.size()); for (size_t c=0; c<_parameterInterfaceDefinition.size(); ++c) { ConsoleRig::DebuggerOnlyWarning(" [%i] %s\n", c, _parameterInterfaceDefinition[c].c_str()); parameterNameHashes[c] = Hash64(AsPointer(_parameterInterfaceDefinition[c].begin()), AsPointer(_parameterInterfaceDefinition[c].end())); } serializer.SerializeSubBlock(parameterNameHashes.get(), ¶meterNameHashes[_parameterInterfaceDefinition.size()]); serializer.SerializeValue(_parameterInterfaceDefinition.size()); }
void DeviceContext::Bind(const ShaderProgram& shaderProgram, const BoundClassInterfaces& dynLinkage) { auto& vsDyn = dynLinkage.GetClassInstances(ShaderStage::Vertex); _underlying->VSSetShader(shaderProgram.GetVertexShader().GetUnderlying(), (ID3D::ClassInstance*const*)AsPointer(vsDyn.cbegin()), (unsigned)vsDyn.size()); auto& psDyn = dynLinkage.GetClassInstances(ShaderStage::Pixel); _underlying->PSSetShader(shaderProgram.GetPixelShader().GetUnderlying(), (ID3D::ClassInstance*const*)AsPointer(psDyn.cbegin()), (unsigned)psDyn.size()); _underlying->GSSetShader(shaderProgram.GetGeometryShader().GetUnderlying(), nullptr, 0); }
void AccessorSerialize( OutputStreamFormatter& formatter, const void* obj, const ClassAccessors& props) { using CharType = utf8; auto charTypeCat = ImpliedTyping::TypeOf<CharType>()._type; CharType buffer[ParsingBufferSize]; for (size_t i=0; i<props.GetPropertyCount(); ++i) { const auto& p = props.GetPropertyByIndex(i); if (p._castTo) { p._castTo( obj, buffer, sizeof(buffer), ImpliedTyping::TypeDesc(charTypeCat, dimof(buffer)), true); formatter.WriteAttribute( AsPointer(p._name.cbegin()), AsPointer(p._name.cend()), buffer, XlStringEnd(buffer)); } if (p._castToArray) { for (size_t e=0; e<p._fixedArrayLength; ++e) { p._castToArray( obj, e, buffer, sizeof(buffer), ImpliedTyping::TypeDesc(charTypeCat, dimof(buffer)), true); StringMeld<256, CharType> name; name << p._name.c_str() << "[" << e << "]"; formatter.WriteAttribute(name.get(), buffer); } } } for (size_t i=0; i<props.GetChildListCount(); ++i) { const auto& childList = props.GetChildListByIndex(i); auto count = childList._getCount(obj); for (size_t e=0; e<count; ++e) { const auto* child = childList._getByIndex(obj, e); auto eleId = formatter.BeginElement(childList._name); AccessorSerialize(formatter, child, *childList._childProps); formatter.EndElement(eleId); } } }
void PushString( std::basic_streambuf<OutChar>& stream, StringSection<InChar> input) { // String conversion process results in several redundant allocations. It's not perfectly // efficient using OutputString = std::basic_string<OutChar>; auto converted = Conversion::Convert<OutputString>(input.AsString()); stream.sputn(AsPointer(converted.begin()), converted.size()); }
static void SerializeToFileJustChunk( ColladaConversion::NascentChunkArray chunks, const char destinationFilename[], const ConsoleRig::LibVersionDesc& versionInfo) { BasicFile outputFile(destinationFilename, "wb"); for (unsigned i=0; i<(unsigned)chunks->size(); ++i) { auto& c = (*chunks)[i]; outputFile.Write(AsPointer(c._data.begin()), c._data.size(), 1); } }
void DirectorySearchRules::ResolveFile(ResChar destination[], unsigned destinationCount, const ResChar baseName[]) const { ResChar tempBuffer[MaxPath]; auto splitter = MakeFileNameSplitter(baseName); bool baseFileExist = false; if (!splitter.ParametersWithDivider().Empty()) { XlCopyString(tempBuffer, splitter.AllExceptParameters()); baseFileExist = DoesFileExist(tempBuffer); } else { baseFileExist = DoesFileExist(baseName); } // by definition, we always check the unmodified file name first if (!baseFileExist) { const ResChar* b = _buffer; if (!_bufferOverflow.empty()) { b = AsPointer(_bufferOverflow.begin()); } // We want to support the case were destination == baseName // But that cases requires another temporary buffer, because we // don't want to trash "baseName" while searching for matches ResChar* workingBuffer = (baseName!=destination) ? destination : tempBuffer; unsigned workingBufferSize = (baseName!=destination) ? destinationCount : unsigned(dimof(tempBuffer)); for (unsigned c=0; c<_startPointCount; ++c) { XlConcatPath(workingBuffer, workingBufferSize, &b[_startOffsets[c]], splitter.AllExceptParameters().begin(), splitter.AllExceptParameters().end()); if (DoesFileExist(workingBuffer)) { SplitPath<ResChar>(workingBuffer).Simplify().Rebuild(workingBuffer, workingBufferSize); if (workingBuffer != destination) { auto workingBufferLen = std::min((ptrdiff_t)XlStringLen(workingBuffer), ptrdiff_t(destinationCount) - 1); auto colonLen = (ptrdiff_t)splitter.ParametersWithDivider().Length(); auto colonCopy = std::min(ptrdiff_t(destinationCount) - workingBufferLen - 1, colonLen); assert((workingBufferLen + colonCopy) < ptrdiff_t(destinationCount)); if (colonCopy > 0) XlMoveMemory(&destination[workingBufferLen], splitter.ParametersWithDivider().begin(), colonCopy); destination[workingBufferLen + colonCopy] = '\0'; assert(workingBufferLen < (ptrdiff_t(destinationCount)-1)); XlCopyMemory(destination, workingBuffer, workingBufferLen); } else { XlCatString(destination, destinationCount, splitter.ParametersWithDivider()); } return; } } } if (baseName != destination) XlCopyString(destination, destinationCount, baseName); SplitPath<ResChar>(destination).Simplify().Rebuild(destination, destinationCount); }
void DirectorySearchRules::AddSearchDirectory(StringSection<ResChar> dir) { // Attempt to fit this directory into our buffer. // note that we have limited space in the buffer, but we can't really // rely on all directory names remaining small and convenient... If we // overflow our fixed size buffer, we can use the dynamically // allocated "_bufferOverflow" assert((_startPointCount+1) <= dimof(_startOffsets)); if ((_startPointCount+1) > dimof(_startOffsets)) { // limited number of directories that can be pushed into a single "search rules" // this allows us to avoid a little bit of awkward dynamic memory allocation return; } // Check for duplicates // Duplicates are bad because they will increase the number of search operations if (HasDirectory(dir)) return; unsigned allocationLength = (unsigned)(dir.Length() + 1); if (_bufferOverflow.empty() && (_bufferUsed + allocationLength <= dimof(_buffer))) { // just append this new string to our buffer, and add a new start offset XlCopyMemory(&_buffer[_bufferUsed], dir.begin(), (allocationLength-1) * sizeof(ResChar)); _buffer[_bufferUsed+allocationLength-1] = '\0'; } else { if (_bufferOverflow.empty()) { _bufferOverflow.resize(_bufferUsed + allocationLength); XlCopyMemory(AsPointer(_bufferOverflow.begin()), _buffer, _bufferUsed * sizeof(ResChar)); XlCopyMemory(PtrAdd(AsPointer(_bufferOverflow.begin()), _bufferUsed * sizeof(ResChar)), dir.begin(), (allocationLength-1) * sizeof(ResChar)); _bufferOverflow[_bufferUsed+allocationLength-1] = '\0'; } else { assert(_bufferOverflow.size() == allocationLength); auto i = _bufferOverflow.insert(_bufferOverflow.end(), dir.begin(), dir.end()); _bufferOverflow.insert(i + dir.Length(), 0); } } _startOffsets[_startPointCount++] = _bufferUsed; _bufferUsed += allocationLength; }
void DirectorySearchRules::Merge(const DirectorySearchRules& mergeFrom) { // Merge in the settings from the given search rules (if the directories // don't already exist here) // We should really do a better job of comparing directories. Where strings // resolve to the same directory, we should consider them identical const ResChar* b = mergeFrom._buffer; if (!mergeFrom._bufferOverflow.empty()) b = AsPointer(mergeFrom._bufferOverflow.begin()); for (unsigned c=0; c<mergeFrom._startPointCount; ++c) AddSearchDirectory(&b[mergeFrom._startOffsets[c]]); }
static void SerializeToFileJustChunk( RenderCore::ColladaConversion::NascentModel& model, RenderCore::ColladaConversion::OCModelSerializeFunction fn, const char destinationFilename[], const ConsoleRig::LibVersionDesc& versionInfo) { auto chunks = (model.*fn)(); BasicFile outputFile(destinationFilename, "wb"); for (unsigned i=0; i<(unsigned)chunks->size(); ++i) { auto& c = (*chunks)[i]; outputFile.Write(AsPointer(c._data.begin()), c._data.size(), 1); } }
bool DirectorySearchRules::HasDirectory(StringSection<ResChar> dir) { const ResChar* b = _buffer; if (!_bufferOverflow.empty()) { b = AsPointer(_bufferOverflow.begin()); } // note -- just doing a string insensitive compare here... // we should really do a more sophisticated path compare // to get a more accurate result // Actually, it might be better to store the paths in some // format that is more convenient for comparisons and combining // paths. for (unsigned c=0; c<_startPointCount; ++c) if (XlEqStringI(dir, &b[_startOffsets[c]])) return true; return false; }
void DivergentAssetBase::AssetIdentifier::OnChange() { // We need to mark the target file invalidated. // this is a little strange, because the target file // hasn't actually changed. // // But this is required because some dependent assets // don't have a dependency on the asset itself (just // on the underlying file). Invalidating the file ensures // that we invoke a update on all assets that require it. if (_targetFilename.empty()) return; auto fn = _targetFilename; auto paramStart = fn.find_last_of(':'); auto end = fn.cend(); if (paramStart != std::basic_string<ResChar>::npos) end = fn.cbegin() + paramStart; Services::GetAsyncMan().GetIntermediateStore().ShadowFile(MakeStringSection(AsPointer(fn.cbegin()), AsPointer(end))); }
void NascentModelCommandStream::Serialize(Serialization::NascentBlockSerializer& serializer) const { serializer.SerializeSubBlock(AsPointer(_geometryInstances.begin()), AsPointer(_geometryInstances.end())); serializer.SerializeValue(_geometryInstances.size()); serializer.SerializeSubBlock(AsPointer(_skinControllerInstances.begin()), AsPointer(_skinControllerInstances.end())); serializer.SerializeValue(_skinControllerInstances.size()); // // Turn our list of input matrices into hash values, and write out the // run-time input interface definition... // ConsoleRig::DebuggerOnlyWarning("Command stream input interface:\n"); auto inputInterface = GetInputInterface(); serializer.SerializeSubBlock(AsPointer(inputInterface.cbegin()), AsPointer(inputInterface.cend())); serializer.SerializeValue(_transformationMachineOutputs.size()); }
void NascentAnimationSet::MergeAnimation( const NascentAnimationSet& animation, const char name[], const std::vector<Assets::RawAnimationCurve>& sourceCurves, std::vector<Assets::RawAnimationCurve>& destinationCurves) { // // Merge the animation drivers in the given input animation, and give // them the supplied name // float minTime = FLT_MAX, maxTime = -FLT_MAX; size_t startIndex = _animationDrivers.size(); size_t constantStartIndex = _constantDrivers.size(); for (auto i=animation._animationDrivers.cbegin(); i!=animation._animationDrivers.end(); ++i) { if (i->_curveIndex >= sourceCurves.size()) continue; const auto* animCurve = &sourceCurves[i->_curveIndex]; if (animCurve) { float curveStart = animCurve->StartTime(); float curveEnd = animCurve->EndTime(); minTime = std::min(minTime, curveStart); maxTime = std::max(maxTime, curveEnd); const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex]; destinationCurves.push_back(Assets::RawAnimationCurve(*animCurve)); AddAnimationDriver( name, unsigned(destinationCurves.size()-1), i->_samplerType, i->_samplerOffset); } } for (auto i=animation._constantDrivers.cbegin(); i!=animation._constantDrivers.end(); ++i) { const std::string& name = animation._parameterInterfaceDefinition[i->_parameterIndex]; AddConstantDriver(name, PtrAdd(AsPointer(animation._constantData.begin()), i->_dataOffset), i->_samplerType, i->_samplerOffset); } _animations.push_back(Animation(name, (unsigned)startIndex, (unsigned)_animationDrivers.size(), (unsigned)constantStartIndex, (unsigned)_constantDrivers.size(), minTime, maxTime)); }
void DirectorySearchRules::ResolveDirectory( ResChar destination[], unsigned destinationCount, const ResChar baseName[]) const { // We have a problem with basic paths (like '../') // These will match for most directories -- which means that // there is some ambiguity. Let's prefer to use the first // registered path for simple relative paths like this. bool useBaseName = (baseName[0] != '.' && DoesDirectoryExist(baseName)); if (!useBaseName) { const ResChar* b = _buffer; if (!_bufferOverflow.empty()) { b = AsPointer(_bufferOverflow.begin()); } const auto* baseEnd = XlStringEnd(baseName); ResChar tempBuffer[MaxPath]; ResChar* workingBuffer = (baseName!=destination) ? destination : tempBuffer; unsigned workingBufferSize = (baseName!=destination) ? destinationCount : unsigned(dimof(tempBuffer)); for (unsigned c=0; c<_startPointCount; ++c) { XlConcatPath(workingBuffer, workingBufferSize, &b[_startOffsets[c]], baseName, baseEnd); if (DoesDirectoryExist(workingBuffer)) { if (workingBuffer != destination) XlCopyString(destination, destinationCount, workingBuffer); return; } } } if (baseName != destination) XlCopyString(destination, destinationCount, baseName); }
static ::Assets::CompilerHelper::CompileResult CompileMaterialScaffold( const ::Assets::ResChar sourceMaterial[], const ::Assets::ResChar sourceModel[], const ::Assets::ResChar destination[]) { // Parameters must be stripped off the source model filename before we get here. // the parameters are irrelevant to the compiler -- so if they stay on the request // name, will we end up with multiple assets that are equivalent assert(MakeFileNameSplitter(sourceModel).ParametersWithDivider().Empty()); // note -- we can throw pending & invalid from here... auto& modelMat = ::Assets::GetAssetComp<RawMatConfigurations>(sourceModel); std::vector<::Assets::DependentFileState> deps; // for each configuration, we want to build a resolved material // Note that this is a bit crazy, because we're going to be loading // and re-parsing the same files over and over again! SerializableVector<std::pair<MaterialGuid, ResolvedMaterial>> resolved; SerializableVector<std::pair<MaterialGuid, std::string>> resolvedNames; resolved.reserve(modelMat._configurations.size()); auto searchRules = ::Assets::DefaultDirectorySearchRules(sourceModel); ::Assets::ResChar resolvedSourceMaterial[MaxPath]; ResolveMaterialFilename(resolvedSourceMaterial, dimof(resolvedSourceMaterial), searchRules, sourceMaterial); searchRules.AddSearchDirectoryFromFilename(resolvedSourceMaterial); AddDep(deps, sourceModel); // we need need a dependency (even if it's a missing file) using Meld = StringMeld<MaxPath, ::Assets::ResChar>; for (auto i=modelMat._configurations.cbegin(); i!=modelMat._configurations.cend(); ++i) { ResolvedMaterial resMat; std::basic_stringstream<::Assets::ResChar> resName; auto guid = MakeMaterialGuid(AsPointer(i->cbegin()), AsPointer(i->cend())); // Our resolved material comes from 3 separate inputs: // 1) model:configuration // 2) material:* // 3) material:configuration // // Some material information is actually stored in the model // source data. This is just for art-pipeline convenience -- // generally texture assignments (and other settings) are // set in the model authoring tool (eg, 3DS Max). The .material // files actually only provide overrides for settings that can't // be set within 3rd party tools. // // We don't combine the model and material information until // this step -- this gives us some flexibility to use the same // model with different material files. The material files can // also override settings from 3DS Max (eg, change texture assignments // etc). This provides a path for reusing the same model with // different material settings (eg, when we want one thing to have // a red version and a blue version) TRY { // resolve in model:configuration auto configName = Conversion::Convert<::Assets::rstring>(*i); Meld meld; meld << sourceModel << ":" << configName; resName << meld; auto& rawMat = RawMaterial::GetAsset(meld); rawMat._asset.Resolve(resMat, searchRules, &deps); } CATCH (const ::Assets::Exceptions::InvalidAsset&) { } CATCH_END if (resolvedSourceMaterial[0] != '\0') { AddDep(deps, resolvedSourceMaterial); // we need need a dependency (even if it's a missing file) TRY { // resolve in material:* Meld meld; meld << resolvedSourceMaterial << ":*"; resName << ";" << meld; auto& rawMat = RawMaterial::GetAsset(meld); rawMat._asset.Resolve(resMat, searchRules, &deps); } CATCH (const ::Assets::Exceptions::InvalidAsset&) { } CATCH_END TRY { // resolve in material:configuration Meld meld; meld << resolvedSourceMaterial << ":" << Conversion::Convert<::Assets::rstring>(*i); resName << ";" << meld; auto& rawMat = RawMaterial::GetAsset(meld); rawMat._asset.Resolve(resMat, searchRules, &deps); } CATCH (const ::Assets::Exceptions::InvalidAsset&) { } CATCH_END } resolved.push_back(std::make_pair(guid, std::move(resMat))); resolvedNames.push_back(std::make_pair(guid, resName.str())); }
static Identifier DeserializeEntity( InputStreamFormatter<utf8>& formatter, IEntityInterface& interf, DocumentId docId) { using Blob = InputStreamFormatter<utf8>::Blob; using Section = InputStreamFormatter<utf8>::InteriorSection; utf8 tempBuffer[256]; auto beginLoc = formatter.GetLocation(); Section objType = { nullptr, nullptr }; if (!formatter.TryBeginElement(objType)) Throw(FormatException("Error in begin element in entity file", formatter.GetLocation())); XlCopyNString(tempBuffer, objType._start, objType._end - objType._start); auto typeId = interf.GetTypeId((const char*)tempBuffer); std::vector<PropertyInitializer> inits; std::vector<char> initsBuffer; initsBuffer.reserve(256); std::vector<Identifier> children; for (;;) { switch (formatter.PeekNext()) { case Blob::BeginElement: { auto child = DeserializeEntity(formatter, interf, docId); if (child.Object()) children.push_back(child); } break; case Blob::AttributeName: { Section name, value; if (!formatter.TryAttribute(name, value)) Throw(FormatException("Error in begin element in entity file", formatter.GetLocation())); // parse the value and add it as a property initializer char intermediateBuffer[64]; auto type = ImpliedTyping::Parse( (const char*)value._start, (const char*)value._end, intermediateBuffer, dimof(intermediateBuffer)); size_t bufferOffset = initsBuffer.size(); if (type._type == ImpliedTyping::TypeCat::Void) { type._type = ImpliedTyping::TypeCat::UInt8; type._arrayCount = uint16(value._end - value._start); type._typeHint = ImpliedTyping::TypeHint::String; initsBuffer.insert(initsBuffer.end(), value._start, value._end); } else { auto size = std::min(type.GetSize(), (unsigned)sizeof(intermediateBuffer)); initsBuffer.insert(initsBuffer.end(), intermediateBuffer, PtrAdd(intermediateBuffer, size)); } XlCopyNString(tempBuffer, name._start, name._end - name._start); auto id = interf.GetPropertyId(typeId, (const char*)tempBuffer); PropertyInitializer i; i._prop = id; i._elementType = unsigned(type._type); i._arrayCount = type._arrayCount; i._src = (const void*)bufferOffset; inits.push_back(i); } break; case Blob::EndElement: default: if (!formatter.TryEndElement()) Throw(FormatException("Expecting end element in entity deserialisation", formatter.GetLocation())); if (typeId != ~ObjectTypeId(0x0)) { for (auto&i:inits) i._src = PtrAdd(AsPointer(initsBuffer.cbegin()), size_t(i._src)); auto id = interf.AssignObjectId(docId, typeId); Identifier identifier(docId, id, typeId); if (!interf.CreateObject(identifier, AsPointer(inits.cbegin()), inits.size())) Throw(FormatException("Error while creating object in entity deserialisation", beginLoc)); for (const auto&c:children) interf.SetParent(c, identifier, -1); typeId = ~ObjectTypeId(0x0); initsBuffer.clear(); return identifier; } return Identifier(); } } }
const uint8* AsyncLoadOperation::GetBuffer() const { return AsPointer(_buffer.get()); }