foo
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 18 Jun 2023 15:04:00 +0000 (18:04 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 18 Jun 2023 15:04:00 +0000 (18:04 +0300)
13 files changed:
src/app.h
src/gaw/gaw_sw.c
src/gaw/gawswtnl.h
src/geom.c [new file with mode: 0644]
src/geom.h [new file with mode: 0644]
src/gfxutil.h [new file with mode: 0644]
src/rend.c
src/rend.h
src/rt.c [deleted file]
src/rt.h [deleted file]
src/scene.c
src/scr_mod.c
src/util.h

index f6aa490..d09be0b 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -113,4 +113,7 @@ void app_resize(int x, int y);
 void app_fullscreen(int fs);
 void app_vsync(int vsync);
 
+/* defined in scr_mod.c for convenience */
+void primray(cgm_ray *ray, int x, int y);
+
 #endif /* APP_H_ */
index 5e4619c..7258d45 100644 (file)
@@ -20,6 +20,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "gaw.h"
 #include "gawswtnl.h"
 #include "polyfill.h"
+#include "../util.h"
 
 static struct pimage textures[MAX_TEXTURES];
 
index d016291..0d78f5d 100644 (file)
@@ -129,29 +129,4 @@ void gaw_swtnl_subtex2d(int lvl, int x, int y, int xsz, int ysz, int fmt, void *
 void gaw_swtnl_drawprim(int prim, struct vertex *v, int vnum);
 
 
-#if defined(__i386__) || defined(__386__) || defined(MSDOS)
-
-#ifndef INLINE
-#if (__STDC_VERSION__ >= 199901) || defined(__GNUC__)
-#define INLINE inline
-#else
-#define INLINE __inline
-#endif
-#endif
-
-/* fast conversion of double -> 32bit int
- * for details see:
- *  - http://chrishecker.com/images/f/fb/Gdmfp.pdf
- *  - http://stereopsis.com/FPU.html#convert
- */
-static INLINE int32_t cround64(double val)
-{
-       val += 6755399441055744.0;
-       return *(int32_t*)&val;
-}
-#else
-#define cround64(x)    ((int32_t)(x))
-#endif
-
-
 #endif /* GAWSWTNL_H_ */
diff --git a/src/geom.c b/src/geom.c
new file mode 100644 (file)
index 0000000..1a89ccd
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "geom.h"
+
+int ray_object(const cgm_ray *ray, const struct object *obj, struct rayhit *hit)
+{
+       struct csghit csghit;
+
+       if(!ray_object_csg(ray, obj, &csghit)) {
+               return 0;
+       }
+       if(hit) {
+               *hit = csghit.ivlist[0].a;
+       }
+       return 1;
+}
+
+int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit *hit)
+{
+       int i, res;
+       cgm_ray localray = *ray;
+
+       cgm_rmul_mr(&localray, obj->inv_xform);
+
+       switch(obj->type) {
+       case OBJ_SPHERE:
+               res = ray_sphere(ray, (const struct sphere*)obj, hit);
+               break;
+
+       default:
+               res = 0;
+       }
+
+       if(res && hit) {
+               for(i=0; i<hit->ivcount; i++) {
+                       cgm_vmul_m4v3(&hit->ivlist[i].a.pos, obj->xform);
+                       cgm_vmul_m3v3(&hit->ivlist[i].a.norm, obj->xform);
+                       cgm_vmul_m4v3(&hit->ivlist[i].b.pos, obj->xform);
+                       cgm_vmul_m3v3(&hit->ivlist[i].b.norm, obj->xform);
+               }
+       }
+       return res;
+}
+
+int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit)
+{
+       int i;
+       float a, b, c, d, sqrt_d, t1, t2;/*, invrad;*/
+       struct rayhit *rhptr;
+
+       a = cgm_vdot(&ray->dir, &ray->dir);
+       b = 2.0f * ray->dir.x * (ray->origin.x - sph->pos.x) +
+               2.0f * ray->dir.y * (ray->origin.y - sph->pos.y) +
+               2.0f * ray->dir.z * (ray->origin.z - sph->pos.z);
+       c = cgm_vdot(&sph->pos, &sph->pos) + cgm_vdot(&ray->origin, &ray->origin) +
+               cgm_vdot(&sph->pos, &ray->origin) * -2.0f - sph->rad * sph->rad;
+
+       if((d = b * b - 4.0 * a * c) < 0.0) return 0;
+
+       sqrt_d = sqrt(d);
+       t1 = (-b + sqrt_d) / (2.0 * a);
+       t2 = (-b - sqrt_d) / (2.0 * a);
+
+       if((t1 < 1e-6f && t2 < 1e-6f) || (t1 > 1.0f && t2 > 1.0f)) {
+               return 0;
+       }
+
+       if(hit) {
+               if(t1 < 1e-6f || t1 > 1.0f) {
+                       t1 = t2;
+               } else if(t2 < 1e-6f || t2 > 1.0f) {
+                       t2 = t1;
+               }
+               if(t2 < t1) {
+                       float tmp = t1;
+                       t1 = t2;
+                       t2 = tmp;
+               }
+
+               hit->ivcount = 1;
+               hit->ivlist[0].a.t = t1;
+               hit->ivlist[0].b.t = t2;
+               /*invrad = 1.0f / sph->rad;*/
+
+               rhptr = &hit->ivlist[0].a;
+               for(i=0; i<2; i++) {
+                       cgm_raypos(&rhptr->pos, ray, rhptr->t);
+                       rhptr->norm = rhptr->pos;
+                       cgm_vnormalize(&rhptr->norm);
+                       /*rhptr->norm.x = rhptr->pos.x * invrad;
+                       rhptr->norm.y = rhptr->pos.y * invrad;
+                       rhptr->norm.z = rhptr->pos.z * invrad;*/
+                       rhptr->uv.x = (atan2(rhptr->norm.z, rhptr->norm.x) + CGM_PI) / (2.0 * CGM_PI);
+                       rhptr->uv.y = acos(rhptr->norm.y) / CGM_PI;
+                       rhptr->obj = (struct object*)sph;
+                       rhptr = &hit->ivlist[0].b;
+               }
+       }
+       return 1;
+}
+
+int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit)
+{
+       return 0;
+}
+
+float ray_object_dist(const cgm_ray *ray, const struct object *obj)
+{
+       /*struct rayhit hit;*/
+       cgm_vec3 norm, pvec;
+
+       /*if(ray_object(ray, obj, &hit)) {
+               return cgm_vdist(&hit.pos, &ray->origin);
+       }*/
+
+       /* if we can't hit the object for some reason, fallback to computing the
+        * distance of obj->pos from the plane perpendicular to the ray at the origin
+        */
+       norm = ray->dir;
+       /*cgm_vnormalize(&norm);*/
+       pvec = obj->pos;
+       cgm_vsub(&pvec, &ray->origin);
+       return cgm_vdot(&pvec, &norm);
+}
diff --git a/src/geom.h b/src/geom.h
new file mode 100644 (file)
index 0000000..bfd9b21
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef GEOM_H_
+#define GEOM_H_
+
+#include "cgmath/cgmath.h"
+#include "scene.h"
+
+struct rayhit {
+       float t;
+       cgm_vec3 pos;
+       cgm_vec3 norm;
+       cgm_vec2 uv;
+       struct object *obj;
+};
+
+struct interval {
+       struct rayhit a, b;
+};
+
+#define MAX_INTERV     32
+struct csghit {
+       struct interval ivlist[MAX_INTERV];
+       int ivcount;
+};
+
+int ray_object(const cgm_ray *ray, const struct object *obj, struct rayhit *hit);
+int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit *hit);
+
+int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit);
+int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit);
+
+float ray_object_dist(const cgm_ray *ray, const struct object *obj);
+
+#endif /* GEOM_H_ */
diff --git a/src/gfxutil.h b/src/gfxutil.h
new file mode 100644 (file)
index 0000000..45fef4a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef GFXUTIL_H_
+#define GFXUTIL_H_
+
+#define PACK_RGB32(r, g, b) \
+       (0xff000000 | ((uint32_t)(r) << 16) | ((uint32_t)(g) << 8) | (uint32_t)(b))
+
+#endif /* GFXUTIL_H_ */
index 09f7f97..c88277f 100644 (file)
@@ -16,10 +16,15 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include "rend.h"
-#include "rt.h"
+#include "app.h"
+#include "geom.h"
+#include "util.h"
+#include "gfxutil.h"
+#include "scene.h"
 
 struct img_pixmap renderbuf;
-struct img_pixmap dbgimg;
+
+int max_ray_depth;
 
 static int rx, ry, rwidth, rheight;
 static int roffs;
@@ -29,11 +34,9 @@ int rend_init(void)
 {
        img_init(&renderbuf);
 
-       img_init(&dbgimg);
-       img_load(&dbgimg, "data/foo.jpg");
-       img_convert(&dbgimg, IMG_FMT_RGBA32);
-
        rx = ry = rwidth = rheight = roffs = 0;
+
+       max_ray_depth = 6;
        return 0;
 }
 
@@ -91,20 +94,43 @@ static void fillrect(uint32_t *fb, int x, int y, int w, int h, uint32_t c)
 
 int render(uint32_t *fb)
 {
-       int i, j, offs;
-       uint32_t *src, *dest;
+       int i, j, w, h, offs, r, g, b;
+       uint32_t *dest, pcol;
+       cgm_vec3 color;
+       cgm_ray ray;
 
-       src = (uint32_t*)dbgimg.pixels + roffs;
        dest = (uint32_t*)renderbuf.pixels + roffs;
        if(fb) fb += roffs;
 
+       if(xstep < 1) xstep = 1;
+       if(ystep < 1) ystep = 1;
+
        for(i=0; i<rheight; i+=ystep) {
+               h = ystep;
+               if(i + h > rheight) h = rheight - i;
+
                for(j=0; j<rwidth; j+=xstep) {
+                       primray(&ray, rx + j, ry + i);
+                       ray_trace(&ray, max_ray_depth, &color);
+
+                       r = cround64(color.x * 255.0f);
+                       g = cround64(color.y * 255.0f);
+                       b = cround64(color.z * 255.0f);
+
+                       if(r > 255) r = 255;
+                       if(g > 255) g = 255;
+                       if(b > 255) b = 255;
+
+                       pcol = PACK_RGB32(r, g, b);
+
                        offs = i * renderbuf.width + j;
-                       dest[offs] = src[offs];
+                       dest[offs] = pcol;
+
                        if(fb) {
-                               fb[offs] = src[offs];
-                               fillrect(fb, j, i, xstep, ystep, src[offs]);
+                               w = xstep;
+                               if(j + w > rwidth) w = rwidth - j;
+
+                               fillrect(fb, j, i, w, h, pcol);
                        }
                }
        }
@@ -117,3 +143,26 @@ int render(uint32_t *fb)
        }
        return 0;
 }
+
+int ray_trace(const cgm_ray *ray, int maxiter, cgm_vec3 *res)
+{
+       struct rayhit hit;
+
+       if(!scn_intersect(scn, ray, &hit)) {
+               *res = bgcolor(ray);
+               return 0;
+       }
+
+       *res = shade(ray, &hit, maxiter);
+       return 1;
+}
+
+cgm_vec3 bgcolor(const cgm_ray *ray)
+{
+       return cgm_vvec(0, 0, 0);
+}
+
+cgm_vec3 shade(const cgm_ray *ray, const struct rayhit *hit, int maxiter)
+{
+       return cgm_vvec(1, 0, 0);
+}
index 7508de4..61d5b5f 100644 (file)
@@ -18,14 +18,25 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef REND_H_
 #define REND_H_
 
+#include "cgmath/cgmath.h"
+#include "geom.h"
 #include "sizeint.h"
 #include "imago2.h"
 
 extern struct img_pixmap renderbuf;
+extern int max_ray_depth;
+
+struct scene;
 
 int rend_init(void);
 void rend_size(int xsz, int ysz);
 void rend_begin(int x, int y, int w, int h);
 int render(uint32_t *fb);
 
+int ray_trace(const cgm_ray *ray, int maxiter, cgm_vec3 *res);
+
+cgm_vec3 bgcolor(const cgm_ray *ray);
+cgm_vec3 shade(const cgm_ray *ray, const struct rayhit *hit, int maxiter);
+
+
 #endif /* REND_H_ */
diff --git a/src/rt.c b/src/rt.c
deleted file mode 100644 (file)
index f917836..0000000
--- a/src/rt.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-RetroRay - integrated standalone vintage modeller/renderer
-Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-#include "rt.h"
-
-int ray_object(const cgm_ray *ray, const struct object *obj, struct rayhit *hit)
-{
-       struct csghit csghit;
-
-       if(!ray_object_csg(ray, obj, &csghit)) {
-               return 0;
-       }
-       if(hit) {
-               *hit = csghit.ivlist[0].a;
-       }
-       return 1;
-}
-
-int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit *hit)
-{
-       int i, res;
-       cgm_ray localray = *ray;
-
-       cgm_rmul_mr(&localray, obj->inv_xform);
-
-       switch(obj->type) {
-       case OBJ_SPHERE:
-               res = ray_sphere(ray, (const struct sphere*)obj, hit);
-               break;
-
-       default:
-               res = 0;
-       }
-
-       if(res && hit) {
-               for(i=0; i<hit->ivcount; i++) {
-                       cgm_vmul_m4v3(&hit->ivlist[i].a.pos, obj->xform);
-                       cgm_vmul_m3v3(&hit->ivlist[i].a.norm, obj->xform);
-                       cgm_vmul_m4v3(&hit->ivlist[i].b.pos, obj->xform);
-                       cgm_vmul_m3v3(&hit->ivlist[i].b.norm, obj->xform);
-               }
-       }
-       return res;
-}
-
-int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit)
-{
-       int i;
-       float a, b, c, d, sqrt_d, t1, t2;/*, invrad;*/
-       struct rayhit *rhptr;
-
-       a = cgm_vdot(&ray->dir, &ray->dir);
-       b = 2.0f * ray->dir.x * (ray->origin.x - sph->pos.x) +
-               2.0f * ray->dir.y * (ray->origin.y - sph->pos.y) +
-               2.0f * ray->dir.z * (ray->origin.z - sph->pos.z);
-       c = cgm_vdot(&sph->pos, &sph->pos) + cgm_vdot(&ray->origin, &ray->origin) +
-               cgm_vdot(&sph->pos, &ray->origin) * -2.0f - sph->rad * sph->rad;
-
-       if((d = b * b - 4.0 * a * c) < 0.0) return 0;
-
-       sqrt_d = sqrt(d);
-       t1 = (-b + sqrt_d) / (2.0 * a);
-       t2 = (-b - sqrt_d) / (2.0 * a);
-
-       if((t1 < 1e-6f && t2 < 1e-6f) || (t1 > 1.0f && t2 > 1.0f)) {
-               return 0;
-       }
-
-       if(hit) {
-               if(t1 < 1e-6f || t1 > 1.0f) {
-                       t1 = t2;
-               } else if(t2 < 1e-6f || t2 > 1.0f) {
-                       t2 = t1;
-               }
-               if(t2 < t1) {
-                       float tmp = t1;
-                       t1 = t2;
-                       t2 = tmp;
-               }
-
-               hit->ivcount = 1;
-               hit->ivlist[0].a.t = t1;
-               hit->ivlist[0].b.t = t2;
-               /*invrad = 1.0f / sph->rad;*/
-
-               rhptr = &hit->ivlist[0].a;
-               for(i=0; i<2; i++) {
-                       cgm_raypos(&rhptr->pos, ray, rhptr->t);
-                       rhptr->norm = rhptr->pos;
-                       cgm_vnormalize(&rhptr->norm);
-                       /*rhptr->norm.x = rhptr->pos.x * invrad;
-                       rhptr->norm.y = rhptr->pos.y * invrad;
-                       rhptr->norm.z = rhptr->pos.z * invrad;*/
-                       rhptr->uv.x = (atan2(rhptr->norm.z, rhptr->norm.x) + CGM_PI) / (2.0 * CGM_PI);
-                       rhptr->uv.y = acos(rhptr->norm.y) / CGM_PI;
-                       rhptr->obj = (struct object*)sph;
-                       rhptr = &hit->ivlist[0].b;
-               }
-       }
-       return 1;
-}
-
-int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit)
-{
-       return 0;
-}
-
-float ray_object_dist(const cgm_ray *ray, const struct object *obj)
-{
-       /*struct rayhit hit;*/
-       cgm_vec3 norm, pvec;
-
-       /*if(ray_object(ray, obj, &hit)) {
-               return cgm_vdist(&hit.pos, &ray->origin);
-       }*/
-
-       /* if we can't hit the object for some reason, fallback to computing the
-        * distance of obj->pos from the plane perpendicular to the ray at the origin
-        */
-       norm = ray->dir;
-       /*cgm_vnormalize(&norm);*/
-       pvec = obj->pos;
-       cgm_vsub(&pvec, &ray->origin);
-       return cgm_vdot(&pvec, &norm);
-}
diff --git a/src/rt.h b/src/rt.h
deleted file mode 100644 (file)
index 9390bd9..0000000
--- a/src/rt.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-RetroRay - integrated standalone vintage modeller/renderer
-Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-#ifndef RT_H_
-#define RT_H_
-
-#include "cgmath/cgmath.h"
-#include "scene.h"
-
-struct rayhit {
-       float t;
-       cgm_vec3 pos;
-       cgm_vec3 norm;
-       cgm_vec2 uv;
-       struct object *obj;
-};
-
-struct interval {
-       struct rayhit a, b;
-};
-
-#define MAX_INTERV     32
-struct csghit {
-       struct interval ivlist[MAX_INTERV];
-       int ivcount;
-};
-
-int ray_object(const cgm_ray *ray, const struct object *obj, struct rayhit *hit);
-int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit *hit);
-
-int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit);
-int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit);
-
-float ray_object_dist(const cgm_ray *ray, const struct object *obj);
-
-#endif /* RT_H_ */
index 0ac2e71..48279cc 100644 (file)
@@ -18,7 +18,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <float.h>
 #include "scene.h"
-#include "rt.h"
+#include "geom.h"
 #include "darray.h"
 #include "logger.h"
 
index 47f0119..65c6384 100644 (file)
@@ -20,7 +20,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "app.h"
 #include "rtk.h"
 #include "scene.h"
-#include "rt.h"
+#include "geom.h"
 #include "cmesh.h"
 #include "meshgen.h"
 #include "font.h"
@@ -88,7 +88,6 @@ static void act_addobj(void);
 static void act_rmobj(void);
 
 static void draw_rband(void);
-static void primray(cgm_ray *ray, int x, int y);
 static void moveobj(struct object *obj, int px0, int py0, int px1, int py1);
 
 
@@ -558,7 +557,7 @@ static void draw_rband(void)
        }
 }
 
-static void primray(cgm_ray *ray, int x, int y)
+void primray(cgm_ray *ray, int x, int y)
 {
        float nx, ny;
        cgm_vec3 npos, farpt;
index 44545d4..cda59bf 100644 (file)
@@ -57,4 +57,28 @@ int match_prefix(const char *str, const char *prefix);
 void enable_fpexcept(void);
 void disable_fpexcept(void);
 
+#ifndef INLINE
+#if (__STDC_VERSION__ >= 199901) || defined(__GNUC__)
+#define INLINE inline
+#else
+#define INLINE __inline
+#endif
+#endif
+
+#if defined(__i386__) || defined(__386__) || defined(MSDOS)
+
+/* fast conversion of double -> 32bit int
+ * for details see:
+ *  - http://chrishecker.com/images/f/fb/Gdmfp.pdf
+ *  - http://stereopsis.com/FPU.html#convert
+ */
+static INLINE int32_t cround64(double val)
+{
+       val += 6755399441055744.0;
+       return *(int32_t*)&val;
+}
+#else
+#define cround64(x)    ((int32_t)(x))
+#endif
+
 #endif /* UTIL_H_ */