У TexPipe убрано ключевое слово tex
This commit is contained in:
@@ -162,92 +162,6 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
}
|
||||
}
|
||||
|
||||
auto resolveModelInfo = [&](std::string_view domain, std::string_view key) -> const ResourceFindInfo* {
|
||||
auto& table = resourcesFirstStage[static_cast<size_t>(AssetType::Model)];
|
||||
auto iterDomain = table.find(std::string(domain));
|
||||
if(iterDomain == table.end())
|
||||
return nullptr;
|
||||
auto iterKey = iterDomain->second.find(std::string(key));
|
||||
if(iterKey == iterDomain->second.end())
|
||||
return nullptr;
|
||||
return &iterKey->second;
|
||||
};
|
||||
|
||||
std::function<std::optional<js::object>(std::string_view, std::string_view, std::unordered_set<std::string>&)> loadModelProfile;
|
||||
loadModelProfile = [&](std::string_view domain, std::string_view key, std::unordered_set<std::string>& visiting)
|
||||
-> std::optional<js::object>
|
||||
{
|
||||
std::string fullKey = std::string(domain) + ':' + std::string(key);
|
||||
if(!visiting.insert(fullKey).second) {
|
||||
LOG.warn() << "Model parent cycle: " << fullKey;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const ResourceFindInfo* info = resolveModelInfo(domain, key);
|
||||
if(!info) {
|
||||
LOG.warn() << "Model file not found for parent: " << fullKey;
|
||||
visiting.erase(fullKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ResourceFile file = readFileBytes(info->Path);
|
||||
std::string_view view(reinterpret_cast<const char*>(file.Data.data()), file.Data.size());
|
||||
js::object obj = js::parse(view).as_object();
|
||||
|
||||
if(auto parentVal = obj.if_contains("parent")) {
|
||||
if(parentVal->is_string()) {
|
||||
std::string parentStr = std::string(parentVal->as_string());
|
||||
auto [pDomain, pKeyRaw] = parseDomainKey(parentStr, domain);
|
||||
fs::path pKeyPath = fs::path(pKeyRaw);
|
||||
if(pKeyPath.extension().empty())
|
||||
pKeyPath += ".json";
|
||||
std::string pKey = pKeyPath.generic_string();
|
||||
|
||||
std::optional<js::object> parent = loadModelProfile(pDomain, pKey, visiting);
|
||||
if(parent) {
|
||||
auto mergeFieldIfMissing = [&](const char* field) {
|
||||
if(!obj.contains(field) && parent->contains(field))
|
||||
obj[field] = parent->at(field);
|
||||
};
|
||||
|
||||
mergeFieldIfMissing("cuboids");
|
||||
mergeFieldIfMissing("sub_models");
|
||||
mergeFieldIfMissing("gui_light");
|
||||
mergeFieldIfMissing("ambient_occlusion");
|
||||
|
||||
if(auto parentTextures = parent->if_contains("textures"); parentTextures && parentTextures->is_object()) {
|
||||
if(auto childTextures = obj.if_contains("textures"); childTextures && childTextures->is_object()) {
|
||||
auto& childObj = childTextures->as_object();
|
||||
const auto& parentObj = parentTextures->as_object();
|
||||
for(const auto& [tkey, tval] : parentObj) {
|
||||
if(!childObj.contains(tkey))
|
||||
childObj.emplace(tkey, tval);
|
||||
}
|
||||
} else if(!obj.contains("textures")) {
|
||||
obj["textures"] = parentTextures->as_object();
|
||||
}
|
||||
}
|
||||
|
||||
if(auto parentDisplay = parent->if_contains("display"); parentDisplay && parentDisplay->is_object()) {
|
||||
if(auto childDisplay = obj.if_contains("display"); childDisplay && childDisplay->is_object()) {
|
||||
auto& childObj = childDisplay->as_object();
|
||||
const auto& parentObj = parentDisplay->as_object();
|
||||
for(const auto& [dkey, dval] : parentObj) {
|
||||
if(!childObj.contains(dkey))
|
||||
childObj.emplace(dkey, dval);
|
||||
}
|
||||
} else if(!obj.contains("display")) {
|
||||
obj["display"] = parentDisplay->as_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visiting.erase(fullKey);
|
||||
return obj;
|
||||
};
|
||||
|
||||
// Функция парсинга ресурсов
|
||||
auto buildResource = [&](AssetType type, std::string_view domain, std::string_view key, const ResourceFindInfo& info) -> PendingResource {
|
||||
PendingResource out;
|
||||
@@ -268,25 +182,11 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
return getId(AssetType::Texture, mDomain, mKey);
|
||||
};
|
||||
|
||||
auto normalizeTexturePipelineSrc = [](std::string_view src) -> std::string {
|
||||
std::string out(src);
|
||||
auto isSpace = [](unsigned char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; };
|
||||
size_t start = 0;
|
||||
while(start < out.size() && isSpace(static_cast<unsigned char>(out[start])))
|
||||
++start;
|
||||
if(out.compare(start, 3, "tex") != 0) {
|
||||
std::string pref = "tex ";
|
||||
pref += out.substr(start);
|
||||
return pref;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
std::function<std::vector<uint8_t>(const std::string_view)> textureResolver
|
||||
= [&](const std::string_view texturePipelineSrc) -> std::vector<uint8_t>
|
||||
{
|
||||
TexturePipelineProgram tpp;
|
||||
bool flag = tpp.compile(normalizeTexturePipelineSrc(texturePipelineSrc));
|
||||
bool flag = tpp.compile(texturePipelineSrc);
|
||||
if(!flag)
|
||||
return {};
|
||||
|
||||
@@ -307,13 +207,9 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
} else if (type == AssetType::Model) {
|
||||
const std::string ext = info.Path.extension().string();
|
||||
if (ext == ".json") {
|
||||
std::unordered_set<std::string> visiting;
|
||||
std::optional<js::object> objOpt = loadModelProfile(domain, key, visiting);
|
||||
if(!objOpt) {
|
||||
LOG.warn() << "Не удалось загрузить модель: " << info.Path.string();
|
||||
throw std::runtime_error("Model profile load failed");
|
||||
}
|
||||
js::object obj = std::move(*objOpt);
|
||||
ResourceFile file = readFileBytes(info.Path);
|
||||
std::string_view view(reinterpret_cast<const char*>(file.Data.data()), file.Data.size());
|
||||
js::object obj = js::parse(view).as_object();
|
||||
|
||||
HeadlessModel hm;
|
||||
out.Header = hm.parse(obj, modelResolver, textureResolver);
|
||||
|
||||
@@ -51,8 +51,8 @@ public:
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
bool compile(std::string src, std::string* err = nullptr) {
|
||||
Source_ = std::move(src);
|
||||
bool compile(std::string_view src, std::string* err = nullptr) {
|
||||
Source_ = src;
|
||||
Code_.clear();
|
||||
Patches_.clear();
|
||||
PendingSub_.clear();
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
if(src.Kind != SrcKind::TexId)
|
||||
return true;
|
||||
if(src.TexId >= remap.size()) {
|
||||
if(err) *err = "Texture id out of remap range";
|
||||
if(err) *err = "Идентификатор текстуры вне диапазона переназначения";
|
||||
return false;
|
||||
}
|
||||
uint32_t newId = remap[src.TexId];
|
||||
@@ -733,7 +733,7 @@ private:
|
||||
explicit VM(TextureProvider provider) : Provider_(std::move(provider)) {}
|
||||
|
||||
bool run(const std::vector<uint8_t>& code, OwnedTexture& out, double timeSeconds, std::string* err) {
|
||||
if(code.empty()) { if(err) *err="Empty bytecode"; return false; }
|
||||
if(code.empty()) { if(err) *err="Пустой байткод"; return false; }
|
||||
|
||||
Image cur;
|
||||
std::unordered_map<uint32_t, Image> texCache;
|
||||
@@ -742,7 +742,7 @@ private:
|
||||
size_t ip = 0;
|
||||
|
||||
auto need = [&](size_t n)->bool{
|
||||
if(ip + n > code.size()) { if(err) *err="Bytecode truncated"; return false; }
|
||||
if(ip + n > code.size()) { if(err) *err="Байткод усечен"; return false; }
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -997,7 +997,7 @@ private:
|
||||
|
||||
auto t = Provider_(id);
|
||||
if(!t || !t->Pixels || !t->Width || !t->Height) {
|
||||
if(err) *err = "Texture id not found: " + std::to_string(id);
|
||||
if(err) *err = "Идентификатор текстуры не найден: " + std::to_string(id);
|
||||
return {};
|
||||
}
|
||||
Image img;
|
||||
@@ -1019,7 +1019,7 @@ private:
|
||||
|
||||
size_t start = size_t(off);
|
||||
size_t end = start + size_t(len);
|
||||
if(end > code.size()) { if(err) *err="Subprogram out of range"; return {}; }
|
||||
if(end > code.size()) { if(err) *err="Подпрограмма выходит за пределы"; return {}; }
|
||||
|
||||
std::vector<uint8_t> slice(code.begin()+start, code.begin()+end);
|
||||
OwnedTexture tmp;
|
||||
@@ -1040,7 +1040,7 @@ private:
|
||||
std::string* err) {
|
||||
if(src.Kind == SrcKind::TexId) return _loadTex(src.TexId24, texCache, err);
|
||||
if(src.Kind == SrcKind::Sub) return _loadSub(code, src.Off24, src.Len24, texCache, subCache, timeSeconds, err);
|
||||
if(err) *err = "Unknown SrcKind";
|
||||
if(err) *err = "Неизвестный SrcKind";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1307,8 +1307,10 @@ private:
|
||||
// ========================
|
||||
// Minimal DSL Lexer/Parser
|
||||
// now supports:
|
||||
// name |> op(...)
|
||||
// 32x32 "#RRGGBBAA"
|
||||
// optional prefix:
|
||||
// tex name |> op(...)
|
||||
// tex 32x32 "#RRGGBBAA"
|
||||
// nested only where op expects a texture arg:
|
||||
// overlay( tex other |> ... )
|
||||
// Also supports overlay(other) / mask(other) / lowpart(50, other)
|
||||
@@ -1501,19 +1503,20 @@ private:
|
||||
bool _parseProgram(std::string* err) {
|
||||
Lexer lx{Source_};
|
||||
Tok t = lx.next();
|
||||
if(!(t.Kind==TokKind::Ident && t.Text=="tex")) {
|
||||
if(err) *err="Expected 'tex' at start";
|
||||
return false;
|
||||
}
|
||||
bool hasTexPrefix = (t.Kind == TokKind::Ident && t.Text == "tex");
|
||||
|
||||
// compile base into main Code_
|
||||
if(!_compileBaseAfterTex(lx, Code_, /*abs*/&Patches_, /*rel*/nullptr, err)) return false;
|
||||
if(hasTexPrefix) {
|
||||
if(!_compileBaseAfterTex(lx, Code_, /*abs*/&Patches_, /*rel*/nullptr, err)) return false;
|
||||
} else {
|
||||
if(!_compileBaseFromToken(lx, t, Code_, /*abs*/&Patches_, /*rel*/nullptr, err)) return false;
|
||||
}
|
||||
|
||||
// pipeline: |> op ...
|
||||
Tok nt = lx.next();
|
||||
while (nt.Kind == TokKind::Pipe) {
|
||||
Tok opName = lx.next();
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Expected op name after |>"; return false; }
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Ожидалось имя операции после |>"; return false; }
|
||||
ParsedOp op; op.Name = opName.Text;
|
||||
|
||||
Tok peek = lx.next();
|
||||
@@ -1530,7 +1533,7 @@ private:
|
||||
_emitOp(Code_, Op::End);
|
||||
if (Code_.size() > MaxCodeBytes) {
|
||||
if (err)
|
||||
*err = "Pipeline bytecode too large: " + std::to_string(Code_.size()) +
|
||||
*err = "Байткод пайплайна слишком большой: " + std::to_string(Code_.size()) +
|
||||
" > MaxCodeBytes(" + std::to_string(MaxCodeBytes) + ")";
|
||||
return false;
|
||||
}
|
||||
@@ -1539,12 +1542,13 @@ private:
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Base compilation after 'tex'
|
||||
// Base compilation (optionally after 'tex')
|
||||
// supports:
|
||||
// 1) tex name
|
||||
// 2) tex "name(.png/.jpg/.jpeg)" (allowed but normalized)
|
||||
// 3) tex anim(...)
|
||||
// 4) tex 32x32 "#RRGGBBAA"
|
||||
// 1) name
|
||||
// 2) "name(.png/.jpg/.jpeg)" (allowed but normalized)
|
||||
// 3) anim(...)
|
||||
// 4) 32x32 "#RRGGBBAA"
|
||||
// optional: all of the above may be prefixed with 'tex'
|
||||
// ========================
|
||||
bool _compileBaseAfterTex(Lexer& lx,
|
||||
std::vector<uint8_t>& out,
|
||||
@@ -1552,10 +1556,23 @@ private:
|
||||
std::vector<RelPatch>* relPatches,
|
||||
std::string* err) {
|
||||
Tok a = lx.next();
|
||||
return _compileBaseFromToken(lx, a, out, absPatches, relPatches, err);
|
||||
}
|
||||
|
||||
bool _compileBaseFromToken(Lexer& lx,
|
||||
const Tok& a,
|
||||
std::vector<uint8_t>& out,
|
||||
std::vector<Patch>* absPatches,
|
||||
std::vector<RelPatch>* relPatches,
|
||||
std::string* err) {
|
||||
if(a.Kind == TokKind::End) {
|
||||
if(err) *err="Ожидалось текстурное выражение";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(a.Kind == TokKind::Ident && a.Text == "anim") {
|
||||
Tok lp = lx.next();
|
||||
if(lp.Kind != TokKind::LParen) { if(err) *err="Expected '(' after anim"; return false; }
|
||||
if(lp.Kind != TokKind::LParen) { if(err) *err="Ожидалась '(' после anim"; return false; }
|
||||
|
||||
ParsedOp op; op.Name="anim";
|
||||
if(!_parseArgList(lx, op, err)) return false;
|
||||
@@ -1581,7 +1598,7 @@ private:
|
||||
};
|
||||
|
||||
std::string tex = namedS("tex").value_or(posS(0).value_or(""));
|
||||
if(tex.empty()) { if(err) *err="anim requires texture name"; return false; }
|
||||
if(tex.empty()) { if(err) *err="anim требует имя текстуры"; return false; }
|
||||
|
||||
uint32_t frameW = namedU("frame_w").value_or(namedU("w").value_or(posU(1).value_or(0)));
|
||||
uint32_t frameH = namedU("frame_h").value_or(namedU("h").value_or(posU(2).value_or(0)));
|
||||
@@ -1593,7 +1610,7 @@ private:
|
||||
bool horizontal = (!axis.empty() && (axis[0] == 'x' || axis[0] == 'h'));
|
||||
|
||||
if(frameW > 65535u || frameH > 65535u || frames > 65535u) {
|
||||
if(err) *err="anim params must fit uint16";
|
||||
if(err) *err="параметры anim должны помещаться в uint16";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1611,28 +1628,28 @@ private:
|
||||
}
|
||||
|
||||
if(a.Kind == TokKind::Ident || a.Kind == TokKind::String) {
|
||||
// tex name (or tex "name.png" => normalized)
|
||||
// name (or "name.png" => normalized)
|
||||
_emitOp(out, Op::Base_Tex);
|
||||
_emitSrcTexName(out, absPatches, relPatches, a.Text);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(a.Kind == TokKind::Number) {
|
||||
// tex 32x32 "#RRGGBBAA"
|
||||
// 32x32 "#RRGGBBAA"
|
||||
Tok xTok = lx.next();
|
||||
Tok b = lx.next();
|
||||
Tok colTok = lx.next();
|
||||
if(xTok.Kind != TokKind::X || b.Kind != TokKind::Number || (colTok.Kind!=TokKind::Ident && colTok.Kind!=TokKind::String)) {
|
||||
if(err) *err="Expected: tex <w>x<h> <#color>";
|
||||
if(err) *err="Ожидалось: <w>x<h> <#color>";
|
||||
return false;
|
||||
}
|
||||
uint32_t w = a.U32, h = b.U32;
|
||||
uint32_t color = 0;
|
||||
if(!_parseHexColor(colTok.Text, color)) {
|
||||
if(err) *err="Bad color literal (use #RRGGBB or #RRGGBBAA)";
|
||||
if(err) *err="Неверный литерал цвета (используйте #RRGGBB или #RRGGBBAA)";
|
||||
return false;
|
||||
}
|
||||
if(w>65535u || h>65535u) { if(err) *err="w/h must fit in uint16"; return false; }
|
||||
if(w>65535u || h>65535u) { if(err) *err="w/h должны помещаться в uint16"; return false; }
|
||||
_emitOp(out, Op::Base_Fill);
|
||||
_emitU16(out, w);
|
||||
_emitU16(out, h);
|
||||
@@ -1640,7 +1657,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(err) *err="Bad 'tex' base expression";
|
||||
if(err) *err="Некорректное базовое текстурное выражение";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1661,7 +1678,7 @@ private:
|
||||
if(!_compileSubProgramFromAlreadySawTex(lx, sub, err)) return false;
|
||||
|
||||
Tok end = lx.next();
|
||||
if(end.Kind != TokKind::RParen) { if(err) *err="Expected ')' after sub texture expr"; return false; }
|
||||
if(end.Kind != TokKind::RParen) { if(err) *err="Ожидалась ')' после подвыражения текстуры"; return false; }
|
||||
|
||||
PendingSub_[&op] = std::move(sub);
|
||||
return true;
|
||||
@@ -1695,7 +1712,7 @@ private:
|
||||
if(t.Kind == TokKind::Comma) { t = lx.next(); continue; }
|
||||
if(t.Kind == TokKind::RParen) return true;
|
||||
|
||||
if(err) *err = "Expected ',' or ')' in argument list";
|
||||
if(err) *err = "Ожидалась ',' или ')' в списке аргументов";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1728,7 +1745,7 @@ private:
|
||||
if(t.Kind == TokKind::Comma) { t = lx.next(); continue; }
|
||||
if(t.Kind == TokKind::RParen) return true;
|
||||
|
||||
if(err) *err = "Expected ',' or ')' in argument list";
|
||||
if(err) *err = "Ожидалась ',' или ')' в списке аргументов";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1737,7 +1754,7 @@ private:
|
||||
if(t.Kind == TokKind::Number) { out.Kind=ArgVal::ValueKind::U32; out.U32=t.U32; return true; }
|
||||
if(t.Kind == TokKind::String) { out.Kind=ArgVal::ValueKind::Str; out.S=t.Text; return true; }
|
||||
if(t.Kind == TokKind::Ident) { out.Kind=ArgVal::ValueKind::Ident; out.S=t.Text; return true; }
|
||||
if(err) *err = "Expected value token";
|
||||
if(err) *err = "Ожидалось значение";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1764,12 +1781,12 @@ private:
|
||||
// peek
|
||||
Tok nt = lx.peek();
|
||||
if(nt.Kind == TokKind::RParen) break;
|
||||
if(nt.Kind != TokKind::Pipe) { if(err) *err="Sub tex: expected '|>' or ')'"; return false; }
|
||||
if(nt.Kind != TokKind::Pipe) { if(err) *err="Подтекстура: ожидалось '|>' или ')'"; return false; }
|
||||
|
||||
// consume pipe
|
||||
lx.next();
|
||||
Tok opName = lx.next();
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Sub tex: expected op name"; return false; }
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Подтекстура: ожидалось имя операции"; return false; }
|
||||
|
||||
ParsedOp op; op.Name = opName.Text;
|
||||
|
||||
@@ -1783,7 +1800,7 @@ private:
|
||||
// Instead: enforce parentheses for ops in subprogram except no-arg ops (brighten/noalpha) which can be without.
|
||||
// To keep behavior identical to main, we handle no-arg by rewinding I one token is not possible,
|
||||
// so we accept that in subprogram, no-arg ops must be written as brighten() etc.
|
||||
if(err) *err="Sub tex: no-arg ops must use parentheses, e.g. brighten()";
|
||||
if(err) *err="Подтекстура: операции без аргументов должны использовать скобки, напр. brighten()";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1795,13 +1812,13 @@ private:
|
||||
while (true) {
|
||||
Tok nt = lx.peek();
|
||||
if(nt.Kind == TokKind::RParen) break;
|
||||
if(nt.Kind != TokKind::Pipe) { if(err) *err="Sub tex: expected '|>' or ')'"; return false; }
|
||||
if(nt.Kind != TokKind::Pipe) { if(err) *err="Подтекстура: ожидалось '|>' или ')'"; return false; }
|
||||
|
||||
// consume pipe
|
||||
lx.next();
|
||||
|
||||
Tok opName = lx.next();
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Sub tex: expected op name"; return false; }
|
||||
if(opName.Kind != TokKind::Ident) { if(err) *err="Подтекстура: ожидалось имя операции"; return false; }
|
||||
|
||||
ParsedOp op; op.Name = opName.Text;
|
||||
|
||||
@@ -1838,12 +1855,12 @@ private:
|
||||
const size_t len = sub.Bytes.size();
|
||||
|
||||
if(offset > 0xFFFFFFu || len > 0xFFFFFFu || (offset + len) > 0xFFFFFFu) {
|
||||
if(err) *err = "Subprogram слишком большой (off/len должны влезать в u24 байт)";
|
||||
if(err) *err = "Подпрограмма слишком большая (off/len должны влезать в u24 байт)";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(offset + len > MaxCodeBytes) {
|
||||
if(err) *err = "Pipeline bytecode too large after sub append: " +
|
||||
if(err) *err = "Байткод пайплайна слишком большой после вставки подпрограммы: " +
|
||||
std::to_string(offset + len) + " > MaxCodeBytes(" + std::to_string(MaxCodeBytes) + ")";
|
||||
return false;
|
||||
}
|
||||
@@ -1904,7 +1921,7 @@ private:
|
||||
|
||||
auto emitSrcFromPendingSub = [&]()->bool{
|
||||
auto it = PendingSub_.find(&op);
|
||||
if(it == PendingSub_.end()) { if(err) *err="Internal: missing subprogram"; return false; }
|
||||
if(it == PendingSub_.end()) { if(err) *err="Внутренняя ошибка: отсутствует подпрограмма"; return false; }
|
||||
uint32_t off=0, len=0;
|
||||
if(!_appendSubprogram(out, std::move(it->second), absPatches, relPatches, off, len, err)) return false;
|
||||
PendingSub_.erase(it);
|
||||
@@ -1919,7 +1936,7 @@ private:
|
||||
|
||||
// allow overlay(name) or overlay(tex=name)
|
||||
std::string tex = namedS("tex").value_or(posS(0).value_or(""));
|
||||
if(tex.empty()) { if(err) *err="overlay requires texture arg"; return false; }
|
||||
if(tex.empty()) { if(err) *err="overlay требует аргумент-текстуру"; return false; }
|
||||
emitSrcFromName(tex);
|
||||
return true;
|
||||
}
|
||||
@@ -1929,14 +1946,14 @@ private:
|
||||
if(!op.Pos.empty() && op.Pos[0].S == "__SUBTEX__") return emitSrcFromPendingSub();
|
||||
|
||||
std::string tex = namedS("tex").value_or(posS(0).value_or(""));
|
||||
if(tex.empty()) { if(err) *err="mask requires texture arg"; return false; }
|
||||
if(tex.empty()) { if(err) *err="mask требует аргумент-текстуру"; return false; }
|
||||
emitSrcFromName(tex);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(op.Name == "lowpart") {
|
||||
uint32_t pct = namedU("percent").value_or(posU(0).value_or(0));
|
||||
if(!pct) { if(err) *err="lowpart requires percent"; return false; }
|
||||
if(!pct) { if(err) *err="lowpart требует процент"; return false; }
|
||||
|
||||
_emitOp(out, Op::LowPart);
|
||||
_emitU8(out, std::min<uint32_t>(100u, pct));
|
||||
@@ -1945,7 +1962,7 @@ private:
|
||||
if(op.Pos.size() >= 2 && op.Pos[1].S == "__SUBTEX__") return emitSrcFromPendingSub();
|
||||
|
||||
std::string tex = namedS("tex").value_or(posS(1).value_or(""));
|
||||
if(tex.empty()) { if(err) *err="lowpart requires texture arg"; return false; }
|
||||
if(tex.empty()) { if(err) *err="lowpart требует аргумент-текстуру"; return false; }
|
||||
emitSrcFromName(tex);
|
||||
return true;
|
||||
}
|
||||
@@ -1954,7 +1971,7 @@ private:
|
||||
if(op.Name == "resize") {
|
||||
uint32_t w = namedU("w").value_or(posU(0).value_or(0));
|
||||
uint32_t h = namedU("h").value_or(posU(1).value_or(0));
|
||||
if(!w || !h || w>65535u || h>65535u) { if(err) *err="resize(w,h) must fit uint16"; return false; }
|
||||
if(!w || !h || w>65535u || h>65535u) { if(err) *err="resize(w,h) должны помещаться в uint16"; return false; }
|
||||
_emitOp(out, Op::Resize); _emitU16(out, w); _emitU16(out, h);
|
||||
return true;
|
||||
}
|
||||
@@ -1979,7 +1996,7 @@ private:
|
||||
if(op.Name == "make_alpha") {
|
||||
std::string col = namedS("color").value_or(posS(0).value_or(""));
|
||||
uint32_t argb=0;
|
||||
if(!_parseHexColor(col, argb)) { if(err) *err="make_alpha requires color #RRGGBB"; return false; }
|
||||
if(!_parseHexColor(col, argb)) { if(err) *err="make_alpha требует цвет #RRGGBB"; return false; }
|
||||
uint32_t rgb24 = argb & 0x00FFFFFFu;
|
||||
_emitOp(out, Op::MakeAlpha);
|
||||
_emitU8(out, (rgb24 >> 16) & 0xFFu);
|
||||
@@ -2020,7 +2037,7 @@ private:
|
||||
auto compileColorOp = [&](Op opcode, bool needsRatio)->bool{
|
||||
std::string col = namedS("color").value_or(posS(0).value_or(""));
|
||||
uint32_t argb=0;
|
||||
if(!_parseHexColor(col, argb)) { if(err) *err="Bad color literal"; return false; }
|
||||
if(!_parseHexColor(col, argb)) { if(err) *err="Неверный литерал цвета"; return false; }
|
||||
_emitOp(out, opcode);
|
||||
_emitU32(out, argb);
|
||||
if(needsRatio) {
|
||||
@@ -2045,7 +2062,7 @@ private:
|
||||
bool horizontal = (!axis.empty() && (axis[0] == 'x' || axis[0] == 'h'));
|
||||
|
||||
if(frameW > 65535u || frameH > 65535u || frames > 65535u) {
|
||||
if(err) *err="anim params must fit uint16";
|
||||
if(err) *err="параметры anim должны помещаться в uint16";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2061,7 +2078,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(err) *err = "Unknown op: " + op.Name;
|
||||
if(err) *err = "Неизвестная операция: " + op.Name;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user