Refactor Live2D plugin and renderer for improved clarity and performance
- Updated EGL and OpenGL ES integration in gl.rs for better context management. - Simplified error handling and logging in model.rs and plugin.rs. - Enhanced texture handling and rendering logic in renderer.rs. - Added a script to find Cargo configuration files for easier debugging. - Removed unused imports and dead code to clean up the codebase.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd /home/showen/Showen/ShowenV2
|
cd /home/showen/Showen/ShowenV2
|
||||||
export PATH=/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:$PATH
|
export PATH=/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:$PATH
|
||||||
cargo check 2>&1 | tail -80
|
cargo check 2>&1 | grep -E "^error" | head -60
|
||||||
echo "EXIT=$?"
|
echo "---SUMMARY---"
|
||||||
|
cargo check 2>&1 | tail -3
|
||||||
|
|||||||
16
.find_cargo.sh
Normal file
16
.find_cargo.sh
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "=== find cargo config ==="
|
||||||
|
find /home/showen -name "config.toml" -path "*.cargo*" 2>/dev/null
|
||||||
|
find /home/showen -name "config" -path "*.cargo*" 2>/dev/null
|
||||||
|
find / -name "config.toml" -path "*cargo*" 2>/dev/null | head -5
|
||||||
|
|
||||||
|
echo "=== check .cargo dir ==="
|
||||||
|
ls -la /home/showen/.cargo/ 2>/dev/null
|
||||||
|
|
||||||
|
echo "=== rustup cargo home ==="
|
||||||
|
echo $CARGO_HOME
|
||||||
|
ls -la ~/.cargo/ 2>/dev/null
|
||||||
|
|
||||||
|
echo "=== project cargo ==="
|
||||||
|
ls -la /home/showen/Showen/ShowenV2/.cargo/ 2>/dev/null
|
||||||
|
find /home/showen/Showen -name ".cargo" -type d 2>/dev/null
|
||||||
@@ -85,39 +85,39 @@ impl AnimationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_blink(&mut self, now: Instant, core: &CubismCore, model: &CubismModel) {
|
fn update_blink(&mut self, now: Instant, core: &CubismCore, model: &CubismModel) {
|
||||||
match &mut self.blink_phase {
|
// 先计算新的眨眼状态和当前 eye_open 值,避免借用冲突
|
||||||
|
let (new_phase, eye_open) = match self.blink_phase {
|
||||||
BlinkPhase::Idle => {
|
BlinkPhase::Idle => {
|
||||||
if now.duration_since(self.last_blink) >= self.next_blink_interval {
|
if now.duration_since(self.last_blink) >= self.next_blink_interval {
|
||||||
self.blink_phase = BlinkPhase::Closing(0.0);
|
(BlinkPhase::Closing(0.0), 1.0)
|
||||||
|
} else {
|
||||||
|
(BlinkPhase::Idle, 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlinkPhase::Closing(mut t) => {
|
||||||
|
t += 0.15;
|
||||||
|
if t >= 1.0 {
|
||||||
|
(BlinkPhase::Opening(1.0), 0.0)
|
||||||
|
} else {
|
||||||
|
(BlinkPhase::Closing(t), 1.0 - t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlinkPhase::Opening(mut t) => {
|
||||||
|
t -= 0.1;
|
||||||
|
if t <= 0.0 {
|
||||||
self.last_blink = now;
|
self.last_blink = now;
|
||||||
}
|
|
||||||
}
|
|
||||||
BlinkPhase::Closing(t) => {
|
|
||||||
*t += 0.15; // 闭眼速度
|
|
||||||
if *t >= 1.0 {
|
|
||||||
*t = 1.0;
|
|
||||||
self.blink_phase = BlinkPhase::Opening(1.0);
|
|
||||||
}
|
|
||||||
let eye_open = 1.0 - *t;
|
|
||||||
model.set_param(core, "ParamEyeLOpen", eye_open);
|
|
||||||
model.set_param(core, "ParamEyeROpen", eye_open);
|
|
||||||
}
|
|
||||||
BlinkPhase::Opening(t) => {
|
|
||||||
*t -= 0.1; // 睁眼速度(比闭眼慢)
|
|
||||||
if *t <= 0.0 {
|
|
||||||
*t = 0.0;
|
|
||||||
self.blink_phase = BlinkPhase::Idle;
|
|
||||||
self.last_blink = now;
|
|
||||||
// 下次眨眼间隔(2-5 秒随机)
|
|
||||||
self.next_blink_interval =
|
self.next_blink_interval =
|
||||||
Duration::from_secs(2 + (now.elapsed().as_nanos() % 3) as u64);
|
Duration::from_secs(2 + (now.elapsed().as_nanos() % 3) as u64);
|
||||||
|
(BlinkPhase::Idle, 1.0)
|
||||||
|
} else {
|
||||||
|
(BlinkPhase::Opening(t), 1.0 - t)
|
||||||
}
|
}
|
||||||
let eye_open = 1.0 - *t;
|
}
|
||||||
|
};
|
||||||
|
self.blink_phase = new_phase;
|
||||||
model.set_param(core, "ParamEyeLOpen", eye_open);
|
model.set_param(core, "ParamEyeLOpen", eye_open);
|
||||||
model.set_param(core, "ParamEyeROpen", eye_open);
|
model.set_param(core, "ParamEyeROpen", eye_open);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_mouth(
|
fn update_mouth(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
//! 动态加载 libLive2DCubismCore.so(需 libm.so 预加载,因 Core 内部使用 powf)。
|
//! 动态加载 libLive2DCubismCore.so(需 libm.so 预加载,因 Core 内部使用 powf)。
|
||||||
|
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_void};
|
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_void};
|
||||||
|
|
||||||
/// moc 对齐要求(字节)
|
/// moc 对齐要求(字节)
|
||||||
@@ -268,9 +267,3 @@ unsafe fn libc_strlen(ptr: *const c_char) -> usize {
|
|||||||
}
|
}
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保留 CString 防止 unused 警告(未来日志函数需要)
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn _ensure_cstring_linked() -> CString {
|
|
||||||
CString::new("").unwrap()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,39 +1,27 @@
|
|||||||
//! OpenGL ES 2.0 / EGL 渲染后端
|
//! OpenGL ES 2.0 / EGL 渲染后端
|
||||||
//!
|
//!
|
||||||
//! 使用 EGL 创建离屏 PBuffer 上下文(无窗口),用 OpenGL ES 2.0 渲染 Live2D 模型。
|
//! 使用 EGL + X11 窗口创建渲染上下文,用 OpenGL ES 2.0 渲染 Live2D 模型。
|
||||||
//! 渲染结果通过 glReadPixels 读取,交给 video 插件或直接显示。
|
|
||||||
//!
|
|
||||||
//! 这里采用 X11 窗口方式渲染(设备有 X11 + kwin),直接显示到屏幕。
|
|
||||||
//! 如需离屏渲染可改为 PBuffer。
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::os::raw::{c_char, c_int, c_uint, c_void as c_void_raw};
|
use std::os::raw::{c_char, c_int, c_long, c_uint, c_void as c_void_raw};
|
||||||
|
|
||||||
// ============ EGL 类型与常量 ============
|
// ============ EGL ============
|
||||||
|
|
||||||
pub mod egl {
|
pub mod egl {
|
||||||
pub const EGL_VERSION_1_5: c_int = 1;
|
use std::os::raw::{c_int, c_uint, c_void};
|
||||||
|
|
||||||
pub const EGL_SURFACE_TYPE: c_int = 0x3033;
|
pub const EGL_SURFACE_TYPE: c_int = 0x3033;
|
||||||
pub const EGL_WINDOW_BIT: c_int = 0x0004;
|
pub const EGL_WINDOW_BIT: c_int = 0x0004;
|
||||||
pub const EGL_PBUFFER_BIT: c_int = 0x0001;
|
|
||||||
pub const EGL_BLUE_SIZE: c_int = 0x3022;
|
pub const EGL_BLUE_SIZE: c_int = 0x3022;
|
||||||
pub const EGL_GREEN_SIZE: c_int = 0x3023;
|
pub const EGL_GREEN_SIZE: c_int = 0x3023;
|
||||||
pub const EGL_RED_SIZE: c_int = 0x3024;
|
pub const EGL_RED_SIZE: c_int = 0x3024;
|
||||||
pub const EGL_DEPTH_SIZE: c_int = 0x3025;
|
|
||||||
pub const EGL_ALPHA_SIZE: c_int = 0x3021;
|
pub const EGL_ALPHA_SIZE: c_int = 0x3021;
|
||||||
pub const EGL_STENCIL_SIZE: c_int = 0x3026;
|
|
||||||
pub const EGL_RENDERABLE_TYPE: c_int = 0x3040;
|
pub const EGL_RENDERABLE_TYPE: c_int = 0x3040;
|
||||||
pub const EGL_OPENGL_ES2_BIT: c_int = 0x0004;
|
pub const EGL_OPENGL_ES2_BIT: c_int = 0x0004;
|
||||||
pub const EGL_NONE: c_int = 0x3038;
|
pub const EGL_NONE: c_int = 0x3038;
|
||||||
pub const EGL_CONTEXT_CLIENT_VERSION: c_int = 0x3098;
|
pub const EGL_CONTEXT_CLIENT_VERSION: c_int = 0x3098;
|
||||||
|
|
||||||
pub const EGL_DISPLAY: usize = 0;
|
|
||||||
pub const EGL_NO_DISPLAY: isize = 0;
|
|
||||||
pub const EGL_NO_CONTEXT: isize = 0;
|
|
||||||
pub const EGL_NO_SURFACE: isize = 0;
|
|
||||||
|
|
||||||
pub type EGLDisplay = *mut c_void;
|
pub type EGLDisplay = *mut c_void;
|
||||||
pub type EGLConfig = *mut c_void;
|
pub type EGLConfig = *mut c_void;
|
||||||
pub type EGLContext = *mut c_void;
|
pub type EGLContext = *mut c_void;
|
||||||
@@ -42,16 +30,20 @@ pub mod egl {
|
|||||||
pub type NativeWindowType = *mut c_void;
|
pub type NativeWindowType = *mut c_void;
|
||||||
pub type EGLBoolean = c_uint;
|
pub type EGLBoolean = c_uint;
|
||||||
pub type EGLint = c_int;
|
pub type EGLint = c_int;
|
||||||
|
|
||||||
|
/// EGL_DEFAULT_DISPLAY(即 NULL)
|
||||||
|
pub fn default_display() -> NativeDisplayType {
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ X11 类型 ============
|
// ============ X11 ============
|
||||||
|
|
||||||
pub mod x11 {
|
pub mod x11 {
|
||||||
use std::os::raw::{c_long, c_uint, c_void};
|
use std::os::raw::{c_int, c_long, c_uint, c_void};
|
||||||
|
|
||||||
pub type Display = c_void;
|
pub type Display = c_void;
|
||||||
pub type Window = c_long;
|
pub type Window = c_long;
|
||||||
pub type XID = c_long;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct XSetWindowAttributes {
|
pub struct XSetWindowAttributes {
|
||||||
@@ -76,10 +68,9 @@ pub mod x11 {
|
|||||||
pub const CWEventMask: c_long = 1 << 11;
|
pub const CWEventMask: c_long = 1 << 11;
|
||||||
pub const ExposureMask: c_long = 1 << 15;
|
pub const ExposureMask: c_long = 1 << 15;
|
||||||
pub const StructureNotifyMask: c_long = 1 << 17;
|
pub const StructureNotifyMask: c_long = 1 << 17;
|
||||||
pub const KeyPressMask: c_long = 1 << 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ GLES2 类型与常量 ============
|
// ============ GLES2 ============
|
||||||
|
|
||||||
pub mod gl {
|
pub mod gl {
|
||||||
use std::os::raw::{c_int, c_uint};
|
use std::os::raw::{c_int, c_uint};
|
||||||
@@ -89,57 +80,42 @@ pub mod gl {
|
|||||||
pub type GLint = c_int;
|
pub type GLint = c_int;
|
||||||
pub type GLsizei = c_int;
|
pub type GLsizei = c_int;
|
||||||
pub type GLbitfield = c_uint;
|
pub type GLbitfield = c_uint;
|
||||||
pub type GLfloat = f32;
|
|
||||||
|
|
||||||
pub const GL_FLOAT: GLenum = 0x1406;
|
pub const GL_FLOAT: GLenum = 0x1406;
|
||||||
pub const GL_FLOAT_VEC2: GLenum = 0x8B50;
|
|
||||||
pub const GL_FLOAT_VEC4: GLenum = 0x8B52;
|
|
||||||
pub const GL_FLOAT_MAT4: GLenum = 0x8B5C;
|
|
||||||
pub const GL_SAMPLER_2D: GLenum = 0x8B5E;
|
|
||||||
|
|
||||||
pub const GL_ARRAY_BUFFER: GLenum = 0x8892;
|
pub const GL_ARRAY_BUFFER: GLenum = 0x8892;
|
||||||
pub const GL_ELEMENT_ARRAY_BUFFER: GLenum = 0x8893;
|
pub const GL_ELEMENT_ARRAY_BUFFER: GLenum = 0x8893;
|
||||||
|
|
||||||
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
||||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||||
pub const GL_RGBA: GLenum = 0x1908;
|
pub const GL_RGBA: GLenum = 0x1908;
|
||||||
pub const GL_UNSIGNED_BYTE: GLenum = 0x1401;
|
pub const GL_UNSIGNED_BYTE: GLenum = 0x1401;
|
||||||
pub const GL_UNSIGNED_SHORT: GLenum = 0x1403;
|
pub const GL_UNSIGNED_SHORT: GLenum = 0x1403;
|
||||||
pub const GL_NEAREST: GLenum = 0x2600;
|
|
||||||
pub const GL_LINEAR: GLenum = 0x2601;
|
pub const GL_LINEAR: GLenum = 0x2601;
|
||||||
pub const GL_CLAMP_TO_EDGE: GLenum = 0x812F;
|
pub const GL_CLAMP_TO_EDGE: GLenum = 0x812F;
|
||||||
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801;
|
||||||
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800;
|
||||||
pub const GL_TEXTURE_WRAP_S: GLenum = 0x2802;
|
pub const GL_TEXTURE_WRAP_S: GLenum = 0x2802;
|
||||||
pub const GL_TEXTURE_WRAP_T: GLenum = 0x2803;
|
pub const GL_TEXTURE_WRAP_T: GLenum = 0x2803;
|
||||||
|
|
||||||
pub const GL_VERTEX_SHADER: GLenum = 0x8B31;
|
pub const GL_VERTEX_SHADER: GLenum = 0x8B31;
|
||||||
pub const GL_FRAGMENT_SHADER: GLenum = 0x8B30;
|
pub const GL_FRAGMENT_SHADER: GLenum = 0x8B30;
|
||||||
pub const GL_COMPILE_STATUS: GLenum = 0x8B81;
|
pub const GL_COMPILE_STATUS: GLenum = 0x8B81;
|
||||||
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
||||||
|
|
||||||
pub const GL_TRIANGLES: GLenum = 0x0004;
|
pub const GL_TRIANGLES: GLenum = 0x0004;
|
||||||
pub const GL_BLEND: GLenum = 0x0BE2;
|
pub const GL_BLEND: GLenum = 0x0BE2;
|
||||||
pub const GL_SRC_ALPHA: GLenum = 0x0302;
|
pub const GL_SRC_ALPHA: GLenum = 0x0302;
|
||||||
pub const GL_ONE_MINUS_SRC_ALPHA: GLenum = 0x0303;
|
pub const GL_ONE_MINUS_SRC_ALPHA: GLenum = 0x0303;
|
||||||
pub const GL_ONE: GLenum = 1;
|
pub const GL_ONE: GLenum = 1;
|
||||||
pub const GL_ZERO: GLenum = 0;
|
pub const GL_ZERO: GLenum = 0;
|
||||||
|
pub const GL_SRC_COLOR: GLenum = 0x0300;
|
||||||
pub const GL_COLOR_BUFFER_BIT: GLbitfield = 0x4000;
|
pub const GL_COLOR_BUFFER_BIT: GLbitfield = 0x4000;
|
||||||
pub const GL_DEPTH_BUFFER_BIT: GLbitfield = 0x0100;
|
|
||||||
pub const GL_BLEND_DST_RGB: GLenum = 0x80C8;
|
|
||||||
pub const GL_BLEND_SRC_RGB: GLenum = 0x80C9;
|
|
||||||
pub const GL_BLEND_DST_ALPHA: GLenum = 0x80CA;
|
|
||||||
pub const GL_BLEND_SRC_ALPHA: GLenum = 0x80CB;
|
|
||||||
pub const GL_BLEND_EQUATION: GLenum = 0x8009;
|
|
||||||
pub const GL_FUNC_ADD: GLenum = 0x8006;
|
|
||||||
pub const GL_FUNC_REVERSE_SUBTRACT: GLenum = 0x800B;
|
|
||||||
pub const GL_STATIC_DRAW: GLenum = 0x88E4;
|
pub const GL_STATIC_DRAW: GLenum = 0x88E4;
|
||||||
pub const GL_FALSE: GLenum = 0;
|
pub const GL_FALSE: GLenum = 0;
|
||||||
pub const GL_TRUE: GLenum = 1;
|
|
||||||
pub const GL_NO_ERROR: GLenum = 0;
|
pub const GL_NO_ERROR: GLenum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 着色器源码(标准模式,支持 mask 和非 mask)
|
pub use gl::{GLenum, GLuint, GLint, GLsizei};
|
||||||
|
|
||||||
|
// ============ 着色器源码 ============
|
||||||
|
|
||||||
pub const VERT_SHADER_SRC: &str = r#"#version 100
|
pub const VERT_SHADER_SRC: &str = r#"#version 100
|
||||||
attribute vec4 a_position;
|
attribute vec4 a_position;
|
||||||
attribute vec2 a_texCoord;
|
attribute vec2 a_texCoord;
|
||||||
@@ -168,113 +144,100 @@ void main() {
|
|||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
/// OpenGL ES2 / EGL 动态库函数集合
|
// ============ 动态库函数集合 ============
|
||||||
|
|
||||||
pub struct Gl {
|
pub struct Gl {
|
||||||
_lib_egl: libloading::Library,
|
_lib_egl: libloading::Library,
|
||||||
_lib_gl: libloading::Library,
|
_lib_gl: libloading::Library,
|
||||||
_lib_x11: libloading::Library,
|
_lib_x11: libloading::Library,
|
||||||
// EGL
|
|
||||||
egl_get_display:
|
pub egl_get_display: unsafe extern "C" fn(disp: egl::NativeDisplayType) -> egl::EGLDisplay,
|
||||||
unsafe extern "C" fn(disp: egl::NativeDisplayType) -> egl::EGLDisplay,
|
pub egl_initialize: unsafe extern "C" fn(
|
||||||
egl_initialize:
|
dpy: egl::EGLDisplay,
|
||||||
unsafe extern "C" fn(dpy: egl::EGLDisplay, major: *mut c_int, minor: *mut c_int) -> egl::EGLBoolean,
|
major: *mut c_int,
|
||||||
egl_choose_config: unsafe extern "C" fn(
|
minor: *mut c_int,
|
||||||
|
) -> egl::EGLBoolean,
|
||||||
|
pub egl_choose_config: unsafe extern "C" fn(
|
||||||
dpy: egl::EGLDisplay,
|
dpy: egl::EGLDisplay,
|
||||||
attrib_list: *const egl::EGLint,
|
attrib_list: *const egl::EGLint,
|
||||||
configs: *mut egl::EGLConfig,
|
configs: *mut egl::EGLConfig,
|
||||||
config_size: egl::EGLint,
|
config_size: egl::EGLint,
|
||||||
num_config: *mut egl::EGLint,
|
num_config: *mut egl::EGLint,
|
||||||
) -> egl::EGLBoolean,
|
) -> egl::EGLBoolean,
|
||||||
egl_create_window_surface: unsafe extern "C" fn(
|
pub egl_create_window_surface: unsafe extern "C" fn(
|
||||||
dpy: egl::EGLDisplay,
|
dpy: egl::EGLDisplay,
|
||||||
config: egl::EGLConfig,
|
config: egl::EGLConfig,
|
||||||
win: egl::NativeWindowType,
|
win: egl::NativeWindowType,
|
||||||
attrib_list: *const egl::EGLint,
|
attrib_list: *const egl::EGLint,
|
||||||
) -> egl::EGLSurface,
|
) -> egl::EGLSurface,
|
||||||
egl_create_context: unsafe extern "C" fn(
|
pub egl_create_context: unsafe extern "C" fn(
|
||||||
dpy: egl::EGLDisplay,
|
dpy: egl::EGLDisplay,
|
||||||
config: egl::EGLConfig,
|
config: egl::EGLConfig,
|
||||||
share_ctx: egl::EGLContext,
|
share_ctx: egl::EGLContext,
|
||||||
attrib_list: *const egl::EGLint,
|
attrib_list: *const egl::EGLint,
|
||||||
) -> egl::EGLContext,
|
) -> egl::EGLContext,
|
||||||
egl_make_current: unsafe extern "C" fn(
|
pub egl_make_current: unsafe extern "C" fn(
|
||||||
dpy: egl::EGLDisplay,
|
dpy: egl::EGLDisplay,
|
||||||
draw: egl::EGLSurface,
|
draw: egl::EGLSurface,
|
||||||
read: egl::EGLSurface,
|
read: egl::EGLSurface,
|
||||||
ctx: egl::EGLContext,
|
ctx: egl::EGLContext,
|
||||||
) -> egl::EGLBoolean,
|
) -> egl::EGLBoolean,
|
||||||
egl_swap_buffers:
|
pub egl_swap_buffers:
|
||||||
unsafe extern "C" fn(dpy: egl::EGLDisplay, surface: egl::EGLSurface) -> egl::EGLBoolean,
|
unsafe extern "C" fn(dpy: egl::EGLDisplay, surface: egl::EGLSurface) -> egl::EGLBoolean,
|
||||||
egl_terminate: unsafe extern "C" fn(dpy: egl::EGLDisplay) -> egl::EGLBoolean,
|
|
||||||
|
|
||||||
// GLES2
|
pub gl_clear: unsafe extern "C" fn(mask: gl::GLbitfield),
|
||||||
gl_clear: unsafe extern "C" fn(mask: gl::GLbitfield),
|
pub gl_clear_color: unsafe extern "C" fn(r: f32, g: f32, b: f32, a: f32),
|
||||||
gl_clear_color: unsafe extern "C" fn(r: f32, g: f32, b: f32, a: f32),
|
pub gl_enable: unsafe extern "C" fn(cap: gl::GLenum),
|
||||||
gl_enable: unsafe extern "C" fn(cap: gl::GLenum),
|
pub gl_blend_func: unsafe extern "C" fn(sfactor: gl::GLenum, dfactor: gl::GLenum),
|
||||||
gl_disable: unsafe extern "C" fn(cap: gl::GLenum),
|
pub gl_viewport: unsafe extern "C" fn(x: gl::GLint, y: gl::GLint, w: gl::GLsizei, h: gl::GLsizei),
|
||||||
gl_blend_func: unsafe extern "C" fn(sfactor: gl::GLenum, dfactor: gl::GLenum),
|
pub gl_create_shader: unsafe extern "C" fn(t: gl::GLenum) -> gl::GLuint,
|
||||||
gl_blend_func_separate: unsafe extern "C" fn(
|
pub gl_shader_source: unsafe extern "C" fn(
|
||||||
src_rgb: gl::GLenum,
|
|
||||||
dst_rgb: gl::GLenum,
|
|
||||||
src_alpha: gl::GLenum,
|
|
||||||
dst_alpha: gl::GLenum,
|
|
||||||
),
|
|
||||||
gl_viewport: unsafe extern "C" fn(x: gl::GLint, y: gl::GLint, w: gl::GLsizei, h: gl::GLsizei),
|
|
||||||
gl_create_shader: unsafe extern "C" fn(t: gl::GLenum) -> gl::GLuint,
|
|
||||||
gl_shader_source: unsafe extern "C" fn(
|
|
||||||
shader: gl::GLuint,
|
shader: gl::GLuint,
|
||||||
count: gl::GLsizei,
|
count: gl::GLsizei,
|
||||||
string: *const *const c_char,
|
string: *const *const c_char,
|
||||||
length: *const gl::GLint,
|
length: *const gl::GLint,
|
||||||
),
|
),
|
||||||
gl_compile_shader: unsafe extern "C" fn(shader: gl::GLuint),
|
pub gl_compile_shader: unsafe extern "C" fn(shader: gl::GLuint),
|
||||||
gl_get_shaderiv: unsafe extern "C" fn(
|
pub gl_get_shaderiv:
|
||||||
shader: gl::GLuint,
|
unsafe extern "C" fn(shader: gl::GLuint, pname: gl::GLenum, params: *mut gl::GLint),
|
||||||
pname: gl::GLenum,
|
pub gl_get_shader_info_log: unsafe extern "C" fn(
|
||||||
params: *mut gl::GLint,
|
|
||||||
),
|
|
||||||
gl_get_shader_info_log: unsafe extern "C" fn(
|
|
||||||
shader: gl::GLuint,
|
shader: gl::GLuint,
|
||||||
buf_size: gl::GLsizei,
|
buf_size: gl::GLsizei,
|
||||||
length: *mut gl::GLsizei,
|
length: *mut gl::GLsizei,
|
||||||
info_log: *mut c_char,
|
info_log: *mut c_char,
|
||||||
),
|
),
|
||||||
gl_create_program: unsafe extern "C" fn() -> gl::GLuint,
|
pub gl_create_program: unsafe extern "C" fn() -> gl::GLuint,
|
||||||
gl_attach_shader: unsafe extern "C" fn(program: gl::GLuint, shader: gl::GLuint),
|
pub gl_attach_shader: unsafe extern "C" fn(program: gl::GLuint, shader: gl::GLuint),
|
||||||
gl_link_program: unsafe extern "C" fn(program: gl::GLuint),
|
pub gl_link_program: unsafe extern "C" fn(program: gl::GLuint),
|
||||||
gl_get_programiv: unsafe extern "C" fn(
|
pub gl_get_programiv:
|
||||||
program: gl::GLuint,
|
unsafe extern "C" fn(program: gl::GLuint, pname: gl::GLenum, params: *mut gl::GLint),
|
||||||
pname: gl::GLenum,
|
pub gl_get_program_info_log: unsafe extern "C" fn(
|
||||||
params: *mut gl::GLint,
|
|
||||||
),
|
|
||||||
gl_get_program_info_log: unsafe extern "C" fn(
|
|
||||||
program: gl::GLuint,
|
program: gl::GLuint,
|
||||||
buf_size: gl::GLsizei,
|
buf_size: gl::GLsizei,
|
||||||
length: *mut gl::GLsizei,
|
length: *mut gl::GLsizei,
|
||||||
info_log: *mut c_char,
|
info_log: *mut c_char,
|
||||||
),
|
),
|
||||||
gl_use_program: unsafe extern "C" fn(program: gl::GLuint),
|
pub gl_use_program: unsafe extern "C" fn(program: gl::GLuint),
|
||||||
gl_get_attrib_location:
|
pub gl_get_attrib_location:
|
||||||
unsafe extern "C" fn(program: gl::GLuint, name: *const c_char) -> gl::GLint,
|
unsafe extern "C" fn(program: gl::GLuint, name: *const c_char) -> gl::GLint,
|
||||||
gl_get_uniform_location:
|
pub gl_get_uniform_location:
|
||||||
unsafe extern "C" fn(program: gl::GLuint, name: *const c_char) -> gl::GLint,
|
unsafe extern "C" fn(program: gl::GLuint, name: *const c_char) -> gl::GLint,
|
||||||
gl_uniform_matrix4fv: unsafe extern "C" fn(
|
pub gl_uniform_matrix4fv: unsafe extern "C" fn(
|
||||||
location: gl::GLint,
|
location: gl::GLint,
|
||||||
count: gl::GLsizei,
|
count: gl::GLsizei,
|
||||||
transpose: gl::GLenum,
|
transpose: gl::GLenum,
|
||||||
value: *const f32,
|
value: *const f32,
|
||||||
),
|
),
|
||||||
gl_uniform1i: unsafe extern "C" fn(location: gl::GLint, v: gl::GLint),
|
pub gl_uniform1i: unsafe extern "C" fn(location: gl::GLint, v: gl::GLint),
|
||||||
gl_uniform4f:
|
pub gl_uniform4f: unsafe extern "C" fn(location: gl::GLint, x: f32, y: f32, z: f32, w: f32),
|
||||||
unsafe extern "C" fn(location: gl::GLint, x: f32, y: f32, z: f32, w: f32),
|
pub gl_gen_textures: unsafe extern "C" fn(n: gl::GLsizei, textures: *mut gl::GLuint),
|
||||||
gl_gen_textures: unsafe extern "C" fn(n: gl::GLsizei, textures: *mut gl::GLuint),
|
pub gl_bind_texture: unsafe extern "C" fn(target: gl::GLenum, texture: gl::GLuint),
|
||||||
gl_bind_texture: unsafe extern "C" fn(target: gl::GLenum, texture: gl::GLuint),
|
pub gl_tex_parameteri:
|
||||||
gl_tex_parameteri:
|
|
||||||
unsafe extern "C" fn(target: gl::GLenum, pname: gl::GLenum, param: gl::GLint),
|
unsafe extern "C" fn(target: gl::GLenum, pname: gl::GLenum, param: gl::GLint),
|
||||||
gl_tex_image_2d: unsafe extern "C" fn(
|
pub gl_tex_image_2d: unsafe extern "C" fn(
|
||||||
target: gl::GLenum,
|
target: gl::GLenum,
|
||||||
level: gl::GLint,
|
level: gl::GLint,
|
||||||
internalformat: gl::GLenum,
|
internalformat: gl::GLint,
|
||||||
width: gl::GLsizei,
|
width: gl::GLsizei,
|
||||||
height: gl::GLsizei,
|
height: gl::GLsizei,
|
||||||
border: gl::GLint,
|
border: gl::GLint,
|
||||||
@@ -282,17 +245,17 @@ pub struct Gl {
|
|||||||
type_: gl::GLenum,
|
type_: gl::GLenum,
|
||||||
data: *const c_void_raw,
|
data: *const c_void_raw,
|
||||||
),
|
),
|
||||||
gl_active_texture: unsafe extern "C" fn(texture: gl::GLenum),
|
pub gl_active_texture: unsafe extern "C" fn(texture: gl::GLenum),
|
||||||
gl_gen_buffers: unsafe extern "C" fn(n: gl::GLsizei, buffers: *mut gl::GLuint),
|
pub gl_gen_buffers: unsafe extern "C" fn(n: gl::GLsizei, buffers: *mut gl::GLuint),
|
||||||
gl_bind_buffer: unsafe extern "C" fn(target: gl::GLenum, buffer: gl::GLuint),
|
pub gl_bind_buffer: unsafe extern "C" fn(target: gl::GLenum, buffer: gl::GLuint),
|
||||||
gl_buffer_data: unsafe extern "C" fn(
|
pub gl_buffer_data: unsafe extern "C" fn(
|
||||||
target: gl::GLenum,
|
target: gl::GLenum,
|
||||||
size: isize,
|
size: isize,
|
||||||
data: *const c_void_raw,
|
data: *const c_void_raw,
|
||||||
usage: gl::GLenum,
|
usage: gl::GLenum,
|
||||||
),
|
),
|
||||||
gl_enable_vertex_attrib_array: unsafe extern "C" fn(index: gl::GLuint),
|
pub gl_enable_vertex_attrib_array: unsafe extern "C" fn(index: gl::GLuint),
|
||||||
gl_vertex_attrib_pointer: unsafe extern "C" fn(
|
pub gl_vertex_attrib_pointer: unsafe extern "C" fn(
|
||||||
index: gl::GLuint,
|
index: gl::GLuint,
|
||||||
size: gl::GLint,
|
size: gl::GLint,
|
||||||
type_: gl::GLenum,
|
type_: gl::GLenum,
|
||||||
@@ -300,21 +263,17 @@ pub struct Gl {
|
|||||||
stride: gl::GLsizei,
|
stride: gl::GLsizei,
|
||||||
pointer: *const c_void_raw,
|
pointer: *const c_void_raw,
|
||||||
),
|
),
|
||||||
gl_draw_elements: unsafe extern "C" fn(
|
pub gl_draw_elements: unsafe extern "C" fn(
|
||||||
mode: gl::GLenum,
|
mode: gl::GLenum,
|
||||||
count: gl::GLsizei,
|
count: gl::GLsizei,
|
||||||
type_: gl::GLenum,
|
type_: gl::GLenum,
|
||||||
indices: *const c_void_raw,
|
indices: *const c_void_raw,
|
||||||
),
|
),
|
||||||
gl_get_error: unsafe extern "C" fn() -> gl::GLenum,
|
pub gl_get_error: unsafe extern "C" fn() -> gl::GLenum,
|
||||||
gl_delete_textures: unsafe extern "C" fn(n: gl::GLsizei, textures: *const gl::GLuint),
|
pub gl_delete_buffers: unsafe extern "C" fn(n: gl::GLsizei, buffers: *const gl::GLuint),
|
||||||
gl_delete_buffers: unsafe extern "C" fn(n: gl::GLsizei, buffers: *const gl::GLuint),
|
|
||||||
|
|
||||||
// X11
|
pub x_open_display: unsafe extern "C" fn(name: *const c_char) -> *mut x11::Display,
|
||||||
x_open_display:
|
pub x_create_window: unsafe extern "C" fn(
|
||||||
unsafe extern "C" fn(name: *const c_char) -> *mut x11::Display,
|
|
||||||
x_close_display: unsafe extern "C" fn(disp: *mut x11::Display) -> c_int,
|
|
||||||
x_create_window: unsafe extern "C" fn(
|
|
||||||
disp: *mut x11::Display,
|
disp: *mut x11::Display,
|
||||||
parent: x11::Window,
|
parent: x11::Window,
|
||||||
x: c_int,
|
x: c_int,
|
||||||
@@ -328,14 +287,13 @@ pub struct Gl {
|
|||||||
valuemask: c_long,
|
valuemask: c_long,
|
||||||
attributes: *mut x11::XSetWindowAttributes,
|
attributes: *mut x11::XSetWindowAttributes,
|
||||||
) -> x11::Window,
|
) -> x11::Window,
|
||||||
x_map_window: unsafe extern "C" fn(disp: *mut x11::Display, w: x11::Window) -> c_int,
|
pub x_map_window: unsafe extern "C" fn(disp: *mut x11::Display, w: x11::Window) -> c_int,
|
||||||
x_store_name:
|
pub x_store_name:
|
||||||
unsafe extern "C" fn(disp: *mut x11::Display, w: x11::Window, name: *const c_char) -> c_int,
|
unsafe extern "C" fn(disp: *mut x11::Display, w: x11::Window, name: *const c_char) -> c_int,
|
||||||
x_flush: unsafe extern "C" fn(disp: *mut x11::Display) -> c_int,
|
pub x_flush: unsafe extern "C" fn(disp: *mut x11::Display) -> c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gl {
|
impl Gl {
|
||||||
/// 加载所有动态库函数
|
|
||||||
pub fn load() -> Result<Self> {
|
pub fn load() -> Result<Self> {
|
||||||
let lib_egl = unsafe { libloading::Library::new("libEGL.so.1")? };
|
let lib_egl = unsafe { libloading::Library::new("libEGL.so.1")? };
|
||||||
let lib_gl = unsafe { libloading::Library::new("libGLESv2.so.2")? };
|
let lib_gl = unsafe { libloading::Library::new("libGLESv2.so.2")? };
|
||||||
@@ -350,14 +308,11 @@ impl Gl {
|
|||||||
egl_create_context: *lib_egl.get(b"eglCreateContext\0")?,
|
egl_create_context: *lib_egl.get(b"eglCreateContext\0")?,
|
||||||
egl_make_current: *lib_egl.get(b"eglMakeCurrent\0")?,
|
egl_make_current: *lib_egl.get(b"eglMakeCurrent\0")?,
|
||||||
egl_swap_buffers: *lib_egl.get(b"eglSwapBuffers\0")?,
|
egl_swap_buffers: *lib_egl.get(b"eglSwapBuffers\0")?,
|
||||||
egl_terminate: *lib_egl.get(b"eglTerminate\0")?,
|
|
||||||
|
|
||||||
gl_clear: *lib_gl.get(b"glClear\0")?,
|
gl_clear: *lib_gl.get(b"glClear\0")?,
|
||||||
gl_clear_color: *lib_gl.get(b"glClearColor\0")?,
|
gl_clear_color: *lib_gl.get(b"glClearColor\0")?,
|
||||||
gl_enable: *lib_gl.get(b"glEnable\0")?,
|
gl_enable: *lib_gl.get(b"glEnable\0")?,
|
||||||
gl_disable: *lib_gl.get(b"glDisable\0")?,
|
|
||||||
gl_blend_func: *lib_gl.get(b"glBlendFunc\0")?,
|
gl_blend_func: *lib_gl.get(b"glBlendFunc\0")?,
|
||||||
gl_blend_func_separate: *lib_gl.get(b"glBlendFuncSeparate\0")?,
|
|
||||||
gl_viewport: *lib_gl.get(b"glViewport\0")?,
|
gl_viewport: *lib_gl.get(b"glViewport\0")?,
|
||||||
gl_create_shader: *lib_gl.get(b"glCreateShader\0")?,
|
gl_create_shader: *lib_gl.get(b"glCreateShader\0")?,
|
||||||
gl_shader_source: *lib_gl.get(b"glShaderSource\0")?,
|
gl_shader_source: *lib_gl.get(b"glShaderSource\0")?,
|
||||||
@@ -387,11 +342,9 @@ impl Gl {
|
|||||||
gl_vertex_attrib_pointer: *lib_gl.get(b"glVertexAttribPointer\0")?,
|
gl_vertex_attrib_pointer: *lib_gl.get(b"glVertexAttribPointer\0")?,
|
||||||
gl_draw_elements: *lib_gl.get(b"glDrawElements\0")?,
|
gl_draw_elements: *lib_gl.get(b"glDrawElements\0")?,
|
||||||
gl_get_error: *lib_gl.get(b"glGetError\0")?,
|
gl_get_error: *lib_gl.get(b"glGetError\0")?,
|
||||||
gl_delete_textures: *lib_gl.get(b"glDeleteTextures\0")?,
|
|
||||||
gl_delete_buffers: *lib_gl.get(b"glDeleteBuffers\0")?,
|
gl_delete_buffers: *lib_gl.get(b"glDeleteBuffers\0")?,
|
||||||
|
|
||||||
x_open_display: *lib_x11.get(b"XOpenDisplay\0")?,
|
x_open_display: *lib_x11.get(b"XOpenDisplay\0")?,
|
||||||
x_close_display: *lib_x11.get(b"XCloseDisplay\0")?,
|
|
||||||
x_create_window: *lib_x11.get(b"XCreateWindow\0")?,
|
x_create_window: *lib_x11.get(b"XCreateWindow\0")?,
|
||||||
x_map_window: *lib_x11.get(b"XMapWindow\0")?,
|
x_map_window: *lib_x11.get(b"XMapWindow\0")?,
|
||||||
x_store_name: *lib_x11.get(b"XStoreName\0")?,
|
x_store_name: *lib_x11.get(b"XStoreName\0")?,
|
||||||
@@ -405,15 +358,14 @@ impl Gl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EGL/GLES2/X11 渲染上下文
|
// ============ 渲染上下文 ============
|
||||||
|
|
||||||
pub struct RenderContext {
|
pub struct RenderContext {
|
||||||
pub gl: Gl,
|
pub gl: Gl,
|
||||||
display: egl::EGLDisplay,
|
pub display: egl::EGLDisplay,
|
||||||
_config: egl::EGLConfig,
|
pub surface: egl::EGLSurface,
|
||||||
context: egl::EGLContext,
|
pub x_display: *mut x11::Display,
|
||||||
surface: egl::EGLSurface,
|
pub x_window: x11::Window,
|
||||||
x_display: *mut x11::Display,
|
|
||||||
x_window: x11::Window,
|
|
||||||
pub program: GLuint,
|
pub program: GLuint,
|
||||||
pub attrib_position: GLint,
|
pub attrib_position: GLint,
|
||||||
pub attrib_tex_coord: GLint,
|
pub attrib_tex_coord: GLint,
|
||||||
@@ -426,9 +378,9 @@ pub struct RenderContext {
|
|||||||
pub height: i32,
|
pub height: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
use gl::*;
|
// 含裸指针,手动声明 Send(仅在单渲染线程使用)
|
||||||
|
unsafe impl Send for RenderContext {}
|
||||||
|
|
||||||
/// 创建并链接着色器程序
|
|
||||||
fn compile_shader(gl: &Gl, shader_type: GLenum, src: &str) -> Result<GLuint> {
|
fn compile_shader(gl: &Gl, shader_type: GLenum, src: &str) -> Result<GLuint> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let shader = (gl.gl_create_shader)(shader_type);
|
let shader = (gl.gl_create_shader)(shader_type);
|
||||||
@@ -441,18 +393,14 @@ fn compile_shader(gl: &Gl, shader_type: GLenum, src: &str) -> Result<GLuint> {
|
|||||||
(gl.gl_compile_shader)(shader);
|
(gl.gl_compile_shader)(shader);
|
||||||
|
|
||||||
let mut status = 0;
|
let mut status = 0;
|
||||||
(gl.gl_get_shaderiv)(shader, GL_COMPILE_STATUS, &mut status);
|
(gl.gl_get_shaderiv)(shader, gl::GL_COMPILE_STATUS, &mut status);
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
let mut log = vec![0i8; 1024];
|
let mut log = vec![0i8; 1024];
|
||||||
(gl.gl_get_shader_info_log)(
|
(gl.gl_get_shader_info_log)(shader, 1024, std::ptr::null_mut(), log.as_mut_ptr());
|
||||||
shader,
|
let log_str = String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||||
|
log.as_ptr() as *const u8,
|
||||||
1024,
|
1024,
|
||||||
std::ptr::null_mut(),
|
));
|
||||||
log.as_mut_ptr(),
|
|
||||||
);
|
|
||||||
let log_str = String::from_utf8_lossy(
|
|
||||||
std::slice::from_raw_parts(log.as_ptr() as *const u8, 1024),
|
|
||||||
);
|
|
||||||
return Err(anyhow!("着色器编译失败: {}", log_str));
|
return Err(anyhow!("着色器编译失败: {}", log_str));
|
||||||
}
|
}
|
||||||
Ok(shader)
|
Ok(shader)
|
||||||
@@ -460,16 +408,14 @@ fn compile_shader(gl: &Gl, shader_type: GLenum, src: &str) -> Result<GLuint> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RenderContext {
|
impl RenderContext {
|
||||||
/// 创建全屏 X11 窗口 + EGL 上下文
|
|
||||||
pub fn new_fullscreen(width: i32, height: i32) -> Result<Self> {
|
pub fn new_fullscreen(width: i32, height: i32) -> Result<Self> {
|
||||||
let gl = Gl::load()?;
|
let gl = Gl::load()?;
|
||||||
|
|
||||||
// X11 窗口
|
// X11 窗口
|
||||||
let x_display = unsafe { (gl.x_open_display)(std::ptr::null()) };
|
let x_display = unsafe { (gl.x_open_display)(std::ptr::null()) };
|
||||||
if x_display.is_null() {
|
if x_display.is_null() {
|
||||||
return Err(anyhow!("XOpenDisplay 失败(DISPLAY 环境变量是否设置?)"));
|
return Err(anyhow!("XOpenDisplay 失败"));
|
||||||
}
|
}
|
||||||
let root_window: x11::Window = 0; // DefaultRootWindow
|
|
||||||
let mut attrs = x11::XSetWindowAttributes {
|
let mut attrs = x11::XSetWindowAttributes {
|
||||||
background_pixmap: 0,
|
background_pixmap: 0,
|
||||||
background_pixel: 0,
|
background_pixel: 0,
|
||||||
@@ -483,21 +429,21 @@ impl RenderContext {
|
|||||||
save_under: 0,
|
save_under: 0,
|
||||||
event_mask: x11::ExposureMask | x11::StructureNotifyMask,
|
event_mask: x11::ExposureMask | x11::StructureNotifyMask,
|
||||||
do_not_propagate_mask: 0,
|
do_not_propagate_mask: 0,
|
||||||
override_redirect: 1, // 全屏无装饰
|
override_redirect: 1,
|
||||||
colormap: 0,
|
colormap: 0,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
};
|
};
|
||||||
let x_window = unsafe {
|
let x_window = unsafe {
|
||||||
(gl.x_create_window)(
|
(gl.x_create_window)(
|
||||||
x_display,
|
x_display,
|
||||||
root_window,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
width as u32,
|
|
||||||
height as u32,
|
|
||||||
0,
|
0,
|
||||||
24, // depth
|
width as c_uint,
|
||||||
1, // InputOutput
|
height as c_uint,
|
||||||
|
0,
|
||||||
|
24,
|
||||||
|
1,
|
||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
x11::CWOverrideRedirect | x11::CWEventMask,
|
x11::CWOverrideRedirect | x11::CWEventMask,
|
||||||
&mut attrs,
|
&mut attrs,
|
||||||
@@ -514,19 +460,17 @@ impl RenderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EGL
|
// EGL
|
||||||
let display = unsafe { (gl.egl_get_display)(egl::EGL_DEFAULT_DISPLAY_PTR()) };
|
let display = unsafe { (gl.egl_get_display)(egl::default_display()) };
|
||||||
if display.is_null() {
|
if display.is_null() {
|
||||||
return Err(anyhow!("eglGetDisplay 失败"));
|
return Err(anyhow!("eglGetDisplay 失败"));
|
||||||
}
|
}
|
||||||
let mut major = 0;
|
let mut major = 0;
|
||||||
let mut minor = 0;
|
let mut minor = 0;
|
||||||
let ok = unsafe { (gl.egl_initialize)(display, &mut major, &mut minor) };
|
if unsafe { (gl.egl_initialize)(display, &mut major, &mut minor) } == 0 {
|
||||||
if ok == 0 {
|
|
||||||
return Err(anyhow!("eglInitialize 失败"));
|
return Err(anyhow!("eglInitialize 失败"));
|
||||||
}
|
}
|
||||||
println!("[Live2D] EGL 版本: {}.{}", major, minor);
|
println!("[Live2D] EGL {}.{}", major, minor);
|
||||||
|
|
||||||
// 选配置
|
|
||||||
let config_attrs = [
|
let config_attrs = [
|
||||||
egl::EGL_RED_SIZE, 8,
|
egl::EGL_RED_SIZE, 8,
|
||||||
egl::EGL_GREEN_SIZE, 8,
|
egl::EGL_GREEN_SIZE, 8,
|
||||||
@@ -538,7 +482,7 @@ impl RenderContext {
|
|||||||
];
|
];
|
||||||
let mut config: egl::EGLConfig = std::ptr::null_mut();
|
let mut config: egl::EGLConfig = std::ptr::null_mut();
|
||||||
let mut num_config = 0;
|
let mut num_config = 0;
|
||||||
let ok = unsafe {
|
if unsafe {
|
||||||
(gl.egl_choose_config)(
|
(gl.egl_choose_config)(
|
||||||
display,
|
display,
|
||||||
config_attrs.as_ptr(),
|
config_attrs.as_ptr(),
|
||||||
@@ -546,107 +490,74 @@ impl RenderContext {
|
|||||||
1,
|
1,
|
||||||
&mut num_config,
|
&mut num_config,
|
||||||
)
|
)
|
||||||
};
|
} == 0 || num_config == 0
|
||||||
if ok == 0 || num_config == 0 {
|
{
|
||||||
return Err(anyhow!("eglChooseConfig 失败"));
|
return Err(anyhow!("eglChooseConfig 失败"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 surface
|
|
||||||
let surface = unsafe {
|
let surface = unsafe {
|
||||||
(gl.egl_create_window_surface)(
|
(gl.egl_create_window_surface)(display, config, x_window as egl::NativeWindowType, std::ptr::null())
|
||||||
display,
|
|
||||||
config,
|
|
||||||
x_window as egl::NativeWindowType,
|
|
||||||
std::ptr::null(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if surface.is_null() {
|
if surface.is_null() {
|
||||||
return Err(anyhow!("eglCreateWindowSurface 失败"));
|
return Err(anyhow!("eglCreateWindowSurface 失败"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 context(GLES2)
|
|
||||||
let ctx_attrs = [egl::EGL_CONTEXT_CLIENT_VERSION, 2, egl::EGL_NONE];
|
let ctx_attrs = [egl::EGL_CONTEXT_CLIENT_VERSION, 2, egl::EGL_NONE];
|
||||||
let context = unsafe {
|
let context = unsafe { (gl.egl_create_context)(display, config, std::ptr::null(), ctx_attrs.as_ptr()) };
|
||||||
(gl.egl_create_context)(display, config, std::ptr::null(), ctx_attrs.as_ptr())
|
|
||||||
};
|
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
return Err(anyhow!("eglCreateContext 失败"));
|
return Err(anyhow!("eglCreateContext 失败"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// make current
|
if unsafe { (gl.egl_make_current)(display, surface, surface, context) } == 0 {
|
||||||
let ok = unsafe {
|
|
||||||
(gl.egl_make_current)(display, surface, surface, context)
|
|
||||||
};
|
|
||||||
if ok == 0 {
|
|
||||||
return Err(anyhow!("eglMakeCurrent 失败"));
|
return Err(anyhow!("eglMakeCurrent 失败"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置视口
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(gl.gl_viewport)(0, 0, width, height);
|
(gl.gl_viewport)(0, 0, width, height);
|
||||||
(gl.gl_clear_color)(0.0, 0.0, 0.0, 0.0);
|
(gl.gl_clear_color)(0.0, 0.0, 0.0, 1.0);
|
||||||
(gl.gl_enable)(GL_BLEND);
|
(gl.gl_enable)(gl::GL_BLEND);
|
||||||
(gl.gl_blend_func)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
(gl.gl_blend_func)(gl::GL_SRC_ALPHA, gl::GL_ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编译着色器
|
let vert = compile_shader(&gl, gl::GL_VERTEX_SHADER, VERT_SHADER_SRC)?;
|
||||||
let vert = compile_shader(&gl, GL_VERTEX_SHADER, VERT_SHADER_SRC)?;
|
let frag = compile_shader(&gl, gl::GL_FRAGMENT_SHADER, FRAG_SHADER_SRC)?;
|
||||||
let frag = compile_shader(&gl, GL_FRAGMENT_SHADER, FRAG_SHADER_SRC)?;
|
|
||||||
let program = unsafe {
|
let program = unsafe {
|
||||||
let p = (gl.gl_create_program)();
|
let p = (gl.gl_create_program)();
|
||||||
(gl.gl_attach_shader)(p, vert);
|
(gl.gl_attach_shader)(p, vert);
|
||||||
(gl.gl_attach_shader)(p, frag);
|
(gl.gl_attach_shader)(p, frag);
|
||||||
(gl.gl_link_program)(p);
|
(gl.gl_link_program)(p);
|
||||||
let mut status = 0;
|
let mut status = 0;
|
||||||
(gl.gl_get_programiv)(p, GL_LINK_STATUS, &mut status);
|
(gl.gl_get_programiv)(p, gl::GL_LINK_STATUS, &mut status);
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
let mut log = vec![0i8; 1024];
|
let mut log = vec![0i8; 1024];
|
||||||
(gl.gl_get_program_info_log)(
|
(gl.gl_get_program_info_log)(p, 1024, std::ptr::null_mut(), log.as_mut_ptr());
|
||||||
p,
|
let log_str = String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||||
|
log.as_ptr() as *const u8,
|
||||||
1024,
|
1024,
|
||||||
std::ptr::null_mut(),
|
));
|
||||||
log.as_mut_ptr(),
|
|
||||||
);
|
|
||||||
let log_str = String::from_utf8_lossy(
|
|
||||||
std::slice::from_raw_parts(log.as_ptr() as *const u8, 1024),
|
|
||||||
);
|
|
||||||
return Err(anyhow!("着色器链接失败: {}", log_str));
|
return Err(anyhow!("着色器链接失败: {}", log_str));
|
||||||
}
|
}
|
||||||
p
|
p
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe { (gl.gl_use_program)(program); }
|
unsafe { (gl.gl_use_program)(program); }
|
||||||
|
|
||||||
// 获取 attribute/uniform 位置
|
let get = |name: &str| -> Result<GLint> {
|
||||||
let attrib_position = unsafe {
|
let c = std::ffi::CString::new(name)?;
|
||||||
let name = std::ffi::CString::new("a_position")?;
|
Ok(unsafe { (gl.gl_get_attrib_location)(program, c.as_ptr()) })
|
||||||
(gl.gl_get_attrib_location)(program, name.as_ptr())
|
|
||||||
};
|
};
|
||||||
let attrib_tex_coord = unsafe {
|
let getu = |name: &str| -> Result<GLint> {
|
||||||
let name = std::ffi::CString::new("a_texCoord")?;
|
let c = std::ffi::CString::new(name)?;
|
||||||
(gl.gl_get_attrib_location)(program, name.as_ptr())
|
Ok(unsafe { (gl.gl_get_uniform_location)(program, c.as_ptr()) })
|
||||||
};
|
|
||||||
let uniform_matrix = unsafe {
|
|
||||||
let name = std::ffi::CString::new("u_matrix")?;
|
|
||||||
(gl.gl_get_uniform_location)(program, name.as_ptr())
|
|
||||||
};
|
|
||||||
let uniform_texture = unsafe {
|
|
||||||
let name = std::ffi::CString::new("s_texture0")?;
|
|
||||||
(gl.gl_get_uniform_location)(program, name.as_ptr())
|
|
||||||
};
|
|
||||||
let uniform_base_color = unsafe {
|
|
||||||
let name = std::ffi::CString::new("u_baseColor")?;
|
|
||||||
(gl.gl_get_uniform_location)(program, name.as_ptr())
|
|
||||||
};
|
|
||||||
let uniform_multiply_color = unsafe {
|
|
||||||
let name = std::ffi::CString::new("u_multiplyColor")?;
|
|
||||||
(gl.gl_get_uniform_location)(program, name.as_ptr())
|
|
||||||
};
|
|
||||||
let uniform_screen_color = unsafe {
|
|
||||||
let name = std::ffi::CString::new("u_screenColor")?;
|
|
||||||
(gl.gl_get_uniform_location)(program, name.as_ptr())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let attrib_position = get("a_position")?;
|
||||||
|
let attrib_tex_coord = get("a_texCoord")?;
|
||||||
|
let uniform_matrix = getu("u_matrix")?;
|
||||||
|
let uniform_texture = getu("s_texture0")?;
|
||||||
|
let uniform_base_color = getu("u_baseColor")?;
|
||||||
|
let uniform_multiply_color = getu("u_multiplyColor")?;
|
||||||
|
let uniform_screen_color = getu("u_screenColor")?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"[Live2D] GL 程序就绪: program={} pos={} tex={} mat={} tex_u={} base={} mult={} scr={}",
|
"[Live2D] GL 程序就绪: program={} pos={} tex={} mat={} tex_u={} base={} mult={} scr={}",
|
||||||
program, attrib_position, attrib_tex_coord, uniform_matrix,
|
program, attrib_position, attrib_tex_coord, uniform_matrix,
|
||||||
@@ -656,8 +567,6 @@ impl RenderContext {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
gl,
|
gl,
|
||||||
display,
|
display,
|
||||||
_config: config,
|
|
||||||
context,
|
|
||||||
surface,
|
surface,
|
||||||
x_display,
|
x_display,
|
||||||
x_window,
|
x_window,
|
||||||
@@ -674,63 +583,41 @@ impl RenderContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 上传纹理到 GPU
|
|
||||||
pub fn create_texture(&self, img: &super::assets::TextureImage) -> GLuint {
|
pub fn create_texture(&self, img: &super::assets::TextureImage) -> GLuint {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
(self.gl.gl_gen_textures)(1, &mut tex);
|
(self.gl.gl_gen_textures)(1, &mut tex);
|
||||||
(self.gl.gl_bind_texture)(GL_TEXTURE_2D, tex);
|
(self.gl.gl_bind_texture)(gl::GL_TEXTURE_2D, tex);
|
||||||
(self.gl.gl_tex_parameteri)(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR as i32);
|
(self.gl.gl_tex_parameteri)(gl::GL_TEXTURE_2D, gl::GL_TEXTURE_MIN_FILTER, gl::GL_LINEAR as GLint);
|
||||||
(self.gl.gl_tex_parameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR as i32);
|
(self.gl.gl_tex_parameteri)(gl::GL_TEXTURE_2D, gl::GL_TEXTURE_MAG_FILTER, gl::GL_LINEAR as GLint);
|
||||||
(self.gl.gl_tex_parameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE as i32);
|
(self.gl.gl_tex_parameteri)(gl::GL_TEXTURE_2D, gl::GL_TEXTURE_WRAP_S, gl::GL_CLAMP_TO_EDGE as GLint);
|
||||||
(self.gl.gl_tex_parameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE as i32);
|
(self.gl.gl_tex_parameteri)(gl::GL_TEXTURE_2D, gl::GL_TEXTURE_WRAP_T, gl::GL_CLAMP_TO_EDGE as GLint);
|
||||||
(self.gl.gl_tex_image_2d)(
|
(self.gl.gl_tex_image_2d)(
|
||||||
GL_TEXTURE_2D,
|
gl::GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
GL_RGBA as i32,
|
gl::GL_RGBA as GLint,
|
||||||
img.width as i32,
|
img.width as GLsizei,
|
||||||
img.height as i32,
|
img.height as GLsizei,
|
||||||
0,
|
0,
|
||||||
GL_RGBA,
|
gl::GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE,
|
gl::GL_UNSIGNED_BYTE,
|
||||||
img.rgba.as_ptr() as *const c_void,
|
img.rgba.as_ptr() as *const c_void,
|
||||||
);
|
);
|
||||||
let err = (self.gl.gl_get_error)();
|
let err = (self.gl.gl_get_error)();
|
||||||
if err != GL_NO_ERROR {
|
if err != gl::GL_NO_ERROR {
|
||||||
eprintln!("[Live2D] glTexImage2D 错误: 0x{:x}", err);
|
eprintln!("[Live2D] glTexImage2D 错误: 0x{:x}", err);
|
||||||
}
|
}
|
||||||
tex
|
tex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 交换缓冲区(显示到屏幕)
|
|
||||||
pub fn swap_buffers(&self) {
|
pub fn swap_buffers(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.gl.gl_clear)(GL_COLOR_BUFFER_BIT);
|
|
||||||
// 注意:clear 在绘制前调用,这里 swap 只是提交
|
|
||||||
// 实际渲染流程:clear → draw → swap
|
|
||||||
(self.gl.egl_swap_buffers)(self.display, self.surface);
|
(self.gl.egl_swap_buffers)(self.display, self.surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 清屏
|
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
unsafe { (self.gl.gl_clear)(GL_COLOR_BUFFER_BIT); }
|
unsafe { (self.gl.gl_clear)(gl::GL_COLOR_BUFFER_BIT); }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for RenderContext {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// 简单清理(EGL/X11 资源在进程退出时自动释放)
|
|
||||||
unsafe {
|
|
||||||
(self.gl.x_flush)(self.x_display);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EGL_DEFAULT_DISPLAY 常量
|
|
||||||
impl egl {
|
|
||||||
pub fn EGL_DEFAULT_DISPLAY_PTR() -> NativeDisplayType {
|
|
||||||
std::ptr::null_mut()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
//! 封装 moc3 读取 → revive → model 初始化 → 参数更新 → drawable 数据提取。
|
//! 封装 moc3 读取 → revive → model 初始化 → 参数更新 → drawable 数据提取。
|
||||||
|
|
||||||
use super::core_ffi::{
|
use super::core_ffi::{
|
||||||
alloc_aligned, AlignedBuffer, CubismCore, CsmVector2, CsmVector4, CSM_ALIGNOF_MOC,
|
alloc_aligned, AlignedBuffer, CubismCore, CsmVector2, CSM_ALIGNOF_MOC, CSM_ALIGNOF_MODEL,
|
||||||
CSM_ALIGNOF_MODEL,
|
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -308,9 +307,3 @@ impl CubismModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CubismModel {
|
|
||||||
// 保留 CsmVector4 引用避免 unused
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn _ensure_v4_linked(_v: CsmVector4) {}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
use crate::core::config::RenderType;
|
use crate::core::config::RenderType;
|
||||||
use crate::core::message::{Destination, Envelope, Message};
|
use crate::core::message::{Destination, Envelope, Message};
|
||||||
use crate::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
|
use crate::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
|
||||||
use crate::core::plugin_ids;
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@@ -103,7 +102,7 @@ impl Plugin for Live2DPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Live2DPlugin {
|
impl Live2DPlugin {
|
||||||
fn start_live2d(&mut self, config: &crate::core::config::Config) -> Result<()> {
|
fn start_live2d(&mut self, config: &crate::core::config::AppConfig) -> Result<()> {
|
||||||
// 先停止旧的渲染
|
// 先停止旧的渲染
|
||||||
self.stop_live2d();
|
self.stop_live2d();
|
||||||
|
|
||||||
@@ -155,8 +154,8 @@ impl Live2DPlugin {
|
|||||||
from: "live2d".to_string(),
|
from: "live2d".to_string(),
|
||||||
to: Destination::Manager,
|
to: Destination::Manager,
|
||||||
message: Message::StateChanged {
|
message: Message::StateChanged {
|
||||||
old_state: Some("live2d_running".into()),
|
old_state: "live2d_running".into(),
|
||||||
new_state: Some("live2d_error".into()),
|
new_state: "live2d_error".into(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -206,7 +205,7 @@ fn find_core_so() -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 查找 live2d 资源根目录
|
/// 查找 live2d 资源根目录
|
||||||
fn find_live2d_base(config: &crate::core::config::Config) -> Result<PathBuf> {
|
fn find_live2d_base(config: &crate::core::config::AppConfig) -> Result<PathBuf> {
|
||||||
let candidates = [
|
let candidates = [
|
||||||
PathBuf::from("configs/live2d"),
|
PathBuf::from("configs/live2d"),
|
||||||
PathBuf::from("/home/showen/Showen/ShowenV2/configs/live2d"),
|
PathBuf::from("/home/showen/Showen/ShowenV2/configs/live2d"),
|
||||||
@@ -219,7 +218,3 @@ fn find_live2d_base(config: &crate::core::config::Config) -> Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
anyhow::bail!("找不到 configs/live2d 目录")
|
anyhow::bail!("找不到 configs/live2d 目录")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保留 plugin_ids 引用避免 unused
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use plugin_ids as _;
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use super::animation::AnimationState;
|
use super::animation::AnimationState;
|
||||||
use super::assets::{self, Model3Json, TextureImage};
|
use super::assets::{self, Model3Json, TextureImage};
|
||||||
use super::core_ffi::{self, CubismCore};
|
use super::core_ffi::{self, CubismCore};
|
||||||
use super::gl::{self, RenderContext};
|
use super::gl::{self as gl_api, RenderContext};
|
||||||
use super::model::{CubismModel, DrawableSnapshot};
|
use super::model::{CubismModel, DrawableSnapshot};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -36,7 +36,7 @@ impl Live2DRenderer {
|
|||||||
let paths = assets::resolve_asset_paths(live2d_base_dir, model3_json_rel)?;
|
let paths = assets::resolve_asset_paths(live2d_base_dir, model3_json_rel)?;
|
||||||
let model3 = Model3Json::from_path(&paths.model3_json)?;
|
let model3 = Model3Json::from_path(&paths.model3_json)?;
|
||||||
println!(
|
println!(
|
||||||
"[Live2D] model3.json: 版本={} moc={} 纹理数={}",
|
"[Live2D] model3.json: 版本={} moc={} 纹ç<EFBFBD>†æ•?{}",
|
||||||
model3.version,
|
model3.version,
|
||||||
model3.file_references.moc,
|
model3.file_references.moc,
|
||||||
model3.file_references.textures.len()
|
model3.file_references.textures.len()
|
||||||
@@ -48,7 +48,7 @@ impl Live2DRenderer {
|
|||||||
let gl_ctx = RenderContext::new_fullscreen(width, height)?;
|
let gl_ctx = RenderContext::new_fullscreen(width, height)?;
|
||||||
|
|
||||||
let texture_ids: Vec<u32> = textures.iter().map(|t| gl_ctx.create_texture(t)).collect();
|
let texture_ids: Vec<u32> = textures.iter().map(|t| gl_ctx.create_texture(t)).collect();
|
||||||
println!("[Live2D] 已上传 {} 个纹理到 GPU", texture_ids.len());
|
println!("[Live2D] 已上ä¼?{} 个纹ç<C2B9>†åˆ° GPU", texture_ids.len());
|
||||||
|
|
||||||
let canvas = model.canvas;
|
let canvas = model.canvas;
|
||||||
let model_matrix = compute_model_matrix(canvas, width, height);
|
let model_matrix = compute_model_matrix(canvas, width, height);
|
||||||
@@ -84,13 +84,13 @@ impl Live2DRenderer {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let gl = &self.gl_ctx.gl;
|
let gl = &self.gl_ctx.gl;
|
||||||
(gl.gl_clear_color)(0.0, 0.0, 0.0, 1.0);
|
(gl.gl_clear_color)(0.0, 0.0, 0.0, 1.0);
|
||||||
(gl.gl_clear)(gl::GL_COLOR_BUFFER_BIT);
|
(gl.gl_clear)(gl_api::GL_COLOR_BUFFER_BIT);
|
||||||
(gl.gl_enable)(gl::GL_BLEND);
|
(gl.gl_enable)(gl_api::GL_BLEND);
|
||||||
(gl.gl_use_program)(self.gl_ctx.program);
|
(gl.gl_use_program)(self.gl_ctx.program);
|
||||||
(gl.gl_uniform_matrix4fv)(
|
(gl.gl_uniform_matrix4fv)(
|
||||||
self.gl_ctx.uniform_matrix,
|
self.gl_ctx.uniform_matrix,
|
||||||
1,
|
1,
|
||||||
gl::GL_FALSE,
|
gl_api::GL_FALSE,
|
||||||
self.model_matrix.as_ptr(),
|
self.model_matrix.as_ptr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -117,13 +117,12 @@ impl Live2DRenderer {
|
|||||||
// 纹ç<C2B9>†
|
// 纹ç<C2B9>†
|
||||||
let tex_idx = snap.texture_index as usize;
|
let tex_idx = snap.texture_index as usize;
|
||||||
if tex_idx < self.texture_ids.len() {
|
if tex_idx < self.texture_ids.len() {
|
||||||
(gl.gl_active_texture)(gl::GL_TEXTURE0);
|
(gl.gl_active_texture)(gl_api::GL_TEXTURE0);
|
||||||
(gl.gl_bind_texture)(gl::GL_TEXTURE_2D, self.texture_ids[tex_idx]);
|
(gl.gl_bind_texture)(gl_api::GL_TEXTURE_2D, self.texture_ids[tex_idx]);
|
||||||
(gl.gl_uniform1i)(self.gl_ctx.uniform_texture, 0);
|
(gl.gl_uniform1i)(self.gl_ctx.uniform_texture, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// base color(不透明度乘到 alpha)
|
// base color(ä¸<EFBFBD>é€<EFBFBD>明度乘åˆ?alphaï¼? (gl.gl_uniform4f)(self.gl_ctx.uniform_base_color, 1.0, 1.0, 1.0, snap.opacity);
|
||||||
(gl.gl_uniform4f)(self.gl_ctx.uniform_base_color, 1.0, 1.0, 1.0, snap.opacity);
|
|
||||||
// multiply/screen color
|
// multiply/screen color
|
||||||
let mc = snap.multiply_color;
|
let mc = snap.multiply_color;
|
||||||
(gl.gl_uniform4f)(self.gl_ctx.uniform_multiply_color, mc[0], mc[1], mc[2], mc[3]);
|
(gl.gl_uniform4f)(self.gl_ctx.uniform_multiply_color, mc[0], mc[1], mc[2], mc[3]);
|
||||||
@@ -133,16 +132,16 @@ impl Live2DRenderer {
|
|||||||
// æ··å<C2B7>ˆæ¨¡å¼<C3A5>
|
// æ··å<C2B7>ˆæ¨¡å¼<C3A5>
|
||||||
match snap.blend_mode {
|
match snap.blend_mode {
|
||||||
core_ffi::blend_mode::NORMAL => {
|
core_ffi::blend_mode::NORMAL => {
|
||||||
(gl.gl_blend_func)(gl::GL_SRC_ALPHA, gl::GL_ONE_MINUS_SRC_ALPHA);
|
(gl.gl_blend_func)(gl_api::GL_SRC_ALPHA, gl_api::GL_ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
core_ffi::blend_mode::ADDITIVE => {
|
core_ffi::blend_mode::ADDITIVE => {
|
||||||
(gl.gl_blend_func)(gl::GL_SRC_ALPHA, gl::GL_ONE);
|
(gl.gl_blend_func)(gl_api::GL_SRC_ALPHA, gl_api::GL_ONE);
|
||||||
}
|
}
|
||||||
core_ffi::blend_mode::MULTIPLICATIVE => {
|
core_ffi::blend_mode::MULTIPLICATIVE => {
|
||||||
(gl.gl_blend_func)(gl::GL_ZERO, gl::GL_SRC_COLOR);
|
(gl.gl_blend_func)(gl_api::GL_ZERO, gl_api::GL_SRC_COLOR);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
(gl.gl_blend_func)(gl::GL_SRC_ALPHA, gl::GL_ONE_MINUS_SRC_ALPHA);
|
(gl.gl_blend_func)(gl_api::GL_SRC_ALPHA, gl_api::GL_ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,22 +157,22 @@ impl Live2DRenderer {
|
|||||||
|
|
||||||
let mut vbo = 0u32;
|
let mut vbo = 0u32;
|
||||||
(gl.gl_gen_buffers)(1, &mut vbo);
|
(gl.gl_gen_buffers)(1, &mut vbo);
|
||||||
(gl.gl_bind_buffer)(gl::GL_ARRAY_BUFFER, vbo);
|
(gl.gl_bind_buffer)(gl_api::GL_ARRAY_BUFFER, vbo);
|
||||||
(gl.gl_buffer_data)(
|
(gl.gl_buffer_data)(
|
||||||
gl::GL_ARRAY_BUFFER,
|
gl_api::GL_ARRAY_BUFFER,
|
||||||
(vertex_data.len() * 4) as isize,
|
(vertex_data.len() * 4) as isize,
|
||||||
vertex_data.as_ptr() as *const std::ffi::c_void,
|
vertex_data.as_ptr() as *const std::ffi::c_void,
|
||||||
gl::GL_STATIC_DRAW,
|
gl_api::GL_STATIC_DRAW,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut ibo = 0u32;
|
let mut ibo = 0u32;
|
||||||
(gl.gl_gen_buffers)(1, &mut ibo);
|
(gl.gl_gen_buffers)(1, &mut ibo);
|
||||||
(gl.gl_bind_buffer)(gl::GL_ELEMENT_ARRAY_BUFFER, ibo);
|
(gl.gl_bind_buffer)(gl_api::GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||||
(gl.gl_buffer_data)(
|
(gl.gl_buffer_data)(
|
||||||
gl::GL_ELEMENT_ARRAY_BUFFER,
|
gl_api::GL_ELEMENT_ARRAY_BUFFER,
|
||||||
(snap.indices.len() * 2) as isize,
|
(snap.indices.len() * 2) as isize,
|
||||||
snap.indices.as_ptr() as *const std::ffi::c_void,
|
snap.indices.as_ptr() as *const std::ffi::c_void,
|
||||||
gl::GL_STATIC_DRAW,
|
gl_api::GL_STATIC_DRAW,
|
||||||
);
|
);
|
||||||
|
|
||||||
let stride = 4 * 4;
|
let stride = 4 * 4;
|
||||||
@@ -182,8 +181,8 @@ impl Live2DRenderer {
|
|||||||
(gl.gl_vertex_attrib_pointer)(
|
(gl.gl_vertex_attrib_pointer)(
|
||||||
self.gl_ctx.attrib_position as u32,
|
self.gl_ctx.attrib_position as u32,
|
||||||
2,
|
2,
|
||||||
gl::GL_FLOAT,
|
gl_api::GL_FLOAT,
|
||||||
gl::GL_FALSE,
|
gl_api::GL_FALSE,
|
||||||
stride,
|
stride,
|
||||||
std::ptr::null(),
|
std::ptr::null(),
|
||||||
);
|
);
|
||||||
@@ -193,17 +192,17 @@ impl Live2DRenderer {
|
|||||||
(gl.gl_vertex_attrib_pointer)(
|
(gl.gl_vertex_attrib_pointer)(
|
||||||
self.gl_ctx.attrib_tex_coord as u32,
|
self.gl_ctx.attrib_tex_coord as u32,
|
||||||
2,
|
2,
|
||||||
gl::GL_FLOAT,
|
gl_api::GL_FLOAT,
|
||||||
gl::GL_FALSE,
|
gl_api::GL_FALSE,
|
||||||
stride,
|
stride,
|
||||||
(2 * 4) as *const std::ffi::c_void,
|
(2 * 4) as *const std::ffi::c_void,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(gl.gl_draw_elements)(
|
(gl.gl_draw_elements)(
|
||||||
gl::GL_TRIANGLES,
|
gl_api::GL_TRIANGLES,
|
||||||
snap.indices.len() as i32,
|
snap.indices.len() as i32,
|
||||||
gl::GL_UNSIGNED_SHORT,
|
gl_api::GL_UNSIGNED_SHORT,
|
||||||
std::ptr::null(),
|
std::ptr::null(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ impl Live2DRenderer {
|
|||||||
while self.running {
|
while self.running {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
if let Err(e) = self.render_frame() {
|
if let Err(e) = self.render_frame() {
|
||||||
eprintln!("[Live2D] 渲染帧失败: {e}");
|
eprintln!("[Live2D] 渲染帧失� {e}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
@@ -235,14 +234,11 @@ impl Live2DRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 计算 model → NDC 变换矩阵(列优先 4x4)
|
/// 计算 model â†?NDC å<EFBFBD>˜æ<EFBFBD>¢çŸ©é˜µï¼ˆåˆ—优先 4x4ï¼?///
|
||||||
///
|
/// Cubism å<><C3A5>æ ‡ï¼šåŽŸç‚¹åœ¨ canvas ä¸å¿ƒï¼ŒY è½´å<C2B4>‘上,å<C592>•ä½<C3A4>为åƒ<C3A5>ç´ ã€?/// 需è¦<C3A8>ç‰æ¯”缩放使模型完整显示在窗å<E28094>£å†…ã€?fn compute_model_matrix(
|
||||||
/// Cubism 坐标:原点在 canvas 中心,Y 轴向上,单位为像素。
|
|
||||||
/// 需要等比缩放使模型完整显示在窗口内。
|
|
||||||
fn compute_model_matrix(
|
|
||||||
canvas: super::model::CanvasInfo,
|
canvas: super::model::CanvasInfo,
|
||||||
width: i32,
|
_width: i32,
|
||||||
height: i32,
|
_height: i32,
|
||||||
) -> [f32; 16] {
|
) -> [f32; 16] {
|
||||||
let canvas_w = canvas.size[0].max(1.0);
|
let canvas_w = canvas.size[0].max(1.0);
|
||||||
let canvas_h = canvas.size[1].max(1.0);
|
let canvas_h = canvas.size[1].max(1.0);
|
||||||
|
|||||||
Reference in New Issue
Block a user