119 lines
2.4 KiB
C
119 lines
2.4 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);
|
|
|
|
//---
|
|
// 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);
|