feat: add device-side subtitle overlay using FreeType for rendering Chinese text

- Updated Cargo.toml to include freetype-rs for font rendering.
- Modified message.rs to introduce a new Message variant for subtitles.
- Enhanced HttpPlugin to send subtitle messages to the live2d plugin.
- Implemented text rendering in the live2d plugin using FreeType for Chinese characters.
- Added OpenGL shaders for rendering text overlays.
- Created a new text.rs module for handling text rasterization and texture rendering.
- Updated renderer.rs to integrate subtitle rendering logic.
This commit is contained in:
2026-07-09 09:15:23 +08:00
parent 9e31aee42d
commit 7cb8cee70d
10 changed files with 717 additions and 14 deletions

View File

@@ -9,10 +9,11 @@ use crate::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
use anyhow::{Context, Result};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
use std::time::{Duration, Instant};
use super::renderer::Live2DRenderer;
use super::renderer::{Live2DRenderer, Subtitle, SubtitleState};
pub struct Live2DPlugin {
ctx: Option<PluginContext>,
@@ -21,6 +22,8 @@ pub struct Live2DPlugin {
worker: Option<JoinHandle<()>>,
/// 渲染停止信号
stop_flag: Arc<AtomicBool>,
/// 字幕共享状态http 插件写入,渲染线程读取)
subtitle: SubtitleState,
}
impl Live2DPlugin {
@@ -30,6 +33,7 @@ impl Live2DPlugin {
renderer: None,
worker: None,
stop_flag: Arc::new(AtomicBool::new(false)),
subtitle: Arc::new(Mutex::new(None)),
}
}
}
@@ -97,6 +101,16 @@ impl Plugin for Live2DPlugin {
Message::Shutdown => {
self.stop_live2d();
}
Message::Subtitle { text } => {
// 设备端字幕:写入共享状态,渲染线程每帧读取,超时自动消失
let ttl = Duration::from_millis(
(text.chars().count().max(1) as u64)
.saturating_mul(220)
.saturating_add(2500),
);
*self.subtitle.lock().unwrap() =
Some(Subtitle { text, expires_at: Instant::now() + ttl });
}
_ => {}
}
Ok(())
@@ -139,7 +153,14 @@ impl Live2DPlugin {
.clone();
let renderer = Arc::new(std::sync::Mutex::new(
Live2DRenderer::new(&core_so, &live2d_base, &model_rel, width, height)?,
Live2DRenderer::new(
&core_so,
&live2d_base,
&model_rel,
width,
height,
Arc::clone(&self.subtitle),
)?,
));
self.renderer = Some(Arc::clone(&renderer));