Created
August 23, 2017 16:31
-
-
Save jaburns/dc02091c64e9b5cdaff6c1e5df3ad93c to your computer and use it in GitHub Desktop.
C++ fixed-point 32 bit type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "fixed32.hpp" | |
#include <cmath> | |
static const int32_t DECIMAL_BITS = 16; | |
const fixed32 fixed32::ZERO = fixed32(0); | |
const fixed32 fixed32::ONE = fixed32(1); | |
const fixed32 fixed32::MINUS_ONE = fixed32(-1); | |
const fixed32 fixed32::TWO = fixed32(2); | |
const fixed32 fixed32::TWO_PI = fixed32::from_raw_int(411774); // fixed32::from_float(6.283185307179586).to_raw_int(); | |
const fixed32 fixed32::PI = TWO_PI / TWO; | |
const fixed32 fixed32::PI_OVER_TWO = PI / TWO; | |
fixed32::fixed32() | |
{ | |
m_int = 0; | |
} | |
fixed32::fixed32(int16_t init) | |
{ | |
m_int = init << DECIMAL_BITS; | |
} | |
fixed32 fixed32::from_raw_int(int32_t raw) | |
{ | |
fixed32 ret; | |
ret.m_int = raw; | |
return ret; | |
} | |
fixed32 fixed32::from_fraction(int32_t numerator, int32_t denominator) | |
{ | |
return from_raw_int(static_cast<int16_t>((numerator << DECIMAL_BITS) / denominator)); | |
} | |
int32_t fixed32::to_raw_int() const | |
{ | |
return m_int; | |
} | |
fixed32 fixed32::from_float(float x) | |
{ | |
return fixed32::from_raw_int(static_cast<int32_t>(x * 65536.0f)); | |
} | |
float fixed32::to_float() const | |
{ | |
return static_cast<float>(m_int) / 65536.0f; | |
} | |
glm::vec2 fixed32::to_float(vec2 v) | |
{ | |
return { v.x.to_float(), v.y.to_float() }; | |
} | |
glm::vec3 fixed32::to_float(vec3 v) | |
{ | |
return { v.x.to_float(), v.y.to_float(), v.z.to_float() }; | |
} | |
fixed32::vec2 fixed32::from_float(glm::vec2 v) | |
{ | |
return { from_float(v.x), from_float(v.y) }; | |
} | |
fixed32::vec3 fixed32::from_float(glm::vec3 v) | |
{ | |
return { from_float(v.x), from_float(v.y), from_float(v.z) }; | |
} | |
fixed32& fixed32::operator +=(fixed32 rhs) | |
{ | |
m_int += rhs.m_int; | |
return *this; | |
} | |
fixed32& fixed32::operator -=(fixed32 rhs) | |
{ | |
m_int -= rhs.m_int; | |
return *this; | |
} | |
fixed32& fixed32::operator *=(fixed32 rhs) | |
{ | |
const int64_t lhs64 = m_int; | |
const int64_t rhs64 = rhs.m_int; | |
const int64_t result = lhs64 * rhs64; | |
m_int = static_cast<int32_t>(result >> DECIMAL_BITS); | |
return *this; | |
} | |
fixed32& fixed32::operator /=(fixed32 rhs) | |
{ | |
const int64_t lhs64 = m_int; | |
const int64_t rhs64 = rhs.m_int; | |
const int64_t result = (lhs64 << DECIMAL_BITS) / rhs64; | |
m_int = static_cast<int32_t>(result); | |
return *this; | |
} | |
fixed32& fixed32::operator %=(fixed32 rhs) | |
{ | |
m_int %= rhs.m_int; | |
return *this; | |
} | |
fixed32 fixed32::operator +(fixed32 rhs) const { fixed32 ret = *this; ret += rhs; return ret; } | |
fixed32 fixed32::operator -(fixed32 rhs) const { fixed32 ret = *this; ret -= rhs; return ret; } | |
fixed32 fixed32::operator *(fixed32 rhs) const { fixed32 ret = *this; ret *= rhs; return ret; } | |
fixed32 fixed32::operator /(fixed32 rhs) const { fixed32 ret = *this; ret /= rhs; return ret; } | |
fixed32 fixed32::operator %(fixed32 rhs) const { fixed32 ret = *this; ret %= rhs; return ret; } | |
fixed32 fixed32::operator -() const { return from_raw_int(-m_int); } | |
bool fixed32::operator < (fixed32 rhs) const { return m_int < rhs.m_int; } | |
bool fixed32::operator > (fixed32 rhs) const { return m_int > rhs.m_int; } | |
bool fixed32::operator <=(fixed32 rhs) const { return m_int <= rhs.m_int; } | |
bool fixed32::operator >=(fixed32 rhs) const { return m_int >= rhs.m_int; } | |
bool fixed32::operator ==(fixed32 rhs) const { return m_int == rhs.m_int; } | |
bool fixed32::operator !=(fixed32 rhs) const { return m_int != rhs.m_int; } | |
fixed32 fixed32::abs() const | |
{ | |
return m_int < 0 ? -(*this) : *this; | |
} | |
fixed32 fixed32::sqrt() const | |
{ | |
# define INT_ABS(x) ((x) < 0 ? -(x) : (x)) | |
fixed32 guess = *this / TWO; | |
int32_t int_diff; | |
do { | |
fixed32 new_guess = (guess + *this / guess) / TWO; | |
int_diff = new_guess.m_int - guess.m_int; | |
guess.m_int = new_guess.m_int; | |
} while(INT_ABS(int_diff) > 16); // within 16 / 65536 = 0.00024 of previous guess | |
return guess; | |
# undef INT_ABS | |
} | |
fixed32 fixed32::sin() const | |
{ | |
return (*this - PI_OVER_TWO).cos(); | |
} | |
static const fixed32 FOUR_FACTORIAL = fixed32(24); | |
static const fixed32 SIX_FACTORIAL = fixed32(720); | |
fixed32 fixed32::cos() const | |
{ | |
auto x = *this; | |
auto negate = false; | |
x %= TWO_PI; | |
if (x < -PI_OVER_TWO) { | |
x += PI; | |
negate = true; | |
} else if (x > PI_OVER_TWO) { | |
x -= PI; | |
negate = true; | |
} | |
const auto x2 = x * x; | |
const auto x4 = x2 * x2; | |
const auto x6 = x4 * x2; | |
const auto ret = ONE - x2 / TWO + x4 / FOUR_FACTORIAL - x6 / SIX_FACTORIAL; | |
return negate ? -ret : ret; | |
} | |
fixed32 fixed32::pow(int32_t p) const | |
{ | |
bool negative_power = false; | |
if (p < 0) { | |
negative_power = true; | |
p = -p; | |
} | |
if (p == 0) return 1; | |
if (p == 1) return *this; | |
fixed32 result = *this; | |
while (--p > 0) result *= *this; | |
return negative_power ? fixed32::ONE / result : result; | |
} | |
fixed32 fixed32::max(fixed32 a, fixed32 b) | |
{ | |
return a.m_int > b.m_int ? a : b; | |
} | |
fixed32 fixed32::length(const fixed32::vec2& v) | |
{ | |
return (v.x * v.x + v.y * v.y).sqrt(); | |
} | |
fixed32::vec2 fixed32::normalize(const fixed32::vec2& v) | |
{ | |
const auto len = length(v); | |
return { v.x / len, v.y / len }; | |
} | |
fixed32::vec2 fixed32::rotate90(const fixed32::vec2& v) | |
{ | |
return { -v.y, v.x }; | |
} | |
fixed32 fixed32::dot(const fixed32::vec2& a, const fixed32::vec2& b) | |
{ | |
return a.x*b.x + a.y*b.y; | |
} | |
fixed32 fixed32::cross(const fixed32::vec2& a, const fixed32::vec2& b) | |
{ | |
return a.x*b.y - a.y*b.x; | |
} | |
fixed32::vec2 fixed32::reflect(const fixed32::vec2& v, const fixed32::vec2& unit_normal, fixed32 normal_scale, fixed32 tangent_scale) | |
{ | |
const auto unit_tangent = rotate90(unit_normal); | |
const auto norm_component = -normal_scale * dot(v, unit_normal); | |
const auto tang_component = tangent_scale * dot(v, unit_tangent); | |
return unit_normal * norm_component + unit_tangent * tang_component; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <glm/vec2.hpp> | |
#include <glm/vec3.hpp> | |
class fixed32 | |
{ | |
int32_t m_int = 0; | |
public: | |
static const fixed32 ZERO; | |
static const fixed32 ONE; | |
static const fixed32 MINUS_ONE; | |
static const fixed32 TWO; | |
static const fixed32 TWO_PI; | |
static const fixed32 PI; | |
static const fixed32 PI_OVER_TWO; | |
fixed32(); | |
fixed32(int16_t init); | |
static fixed32 from_raw_int(int32_t raw); | |
static fixed32 from_fraction(int32_t numerator, int32_t denominator); | |
static fixed32 from_float(float x); | |
int32_t to_raw_int() const; | |
float to_float() const; | |
typedef glm::tvec2<fixed32> vec2; | |
typedef glm::tvec3<fixed32> vec3; | |
static glm::vec2 to_float(vec2 v); | |
static glm::vec3 to_float(vec3 v); | |
static vec2 from_float(glm::vec2 v); | |
static vec3 from_float(glm::vec3 v); | |
fixed32& operator +=(fixed32 rhs); | |
fixed32& operator -=(fixed32 rhs); | |
fixed32& operator *=(fixed32 rhs); | |
fixed32& operator /=(fixed32 rhs); | |
fixed32& operator %=(fixed32 rhs); | |
fixed32 operator +(fixed32 rhs) const; | |
fixed32 operator -(fixed32 rhs) const; | |
fixed32 operator *(fixed32 rhs) const; | |
fixed32 operator /(fixed32 rhs) const; | |
fixed32 operator %(fixed32 rhs) const; | |
fixed32 operator -() const; | |
bool operator < (fixed32 rhs) const; | |
bool operator > (fixed32 rhs) const; | |
bool operator <=(fixed32 rhs) const; | |
bool operator >=(fixed32 rhs) const; | |
bool operator ==(fixed32 rhs) const; | |
bool operator !=(fixed32 rhs) const; | |
fixed32 abs() const; | |
fixed32 sqrt() const; | |
fixed32 sin() const; | |
fixed32 cos() const; | |
fixed32 pow(int32_t p) const; | |
static fixed32 max(fixed32 a, fixed32 b); | |
static fixed32 length(const vec2& v); | |
static vec2 normalize(const vec2& v); | |
static vec2 rotate90(const vec2& v); | |
static fixed32 dot(const fixed32::vec2& a, const fixed32::vec2& b); | |
static fixed32 cross(const fixed32::vec2& a, const fixed32::vec2& b); | |
static vec2 reflect(const vec2& v, const vec2& unit_normal, fixed32 normal_scale, fixed32 tangent_scale); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment