Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3328b32
feat: 添加视频纹理支持及相关功能
BAKAOLC Feb 20, 2026
d429671
feat: enhance video texture support with memory stream handling and r…
BAKAOLC Feb 21, 2026
6abbc68
feat: add D3D11 video decoding support and multithreading enhancements
BAKAOLC Feb 21, 2026
132dffb
refactor: remove video support flag from D3D11 device creation
BAKAOLC Feb 22, 2026
a78e11a
feat: enhance video decoding with frame rate handling and dynamic tol…
BAKAOLC Feb 22, 2026
8178663
feat: add frame interval and fps calculation to video resource manage…
BAKAOLC Feb 22, 2026
a3e929b
feat: enhance video resource management with flexible loading options…
BAKAOLC Feb 22, 2026
d11f94e
feat: improve video decoding by adding resolution retry logic and adj…
BAKAOLC Feb 22, 2026
654caa9
docs: update video loading example to simplify options description
BAKAOLC Feb 22, 2026
9d76903
feat(video): add Lua bindings for video playback and stream management
BAKAOLC Feb 22, 2026
80abe38
feat(video): add null checks and refactor video options parsing
BAKAOLC Feb 22, 2026
1b01a54
feat(video): update hardware video decode configuration and frame rat…
BAKAOLC Feb 25, 2026
05cae60
feat(video): remove Chinese comments and refactor error handling
BAKAOLC Feb 26, 2026
a800bbd
feat(video): extract video binding helpers and refactor decoder access
BAKAOLC Feb 26, 2026
bf6a101
feat(video): replace custom PropVariantGuard with WIL unique_prop_var…
BAKAOLC Feb 27, 2026
dc7f566
feat(video): refactor Lua bindings to use lua::plus stack API
BAKAOLC Feb 27, 2026
1897a71
feat(video): simplify type casting and remove unused pragma directives
BAKAOLC Feb 27, 2026
882f838
feat(video): simplify Lua binding table creation and remove unused in…
BAKAOLC Feb 27, 2026
13c4ca2
feat(resource): add video texture detection to resource interface
BAKAOLC Feb 27, 2026
69d13bd
docs(video): add video API documentation and type definitions
BAKAOLC Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions LuaSTG/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ set(LUASTG_ENGINE_SOURCES
LuaSTG/LuaBinding/modern/SwapChain.cpp
LuaSTG/LuaBinding/modern/Texture2D.hpp
LuaSTG/LuaBinding/modern/Texture2D.cpp
LuaSTG/LuaBinding/modern/Video.hpp
LuaSTG/LuaBinding/modern/Video.cpp
LuaSTG/LuaBinding/VideoBindingHelpers.hpp
LuaSTG/LuaBinding/VideoBindingHelpers.cpp
LuaSTG/LuaBinding/modern/RenderTarget.hpp
LuaSTG/LuaBinding/modern/RenderTarget.cpp
LuaSTG/LuaBinding/modern/DepthStencilBuffer.hpp
Expand Down
2 changes: 2 additions & 0 deletions LuaSTG/LuaSTG/GameResource/Implement/ResourceTextureImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace luastg
core::IRenderTarget* GetRenderTarget() { return m_rt.get(); }
core::IDepthStencilBuffer* GetDepthStencilBuffer() { return m_ds.get(); }
bool IsRenderTarget() { return m_is_rendertarget; }
bool IsVideoTexture() { return m_texture && m_texture->isVideoTexture(); }
bool HasDepthStencilBuffer() { return m_enable_depthbuffer; }
public:
// 纹理容器
Expand All @@ -47,6 +48,7 @@ namespace luastg
core::IRenderTarget* GetRenderTarget() override { return m_rt.get(); }
core::IDepthStencilBuffer* GetDepthStencilBuffer() override { return m_ds.get(); }
bool IsRenderTarget() override { return true; }
bool IsVideoTexture() override { return false; }
bool HasDepthStencilBuffer() override { return !!m_ds; }

// RenderTargetStackResourceTextureImpl
Expand Down
13 changes: 8 additions & 5 deletions LuaSTG/LuaSTG/GameResource/ResourceDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,21 @@ namespace luastg
};
auto draw_texture = [](IResourceTexture* p_res, bool show_info, float scale) -> void
{
auto const size = p_res->GetTexture()->getSize();
auto* p_tex = p_res->GetTexture();
auto const size = p_tex->getSize();
if (show_info)
{
ImGui::Text("Size: %u x %u", size.x, size.y);
ImGui::Text("RenderTarget: %s", p_res->IsRenderTarget() ? "Yes" : "Not");
ImGui::Text("Dynamic: %s", p_res->IsRenderTarget() ? "Yes" : "Not");
unsigned long long mem_usage = size.x * size.y * 4;
char const* type_str = p_tex->isVideoTexture() ? "Video" : (p_res->IsRenderTarget() ? "RenderTarget" : "Texture");
ImGui::Text("Type: %s", type_str);
ImGui::Text("Dynamic: %s", p_tex->isDynamic() ? "Yes" : "Not");
unsigned long long display_mem = (unsigned long long)size.x * size.y * 4;
unsigned long long mem_usage = display_mem;
ImGui::Text("Adapter Memory Usage (Approximate): %s", bytes_count_to_string(mem_usage).c_str());
}
ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, 1.0);
ImGui::Image(
reinterpret_cast<size_t>(p_res->GetTexture()->getNativeView()),
reinterpret_cast<size_t>(p_tex->getNativeView()),
ImVec2(scale * (float)size.x, scale * (float)size.y),
ImVec2(0.0f, 0.0f),
ImVec2(1.0f, 1.0f));
Expand Down
3 changes: 3 additions & 0 deletions LuaSTG/LuaSTG/GameResource/ResourceManager.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "core/SmartReference.hpp"
#include "core/VideoDecoder.hpp"
#include "GameResource/ResourceTexture.hpp"
#include "GameResource/ResourceSprite.hpp"
#include "GameResource/ResourceAnimation.hpp"
Expand Down Expand Up @@ -98,6 +99,8 @@ namespace luastg
// 纹理
bool LoadTexture(const char* name, const char* path, bool mipmaps = true) noexcept;
bool CreateTexture(const char* name, int width, int height) noexcept;
// 视频纹理(options 为 nullptr 时使用默认选项)
bool LoadVideo(const char* name, const char* path, core::VideoOpenOptions const* options = nullptr) noexcept;
// 渲染目标
bool CreateRenderTarget(const char* name, int width = 0, int height = 0, bool depth_buffer = false) noexcept;
// 图片精灵
Expand Down
42 changes: 42 additions & 0 deletions LuaSTG/LuaSTG/GameResource/ResourcePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "GameResource/Implement/ResourcePostEffectShaderImpl.hpp"
#include "GameResource/Implement/ResourceModelImpl.hpp"
#include "core/FileSystem.hpp"
#include "core/AudioEngine.hpp"
#include "AppFrame.h"
#include "lua/plus.hpp"

Expand Down Expand Up @@ -227,6 +228,47 @@ namespace luastg
return true;
}

bool ResourcePool::LoadVideo(const char* name, const char* path, core::VideoOpenOptions const* options) noexcept
{
if (m_TexturePool.find(std::string_view(name)) != m_TexturePool.end())
{
if (ResourceMgr::GetResourceLoadingLog())
{
spdlog::warn("[luastg] LoadVideo: 纹理 '{}' 已存在,加载操作已取消", name);
}
return true;
}

core::SmartReference<core::ITexture2D> p_texture;
bool ok = options
? LAPP.getGraphicsDevice()->createVideoTexture(path, *options, p_texture.put())
: LAPP.getGraphicsDevice()->createVideoTexture(path, p_texture.put());
if (!ok)
{
spdlog::error("[luastg] 从 '{}' 创建视频纹理 '{}' 失败", path, name);
return false;
}

try
{
core::SmartReference<IResourceTexture> tRes;
tRes.attach(new ResourceTextureImpl(name, p_texture.get()));
m_TexturePool.emplace(name, tRes);
}
catch (std::exception const& e)
{
spdlog::error("[luastg] LoadVideo: 创建视频纹理 '{}' 失败 ({})", name, e.what());
return false;
}

if (ResourceMgr::GetResourceLoadingLog())
{
spdlog::info("[luastg] LoadVideo: 已从 '{}' 加载视频 '{}' ({})", path, name, getResourcePoolTypeName());
}

return true;
}

bool ResourcePool::CreateTexture(const char* name, int width, int height) noexcept
{
if (m_TexturePool.find(std::string_view(name)) != m_TexturePool.end())
Expand Down
1 change: 1 addition & 0 deletions LuaSTG/LuaSTG/GameResource/ResourceTexture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace luastg
virtual core::IRenderTarget* GetRenderTarget() = 0;
virtual core::IDepthStencilBuffer* GetDepthStencilBuffer() = 0;
virtual bool IsRenderTarget() = 0;
virtual bool IsVideoTexture() = 0;
virtual bool HasDepthStencilBuffer() = 0;
};
};
Expand Down
135 changes: 135 additions & 0 deletions LuaSTG/LuaSTG/LuaBinding/LW_ResourceMgr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "LuaBinding/LuaWrapper.hpp"
#include "LuaBinding/VideoBindingHelpers.hpp"
#include "lua/plus.hpp"
#include "AppFrame.h"
#include "d3d11/VideoTexture.hpp"
#include "core/VideoDecoder.hpp"

void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
{
Expand Down Expand Up @@ -52,6 +55,25 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
return luaL_error(L, "can't load texture from file '%s'.", path);
return 0;
}
static int LoadVideo(lua_State* L) noexcept
{
lua::stack_t const ctx(L);
const char* name = luaL_checkstring(L, 1);
const char* path = luaL_checkstring(L, 2);

ResourcePool* pActivedPool = LRES.GetActivedPool();
if (!pActivedPool)
return luaL_error(L, "can't load resource at this time.");

core::VideoOpenOptions opt;
bool const has_options = ctx.index_of_top() >= 3 && ctx.is_table(3);
if (has_options)
video::parseVideoOptions(L, 3, opt);

if (!pActivedPool->LoadVideo(name, path, has_options ? &opt : nullptr))
return luaL_error(L, "can't load video from file '%s'.", path);
return 0;
}
static int LoadSprite(lua_State* L) noexcept
{
const char* name = luaL_checkstring(L, 1);
Expand Down Expand Up @@ -414,6 +436,14 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
lua_pushboolean(L, p->IsRenderTarget());
return 1;
}
static int IsVideoTexture(lua_State* L) noexcept
{
core::SmartReference<IResourceTexture> p = LRES.FindTexture(luaL_checkstring(L, 1));
if (!p)
return luaL_error(L, "texture '%s' not found.", luaL_checkstring(L, 1));
lua_pushboolean(L, p->IsVideoTexture());
return 1;
}
static int SetTexturePreMulAlphaState(lua_State* L) noexcept
{
core::SmartReference<IResourceTexture> p = LRES.FindTexture(luaL_checkstring(L, 1));
Expand Down Expand Up @@ -696,13 +726,106 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
LRES.CacheTTFFontString(luaL_checkstring(L, 1), str, len);
return 0;
}

// Video control functions

static int VideoSeek(lua_State* L) noexcept {
lua::stack_t const ctx(L);
const char* name = luaL_checkstring(L, 1);
double time = luaL_checknumber(L, 2);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found or is not a video texture.", name);
bool ok = decoder->seek(time);
ctx.push_value(ok);
return 1;
}

static int VideoSetLooping(lua_State* L) noexcept {
lua::stack_t const ctx(L);
const char* name = luaL_checkstring(L, 1);
bool loop = ctx.get_value<bool>(2);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
decoder->setLooping(loop);
return 0;
}

static int VideoSetLoopRange(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
double loop_end = luaL_checknumber(L, 2);
double loop_duration = luaL_checknumber(L, 3);
decoder->setLoopRange(loop_end, loop_duration);
return 0;
}

static int VideoUpdate(lua_State* L) noexcept {
lua::stack_t const ctx(L);
const char* name = luaL_checkstring(L, 1);
double time = luaL_checknumber(L, 2);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found or is not a video texture.", name);
bool ok = decoder->updateToTime(time);
ctx.push_value(ok);
return 1;
}

static int VideoGetInfo(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
video::pushVideoInfoToLua(L, decoder);
return 1;
}

static int VideoGetVideoStreams(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
video::pushVideoStreamsToLua(L, decoder);
return 1;
}

static int VideoGetAudioStreams(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
video::pushAudioStreamsToLua(L, decoder);
return 1;
}

static int VideoReopen(lua_State* L) noexcept {
lua::stack_t const ctx(L);
const char* name = luaL_checkstring(L, 1);
auto decoder = video::getDecoderFromResourceName(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found or is not a video texture.", name);
core::VideoOpenOptions opt = decoder->getLastOpenOptions();
if (ctx.index_of_top() >= 2 && ctx.is_table(2))
video::parseVideoOptions(L, 2, opt);
if (!decoder->reopen(opt)) {
ctx.push_value(false);
return 1;
}
ctx.push_value(true);
return 1;
}
};

luaL_Reg const lib[] = {
{ "SetResLoadInfo", &Wrapper::SetResLoadInfo },
{ "SetResourceStatus", &Wrapper::SetResourceStatus },
{ "GetResourceStatus", &Wrapper::GetResourceStatus },
{ "LoadTexture", &Wrapper::LoadTexture },
{ "LoadVideo", &Wrapper::LoadVideo },
{ "LoadImage", &Wrapper::LoadSprite },
{ "CopyImage", &Wrapper::CopySprite },
{ "LoadAnimation", &Wrapper::LoadAnimation },
Expand All @@ -716,6 +839,7 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
{ "LoadModel", &Wrapper::LoadModel },
{ "CreateRenderTarget", &Wrapper::CreateRenderTarget },
{ "IsRenderTarget", &Wrapper::IsRenderTarget },
{ "IsVideoTexture", &Wrapper::IsVideoTexture },
{ "SetTexturePreMulAlphaState", &Wrapper::SetTexturePreMulAlphaState },
{ "SetTextureSamplerState", &Wrapper::SetTextureSamplerState },
{ "GetTextureSize", &Wrapper::GetTextureSize },
Expand All @@ -737,6 +861,17 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
{ "SetFontState", &Wrapper::SetFontState },

{ "CacheTTFString", &Wrapper::CacheTTFString },

// Video control functions
{ "VideoSeek", &Wrapper::VideoSeek },
{ "VideoSetLooping", &Wrapper::VideoSetLooping },
{ "VideoSetLoopRange", &Wrapper::VideoSetLoopRange },
{ "VideoUpdate", &Wrapper::VideoUpdate },
{ "VideoGetInfo", &Wrapper::VideoGetInfo },
{ "VideoGetVideoStreams", &Wrapper::VideoGetVideoStreams },
{ "VideoGetAudioStreams", &Wrapper::VideoGetAudioStreams },
{ "VideoReopen", &Wrapper::VideoReopen },

{ NULL, NULL },
};

Expand Down
2 changes: 2 additions & 0 deletions LuaSTG/LuaSTG/LuaBinding/LuaWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "LuaBinding/modern/Window.hpp"
#include "LuaBinding/modern/SwapChain.hpp"
#include "LuaBinding/modern/Texture2D.hpp"
#include "LuaBinding/modern/Video.hpp"
#include "LuaBinding/modern/RenderTarget.hpp"
#include "LuaBinding/modern/DepthStencilBuffer.hpp"
#include "LuaBinding/modern/Mesh.hpp"
Expand Down Expand Up @@ -82,6 +83,7 @@ namespace luastg::binding
Window_Windows11Extension::registerClass(L);
SwapChain::registerClass(L);
Texture2D::registerClass(L);
Video::registerClass(L);
RenderTarget::registerClass(L);
DepthStencilBuffer::registerClass(L);
Mesh::registerClass(L);
Expand Down
18 changes: 18 additions & 0 deletions LuaSTG/LuaSTG/LuaBinding/VideoBindingHelpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "VideoBindingHelpers.hpp"
#include "AppFrame.h"

namespace luastg::binding::video {
core::IVideoDecoder* getDecoderFromResourceName(const char* name) noexcept {
auto texture = LRES.FindTexture(name);
if (!texture) {
return nullptr;
}

auto texture2d = texture->GetTexture();
if (!texture2d) {
return nullptr;
}

return getDecoderFromTexture(texture2d);
}
}
Loading