From c573d01cb7dcb32a85bfda67d912498a45a8730d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 23 Sep 2026 22:26:54 +0300 Subject: [PATCH 1/4] add 'texture' vca directive --- res/modules/animation.lua | 3 ++- res/modules/internal/animation_codegen.lua | 22 ++++++++++++++++---- res/modules/internal/formats/vca.lua | 24 +++++++++++++++++++--- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/res/modules/animation.lua b/res/modules/animation.lua index 3f6acf351..e6b00e7ca 100644 --- a/res/modules/animation.lua +++ b/res/modules/animation.lua @@ -42,13 +42,14 @@ local this = { CH_ROTATE = 2, CH_SCALE = 3, CH_ZOOM = 4, + CH_TEXTURE = 5, INT_CONST = 1, INT_LINEAR = 2, INT_BEZIER = 3, INT_CUSTOM = 4, - TRACE_CODEGEN = false, + TRACE_CODEGEN = true, maths = { bezier_interpolation = bezier_interpolation diff --git a/res/modules/internal/animation_codegen.lua b/res/modules/internal/animation_codegen.lua index 0b2cd7ce3..7eadfb4e6 100644 --- a/res/modules/internal/animation_codegen.lua +++ b/res/modules/internal/animation_codegen.lua @@ -60,6 +60,11 @@ local env = { Y = {0, 1, 0}, Z = {0, 0, 1}, DST = mat4.idt(), + string_at = function(keys, frame) + local left, _ = key_neighbors(keys, frame) + left = keys[left] + return left.value + end, value_at = function(keys, frame, interp) local left, right = key_neighbors(keys, frame) if left == right then @@ -147,6 +152,10 @@ local function codegen_track(raw_track, lineset, memoised, keysets, use_tsf) code = code .. string.format( "\n local l%d = value_at_custom(keysets['%s'][%d], t * %s, %s)", i, lineset.target_name, i, raw_track.fps, valueat) + elseif line.channel == animation.CH_TEXTURE then + code = code .. string.format( + "\n local l%d = string_at(keysets['%s'][%d], t * %s)", + i, lineset.target_name, i, raw_track.fps) else code = code .. string.format( "\n local l%d = value_at(keysets['%s'][%d], t * %s, %s)", @@ -164,7 +173,9 @@ local function codegen_track(raw_track, lineset, memoised, keysets, use_tsf) scale[line.axis] = i has_tsf = true elseif line.channel == animation.CH_ZOOM then - code = code .. "\n zoom = l" .. i + code = code .. "\n zoom = l" .. i + elseif line.channel == animation.CH_TEXTURE then + code = code .. string.format("\n target:set_texture(%s, %s)", lineset.target_name:escape(), "l"..i) end end @@ -206,14 +217,17 @@ local function codegen_rig_target(raw_track, context) local code = "\n if target.set_matrix and target.index then\n" code = code .. " local dst = DST\n" for bone, lineset in pairs(raw_track.linesets) do - if lineset.target_type ~= "bone" then + if lineset.target_type ~= "bone" and lineset.target_type ~= "texture" then goto continue end local lineset_code = codegen_track( raw_track, lineset, context.memoised, context.keysets, true) - code = code .. "\n do" .. lineset_code .. "\n end\n" .. - " target:set_matrix(target:index(" .. string.escape(bone) .. "), dst)\n" + code = code .. "\n do" .. lineset_code .. "\n end\n" + if lineset.target_type == "bone" then + code = code .. + " target:set_matrix(target:index(" .. string.escape(bone) .. "), dst)\n" + end ::continue:: end return code .. " end" diff --git a/res/modules/internal/formats/vca.lua b/res/modules/internal/formats/vca.lua index f06c99a7b..e22e220eb 100644 --- a/res/modules/internal/formats/vca.lua +++ b/res/modules/internal/formats/vca.lua @@ -7,6 +7,7 @@ local action_to_channel = { rotate = animation.CH_ROTATE, scale = animation.CH_SCALE, zoom = animation.CH_ZOOM, + texture = animation.CH_TEXTURE, } local curve_to_interp = { @@ -50,6 +51,17 @@ local function parse_curve(line, node) end end +local function parse_simple_frames(line, node) + line.keys = {} + for j, key_node in ipairs(node) do + local keyframe = { + frame = tonumber(key_node.frame), + value = key_node.value, + } + table.insert(line.keys, keyframe) + end +end + local function parse_track(root) local raw_track = { duration = math.huge, @@ -74,8 +86,10 @@ local function parse_track(root) local target_type = nil if node.bone then target_type = "bone" + elseif tag == "texture" then + target_type = "texture" end - local target_name = node.bone or "" + local target_name = node.bone or node.name or "" local lineset = linesets[target_name] if not lineset then lineset = { @@ -86,16 +100,20 @@ local function parse_track(root) linesets[target_name] = lineset end + local channel = action_to_channel[tag] + if not channel then + error("unknown directive " .. tag:escape()) + end local line = { axis = node.by and ("xyz"):find(node.by) or "", - channel = action_to_channel[tag] + channel = channel } if node.func then line.expression = node.func elseif node.curve then parse_curve(line, node) else - error("not implemented") + parse_simple_frames(line, node) end table.insert(lineset.lines, line) From 8b4cfd1099810033ece6781a00f9f9b69ff8dcb3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 23 Sep 2026 22:27:12 +0300 Subject: [PATCH 2/4] disable codegen trace --- res/modules/animation.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/modules/animation.lua b/res/modules/animation.lua index e6b00e7ca..cbed8a941 100644 --- a/res/modules/animation.lua +++ b/res/modules/animation.lua @@ -49,7 +49,7 @@ local this = { INT_BEZIER = 3, INT_CUSTOM = 4, - TRACE_CODEGEN = true, + TRACE_CODEGEN = false, maths = { bezier_interpolation = bezier_interpolation From 325db431bdcf0ee563a7df0b1a5ecfd7fe71448a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 23 Sep 2026 22:36:09 +0300 Subject: [PATCH 3/4] update doc/*/vca.md --- doc/en/vca.md | 13 +++++++++++++ doc/ru/vca.md | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/doc/en/vca.md b/doc/en/vca.md index adde137f6..d8c0c238f 100644 --- a/doc/en/vca.md +++ b/doc/en/vca.md @@ -27,6 +27,7 @@ Two kinds of curve definitions are currently available, each producing a value ` - `@rotate` - rotates an object/bone - `@scale` - scales an object/bone (multiplier) - `@zoom` - camera zoom (multiplier) +- `@texture` - change of a dynamically assigned texture (see [skeleton:set_texture](scripting/ecs.md#skeleton)) ## Metadata @@ -73,6 +74,18 @@ Example for `curve bezier`: @key frame 138 value 53.00411 lx 127.067 ly 53.00411 rx 138.001 ry 53.00411 ``` +For the `texture` directive, it is simpler. Example: + +```vcd +@texture name $0 { + @key frame 0 value entities/tireman:face_0 + @key frame 24 value entities/tireman:face_1 +} +``` + +> Here, `entities/tireman` is the name of the texture atlas containing `face_*` textures. +> The texture does not necessarily have to be in an atlas. + ## Expression curves The attribute describes a function `f(t) = x`, where t is time in seconds. diff --git a/doc/ru/vca.md b/doc/ru/vca.md index 795541dc1..c4d97c2ec 100644 --- a/doc/ru/vca.md +++ b/doc/ru/vca.md @@ -27,6 +27,7 @@ VCA файл состоит из набора директив, порядок - `@rotate` - поворот объекта/кости - `@scale` - масштабирование объекта/кости (множитель) - `@zoom` - масштаб камеры (множитель) +- `@texture` - смена динамически-назначаемой текстуры (см. [skeleton:set_texture](scripting/ecs.md#skeleton)) ## Мета-информация @@ -73,6 +74,18 @@ VCA файл состоит из набора директив, порядок @key frame 138 value 53.00411 lx 127.067 ly 53.00411 rx 138.001 ry 53.00411 ``` +Для директивы texture всё проще. Пример: + +```vcd +@texture name $0 { + @key frame 0 value entities/tireman:face_0 + @key frame 24 value entities/tireman:face_1 +} +``` + +> entities/tireman здесь - имя текстурного атласа, в котором находятся face_\* текстуры. +> Текстура не обязательно должна находиться в атласе. + ## Кривые через выражения Через атрибут описывается функция `f(t) = x` где t - время в секундах. From 3de6d7f4025f310426a5111fa6ce047e190888f1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 24 Sep 2026 12:35:53 +0300 Subject: [PATCH 4/4] fix camera exponentially shaking --- src/logic/PlayerController.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 2a63f131b..891c4c086 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -104,6 +104,8 @@ void CameraControl::updateMouse(PlayerInput& input, int windowHeight) { glm::vec3 CameraControl::updateCameraShaking( const Hitbox& hitbox, float delta ) { + delta = glm::min(delta, 0.1f); + glm::vec3 offset {}; const float k = CAM_SHAKE_DELTA_K; const float ov = CAM_SHAKE_OFFSET_Y;