Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions LuaSTG/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ 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/modern/RenderTarget.hpp
LuaSTG/LuaBinding/modern/RenderTarget.cpp
LuaSTG/LuaBinding/modern/DepthStencilBuffer.hpp
Expand Down
14 changes: 9 additions & 5 deletions LuaSTG/LuaSTG/GameResource/ResourceDebug.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "GameResource/ResourceManager.h"
#ifdef USING_DEAR_IMGUI
#include "imgui.h"
#include "d3d11/VideoTexture.hpp"
#endif

static std::string bytes_count_to_string(unsigned long long size)
Expand Down Expand Up @@ -81,18 +82,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
387 changes: 195 additions & 192 deletions LuaSTG/LuaSTG/GameResource/ResourceManager.h

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions LuaSTG/LuaSTG/GameResource/ResourcePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "GameResource/Implement/ResourcePostEffectShaderImpl.hpp"
#include "GameResource/Implement/ResourceModelImpl.hpp"
#include "core/FileSystem.hpp"
#include "core/AudioEngine.hpp"
#include "d3d11/VideoTexture.hpp"
#include "AppFrame.h"
#include "lua/plus.hpp"

Expand Down Expand Up @@ -227,6 +229,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
241 changes: 241 additions & 0 deletions LuaSTG/LuaSTG/LuaBinding/LW_ResourceMgr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#include "LuaBinding/LuaWrapper.hpp"
#include "lua/plus.hpp"
#include "AppFrame.h"
#include "d3d11/VideoTexture.hpp"
#include "core/VideoDecoder.hpp"
#include "core/AudioEngine.hpp"
#include <unordered_map>
#include <unordered_set>
#include <vector>

void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
{
Expand Down Expand Up @@ -52,6 +58,45 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
return luaL_error(L, "can't load texture from file '%s'.", path);
return 0;
}
static void ReadVideoOptions(lua_State* L, int index, core::VideoOpenOptions& opt) noexcept {
if (!lua_istable(L, index)) return;
lua_getfield(L, index, "video_stream");
if (lua_isnumber(L, -1)) opt.video_stream_index = (uint32_t)lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "width");
if (lua_isnumber(L, -1)) opt.output_width = (uint32_t)lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "height");
if (lua_isnumber(L, -1)) opt.output_height = (uint32_t)lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "premultiplied_alpha");
if (lua_isboolean(L, -1)) opt.premultiplied_alpha = lua_toboolean(L, -1) != 0;
lua_pop(L, 1);
lua_getfield(L, index, "looping");
if (lua_isboolean(L, -1)) opt.looping = lua_toboolean(L, -1) != 0;
lua_pop(L, 1);
lua_getfield(L, index, "loop_end");
if (lua_isnumber(L, -1)) opt.loop_end = (double)lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "loop_duration");
if (lua_isnumber(L, -1)) opt.loop_duration = (double)lua_tonumber(L, -1);
lua_pop(L, 1);
}
static int LoadVideo(lua_State* L) noexcept
{
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;
if (lua_gettop(L) >= 3 && lua_istable(L, 3))
ReadVideoOptions(L, 3, opt);
if (!pActivedPool->LoadVideo(name, path, lua_gettop(L) >= 3 && lua_istable(L, 3) ? &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 @@ -671,13 +716,198 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
LRES.CacheTTFFontString(luaL_checkstring(L, 1), str, len);
return 0;
}

// 视频控制函数
static core::IVideoDecoder* GetVideoDecoder(const char* name) noexcept {
auto tex = LRES.FindTexture(name);
if (!tex) return nullptr;

auto texture2d = tex->GetTexture();
if (!texture2d) return nullptr;

// 尝试转换为VideoTexture
auto video_texture = dynamic_cast<core::VideoTexture*>(texture2d);
if (!video_texture) return nullptr;

return video_texture->getVideoDecoder();
}

static int VideoSeek(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
double time = luaL_checknumber(L, 2);
auto tex = LRES.FindTexture(name);
if (!tex)
return luaL_error(L, "video texture '%s' not found.", name);
auto* vt = dynamic_cast<core::VideoTexture*>(tex->GetTexture());
if (!vt)
return luaL_error(L, "texture '%s' is not a video texture.", name);
auto* decoder = vt->getVideoDecoder();
if (!decoder)
return luaL_error(L, "video texture '%s' has no video decoder.", name);
bool ok = decoder->seek(time);
lua_pushboolean(L, ok);
return 1;
}

static int VideoSetLooping(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
bool loop = lua_toboolean(L, 2) != 0;
auto decoder = GetVideoDecoder(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 = GetVideoDecoder(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 {
const char* name = luaL_checkstring(L, 1);
double time = luaL_checknumber(L, 2);
auto tex = LRES.FindTexture(name);
if (!tex)
return luaL_error(L, "video texture '%s' not found.", name);
auto* vt = dynamic_cast<core::VideoTexture*>(tex->GetTexture());
if (!vt)
return luaL_error(L, "texture '%s' is not a video texture.", name);
auto* decoder = vt->getVideoDecoder();
if (!decoder)
return luaL_error(L, "video texture '%s' has no video decoder.", name);
bool ok = decoder->updateToTime(time);
lua_pushboolean(L, ok);
return 1;
}
static int VideoGetInfo(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = GetVideoDecoder(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);

lua_createtable(L, 0, 8);

lua_pushnumber(L, decoder->getDuration());
lua_setfield(L, -2, "duration");

lua_pushnumber(L, decoder->getCurrentTime());
lua_setfield(L, -2, "time");

lua_pushboolean(L, decoder->isLooping());
lua_setfield(L, -2, "looping");

double loop_end = 0.0, loop_duration = 0.0;
decoder->getLoopRange(&loop_end, &loop_duration);
lua_pushnumber(L, loop_end);
lua_setfield(L, -2, "loop_end");
lua_pushnumber(L, loop_duration);
lua_setfield(L, -2, "loop_duration");

auto size = decoder->getVideoSize();
lua_pushinteger(L, size.x);
lua_setfield(L, -2, "width");

lua_pushinteger(L, size.y);
lua_setfield(L, -2, "height");

lua_pushinteger(L, (lua_Integer)decoder->getVideoStreamIndex());
lua_setfield(L, -2, "video_stream");

double fi = decoder->getFrameInterval();
lua_pushnumber(L, fi);
lua_setfield(L, -2, "frame_interval");
if (fi > 0.0) {
lua_pushnumber(L, 1.0 / fi);
lua_setfield(L, -2, "fps");
}
return 1;
}
static int VideoGetVideoStreams(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = GetVideoDecoder(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
std::vector<core::VideoStreamInfo> list;
auto cb = [](core::VideoStreamInfo const& info, void* ud) {
static_cast<std::vector<core::VideoStreamInfo>*>(ud)->push_back(info);
};
decoder->getVideoStreams(cb, &list);
lua_createtable(L, (int)list.size(), 0);
for (size_t i = 0; i < list.size(); ++i) {
lua_createtable(L, 0, 5);
lua_pushinteger(L, (lua_Integer)list[i].index);
lua_setfield(L, -2, "index");
lua_pushinteger(L, (lua_Integer)list[i].width);
lua_setfield(L, -2, "width");
lua_pushinteger(L, (lua_Integer)list[i].height);
lua_setfield(L, -2, "height");
lua_pushnumber(L, list[i].fps);
lua_setfield(L, -2, "fps");
lua_pushnumber(L, list[i].duration_seconds);
lua_setfield(L, -2, "duration");
lua_rawseti(L, -2, (int)i + 1);
}
return 1;
}
static int VideoGetAudioStreams(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto decoder = GetVideoDecoder(name);
if (!decoder)
return luaL_error(L, "video texture '%s' not found.", name);
std::vector<core::AudioStreamInfo> list;
auto cb = [](core::AudioStreamInfo const& info, void* ud) {
static_cast<std::vector<core::AudioStreamInfo>*>(ud)->push_back(info);
};
decoder->getAudioStreams(cb, &list);
lua_createtable(L, (int)list.size(), 0);
for (size_t i = 0; i < list.size(); ++i) {
lua_createtable(L, 0, 4);
lua_pushinteger(L, (lua_Integer)list[i].index);
lua_setfield(L, -2, "index");
lua_pushinteger(L, (lua_Integer)list[i].channels);
lua_setfield(L, -2, "channels");
lua_pushinteger(L, (lua_Integer)list[i].sample_rate);
lua_setfield(L, -2, "sample_rate");
lua_pushnumber(L, list[i].duration_seconds);
lua_setfield(L, -2, "duration");
lua_rawseti(L, -2, (int)i + 1);
}
return 1;
}
static int VideoReopen(lua_State* L) noexcept {
const char* name = luaL_checkstring(L, 1);
auto tex = LRES.FindTexture(name);
if (!tex)
return luaL_error(L, "texture '%s' not found.", name);
auto* vt = dynamic_cast<core::VideoTexture*>(tex->GetTexture());
if (!vt)
return luaL_error(L, "texture '%s' is not a video texture.", name);
core::IVideoDecoder* dec = vt->getVideoDecoder();
if (!dec)
return luaL_error(L, "texture '%s' does not have a valid video decoder.", name);
core::VideoOpenOptions opt = dec->getLastOpenOptions();
if (lua_gettop(L) >= 2 && lua_istable(L, 2))
ReadVideoOptions(L, 2, opt);
if (!dec->reopen(opt)) {
lua_pushboolean(L, false);
return 1;
}
lua_pushboolean(L, 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 },
{ "LoadAnimation", &Wrapper::LoadAnimation },
{ "LoadPS", &Wrapper::LoadPS },
Expand Down Expand Up @@ -710,6 +940,17 @@ void luastg::binding::ResourceManager::Register(lua_State* L) noexcept
{ "SetFontState", &Wrapper::SetFontState },

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

// 视频控制函数
{ "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
Loading