mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
Also add missing f16 case to core:reflect as_u64 & as_f64 Add tests for above & add previous tests missing from test/core/build.bat
194 lines
4.6 KiB
Odin
194 lines
4.6 KiB
Odin
package encoding_hxa
|
|
|
|
import "core:os"
|
|
import "core:mem"
|
|
|
|
Write_Error :: enum {
|
|
None,
|
|
Buffer_Too_Small,
|
|
Failed_File_Write,
|
|
}
|
|
|
|
write_to_file :: proc(filepath: string, file: File) -> (err: Write_Error) {
|
|
required := required_write_size(file)
|
|
buf, alloc_err := make([]byte, required)
|
|
if alloc_err == .Out_Of_Memory {
|
|
return .Failed_File_Write
|
|
}
|
|
defer delete(buf)
|
|
|
|
write_internal(&Writer{data = buf}, file)
|
|
if !os.write_entire_file(filepath, buf) {
|
|
err =.Failed_File_Write
|
|
}
|
|
return
|
|
}
|
|
|
|
write :: proc(buf: []byte, file: File) -> (n: int, err: Write_Error) {
|
|
required := required_write_size(file)
|
|
if len(buf) < required {
|
|
err = .Buffer_Too_Small
|
|
return
|
|
}
|
|
n = required
|
|
write_internal(&Writer{data = buf}, file)
|
|
return
|
|
}
|
|
|
|
required_write_size :: proc(file: File) -> (n: int) {
|
|
writer := &Writer{dummy_pass = true}
|
|
write_internal(writer, file)
|
|
n = writer.offset
|
|
return
|
|
}
|
|
|
|
|
|
@(private)
|
|
Writer :: struct {
|
|
data: []byte,
|
|
offset: int,
|
|
dummy_pass: bool,
|
|
}
|
|
|
|
@(private)
|
|
write_internal :: proc(w: ^Writer, file: File) {
|
|
write_value :: proc(w: ^Writer, value: $T) {
|
|
if !w.dummy_pass {
|
|
remaining := len(w.data) - w.offset
|
|
assert(size_of(T) <= remaining)
|
|
ptr := raw_data(w.data[w.offset:])
|
|
(^T)(ptr)^ = value
|
|
}
|
|
w.offset += size_of(T)
|
|
}
|
|
write_array :: proc(w: ^Writer, array: []$T) {
|
|
if !w.dummy_pass {
|
|
remaining := len(w.data) - w.offset
|
|
assert(size_of(T)*len(array) <= remaining)
|
|
ptr := raw_data(w.data[w.offset:])
|
|
dst := mem.slice_ptr((^T)(ptr), len(array))
|
|
copy(dst, array)
|
|
}
|
|
w.offset += size_of(T)*len(array)
|
|
}
|
|
write_string :: proc(w: ^Writer, str: string) {
|
|
if !w.dummy_pass {
|
|
remaining := len(w.data) - w.offset
|
|
assert(size_of(byte)*len(str) <= remaining)
|
|
ptr := raw_data(w.data[w.offset:])
|
|
dst := mem.slice_ptr((^byte)(ptr), len(str))
|
|
copy(dst, str)
|
|
}
|
|
w.offset += size_of(byte)*len(str)
|
|
}
|
|
|
|
write_metadata :: proc(w: ^Writer, meta_data: []Meta) {
|
|
for m in meta_data {
|
|
name_len := min(len(m.name), 255)
|
|
write_value(w, u8(name_len))
|
|
write_string(w, m.name[:name_len])
|
|
|
|
meta_data_type: Meta_Value_Type
|
|
length: u32le = 0
|
|
switch v in m.value {
|
|
case []i64le:
|
|
meta_data_type = .Int64
|
|
length = u32le(len(v))
|
|
case []f64le:
|
|
meta_data_type = .Double
|
|
length = u32le(len(v))
|
|
case []Node_Index:
|
|
meta_data_type = .Node
|
|
length = u32le(len(v))
|
|
case string:
|
|
meta_data_type = .Text
|
|
length = u32le(len(v))
|
|
case []byte:
|
|
meta_data_type = .Binary
|
|
length = u32le(len(v))
|
|
case []Meta:
|
|
meta_data_type = .Meta
|
|
length = u32le(len(v))
|
|
}
|
|
write_value(w, meta_data_type)
|
|
write_value(w, length)
|
|
|
|
switch v in m.value {
|
|
case []i64le: write_array(w, v)
|
|
case []f64le: write_array(w, v)
|
|
case []Node_Index: write_array(w, v)
|
|
case string: write_string(w, v)
|
|
case []byte: write_array(w, v)
|
|
case []Meta: write_metadata(w, v)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) {
|
|
write_value(w, u32(len(layers)))
|
|
for layer in layers {
|
|
name_len := min(len(layer.name), 255)
|
|
write_value(w, u8(name_len))
|
|
write_string(w, layer .name[:name_len])
|
|
|
|
write_value(w, layer.components)
|
|
|
|
layer_data_type: Layer_Data_Type
|
|
switch v in layer.data {
|
|
case []u8: layer_data_type = .Uint8
|
|
case []i32le: layer_data_type = .Int32
|
|
case []f32le: layer_data_type = .Float
|
|
case []f64le: layer_data_type = .Double
|
|
}
|
|
write_value(w, layer_data_type)
|
|
|
|
switch v in layer.data {
|
|
case []u8: write_array(w, v)
|
|
case []i32le: write_array(w, v)
|
|
case []f32le: write_array(w, v)
|
|
case []f64le: write_array(w, v)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
write_value(w, Header{
|
|
magic_number = MAGIC_NUMBER,
|
|
version = LATEST_VERSION,
|
|
internal_node_count = u32le(len(file.nodes)),
|
|
})
|
|
|
|
for node in file.nodes {
|
|
node_type: Node_Type
|
|
switch content in node.content {
|
|
case Node_Geometry: node_type = .Geometry
|
|
case Node_Image: node_type = .Image
|
|
}
|
|
write_value(w, node_type)
|
|
|
|
write_value(w, u32(len(node.meta_data)))
|
|
write_metadata(w, node.meta_data)
|
|
|
|
switch content in node.content {
|
|
case Node_Geometry:
|
|
write_value(w, content.vertex_count)
|
|
write_layer_stack(w, content.vertex_stack)
|
|
write_value(w, content.edge_corner_count)
|
|
write_layer_stack(w, content.corner_stack)
|
|
write_layer_stack(w, content.edge_stack)
|
|
write_value(w, content.face_count)
|
|
write_layer_stack(w, content.face_stack)
|
|
case Node_Image:
|
|
write_value(w, content.type)
|
|
dimensions := int(content.type)
|
|
if content.type == .Image_Cube {
|
|
dimensions = 2
|
|
}
|
|
for d in 0..<dimensions {
|
|
write_value(w, content.resolution[d])
|
|
}
|
|
write_layer_stack(w, content.image_stack)
|
|
}
|
|
}
|
|
}
|