RogueLife/src/geometry.h

130 lines
2.6 KiB
C

//---
// geometry: Geometry utilities
//---
#pragma once
#include "fixed.h"
#include <stdbool.h>
#include <stdlib.h>
/* Directions */
enum { UP=0, RIGHT=1, DOWN=2, LEFT=3 };
/* Orientations */
enum { VERTICAL=0, HORIZONTAL=1, CEILING=2 };
//---
// Geometric primitives; the engine types are the fixed-point versions, but the
// integer versions are useful as input/output, either to specify model data or
// to draw to screen using pixel-based methods.
//---
typedef struct
{
fixed_t x, y;
} vec2;
typedef struct
{
int16_t x, y;
} ivec2;
typedef struct
{
/* Left edge, right edge */
fixed_t l, r;
/* Top edge, bottom edge */
fixed_t t, b;
} rect;
typedef struct
{
int16_t l, r;
int16_t t, b;
} irect;
/* Functions converting integer shapes to fixed-point. */
vec2 vec_i2f(ivec2);
rect rect_i2f(irect);
/* Same as vec_i2f() but adds +0.5 at each coordinate. */
vec2 vec_i2f_center(ivec2);
/* Functions converting fixed-point shapes to integer. */
ivec2 vec_f2i(vec2);
irect rect_f2i(rect);
/* Dot product. */
fixed_t vec_dot(vec2, vec2);
/* Rotate a vector by some constants */
vec2 vec_rotate_30(vec2);
vec2 vec_rotate_m30(vec2);
vec2 vec_rotate_45(vec2);
vec2 vec_rotate_m45(vec2);
vec2 vec_rotate_60(vec2);
vec2 vec_rotate_m60(vec2);
//---
// Point operations
//---
/* Distance-squared between two points */
static inline fixed_t dist2(vec2 p1, vec2 p2)
{
fixed_t dx = p2.x - p1.x;
fixed_t dy = p2.y - p1.y;
return fmul(dx, dx) + fmul(dy, dy);
}
/* Unit vector in the specified direction */
static inline vec2 fdir(int dir)
{
return (vec2){
.x = fix((dir == RIGHT) - (dir == LEFT)),
.y = fix((dir == DOWN) - (dir == UP)),
};
}
/* Direction closest to specified vector */
static inline int frdir(vec2 v)
{
if(v.x >= abs(v.y)) return RIGHT;
if(v.x <= -abs(v.y)) return LEFT;
if(v.y < 0) return UP;
return DOWN;
}
/* Normalize vector */
static inline vec2 fnormalize(vec2 v)
{
fixed_t norm = fmul(v.x, v.x) + fmul(v.y, v.y);
if(norm == 0) return v;
norm = fsqrt(norm);
return (vec2){ fdiv(v.x, norm), fdiv(v.y, norm) };
}
//---
// Rect operations
//---
/* Center of rectangle */
vec2 rect_center(rect r);
/* Scale a rectangle by the specified factor. */
rect rect_scale(rect r, fixed_t factor);
/* Translate a rectangle by the specified point coordinates. */
rect rect_translate(rect r, vec2 vec);
/* Draw rectangle on-screen; expects a rectangle in the screen coordinate system. */
void rect_draw(rect r, int color);
/* Check whether two rectangles collide */
bool rect_collide(rect r1, rect r2);
/* Rotate rectangle from one quad direction to another */
rect rect_rotate(rect r, int from_dir, int to_dir);