Skip to main content

oxihuman_export/
webgl_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! WebGL buffer/shader stub export.
6
7/// WebGL buffer type.
8#[derive(Clone, Copy, PartialEq, Debug)]
9pub enum WebGlBufferType {
10    ArrayBuffer,
11    ElementArrayBuffer,
12}
13
14/// A WebGL buffer export entry.
15pub struct WebGlBuffer {
16    pub buffer_type: WebGlBufferType,
17    pub data: Vec<u8>,
18    pub name: String,
19}
20
21/// WebGL export containing buffers and shader stubs.
22pub struct WebGlExport {
23    pub buffers: Vec<WebGlBuffer>,
24    pub vertex_shader_src: String,
25    pub fragment_shader_src: String,
26}
27
28/// Create a new WebGL export with minimal shaders.
29pub fn new_webgl_export() -> WebGlExport {
30    WebGlExport {
31        buffers: Vec::new(),
32        vertex_shader_src: "attribute vec3 aPos;\nvoid main(){gl_Position=vec4(aPos,1.0);}"
33            .to_string(),
34        fragment_shader_src: "void main(){gl_FragColor=vec4(1.0);}".to_string(),
35    }
36}
37
38/// Add a buffer from f32 data.
39pub fn add_webgl_f32_buffer(exp: &mut WebGlExport, name: &str, data: &[f32]) {
40    let bytes: Vec<u8> = data.iter().flat_map(|f| f.to_le_bytes()).collect();
41    exp.buffers.push(WebGlBuffer {
42        buffer_type: WebGlBufferType::ArrayBuffer,
43        data: bytes,
44        name: name.to_string(),
45    });
46}
47
48/// Add an index buffer from u16 data.
49pub fn add_webgl_index_buffer(exp: &mut WebGlExport, name: &str, indices: &[u16]) {
50    let bytes: Vec<u8> = indices.iter().flat_map(|i| i.to_le_bytes()).collect();
51    exp.buffers.push(WebGlBuffer {
52        buffer_type: WebGlBufferType::ElementArrayBuffer,
53        data: bytes,
54        name: name.to_string(),
55    });
56}
57
58/// Buffer count.
59pub fn webgl_buffer_count(exp: &WebGlExport) -> usize {
60    exp.buffers.len()
61}
62
63/// Total byte size of all buffers.
64pub fn webgl_total_bytes(exp: &WebGlExport) -> usize {
65    exp.buffers.iter().map(|b| b.data.len()).sum()
66}
67
68/// Find a buffer by name.
69pub fn find_webgl_buffer<'a>(exp: &'a WebGlExport, name: &str) -> Option<&'a WebGlBuffer> {
70    exp.buffers.iter().find(|b| b.name == name)
71}
72
73/// Validate export (at least vertex shader non-empty).
74pub fn validate_webgl_export(exp: &WebGlExport) -> bool {
75    !exp.vertex_shader_src.is_empty() && !exp.fragment_shader_src.is_empty()
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn new_export_has_no_buffers() {
84        let exp = new_webgl_export();
85        assert_eq!(webgl_buffer_count(&exp), 0 /* no buffers */);
86    }
87
88    #[test]
89    fn add_f32_buffer_increments_count() {
90        let mut exp = new_webgl_export();
91        add_webgl_f32_buffer(&mut exp, "pos", &[0.0, 1.0, 2.0]);
92        assert_eq!(webgl_buffer_count(&exp), 1 /* one buffer */);
93    }
94
95    #[test]
96    fn f32_buffer_correct_byte_size() {
97        let mut exp = new_webgl_export();
98        add_webgl_f32_buffer(&mut exp, "verts", &[0.0f32; 9]);
99        let b = find_webgl_buffer(&exp, "verts").expect("should succeed");
100        assert_eq!(b.data.len(), 36 /* 9 * 4 bytes */);
101    }
102
103    #[test]
104    fn index_buffer_correct_byte_size() {
105        let mut exp = new_webgl_export();
106        add_webgl_index_buffer(&mut exp, "idx", &[0u16, 1, 2]);
107        let b = find_webgl_buffer(&exp, "idx").expect("should succeed");
108        assert_eq!(b.data.len(), 6 /* 3 * 2 bytes */);
109    }
110
111    #[test]
112    fn total_bytes_sum() {
113        let mut exp = new_webgl_export();
114        add_webgl_f32_buffer(&mut exp, "a", &[0.0f32; 3]);
115        add_webgl_index_buffer(&mut exp, "b", &[0u16; 3]);
116        assert_eq!(webgl_total_bytes(&exp), 18 /* 12 + 6 */);
117    }
118
119    #[test]
120    fn find_buffer_by_name() {
121        let mut exp = new_webgl_export();
122        add_webgl_f32_buffer(&mut exp, "normals", &[0.0, 1.0, 0.0]);
123        assert!(find_webgl_buffer(&exp, "normals").is_some() /* found */);
124    }
125
126    #[test]
127    fn find_missing_buffer_none() {
128        let exp = new_webgl_export();
129        assert!(find_webgl_buffer(&exp, "x").is_none() /* not found */);
130    }
131
132    #[test]
133    fn validate_new_export() {
134        let exp = new_webgl_export();
135        assert!(validate_webgl_export(&exp) /* valid */);
136    }
137
138    #[test]
139    fn index_buffer_type_correct() {
140        let mut exp = new_webgl_export();
141        add_webgl_index_buffer(&mut exp, "i", &[0u16]);
142        let b = find_webgl_buffer(&exp, "i").expect("should succeed");
143        assert_eq!(
144            b.buffer_type,
145            WebGlBufferType::ElementArrayBuffer /* element buffer */
146        );
147    }
148}