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); }
static std::shared_ptr<MaterialScaffold> CreateMaterialScaffold( const ::Assets::ResChar model[], const ::Assets::ResChar material[], RenderCore::Assets::IModelFormat& modelFormat) { // note -- we need to remove any parameters after ':' in the model name // these are references to sub-nodes within the model hierarchy // (which are irrelevant when dealing with materials, since the // materials are shared for the entire model file) ::Assets::ResChar temp[MaxPath]; const auto paramStart = XlFindChar(model, (::Assets::ResChar)':'); if (paramStart) { XlCopyString(temp, MakeStringSection(model, paramStart)); model = temp; } auto& compilers = ::Assets::Services::GetAsyncMan().GetIntermediateCompilers(); auto& store = ::Assets::Services::GetAsyncMan().GetIntermediateStore(); const ::Assets::ResChar* inits[] = { material, model }; auto marker = compilers.PrepareAsset( MaterialScaffold::CompileProcessType, inits, dimof(inits), store); if (!marker) return nullptr; return std::make_shared<MaterialScaffold>(std::move(marker)); }
RenderCore::Metal::BoundUniforms* SharedStateSet::BeginVariation( const ModelRendererContext& context, SharedShaderName shaderName, SharedTechniqueInterface techniqueInterface, SharedParameterBox geoParamBox, SharedParameterBox materialParamBox) const { if ( shaderName == _currentShaderName && techniqueInterface == _currentTechniqueInterface && geoParamBox == _currentGeoParamBox && materialParamBox == _currentMaterialParamBox) { return _currentBoundUniforms; } // we need to check both the "xleres" and "xleres_cry" folders for material files char buffer[MaxPath]; XlCopyString(buffer, "game/xleres/"); XlCatString(buffer, dimof(buffer), _pimpl->_shaderNames[shaderName.Value()].c_str()); XlCatString(buffer, dimof(buffer), ".txt"); if (!DoesFileExist(buffer)) { XlCopyString(buffer, "game/xleres_cry/"); XlCatString(buffer, dimof(buffer), _pimpl->_shaderNames[shaderName.Value()].c_str()); XlCatString(buffer, dimof(buffer), ".txt"); } auto& techniqueContext = context._parserContext->GetTechniqueContext(); auto& shaderType = ::Assets::GetAssetDep<Techniques::ShaderType>(buffer); const ParameterBox* state[] = { &_pimpl->_parameterBoxes[geoParamBox.Value()], &techniqueContext._globalEnvironmentState, &techniqueContext._runtimeState, &_pimpl->_parameterBoxes[materialParamBox.Value()] }; auto& techniqueInterfaceObj = _pimpl->_techniqueInterfaces[techniqueInterface.Value()]; // (FindVariation can throw pending/invalid resource) auto variation = shaderType.FindVariation(context._techniqueIndex, state, techniqueInterfaceObj); if (variation._shaderProgram && variation._boundLayout) { context._context->Bind(*variation._shaderProgram); context._context->Bind(*variation._boundLayout); } _currentShaderName = shaderName; _currentTechniqueInterface = techniqueInterface; _currentMaterialParamBox = materialParamBox; _currentGeoParamBox = geoParamBox; _currentBoundUniforms = variation._boundUniforms; return _currentBoundUniforms; }
CompiledShaderByteCode::CompiledShaderByteCode(const ::Assets::ResChar initializer[], const ::Assets::ResChar definesTable[]) { _stage = ShaderStage::Null; auto validationCallback = std::make_shared<Assets::DependencyValidation>(); std::shared_ptr<ShaderService::IPendingMarker> compileHelper; DEBUG_ONLY(XlCopyString(_initializer, initializer);) if (initializer && initializer[0] != '\0') {
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); }
void AsyncLoadOperation::Enqueue(const ResChar filename[], CompletionThreadPool& pool) { assert(!_hasBeenQueued); _hasBeenQueued = true; XlCopyString(_filename, filename); // We will hold an extra reference to this object // during the queueing processing and while the background // load is occurring. // // Before the file open is started, it will be just a // weak reference. If all client references are destroyed // before we open the file, then we will cancel. // However, once the file has been opened we need to // hold a strong reference at least until the read has // completed std::weak_ptr<AsyncLoadOperation> weakToThis = shared_from_this(); pool.Enqueue( [weakToThis]() { auto thisOp = weakToThis.lock(); // if all other references to this object have been released // then the weak_ptr::lock() will fail, and we can consider // it a cancel if (!thisOp) return; // if we got to this point, we cannot cancel until the load // level read operation has been completed auto h = CreateFile( thisOp->_filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if (h == INVALID_HANDLE_VALUE) { // failed to load the file -- probably because it's missing thisOp->SetState(::Assets::AssetState::Invalid); return; } auto fileSize = GetFileSize(h, nullptr); if (!fileSize || fileSize == INVALID_FILE_SIZE) { thisOp->SetState(::Assets::AssetState::Invalid); CloseHandle(h); return; } thisOp->_buffer.reset((uint8*)XlMemAlign(fileSize, 16)); thisOp->_bufferLength = fileSize; thisOp->_overlapped = std::make_unique<SpecialOverlapped>(); XlSetMemory(thisOp->_overlapped.get(), 0, sizeof(OVERLAPPED)); thisOp->_overlapped->_fileHandle = INVALID_HANDLE_VALUE; thisOp->_overlapped->_returnPointer = thisOp; auto readResult = ReadFileEx( h, thisOp->_buffer.get(), fileSize, thisOp->_overlapped.get(), &SpecialOverlapped::CompletionRoutine); if (!readResult) { CloseHandle(h); thisOp->SetState(::Assets::AssetState::Invalid); thisOp->_overlapped->_returnPointer.reset(); return; } thisOp->_overlapped->_fileHandle = h; // execution will pass to AsyncLoadOperation::CompletionRoutine, which // will complete the load operation }); }