mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
Add support for half floats.
iqm and OpenGL use them, so they might come in handy. The tests use values from wikipedia and a couple extra.
This commit is contained in:
parent
e06ee34287
commit
8791b35e55
4 changed files with 133 additions and 1 deletions
|
@ -449,6 +449,8 @@ void Mat4Mult (const mat4_t a, const mat4_t b, mat4_t c);
|
|||
VectorNegate ((sp)->normal, (dp)->normal); \
|
||||
} while (0)
|
||||
|
||||
int16_t FloatToHalf (float x);
|
||||
float HalfToFloat (int16_t x);
|
||||
extern plane_t * const frustum;
|
||||
extern inline qboolean R_CullBox (const vec3_t mins, const vec3_t maxs);
|
||||
extern inline qboolean R_CullSphere (const vec3_t origin, const float radius);
|
||||
|
|
|
@ -54,6 +54,80 @@ VISIBLE const vec_t * const quat_origin = _quat_origin;
|
|||
|
||||
#define DEG2RAD(a) (a * (M_PI / 180.0))
|
||||
|
||||
#define FMANTBITS 23
|
||||
#define FMANTMASK ((1 << FMANTBITS) - 1)
|
||||
#define FEXPBITS 8
|
||||
#define FEXPMASK ((1 << FEXPBITS) - 1)
|
||||
#define FBIAS (1 << (FEXPBITS - 1))
|
||||
#define FEXPMAX ((1 << FEXPBITS) - 1)
|
||||
|
||||
#define HMANTBITS 10
|
||||
#define HMANTMASK ((1 << HMANTBITS) - 1)
|
||||
#define HEXPBITS 5
|
||||
#define HEXPMASK ((1 << HEXPBITS) - 1)
|
||||
#define HBIAS (1 << (HEXPBITS - 1))
|
||||
#define HEXPMAX ((1 << HEXPBITS) - 1)
|
||||
|
||||
int16_t
|
||||
FloatToHalf (float x)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t u;
|
||||
} uf;
|
||||
unsigned sign;
|
||||
int exp;
|
||||
unsigned mant;
|
||||
int16_t half;
|
||||
|
||||
uf.f = x;
|
||||
sign = (uf.u >> (FEXPBITS + FMANTBITS)) & 1;
|
||||
exp = ((uf.u >> FMANTBITS) & FEXPMASK) - FBIAS + HBIAS;
|
||||
mant = (uf.u & FMANTMASK) >> (FMANTBITS - HMANTBITS);
|
||||
if (exp <= 0) {
|
||||
mant |= 1 << HMANTBITS;
|
||||
mant >>= min (1 - exp, HMANTBITS + 1);
|
||||
exp = 0;
|
||||
} else if (exp >= HEXPMAX) {
|
||||
mant = 0;
|
||||
exp = HEXPMAX;
|
||||
}
|
||||
half = (sign << (HEXPBITS + HMANTBITS)) | (exp << HMANTBITS) | mant;
|
||||
return half;
|
||||
}
|
||||
|
||||
float
|
||||
HalfToFloat (int16_t x)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t u;
|
||||
} uf;
|
||||
unsigned sign;
|
||||
int exp;
|
||||
unsigned mant;
|
||||
|
||||
sign = (x >> (HEXPBITS + HMANTBITS)) & 1;
|
||||
exp = ((x >> HMANTBITS) & HEXPMASK);
|
||||
mant = (x & HMANTMASK) << (FMANTBITS - HMANTBITS);
|
||||
|
||||
if (exp == 0) {
|
||||
if (mant) {
|
||||
while (mant < (1 << FMANTBITS)) {
|
||||
mant <<= 1;
|
||||
exp--;
|
||||
}
|
||||
mant &= (1 << FMANTBITS) - 1;
|
||||
exp += FBIAS - HBIAS + 1;
|
||||
}
|
||||
} else if (exp == HEXPMAX) {
|
||||
exp = FEXPMAX;
|
||||
} else {
|
||||
exp += FBIAS - HBIAS;
|
||||
}
|
||||
uf.u = (sign << (FEXPBITS + FMANTBITS)) | (exp << FMANTBITS) | mant;
|
||||
return uf.f;
|
||||
}
|
||||
|
||||
static void
|
||||
ProjectPointOnPlane (vec3_t dst, const vec3_t p, const vec3_t normal)
|
||||
|
|
|
@ -2,7 +2,11 @@ AUTOMAKE_OPTIONS= foreign
|
|||
|
||||
INCLUDES= -I$(top_srcdir)/include
|
||||
|
||||
check_PROGRAMS=test-qfs test-quat test-vrect
|
||||
check_PROGRAMS=test-half test-qfs test-quat test-vrect
|
||||
|
||||
test_half_SOURCES=test-half.c
|
||||
test_half_LDADD=$(top_builddir)/libs/util/libQFutil.la
|
||||
test_half_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la
|
||||
|
||||
test_qfs_SOURCES=test-qfs.c
|
||||
test_qfs_LDADD=$(top_builddir)/libs/util/libQFutil.la
|
||||
|
|
52
libs/util/test/test-half.c
Normal file
52
libs/util/test/test-half.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "QF/mathlib.h"
|
||||
|
||||
struct {
|
||||
int16_t half;
|
||||
float flt;
|
||||
} tests [] = {
|
||||
{0x3c00, 1.0f},
|
||||
{0x3c01, 1.0009765625f},
|
||||
{0xc000, -2.0f},
|
||||
{0x7bff, 65504.0f},
|
||||
{0x0400, 6.103515625e-05f},
|
||||
{0x03ff, 6.0975551605224609375e-05f},
|
||||
{0x0001, 5.9604644775390625e-08f},
|
||||
{0x0000, 0.0f},
|
||||
{0x8000, -0.0f},
|
||||
#if __GNUC_PREREQ(3,3)
|
||||
{0x7c00, __builtin_huge_val ()},
|
||||
{0xfc00, -__builtin_huge_val ()},
|
||||
#endif
|
||||
{0x3555, 0.333251953125f},
|
||||
{0x3e00, 1.5f},
|
||||
{0x0000, 0.0f},
|
||||
};
|
||||
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
||||
|
||||
int
|
||||
main (int argc, const char **argv)
|
||||
{
|
||||
size_t i;
|
||||
int res = 0;
|
||||
|
||||
for (i = 0; i < num_tests; i++) {
|
||||
float flt;
|
||||
int16_t half;
|
||||
|
||||
flt = HalfToFloat (tests[i].half);
|
||||
half = FloatToHalf (tests[i].flt);
|
||||
|
||||
if (flt != tests[i].flt || half != tests[i].half) {
|
||||
res |= 1;
|
||||
printf ("test %d failed\n", (int) i);
|
||||
printf ("expect: %4x %.20g\n", tests[i].half, tests[i].flt);
|
||||
printf ("got : %4x %.20g\n", half, flt);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
Loading…
Reference in a new issue