Browse Source

Merge branch 'odin-lang:master' into master

ftphikari 3 years ago
parent
commit
240fb9b953

+ 15 - 6
core/container/lru/lru_cache.odin

@@ -60,6 +60,8 @@ clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
 set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error {
 	if e, ok := c.entries[key]; ok {
 		e.value = value
+		_pop_node(c, e)
+		_push_front_node(c, e)
 		return nil
 	}
 
@@ -67,10 +69,14 @@ set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Alloc
 	e.key = key
 	e.value = value
 
-	_push_front_node(c, e)
-	if c.count > c.capacity {
+	assert(c.count <= c.capacity)
+	if c.count == c.capacity {
 		_remove_node(c, c.tail)
 	}
+	else {
+		c.count += 1
+	}
+	_push_front_node(c, e)
 
 	c.entries[key] = e
 	return nil
@@ -122,6 +128,7 @@ remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
 		return false
 	}
 	_remove_node(c, e)
+	c.count -= 1
 	return true
 }
 
@@ -143,8 +150,6 @@ _remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
 	node.prev = nil
 	node.next = nil
 
-	c.count -= 1
-
 	delete_key(&c.entries, node.key)
 
 	_call_on_remove(c, node)
@@ -171,8 +176,6 @@ _push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
 		c.tail = e
 	}
 	e.prev = nil
-
-	c.count += 1
 }
 
 @(private)
@@ -180,6 +183,12 @@ _pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
 	if e == nil {
 		return
 	}
+	if c.head == e {
+		c.head = e.next
+	}
+	if c.tail == e {
+		c.tail = e.prev
+	}
 	if e.prev != nil {
 		e.prev.next = e.next
 	}

+ 14 - 0
core/image/common.odin

@@ -320,6 +320,20 @@ QOI_Info :: struct {
 	header: QOI_Header,
 }
 
+TGA_Header :: struct #packed {
+	id_length:        u8,
+	color_map_type:   u8,
+	data_type_code:   u8,
+	color_map_origin: u16le,
+	color_map_length: u16le,
+	color_map_depth:  u8,
+	origin:           [2]u16le,
+	dimensions:       [2]u16le,
+	bits_per_pixel:   u8,
+	image_descriptor: u8,
+}
+#assert(size_of(TGA_Header) == 18)
+
 // Function to help with image buffer calculations
 compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
 	size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height

+ 103 - 0
core/image/tga/tga.odin

@@ -0,0 +1,103 @@
+/*
+	Copyright 2022 Jeroen van Rijn <[email protected]>.
+	Made available under Odin's BSD-3 license.
+
+	List of contributors:
+		Jeroen van Rijn: Initial implementation.
+*/
+
+
+// package tga implements a TGA image writer for 8-bit RGB and RGBA images.
+package tga
+
+import "core:mem"
+import "core:image"
+import "core:compress"
+import "core:bytes"
+import "core:os"
+
+Error   :: image.Error
+General :: compress.General_Error
+Image   :: image.Image
+Options :: image.Options
+
+RGB_Pixel  :: image.RGB_Pixel
+RGBA_Pixel :: image.RGBA_Pixel
+
+save_to_memory  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	if img == nil {
+		return .Invalid_Input_Image
+	}
+
+	if output == nil {
+		return .Invalid_Output
+	}
+
+	pixels := img.width * img.height
+	if pixels == 0 || pixels > image.MAX_DIMENSIONS || img.width > 65535 || img.height > 65535 {
+		return .Invalid_Input_Image
+	}
+
+	// Our TGA writer supports only 8-bit images with 3 or 4 channels.
+	if img.depth != 8 || img.channels < 3 || img.channels > 4 {
+		return .Invalid_Input_Image
+	}
+
+	if img.channels * pixels != len(img.pixels.buf) {
+		return .Invalid_Input_Image
+	}
+
+	written := 0
+
+	// Calculate and allocate necessary space.
+	necessary := pixels * img.channels + size_of(image.TGA_Header)
+
+	if !resize(&output.buf, necessary) {
+		return General.Resize_Failed
+	}
+
+	header := image.TGA_Header{
+		data_type_code   = 0x02, // Color, uncompressed.
+		dimensions       = {u16le(img.width), u16le(img.height)},
+		bits_per_pixel   = u8(img.depth * img.channels),
+		image_descriptor = 1 << 5, // Origin is top left.
+	}
+	header_bytes := transmute([size_of(image.TGA_Header)]u8)header
+
+	copy(output.buf[written:], header_bytes[:])
+	written += size_of(image.TGA_Header)
+
+	/*
+		Encode loop starts here.
+	*/
+	if img.channels == 3 {
+		pix := mem.slice_data_cast([]RGB_Pixel, img.pixels.buf[:])
+		out := mem.slice_data_cast([]RGB_Pixel, output.buf[written:])
+		for p, i in pix {
+			out[i] = p.bgr
+		}
+	} else if img.channels == 4 {
+		pix := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:])
+		out := mem.slice_data_cast([]RGBA_Pixel, output.buf[written:])
+		for p, i in pix {
+			out[i] = p.bgra
+		}
+	}
+	return nil
+}
+
+save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	out := &bytes.Buffer{}
+	defer bytes.buffer_destroy(out)
+
+	save_to_memory(out, img, options) or_return
+	write_ok := os.write_entire_file(output, out.buf[:])
+
+	return nil if write_ok else General.Cannot_Open_File
+}
+
+save :: proc{save_to_memory, save_to_file}

+ 47 - 0
core/slice/slice.odin

@@ -10,6 +10,53 @@ _ :: builtin
 _ :: bits
 _ :: mem
 
+/*
+	Turn a pointer and a length into a slice.
+*/
+from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
+    return ([^]T)(ptr)[:count]
+}
+
+/*
+	Turn a pointer and a length into a byte slice.
+*/
+bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
+    return ([^]byte)(ptr)[:byte_count]
+}
+
+/*
+	Turn a slice into a byte slice.
+
+	See `slice.reinterpret` to go the other way.
+*/
+to_bytes :: proc "contextless" (s: []$T) -> []byte {
+	return ([^]byte)(raw_data(s))[:len(s) * size_of(T)]
+}
+
+/*
+	Turn a slice of one type, into a slice of another type.
+
+	Only converts the type and length of the slice itself.
+	The length is rounded down to the nearest whole number of items.
+
+	```
+	large_items := []i64{1, 2, 3, 4}
+	small_items := slice.reinterpret([]i32, large_items)
+	assert(len(small_items) == 8)
+	```
+	```
+	small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
+	                      2, 0, 0, 0}
+	large_items := slice.reinterpret([]i64, small_items)
+	assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
+	```
+*/
+reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U {
+	bytes := to_bytes(s)
+	n := len(bytes) / size_of(U)
+	return ([^]U)(raw_data(bytes))[:n]
+}
+
 
 swap :: proc(array: $T/[]$E, a, b: int) {
 	when size_of(E) > 8 {

BIN
tests/core/encoding/varint/varint