/*************************************************************************/
/*  data_buffer.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

/**
	@author AndreaCatania
*/

#include "data_buffer.h"

#include "core/io/marshalls.h"

// TODO improve the allocation mechanism.

void DataBuffer::_bind_methods() {
	BIND_ENUM_CONSTANT(DATA_TYPE_BOOL);
	BIND_ENUM_CONSTANT(DATA_TYPE_INT);
	BIND_ENUM_CONSTANT(DATA_TYPE_REAL);
	BIND_ENUM_CONSTANT(DATA_TYPE_UNIT_REAL);
	BIND_ENUM_CONSTANT(DATA_TYPE_VECTOR2);
	BIND_ENUM_CONSTANT(DATA_TYPE_NORMALIZED_VECTOR2);
	BIND_ENUM_CONSTANT(DATA_TYPE_VECTOR3);
	BIND_ENUM_CONSTANT(DATA_TYPE_NORMALIZED_VECTOR3);

	BIND_ENUM_CONSTANT(COMPRESSION_LEVEL_0);
	BIND_ENUM_CONSTANT(COMPRESSION_LEVEL_1);
	BIND_ENUM_CONSTANT(COMPRESSION_LEVEL_2);
	BIND_ENUM_CONSTANT(COMPRESSION_LEVEL_3);

	ClassDB::bind_method(D_METHOD("size"), &DataBuffer::size);

	ClassDB::bind_method(D_METHOD("add_bool", "value"), &DataBuffer::add_bool);
	ClassDB::bind_method(D_METHOD("add_int", "value", "compression_level"), &DataBuffer::add_int, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_real", "value", "compression_level"), &DataBuffer::add_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_positive_unit_real", "value", "compression_level"), &DataBuffer::add_positive_unit_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_unit_real", "value", "compression_level"), &DataBuffer::add_unit_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_vector2", "value", "compression_level"), &DataBuffer::add_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_normalized_vector2", "value", "compression_level"), &DataBuffer::add_normalized_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_vector3", "value", "compression_level"), &DataBuffer::add_vector3, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_normalized_vector3", "value", "compression_level"), &DataBuffer::add_normalized_vector3, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("add_variant", "value"), &DataBuffer::add_variant);

	ClassDB::bind_method(D_METHOD("read_bool"), &DataBuffer::read_bool);
	ClassDB::bind_method(D_METHOD("read_int", "compression_level"), &DataBuffer::read_int, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_real", "compression_level"), &DataBuffer::read_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_unit_real", "compression_level"), &DataBuffer::read_unit_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_vector2", "compression_level"), &DataBuffer::read_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_normalized_vector2", "compression_level"), &DataBuffer::read_normalized_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_vector3", "compression_level"), &DataBuffer::read_vector3, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_normalized_vector3", "compression_level"), &DataBuffer::read_normalized_vector3, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_variant"), &DataBuffer::read_variant);

	ClassDB::bind_method(D_METHOD("skip_bool"), &DataBuffer::skip_bool);
	ClassDB::bind_method(D_METHOD("skip_int", "compression_level"), &DataBuffer::skip_int, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_real", "compression_level"), &DataBuffer::skip_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_unit_real", "compression_level"), &DataBuffer::skip_unit_real, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_vector2", "compression_level"), &DataBuffer::skip_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_normalized_vector2", "compression_level"), &DataBuffer::skip_normalized_vector2, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_vector3", "compression_level"), &DataBuffer::skip_vector3, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("skip_normalized_vector3", "compression_level"), &DataBuffer::skip_normalized_vector3, DEFVAL(COMPRESSION_LEVEL_1));

	ClassDB::bind_method(D_METHOD("get_bool_size"), &DataBuffer::get_bool_size);
	ClassDB::bind_method(D_METHOD("get_int_size", "compression_level"), &DataBuffer::get_int_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_real_size", "compression_level"), &DataBuffer::get_real_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_unit_real_size", "compression_level"), &DataBuffer::get_unit_real_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_vector2_size", "compression_level"), &DataBuffer::get_vector2_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_normalized_vector2_size", "compression_level"), &DataBuffer::get_normalized_vector2_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_vector3_size", "compression_level"), &DataBuffer::get_vector3_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("get_normalized_vector3_size", "compression_level"), &DataBuffer::get_normalized_vector3_size, DEFVAL(COMPRESSION_LEVEL_1));

	ClassDB::bind_method(D_METHOD("read_bool_size"), &DataBuffer::read_bool_size);
	ClassDB::bind_method(D_METHOD("read_int_size", "compression_level"), &DataBuffer::read_int_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_real_size", "compression_level"), &DataBuffer::read_real_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_unit_real_size", "compression_level"), &DataBuffer::read_unit_real_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_vector2_size", "compression_level"), &DataBuffer::read_vector2_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_normalized_vector2_size", "compression_level"), &DataBuffer::read_normalized_vector2_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_vector3_size", "compression_level"), &DataBuffer::read_vector3_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_normalized_vector3_size", "compression_level"), &DataBuffer::read_normalized_vector3_size, DEFVAL(COMPRESSION_LEVEL_1));
	ClassDB::bind_method(D_METHOD("read_variant_size"), &DataBuffer::read_variant_size);

	ClassDB::bind_method(D_METHOD("begin_read"), &DataBuffer::begin_read);
	ClassDB::bind_method(D_METHOD("begin_write", "meta_size"), &DataBuffer::begin_write);
	ClassDB::bind_method(D_METHOD("dry"), &DataBuffer::dry);
}

DataBuffer::DataBuffer(const DataBuffer &p_other) :
		Object(),
		metadata_size(p_other.metadata_size),
		bit_offset(p_other.bit_offset),
		bit_size(p_other.bit_size),
		is_reading(p_other.is_reading),
		buffer(p_other.buffer) {}

DataBuffer::DataBuffer(const BitArray &p_buffer) :
		Object(),
		bit_size(p_buffer.size_in_bits()),
		is_reading(true),
		buffer(p_buffer) {}

void DataBuffer::begin_write(int p_metadata_size) {
	CRASH_COND_MSG(p_metadata_size < 0, "Metadata size can't be negative");
	metadata_size = p_metadata_size;
	bit_size = 0;
	bit_offset = 0;
	is_reading = false;
}

void DataBuffer::dry() {
	buffer.resize_in_bits(metadata_size + bit_size);
}

void DataBuffer::seek(int p_bits) {
	ERR_FAIL_INDEX(p_bits, metadata_size + bit_size + 1);
	bit_offset = p_bits;
}

void DataBuffer::shrink_to(int p_metadata_bit_size, int p_bit_size) {
	CRASH_COND_MSG(p_metadata_bit_size < 0, "Metadata size can't be negative");
	ERR_FAIL_COND_MSG(p_bit_size < 0, "Bit size can't be negative");
	ERR_FAIL_COND_MSG(buffer.size_in_bits() < (p_metadata_bit_size + p_bit_size), "The buffer is smaller than the new given size.");
	metadata_size = p_metadata_bit_size;
	bit_size = p_bit_size;
}

int DataBuffer::get_metadata_size() const {
	return metadata_size;
}

int DataBuffer::size() const {
	return bit_size;
}

int DataBuffer::total_size() const {
	return bit_size + metadata_size;
}

int DataBuffer::get_bit_offset() const {
	return bit_offset;
}

void DataBuffer::skip(int p_bits) {
	ERR_FAIL_COND((metadata_size + bit_size) < (bit_offset + p_bits));
	bit_offset += p_bits;
}

void DataBuffer::begin_read() {
	bit_offset = 0;
	is_reading = true;
}

bool DataBuffer::add_bool(bool p_input) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const int bits = get_bit_taken(DATA_TYPE_BOOL, COMPRESSION_LEVEL_0);

	make_room_in_bits(bits);
	buffer.store_bits(bit_offset, p_input, bits);
	bit_offset += bits;

#ifdef DEBUG_ENABLED
	// Can't never happen because the buffer size is correctly handled.
	CRASH_COND((metadata_size + bit_size) > buffer.size_in_bits() && bit_offset > buffer.size_in_bits());
#endif

	return p_input;
}

bool DataBuffer::read_bool() {
	ERR_FAIL_COND_V(is_reading == false, false);

	const int bits = get_bit_taken(DATA_TYPE_BOOL, COMPRESSION_LEVEL_0);
	const bool d = buffer.read_bits(bit_offset, bits);
	bit_offset += bits;
	return d;
}

int64_t DataBuffer::add_int(int64_t p_input, CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const int bits = get_bit_taken(DATA_TYPE_INT, p_compression_level);

	int64_t value = p_input;

	// Clamp the value to the max that the bit can store.
	if (bits == 8) {
		value = CLAMP(value, INT8_MIN, INT8_MAX);
	} else if (bits == 16) {
		value = CLAMP(value, INT16_MIN, INT16_MAX);
	} else if (bits == 32) {
		value = CLAMP(value, INT32_MIN, INT32_MAX);
	} else {
		// Nothing to do here
	}

	make_room_in_bits(bits);
	buffer.store_bits(bit_offset, value, bits);
	bit_offset += bits;

#ifdef DEBUG_ENABLED
	// Can't never happen because the buffer size is correctly handled.
	CRASH_COND((metadata_size + bit_size) > buffer.size_in_bits() && bit_offset > buffer.size_in_bits());
#endif

	if (bits == 8) {
		return static_cast<int8_t>(value);
	} else if (bits == 16) {
		return static_cast<int16_t>(value);
	} else if (bits == 32) {
		return static_cast<int32_t>(value);
	} else {
		return value;
	}
}

int64_t DataBuffer::read_int(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, 0);

	const int bits = get_bit_taken(DATA_TYPE_INT, p_compression_level);

	const uint64_t value = buffer.read_bits(bit_offset, bits);
	bit_offset += bits;

	if (bits == 8) {
		return static_cast<int8_t>(value);
	} else if (bits == 16) {
		return static_cast<int16_t>(value);
	} else if (bits == 32) {
		return static_cast<int32_t>(value);
	} else {
		return static_cast<int64_t>(value);
	}
}

double DataBuffer::add_real(double p_input, CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

	// Clamp the input value according to the compression level
	// Minifloat (compression level 0) have a special bias
	const int exponent_bits = get_exponent_bits(p_compression_level);
	const int mantissa_bits = get_mantissa_bits(p_compression_level);
	const double bias = p_compression_level == COMPRESSION_LEVEL_3 ? Math::pow(2.0, exponent_bits) - 3 : Math::pow(2.0, exponent_bits - 1) - 1;
	const double max_value = (2.0 - Math::pow(2.0, -(mantissa_bits - 1))) * Math::pow(2.0, bias);
	const double clamped_input = CLAMP(p_input, -max_value, max_value);

	// Split number according to IEEE 754 binary format.
	// Mantissa floating point value represented in range (-1;-0.5], [0.5; 1).
	int exponent;
	double mantissa = frexp(clamped_input, &exponent);

	// Extract sign.
	const bool sign = mantissa < 0;
	mantissa = Math::abs(mantissa);

	// Round mantissa into the specified number of bits (like float -> double conversion).
	double mantissa_scale = Math::pow(2.0, mantissa_bits);
	if (exponent <= 0) {
		// Subnormal value, apply exponent to mantissa and reduce power of scale by one.
		mantissa *= Math::pow(2.0, exponent);
		exponent = 0;
		mantissa_scale /= 2.0;
	}
	mantissa = Math::round(mantissa * mantissa_scale) / mantissa_scale; // Round to specified number of bits.
	if (mantissa < 0.5 && mantissa != 0) {
		// Check underflow, extract exponent from mantissa.
		exponent += ilogb(mantissa) + 1;
		mantissa /= Math::pow(2.0, exponent);
	} else if (mantissa == 1) {
		// Check overflow, increment the exponent.
		++exponent;
		mantissa = 0.5;
	}
	// Convert the mantissa to an integer that represents the offset index (IEE 754 floating point representation) to send over network safely.
	const uint64_t integer_mantissa = exponent <= 0 ? mantissa * mantissa_scale * Math::pow(2.0, exponent) : (mantissa - 0.5) * mantissa_scale;

	make_room_in_bits(mantissa_bits + exponent_bits);
	buffer.store_bits(bit_offset, sign, 1);
	bit_offset += 1;
	buffer.store_bits(bit_offset, integer_mantissa, mantissa_bits - 1);
	bit_offset += mantissa_bits - 1;
	// Send unsigned value (just shift it by bias) to avoid sign issues.
	buffer.store_bits(bit_offset, exponent + bias, exponent_bits);
	bit_offset += exponent_bits;

	return ldexp(sign ? -mantissa : mantissa, exponent);
}

double DataBuffer::read_real(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, 0.0);

	const bool sign = buffer.read_bits(bit_offset, 1);
	bit_offset += 1;

	const int mantissa_bits = get_mantissa_bits(p_compression_level);
	const uint64_t integer_mantissa = buffer.read_bits(bit_offset, mantissa_bits - 1);
	bit_offset += mantissa_bits - 1;

	const int exponent_bits = get_exponent_bits(p_compression_level);
	const double bias = p_compression_level == COMPRESSION_LEVEL_3 ? Math::pow(2.0, exponent_bits) - 3 : Math::pow(2.0, exponent_bits - 1) - 1;
	int exponent = static_cast<int>(buffer.read_bits(bit_offset, exponent_bits)) - static_cast<int>(bias);
	bit_offset += exponent_bits;

	// Convert integer mantissa into the floating point representation
	// When the index of the mantissa and exponent are 0, then this is a special case and the mantissa is 0.
	const double mantissa_scale = Math::pow(2.0, exponent <= 0 ? mantissa_bits - 1 : mantissa_bits);
	const double mantissa = exponent <= 0 ? integer_mantissa / mantissa_scale / Math::pow(2.0, exponent) : integer_mantissa / mantissa_scale + 0.5;

	return ldexp(sign ? -mantissa : mantissa, exponent);
}

real_t DataBuffer::add_positive_unit_real(real_t p_input, CompressionLevel p_compression_level) {
#ifdef DEBUG_ENABLED
	ERR_FAIL_COND_V_MSG(p_input < 0 || p_input > 1, p_input, "Value must be between zero and one.");
#endif
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const int bits = get_bit_taken(DATA_TYPE_UNIT_REAL, p_compression_level);

	const double max_value = static_cast<double>(~(UINT64_MAX << bits));

	const uint64_t compressed_val = compress_unit_float(p_input, max_value);

	make_room_in_bits(bits);
	buffer.store_bits(bit_offset, compressed_val, bits);
	bit_offset += bits;

#ifdef DEBUG_ENABLED
	// Can't never happen because the buffer size is correctly handled.
	CRASH_COND((metadata_size + bit_size) > buffer.size_in_bits() && bit_offset > buffer.size_in_bits());
#endif

	return decompress_unit_float(compressed_val, max_value);
}

real_t DataBuffer::read_positive_unit_real(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, 0.0);

	const int bits = get_bit_taken(DATA_TYPE_UNIT_REAL, p_compression_level);

	const double max_value = static_cast<double>(~(UINT64_MAX << bits));

	const uint64_t compressed_val = buffer.read_bits(bit_offset, bits);
	bit_offset += bits;

	return decompress_unit_float(compressed_val, max_value);
}

real_t DataBuffer::add_unit_real(real_t p_input, CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const real_t added_real = add_positive_unit_real(ABS(p_input), p_compression_level);

	const int bits_for_sign = 1;
	const uint32_t is_negative = p_input < 0.0;
	make_room_in_bits(bits_for_sign);
	buffer.store_bits(bit_offset, is_negative, bits_for_sign);
	bit_offset += bits_for_sign;

#ifdef DEBUG_ENABLED
	// Can't never happen because the buffer size is correctly handled.
	CRASH_COND((metadata_size + bit_size) > buffer.size_in_bits() && bit_offset > buffer.size_in_bits());
#endif

	return is_negative ? -added_real : added_real;
}

real_t DataBuffer::read_unit_real(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, 0.0);

	const real_t value = read_positive_unit_real(p_compression_level);

	const int bits_for_sign = 1;
	const bool is_negative = buffer.read_bits(bit_offset, bits_for_sign);
	bit_offset += bits_for_sign;

	return is_negative ? -value : value;
}

Vector2 DataBuffer::add_vector2(Vector2 p_input, CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

#ifndef REAL_T_IS_DOUBLE
	// Fallback to compression level 1 if real_t is float
	if (p_compression_level == DataBuffer::COMPRESSION_LEVEL_0) {
		WARN_PRINT_ONCE("Compression level 0 is not supported for Vector2 for a binary compiled with single precision float. Falling back to compression level 1");
		p_compression_level = DataBuffer::COMPRESSION_LEVEL_1;
	}
#endif

	Vector2 r;
	r[0] = add_real(p_input[0], p_compression_level);
	r[1] = add_real(p_input[1], p_compression_level);
	return r;
}

Vector2 DataBuffer::read_vector2(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, Vector2());

#ifndef REAL_T_IS_DOUBLE
	// Fallback to compression level 1 if real_t is float
	if (p_compression_level == DataBuffer::COMPRESSION_LEVEL_0) {
		WARN_PRINT_ONCE("Compression level 0 is not supported for Vector2 for a binary compiled with single precision float. Falling back to compression level 1");
		p_compression_level = DataBuffer::COMPRESSION_LEVEL_1;
	}
#endif

	Vector2 r;
	r[0] = read_real(p_compression_level);
	r[1] = read_real(p_compression_level);
	return r;
}

Vector2 DataBuffer::add_normalized_vector2(Vector2 p_input, CompressionLevel p_compression_level) {
#ifdef DEBUG_ENABLED
	ERR_FAIL_COND_V(p_input.is_normalized() == false, p_input);
#endif
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const int bits = get_bit_taken(DATA_TYPE_NORMALIZED_VECTOR2, p_compression_level);
	const int bits_for_the_angle = bits - 1;
	const int bits_for_zero = 1;

	const double angle = p_input.angle();
	const uint32_t is_not_zero = p_input.length_squared() > CMP_EPSILON;

	const double max_value = static_cast<double>(~(UINT64_MAX << bits_for_the_angle));

	const uint64_t compressed_angle = compress_unit_float((angle + Math_PI) / Math_TAU, max_value);

	make_room_in_bits(bits);
	buffer.store_bits(bit_offset, is_not_zero, bits_for_zero);
	buffer.store_bits(bit_offset + 1, compressed_angle, bits_for_the_angle);
	bit_offset += bits;

	const real_t decompressed_angle = (decompress_unit_float(compressed_angle, max_value) * Math_TAU) - Math_PI;
	const real_t x = Math::cos(decompressed_angle);
	const real_t y = Math::sin(decompressed_angle);

#ifdef DEBUG_ENABLED
	// Can't never happen because the buffer size is correctly handled.
	CRASH_COND((metadata_size + bit_size) > buffer.size_in_bits() && bit_offset > buffer.size_in_bits());
#endif

	return Vector2(x, y) * is_not_zero;
}

Vector2 DataBuffer::read_normalized_vector2(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, Vector2());

	const int bits = get_bit_taken(DATA_TYPE_NORMALIZED_VECTOR2, p_compression_level);
	const int bits_for_the_angle = bits - 1;
	const int bits_for_zero = 1;

	const double max_value = static_cast<double>(~(UINT64_MAX << bits_for_the_angle));

	const real_t is_not_zero = buffer.read_bits(bit_offset, bits_for_zero);
	const uint64_t compressed_angle = buffer.read_bits(bit_offset + 1, bits_for_the_angle);
	bit_offset += bits;

	const real_t decompressed_angle = (decompress_unit_float(compressed_angle, max_value) * Math_TAU) - Math_PI;
	const real_t x = Math::cos(decompressed_angle);
	const real_t y = Math::sin(decompressed_angle);

	return Vector2(x, y) * is_not_zero;
}

Vector3 DataBuffer::add_vector3(Vector3 p_input, CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == true, p_input);

#ifndef REAL_T_IS_DOUBLE
	// Fallback to compression level 1 if real_t is float
	if (p_compression_level == DataBuffer::COMPRESSION_LEVEL_0) {
		WARN_PRINT_ONCE("Compression level 0 is not supported for Vector3 for a binary compiled with single precision float. Falling back to compression level 1");
		p_compression_level = DataBuffer::COMPRESSION_LEVEL_1;
	}
#endif

	Vector3 r;
	r[0] = add_real(p_input[0], p_compression_level);
	r[1] = add_real(p_input[1], p_compression_level);
	r[2] = add_real(p_input[2], p_compression_level);
	return r;
}

Vector3 DataBuffer::read_vector3(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, Vector3());

#ifndef REAL_T_IS_DOUBLE
	// Fallback to compression level 1 if real_t is float
	if (p_compression_level == DataBuffer::COMPRESSION_LEVEL_0) {
		WARN_PRINT_ONCE("Compression level 0 is not supported for Vector3 for a binary compiled with single precision float. Falling back to compression level 1");
		p_compression_level = DataBuffer::COMPRESSION_LEVEL_1;
	}
#endif

	Vector3 r;
	r[0] = read_real(p_compression_level);
	r[1] = read_real(p_compression_level);
	r[2] = read_real(p_compression_level);
	return r;
}

Vector3 DataBuffer::add_normalized_vector3(Vector3 p_input, CompressionLevel p_compression_level) {
#ifdef DEBUG_ENABLED
	ERR_FAIL_COND_V(p_input.is_normalized() == false, p_input);
#endif
	ERR_FAIL_COND_V(is_reading == true, p_input);

	const real_t x_axis = add_unit_real(p_input.x, p_compression_level);
	const real_t y_axis = add_unit_real(p_input.y, p_compression_level);
	const real_t z_axis = add_unit_real(p_input.z, p_compression_level);

	return Vector3(x_axis, y_axis, z_axis);
}

Vector3 DataBuffer::read_normalized_vector3(CompressionLevel p_compression_level) {
	ERR_FAIL_COND_V(is_reading == false, Vector3());

	const real_t x_axis = read_unit_real(p_compression_level);
	const real_t y_axis = read_unit_real(p_compression_level);
	const real_t z_axis = read_unit_real(p_compression_level);

	return Vector3(x_axis, y_axis, z_axis);
}

Variant DataBuffer::add_variant(const Variant &p_input) {
	// TODO consider to use a method similar to `_encode_and_compress_variant`
	// to compress the encoded data a bit.

	// Get the variant size.
	int len = 0;

	const Error len_err = encode_variant(
			p_input,
			nullptr,
			len,
			false);

	ERR_FAIL_COND_V_MSG(
			len_err != OK,
			Variant(),
			"Was not possible encode the variant.");

	// Variant encoding pads the data to byte, so doesn't make sense write it
	// unpadded.
	make_room_pad_to_next_byte();
	make_room_in_bits(len * 8);

#ifdef DEBUG_ENABLED
	// This condition is always false thanks to the `make_room_pad_to_next_byte`.
	// so it's safe to assume we are starting from the begin of the byte.
	CRASH_COND((bit_offset % 8) != 0);
#endif

	const Error write_err = encode_variant(
			p_input,
			buffer.get_bytes_mut().write().ptr() + (bit_offset / 8),
			len,
			false);

	ERR_FAIL_COND_V_MSG(
			write_err != OK,
			Variant(),
			"Was not possible encode the variant.");

	bit_offset += len * 8;

	return p_input;
}

Variant DataBuffer::read_variant() {
	Variant ret;

	int len = 0;

	// The Variant is always written starting from the beginning of the byte.
	const bool success = pad_to_next_byte();
	ERR_FAIL_COND_V_MSG(success == false, Variant(), "Padding failed.");

#ifdef DEBUG_ENABLED
	// This condition is always false thanks to the `pad_to_next_byte`; So is
	// safe to assume we are starting from the begin of the byte.
	CRASH_COND((bit_offset % 8) != 0);
#endif

	const Error read_err = decode_variant(
			ret,
			buffer.get_bytes_mut().write().ptr() + (bit_offset / 8),
			buffer.size_in_bytes() - (bit_offset / 8),
			&len,
			false);

	ERR_FAIL_COND_V_MSG(
			read_err != OK,
			Variant(),
			"Was not possible decode the variant.");

	bit_offset += len * 8;

	return ret;
}

void DataBuffer::zero() {
	buffer.zero();
}

void DataBuffer::skip_bool() {
	const int bits = get_bool_size();
	skip(bits);
}

void DataBuffer::skip_int(CompressionLevel p_compression) {
	const int bits = get_int_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_real(CompressionLevel p_compression) {
	const int bits = get_real_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_unit_real(CompressionLevel p_compression) {
	const int bits = get_unit_real_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_vector2(CompressionLevel p_compression) {
	const int bits = get_vector2_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_normalized_vector2(CompressionLevel p_compression) {
	const int bits = get_normalized_vector2_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_vector3(CompressionLevel p_compression) {
	const int bits = get_vector3_size(p_compression);
	skip(bits);
}

void DataBuffer::skip_normalized_vector3(CompressionLevel p_compression) {
	const int bits = get_normalized_vector3_size(p_compression);
	skip(bits);
}

int DataBuffer::get_bool_size() const {
	return DataBuffer::get_bit_taken(DATA_TYPE_BOOL, COMPRESSION_LEVEL_0);
}

int DataBuffer::get_int_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_INT, p_compression);
}

int DataBuffer::get_real_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_REAL, p_compression);
}

int DataBuffer::get_unit_real_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_UNIT_REAL, p_compression);
}

int DataBuffer::get_vector2_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_VECTOR2, p_compression);
}

int DataBuffer::get_normalized_vector2_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_NORMALIZED_VECTOR2, p_compression);
}

int DataBuffer::get_vector3_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_VECTOR3, p_compression);
}

int DataBuffer::get_normalized_vector3_size(CompressionLevel p_compression) const {
	return DataBuffer::get_bit_taken(DATA_TYPE_NORMALIZED_VECTOR3, p_compression);
}

int DataBuffer::read_bool_size() {
	const int bits = get_bool_size();
	skip(bits);
	return bits;
}

int DataBuffer::read_int_size(CompressionLevel p_compression) {
	const int bits = get_int_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_real_size(CompressionLevel p_compression) {
	const int bits = get_real_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_unit_real_size(CompressionLevel p_compression) {
	const int bits = get_unit_real_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_vector2_size(CompressionLevel p_compression) {
	const int bits = get_vector2_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_normalized_vector2_size(CompressionLevel p_compression) {
	const int bits = get_normalized_vector2_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_vector3_size(CompressionLevel p_compression) {
	const int bits = get_vector3_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_normalized_vector3_size(CompressionLevel p_compression) {
	const int bits = get_normalized_vector3_size(p_compression);
	skip(bits);
	return bits;
}

int DataBuffer::read_variant_size() {
	int len = 0;

	Variant ret;

	// The Variant is always written starting from the beginning of the byte.
	const bool success = pad_to_next_byte();
	ERR_FAIL_COND_V_MSG(success == false, Variant(), "Padding failed.");

#ifdef DEBUG_ENABLED
	// This condition is always false thanks to the `pad_to_next_byte`; So is
	// safe to assume we are starting from the begin of the byte.
	CRASH_COND((bit_offset % 8) != 0);
#endif

	const Error read_err = decode_variant(
			ret,
			buffer.get_bytes_mut().write().ptr() + (bit_offset / 8),
			buffer.size_in_bytes() - (bit_offset / 8),
			&len,
			false);

	ERR_FAIL_COND_V_MSG(
			read_err != OK,
			0,
			"Was not possible to decode the variant, error: " + itos(read_err));

	bit_offset += len * 8;

	return len * 8;
}

int DataBuffer::get_bit_taken(DataType p_data_type, CompressionLevel p_compression) {
	switch (p_data_type) {
		case DATA_TYPE_BOOL:
			// No matter what, 1 bit.
			return 1;
		case DATA_TYPE_INT: {
			switch (p_compression) {
				case COMPRESSION_LEVEL_0:
					return 64;
				case COMPRESSION_LEVEL_1:
					return 32;
				case COMPRESSION_LEVEL_2:
					return 16;
				case COMPRESSION_LEVEL_3:
					return 8;
				default:
					// Unreachable
					CRASH_NOW_MSG("Compression level not supported!");
			}
		} break;
		case DATA_TYPE_REAL: {
			return get_mantissa_bits(p_compression) +
				   get_exponent_bits(p_compression);
		} break;
		case DATA_TYPE_POSITIVE_UNIT_REAL: {
			switch (p_compression) {
				case COMPRESSION_LEVEL_0:
					return 10;
				case COMPRESSION_LEVEL_1:
					return 8;
				case COMPRESSION_LEVEL_2:
					return 6;
				case COMPRESSION_LEVEL_3:
					return 4;
				default:
					// Unreachable
					CRASH_NOW_MSG("Compression level not supported!");
			}
		} break;
		case DATA_TYPE_UNIT_REAL: {
			return get_bit_taken(DATA_TYPE_POSITIVE_UNIT_REAL, p_compression) + 1;
		} break;
		case DATA_TYPE_VECTOR2: {
			return get_bit_taken(DATA_TYPE_REAL, p_compression) * 2;
		} break;
		case DATA_TYPE_NORMALIZED_VECTOR2: {
			// +1 bit to know if the vector is 0 or a direction
			switch (p_compression) {
				case CompressionLevel::COMPRESSION_LEVEL_0:
					return 11 + 1;
				case CompressionLevel::COMPRESSION_LEVEL_1:
					return 10 + 1;
				case CompressionLevel::COMPRESSION_LEVEL_2:
					return 9 + 1;
				case CompressionLevel::COMPRESSION_LEVEL_3:
					return 8 + 1;
			}
		} break;
		case DATA_TYPE_VECTOR3: {
			return get_bit_taken(DATA_TYPE_REAL, p_compression) * 3;
		} break;
		case DATA_TYPE_NORMALIZED_VECTOR3: {
			switch (p_compression) {
				case CompressionLevel::COMPRESSION_LEVEL_0:
					return 11 * 3;
				case CompressionLevel::COMPRESSION_LEVEL_1:
					return 10 * 3;
				case CompressionLevel::COMPRESSION_LEVEL_2:
					return 8 * 3;
				case CompressionLevel::COMPRESSION_LEVEL_3:
					return 6 * 3;
			}
		} break;
		case DATA_TYPE_VARIANT: {
			ERR_FAIL_V_MSG(0, "The variant size is dynamic and can't be know at compile time.");
		}
		default:
			// Unreachable
			CRASH_NOW_MSG("Input type not supported!");
	}

	// Unreachable
	CRASH_NOW_MSG("It was not possible to obtain the bit taken by this input data.");
	return 0; // Useless, but MS CI is too noisy.
}

int DataBuffer::get_mantissa_bits(CompressionLevel p_compression) {
	// https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats
	switch (p_compression) {
		case CompressionLevel::COMPRESSION_LEVEL_0:
			return 53; // Binary64 format
		case CompressionLevel::COMPRESSION_LEVEL_1:
			return 24; // Binary32 format
		case CompressionLevel::COMPRESSION_LEVEL_2:
			return 11; // Binary16 format
		case CompressionLevel::COMPRESSION_LEVEL_3:
			return 4; // https://en.wikipedia.org/wiki/Minifloat
	}

	// Unreachable
	CRASH_NOW_MSG("Unknown compression level.");
	return 0; // Useless, but MS CI is too noisy.
}

int DataBuffer::get_exponent_bits(CompressionLevel p_compression) {
	// https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats
	switch (p_compression) {
		case CompressionLevel::COMPRESSION_LEVEL_0:
			return 11; // Binary64 format
		case CompressionLevel::COMPRESSION_LEVEL_1:
			return 8; // Binary32 format
		case CompressionLevel::COMPRESSION_LEVEL_2:
			return 5; // Binary16 format
		case CompressionLevel::COMPRESSION_LEVEL_3:
			return 4; // https://en.wikipedia.org/wiki/Minifloat
	}

	// Unreachable
	CRASH_NOW_MSG("Unknown compression level.");
	return 0; // Useless, but MS CI is too noisy.
}

uint64_t DataBuffer::compress_unit_float(double p_value, double p_scale_factor) {
	return Math::round(MIN(p_value * p_scale_factor, p_scale_factor));
}

double DataBuffer::decompress_unit_float(uint64_t p_value, double p_scale_factor) {
	return static_cast<double>(p_value) / p_scale_factor;
}

void DataBuffer::make_room_in_bits(int p_dim) {
	const int array_min_dim = bit_offset + p_dim;
	if (array_min_dim > buffer.size_in_bits()) {
		buffer.resize_in_bits(array_min_dim);
	}

	if (array_min_dim > metadata_size) {
		const int new_bit_size = array_min_dim - metadata_size;
		if (new_bit_size > bit_size) {
			bit_size = new_bit_size;
		}
	}
}

void DataBuffer::make_room_pad_to_next_byte() {
	const int bits_to_next_byte = ((bit_offset + 7) & ~7) - bit_offset;
	make_room_in_bits(bits_to_next_byte);
	bit_offset += bits_to_next_byte;
}

bool DataBuffer::pad_to_next_byte() {
	const int bits_to_next_byte = ((bit_offset + 7) & ~7) - bit_offset;
	ERR_FAIL_COND_V_MSG(
			bit_offset + bits_to_next_byte > buffer.size_in_bits(),
			false,
			"");
	bit_offset += bits_to_next_byte;
	return true;
}