refactoring math suite into GBAVector, added tests for point rotation, stub for sin/cos
This commit is contained in:
parent
6fe6187d2c
commit
e690007190
|
@ -5,15 +5,15 @@
|
||||||
#include <libgba-sprite-engine/background/text_stream.h>
|
#include <libgba-sprite-engine/background/text_stream.h>
|
||||||
#include <libgba-sprite-engine/gba/tonc_bios.h>
|
#include <libgba-sprite-engine/gba/tonc_bios.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <libgba-sprite-engine/math.h>
|
#include <libgba-sprite-engine/gbavector.h>
|
||||||
#include "bullet.h"
|
#include "bullet.h"
|
||||||
|
|
||||||
|
|
||||||
void Bullet::setDestination(VECTOR destination) {
|
void Bullet::setDestination(VECTOR destination) {
|
||||||
auto currentPos = sprite->getPos();
|
auto currentPos = sprite->getPosAsVector();
|
||||||
this->dest = destination;
|
this->dest = destination;
|
||||||
|
|
||||||
this->coords = Math::bresenhamLineBetween(currentPos, destination);
|
this->coords = currentPos.bresenhamLineTo(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bullet::tick() {
|
void Bullet::tick() {
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
|
|
||||||
#include <libgba-sprite-engine/sprites/sprite.h>
|
#include <libgba-sprite-engine/sprites/sprite.h>
|
||||||
|
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||||
|
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||||
|
#else
|
||||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||||
|
#endif
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
class Bullet {
|
class Bullet {
|
||||||
|
|
|
@ -42,18 +42,7 @@ void FoodScene::removeBulletsOffScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR FoodScene::rotateAround(VECTOR center, VECTOR point) {
|
VECTOR FoodScene::rotateAround(VECTOR center, VECTOR point) {
|
||||||
s32 centerx = center.x, centery = center.y;
|
return GBAVector(center).rotateAsCenter(point, avatarRotation);
|
||||||
s32 defaultx = point.x, defaulty = point.y;
|
|
||||||
|
|
||||||
s32 cos = lu_cos(avatarRotation) >> 4;
|
|
||||||
s32 sin = lu_sin(avatarRotation) >> 4;
|
|
||||||
|
|
||||||
// affine matriches are 8.8 fixed point numbers, so shift all input 8 spaces up and forth
|
|
||||||
// possibilities: instead of between [-1.0, 1.0] it's between [-256, +256]
|
|
||||||
// 90° rotation in inversed y-axis needs to flip sin sign
|
|
||||||
return {
|
|
||||||
( cos * (defaultx - centerx) + sin * (defaulty - centery) + (centerx << 8)) >> 8,
|
|
||||||
(-sin * (defaultx - centerx) + cos * (defaulty - centery) + (centery << 8)) >> 8};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FoodScene::tick(u16 keys) {
|
void FoodScene::tick(u16 keys) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
project(gba-sprite-engine)
|
project(gba-sprite-engine)
|
||||||
set_property(SOURCE src/gba/sin_lut.s PROPERTY LANGUAGE C)
|
set_property(SOURCE src/gba/sin_lut.s PROPERTY LANGUAGE C)
|
||||||
|
|
||||||
set_property(SOURCE src/gba/tonc_bios.s PROPERTY LANGUAGE C)
|
set_property(SOURCE src/gba/tonc_bios.s PROPERTY LANGUAGE C)
|
||||||
set_source_files_properties(src/gba/tonc_bios.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
|
set_source_files_properties(src/gba/tonc_bios.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ add_library(${PROJECT_NAME}
|
||||||
src/background/text_stream.cpp
|
src/background/text_stream.cpp
|
||||||
src/background/background.cpp
|
src/background/background.cpp
|
||||||
src/effects/fade_out_scene.cpp
|
src/effects/fade_out_scene.cpp
|
||||||
src/sound_control.cpp src/scene.cpp src/timer.cpp include/libgba-sprite-engine/math.h src/math.cpp)
|
src/sound_control.cpp src/scene.cpp src/timer.cpp include/libgba-sprite-engine/gbavector.h src/gbavector.cpp)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
|
|
@ -0,0 +1,702 @@
|
||||||
|
//
|
||||||
|
// Created by Wouter Groeneveld on 14/12/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
||||||
|
#define GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mathematical functions
|
||||||
|
//
|
||||||
|
//! \file tonc_math.h
|
||||||
|
//! \author J Vijn
|
||||||
|
//! \date 20060508 - 20060908
|
||||||
|
//
|
||||||
|
// === NOTES ===
|
||||||
|
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include "tonc_types.h"
|
||||||
|
|
||||||
|
// --- Doxygen modules ---
|
||||||
|
|
||||||
|
/*! \defgroup grpMathBase Base math
|
||||||
|
* \brief Basic math macros and functions like MIN, MAX
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup grpMathFixed Fixed point math
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup grpMathLut Look-up tables
|
||||||
|
* \brief Tonc's internal look-up tables and related routines.
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup grpMathPoint Point functions
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup grpMathVector Vector functions
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup grpMathRect Rect functions
|
||||||
|
* \ingroup grpMath
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// GENERAL
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/*! \addtogroup grpMathBase */
|
||||||
|
/*! \{ */
|
||||||
|
|
||||||
|
// Also available as inline functions
|
||||||
|
|
||||||
|
//! \name core math macros
|
||||||
|
//\{
|
||||||
|
|
||||||
|
#ifndef ABS
|
||||||
|
//! Get the absolute value of \a x
|
||||||
|
#define ABS(x) ( (x)>=0 ? (x) : -(x) )
|
||||||
|
#endif // ABS
|
||||||
|
|
||||||
|
#ifndef SGN
|
||||||
|
//! Get the sign of \a x.
|
||||||
|
#define SGN(x) ( (x)>=0 ? 1 : -1 )
|
||||||
|
#define SGN2 SGN
|
||||||
|
#endif // SGN
|
||||||
|
|
||||||
|
#ifndef SGN3
|
||||||
|
//! Tri-state sign: -1 for negative, 0 for 0, +1 for positive.
|
||||||
|
#define SGN3(x) ( (x)>0 ? 1 : ( (x)<0 ? -1 : 0) )
|
||||||
|
#endif // SGN3
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
|
||||||
|
//! Get the maximum of \a a and \a b
|
||||||
|
#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
|
||||||
|
|
||||||
|
//! Get the minimum of \a a and \a b
|
||||||
|
#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
|
||||||
|
#endif // MAX
|
||||||
|
|
||||||
|
#ifndef SWAP
|
||||||
|
//! In-place swap.
|
||||||
|
#define SWAP2(a, b) do { a=(a)-(b); b=(a)+(b); a=(b)-(a); } while(0)
|
||||||
|
|
||||||
|
#define SWAP SWAP2
|
||||||
|
|
||||||
|
//Alternative:
|
||||||
|
//#define SWAP2(a, b) ( (b) ^= ((a) ^= ((b) ^= (a))) )
|
||||||
|
|
||||||
|
//! Swaps \a a and \a b, using \a tmp as a temporary
|
||||||
|
#define SWAP3(a, b, tmp) do { (tmp)=(a); (a)=(b); (b)=(tmp); } while(0)
|
||||||
|
#endif // SWAP
|
||||||
|
|
||||||
|
|
||||||
|
INLINE int sgn(int x);
|
||||||
|
INLINE int sgn3(int x);
|
||||||
|
INLINE int max(int a, int b);
|
||||||
|
INLINE int min(int a, int b);
|
||||||
|
|
||||||
|
//\}
|
||||||
|
|
||||||
|
|
||||||
|
//! \name Boundary response macros
|
||||||
|
//\{
|
||||||
|
|
||||||
|
|
||||||
|
//! Range check
|
||||||
|
#define IN_RANGE(x, min, max) ( ((x)>=(min)) && ((x)<(max)) )
|
||||||
|
|
||||||
|
//! Truncates \a x to stay in range [\a min, \a max>
|
||||||
|
/*! \return Truncated value of \a x.
|
||||||
|
* \note \a max is exclusive!
|
||||||
|
*/
|
||||||
|
#define CLAMP(x, min, max) \
|
||||||
|
( (x)>=(max) ? ((max)-1) : ( ((x)<(min)) ? (min) : (x) ) )
|
||||||
|
|
||||||
|
//! Reflects \a x at boundaries \a min and \a max
|
||||||
|
/*! If \a x is outside the range [\a min, \a max>,
|
||||||
|
* it'll be placed inside again with the same distance
|
||||||
|
* to the 'wall', but on the other side. Example for lower
|
||||||
|
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||||
|
* \return Reflected value of \a x.
|
||||||
|
* \note \a max is exclusive!
|
||||||
|
*/
|
||||||
|
#define REFLECT(x, min, max) \
|
||||||
|
( (x)>=(max) ? 2*((max)-1)-(x) : ( ((x)<(min)) ? 2*(min)-(x) : (x) ) )
|
||||||
|
|
||||||
|
//! Wraps \a x to stay in range [\a min, \a max>
|
||||||
|
#define WRAP(x, min, max) \
|
||||||
|
( (x)>=(max) ? (x)+(min)-(max) : ( ((x)<(min)) ? (x)+(max)-(min) : (x) ) )
|
||||||
|
|
||||||
|
|
||||||
|
INLINE BOOL in_range(int x, int min, int max);
|
||||||
|
INLINE int clamp(int x, int min, int max);
|
||||||
|
INLINE int reflect(int x, int min, int max);
|
||||||
|
INLINE int wrap(int x, int min, int max);
|
||||||
|
|
||||||
|
//\}
|
||||||
|
|
||||||
|
/* \} */
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// FIXED POINT
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/*! \addtogroup grpMathFixed */
|
||||||
|
/*! \{ */
|
||||||
|
|
||||||
|
#define FIX_SHIFT 8
|
||||||
|
#define FIX_SCALE ( 1<<FIX_SHIFT )
|
||||||
|
#define FIX_MASK ( FIX_SCALE-1 )
|
||||||
|
#define FIX_SCALEF ( (float)FIX_SCALE )
|
||||||
|
#define FIX_SCALEF_INV ( 1.0/FIX_SCALEF )
|
||||||
|
|
||||||
|
#define FIX_ONE FIX_SCALE
|
||||||
|
|
||||||
|
//! Get the fixed point reciprocal of \a a, in \a fp fractional bits.
|
||||||
|
/*!
|
||||||
|
* \param a Value to take the reciprocal of.
|
||||||
|
* \param fp Number of fixed point bits
|
||||||
|
* \note The routine does do a division, but the compiler will
|
||||||
|
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||||
|
* are constants!
|
||||||
|
* \sa #FX_RECIMUL
|
||||||
|
*/
|
||||||
|
#define FX_RECIPROCAL(a, fp) ( ((1<<(fp))+(a)-1)/(a) )
|
||||||
|
|
||||||
|
//! Perform the division \a x/ \a a by reciprocal multiplication
|
||||||
|
/*! Division is slow, but you can approximate division by a constant
|
||||||
|
* by multiplying with its reciprocal: x/a vs x*(1/a). This routine
|
||||||
|
* gives the reciprocal of \a a as a fixed point number with \a fp
|
||||||
|
* fractional bits.
|
||||||
|
* \param a Value to take the reciprocal of.
|
||||||
|
* \param fp Number of fixed point bits
|
||||||
|
* \note The routine does do a division, but the compiler will
|
||||||
|
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||||
|
* are constants!
|
||||||
|
* \note Rules for safe reciprocal division, using
|
||||||
|
* n = 2<sup>fp</sup> and m = (n+a-1)/a (i.e., rounding up)
|
||||||
|
* \li Maximum safe numerator \a x: x < n/(m*a-n)
|
||||||
|
* \li Minimum n for known \a x: n > x*(a-1)
|
||||||
|
*/
|
||||||
|
#define FX_RECIMUL(x, a, fp) ( ((x)*((1<<(fp))+(a)-1)/(a))>>(fp) )
|
||||||
|
|
||||||
|
INLINE FIXED int2fx(int d);
|
||||||
|
INLINE FIXED float2fx(float f);
|
||||||
|
INLINE u32 fx2uint(FIXED fx);
|
||||||
|
INLINE u32 fx2ufrac(FIXED fx);
|
||||||
|
INLINE int fx2int(FIXED fx);
|
||||||
|
INLINE float fx2float(FIXED fx);
|
||||||
|
INLINE FIXED fxadd(FIXED fa, FIXED fb);
|
||||||
|
INLINE FIXED fxsub(FIXED fa, FIXED fb);
|
||||||
|
INLINE FIXED fxmul(FIXED fa, FIXED fb);
|
||||||
|
INLINE FIXED fxdiv(FIXED fa, FIXED fb);
|
||||||
|
|
||||||
|
INLINE FIXED fxmul64(FIXED fa, FIXED fb);
|
||||||
|
INLINE FIXED fxdiv64(FIXED fa, FIXED fb);
|
||||||
|
|
||||||
|
/*! \} */
|
||||||
|
|
||||||
|
// === LUT ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
/*! \addtogroup grpMathLut */
|
||||||
|
/*! \{ */
|
||||||
|
|
||||||
|
#define SIN_LUT_SIZE 514 // 512 for main lut, 2 extra for lerp
|
||||||
|
#define DIV_LUT_SIZE 257 // 256 for main lut, 1 extra for lerp
|
||||||
|
|
||||||
|
INLINE s32 lu_sin(uint theta);
|
||||||
|
INLINE s32 lu_cos(uint theta);
|
||||||
|
INLINE uint lu_div(uint x);
|
||||||
|
|
||||||
|
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift);
|
||||||
|
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift);
|
||||||
|
|
||||||
|
/*! \} */
|
||||||
|
|
||||||
|
// === POINT ==========================================================
|
||||||
|
|
||||||
|
struct RECT;
|
||||||
|
|
||||||
|
//! \addtogroup grpMathPoint
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! 2D Point struct
|
||||||
|
typedef struct POINT { int x, y; } POINT, POINT32;
|
||||||
|
|
||||||
|
|
||||||
|
// --- Point functions ---
|
||||||
|
INLINE POINT *pt_set(POINT *pd, int x, int y);
|
||||||
|
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb);
|
||||||
|
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb);
|
||||||
|
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c);
|
||||||
|
|
||||||
|
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb);
|
||||||
|
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb);
|
||||||
|
INLINE POINT *pt_scale_eq(POINT *pd, int c);
|
||||||
|
|
||||||
|
INLINE int pt_cross(const POINT *pa, const POINT *pb);
|
||||||
|
INLINE int pt_dot(const POINT *pa, const POINT *pb);
|
||||||
|
|
||||||
|
int pt_in_rect(const POINT *pt, const struct RECT *rc);
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
|
||||||
|
// === RECT ===========================================================
|
||||||
|
|
||||||
|
/*! \addtogroup grpMathRect */
|
||||||
|
/*! \{ */
|
||||||
|
|
||||||
|
//! Rectangle struct
|
||||||
|
typedef struct RECT
|
||||||
|
{
|
||||||
|
int left, top;
|
||||||
|
int right, bottom;
|
||||||
|
} RECT, RECT32;
|
||||||
|
|
||||||
|
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b);
|
||||||
|
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h);
|
||||||
|
INLINE int rc_width(const RECT *rc);
|
||||||
|
INLINE int rc_height(const RECT *rc);
|
||||||
|
INLINE RECT *rc_set_pos(RECT *rc, int x, int y);
|
||||||
|
INLINE RECT *rc_set_size(RECT *rc, int w, int h);
|
||||||
|
INLINE RECT *rc_move(RECT *rc, int dx, int dy);
|
||||||
|
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh);
|
||||||
|
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr);
|
||||||
|
|
||||||
|
RECT *rc_normalize(RECT *rc);
|
||||||
|
|
||||||
|
/*! \} */
|
||||||
|
|
||||||
|
|
||||||
|
// === VECTOR =========================================================
|
||||||
|
|
||||||
|
/*! \addtogroup grpMathVector */
|
||||||
|
/*! \{ */
|
||||||
|
|
||||||
|
//! Vector struct
|
||||||
|
typedef struct VECTOR { FIXED x, y, z; } VECTOR;
|
||||||
|
|
||||||
|
|
||||||
|
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z);
|
||||||
|
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c);
|
||||||
|
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb);
|
||||||
|
|
||||||
|
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb);
|
||||||
|
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c);
|
||||||
|
|
||||||
|
VECTOR *vec_cross(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||||
|
|
||||||
|
/*! \} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === INLINE =========================================================
|
||||||
|
|
||||||
|
// --- General --------------------------------------------------------
|
||||||
|
|
||||||
|
//! Get the sign of \a x.
|
||||||
|
INLINE int sgn(int x)
|
||||||
|
{ return (x>=0) ? +1 : -1; }
|
||||||
|
|
||||||
|
//! Tri-state sign of \a x: -1 for negative, 0 for 0, +1 for positive.
|
||||||
|
INLINE int sgn3(int x)
|
||||||
|
{ return (x>>31) - (-x>>31); }
|
||||||
|
|
||||||
|
//! Get the maximum of \a a and \a b
|
||||||
|
INLINE int max(int a, int b)
|
||||||
|
{ return (a > b) ? (a) : (b); }
|
||||||
|
|
||||||
|
//! Get the minimum of \a a and \a b
|
||||||
|
INLINE int min(int a, int b)
|
||||||
|
{ return (a < b) ? (a) : (b); }
|
||||||
|
|
||||||
|
|
||||||
|
//! Range check
|
||||||
|
INLINE BOOL in_range(int x, int min, int max)
|
||||||
|
{ return (u32)(x-min) < (u32)(max-min); }
|
||||||
|
|
||||||
|
|
||||||
|
//! Truncates \a x to stay in range [\a min, \a max>
|
||||||
|
/*! \return Truncated value of \a x.
|
||||||
|
* \note \a max is exclusive!
|
||||||
|
*/
|
||||||
|
INLINE int clamp(int x, int min, int max)
|
||||||
|
{ return (x>=max) ? (max-1) : ( (x<min) ? min : x ); }
|
||||||
|
|
||||||
|
//! Reflects \a x at boundaries \a min and \a max
|
||||||
|
/*! If \a x is outside the range [\a min, \a max>,
|
||||||
|
* it'll be placed inside again with the same distance
|
||||||
|
* to the 'wall', but on the other side. Example for lower
|
||||||
|
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||||
|
* \return Reflected value of \a x.
|
||||||
|
* \note \a max is exclusive!
|
||||||
|
*/
|
||||||
|
INLINE int reflect(int x, int min, int max)
|
||||||
|
{ return (x>=max) ? (2*(max-1)-x) : ( (x<min) ? (2*min-x) : x ); }
|
||||||
|
|
||||||
|
//! Wraps \a x to stay in range [\a min, \a max>
|
||||||
|
INLINE int wrap(int x, int min, int max)
|
||||||
|
{ return (x>=max) ? (x+min-max) : ( (x<min) ? (x+max-min) : x ); }
|
||||||
|
|
||||||
|
|
||||||
|
// --- Fixed point ----------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//! Convert an integer to fixed-point
|
||||||
|
INLINE FIXED int2fx(int d)
|
||||||
|
{ return d<<FIX_SHIFT; }
|
||||||
|
|
||||||
|
//! Convert a float to fixed-point
|
||||||
|
INLINE FIXED float2fx(float f)
|
||||||
|
{ return (FIXED)(f*FIX_SCALEF); }
|
||||||
|
|
||||||
|
|
||||||
|
//! Convert a FIXED point value to an unsigned integer (orly?).
|
||||||
|
INLINE u32 fx2uint(FIXED fx)
|
||||||
|
{ return fx>>FIX_SHIFT; }
|
||||||
|
|
||||||
|
//! Get the unsigned fractional part of a fixed point value (orly?).
|
||||||
|
INLINE u32 fx2ufrac(FIXED fx)
|
||||||
|
{ return fx&FIX_MASK; }
|
||||||
|
|
||||||
|
//! Convert a FIXED point value to an signed integer.
|
||||||
|
INLINE int fx2int(FIXED fx)
|
||||||
|
{ return fx/FIX_SCALE; }
|
||||||
|
|
||||||
|
//! Convert a fixed point value to floating point.
|
||||||
|
INLINE float fx2float(FIXED fx)
|
||||||
|
{ return fx/FIX_SCALEF; }
|
||||||
|
|
||||||
|
//! Add two fixed point values
|
||||||
|
INLINE FIXED fxadd(FIXED fa, FIXED fb)
|
||||||
|
{ return fa + fb; }
|
||||||
|
|
||||||
|
//! Subtract two fixed point values
|
||||||
|
INLINE FIXED fxsub(FIXED fa, FIXED fb)
|
||||||
|
{ return fa - fb; }
|
||||||
|
|
||||||
|
|
||||||
|
//! Multiply two fixed point values
|
||||||
|
INLINE FIXED fxmul(FIXED fa, FIXED fb)
|
||||||
|
{ return (fa*fb)>>FIX_SHIFT; }
|
||||||
|
|
||||||
|
//! Divide two fixed point values.
|
||||||
|
INLINE FIXED fxdiv(FIXED fa, FIXED fb)
|
||||||
|
{ return ((fa)*FIX_SCALE)/(fb); }
|
||||||
|
|
||||||
|
|
||||||
|
//! Multiply two fixed point values using 64bit math.
|
||||||
|
INLINE FIXED fxmul64(FIXED fa, FIXED fb)
|
||||||
|
{ return (((s64)fa)*fb)>>FIX_SHIFT; }
|
||||||
|
|
||||||
|
|
||||||
|
//! Divide two fixed point values using 64bit math.
|
||||||
|
INLINE FIXED fxdiv64(FIXED fa, FIXED fb)
|
||||||
|
{ return ( ((s64)fa)<<FIX_SHIFT)/(fb); }
|
||||||
|
|
||||||
|
|
||||||
|
// --- LUT ------------------------------------------------------------
|
||||||
|
|
||||||
|
//! Look-up a sine value (2π = 0x10000)
|
||||||
|
/*! \param theta Angle in [0,FFFFh] range
|
||||||
|
* \return .12f sine value
|
||||||
|
*/
|
||||||
|
INLINE s32 lu_sin(uint theta) {
|
||||||
|
// Stub expects for testing the angle in degrees
|
||||||
|
double rad = theta*M_PI/180;
|
||||||
|
auto x = sin(rad);
|
||||||
|
return (int)(x * 65536.0f / 16.0f);;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Look-up a cosine value (2π = 0x10000)
|
||||||
|
/*! \param theta Angle in [0,FFFFh] range
|
||||||
|
* \return .12f cosine value
|
||||||
|
*/
|
||||||
|
INLINE s32 lu_cos(uint theta) {
|
||||||
|
// Stub expects for testing the angle in degrees
|
||||||
|
double rad = theta*M_PI/180;
|
||||||
|
auto x = cos(rad);
|
||||||
|
return (int)(x * 65536.0f / 16.0f);;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Look-up a division value between 0 and 255
|
||||||
|
/*! \param x reciprocal to look up.
|
||||||
|
* \return 1/x (.16f)
|
||||||
|
*/
|
||||||
|
INLINE uint lu_div(uint x)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
|
||||||
|
//! Linear interpolator for 32bit LUTs.
|
||||||
|
/*! A lut is essentially the discrete form of a function, f(<i>x</i>).
|
||||||
|
* You can get values for non-integer \e x via (linear)
|
||||||
|
* interpolation between f(x) and f(x+1).
|
||||||
|
* \param lut The LUT to interpolate from.
|
||||||
|
* \param x Fixed point number to interpolate at.
|
||||||
|
* \param shift Number of fixed-point bits of \a x.
|
||||||
|
*/
|
||||||
|
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift)
|
||||||
|
{
|
||||||
|
int xa, ya, yb;
|
||||||
|
xa=x>>shift;
|
||||||
|
ya= lut[xa]; yb= lut[xa+1];
|
||||||
|
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! As lu_lerp32, but for 16bit LUTs.
|
||||||
|
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift)
|
||||||
|
{
|
||||||
|
int xa, ya, yb;
|
||||||
|
xa=x>>shift;
|
||||||
|
ya= lut[xa]; yb= lut[xa+1];
|
||||||
|
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Point ----------------------------------------------------------
|
||||||
|
|
||||||
|
//! Initialize \a pd to (\a x, \a y)
|
||||||
|
INLINE POINT *pt_set(POINT *pd, int x, int y)
|
||||||
|
{
|
||||||
|
pd->x= x; pd->y= y;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point addition: \a pd = \a pa + \a pb
|
||||||
|
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb)
|
||||||
|
{
|
||||||
|
pd->x= pa->x + pb->x;
|
||||||
|
pd->y= pa->x + pb->y;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point subtraction: \a pd = \a pa - \a pb
|
||||||
|
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb)
|
||||||
|
{
|
||||||
|
pd->x= pa->x - pb->x;
|
||||||
|
pd->y= pa->x - pb->y;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point scale: \a pd = \a c * \a pa
|
||||||
|
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c)
|
||||||
|
{
|
||||||
|
pd->x= pa->x*c;
|
||||||
|
pd->y= pa->y*c;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point increment: \a pd += \a pb
|
||||||
|
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb)
|
||||||
|
{
|
||||||
|
pd->x += pb->y;
|
||||||
|
pd->y += pb->y;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point decrement: \a pd -= \a pb
|
||||||
|
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb)
|
||||||
|
{
|
||||||
|
pd->x -= pb->y;
|
||||||
|
pd->y -= pb->y;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point scale: \a pd *= \a c
|
||||||
|
INLINE POINT *pt_scale_eq(POINT *pd, int c)
|
||||||
|
{
|
||||||
|
pd->x *= c;
|
||||||
|
pd->y *= c;
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Point 'cross'-product: \a pa \htmlonly × \endhtmlonly \a pb
|
||||||
|
/*! Actually, there's no such thing as a 2D cross-product, but you could
|
||||||
|
* extend it to 3D and get the value of its <i>z</i>-component,
|
||||||
|
* which can be used for a test for parallelism.
|
||||||
|
*/
|
||||||
|
INLINE int pt_cross(const POINT *pa, const POINT *pb)
|
||||||
|
{ return pa->x * pb->y - pa->y * pb->x; }
|
||||||
|
|
||||||
|
|
||||||
|
//! Point 'dot'-product:\a pa \htmlonly · \endhtmlonly \a pb
|
||||||
|
INLINE int pt_dot(const POINT *pa, const POINT *pb)
|
||||||
|
{ return pa->x * pb->x + pa->y * pb->y; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- Rect -----------------------------------------------------------
|
||||||
|
|
||||||
|
//! Initialize a rectangle.
|
||||||
|
/*! \param l Left side.
|
||||||
|
* \param t Top side.
|
||||||
|
* \param r Right side.
|
||||||
|
* \param b Bottom side.
|
||||||
|
*/
|
||||||
|
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b)
|
||||||
|
{
|
||||||
|
rc->left= l; rc->top= t; rc->right= r; rc->bottom= b;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Initialize a rectangle, with sizes inside of max boundaries.
|
||||||
|
/*! \param x Left side.
|
||||||
|
* \param y Top side.
|
||||||
|
* \param w Width.
|
||||||
|
* \param h Height.
|
||||||
|
*/
|
||||||
|
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
rc->left= x; rc->top= y; rc->right= x+w; rc->bottom= y+h;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get rectangle width.
|
||||||
|
INLINE int rc_width(const RECT *rc)
|
||||||
|
{ return rc->right - rc->left; }
|
||||||
|
|
||||||
|
//! Get rectangle height
|
||||||
|
INLINE int rc_height(const RECT *rc)
|
||||||
|
{ return rc->bottom - rc->top; }
|
||||||
|
|
||||||
|
//! Move rectangle to (\a x, \a y) position.
|
||||||
|
INLINE RECT *rc_set_pos(RECT *rc, int x, int y)
|
||||||
|
{
|
||||||
|
rc->right += x-rc->left; rc->left= x;
|
||||||
|
rc->bottom += y-rc->top; rc->top= y;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Reside rectangle.
|
||||||
|
INLINE RECT *rc_set_size(RECT *rc, int w, int h)
|
||||||
|
{
|
||||||
|
rc->right= rc->left+w; rc->bottom= rc->top+h;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Move rectangle by (\a dx, \a dy).
|
||||||
|
INLINE RECT *rc_move(RECT *rc, int dx, int dy)
|
||||||
|
{
|
||||||
|
rc->left += dx; rc->top += dy;
|
||||||
|
rc->right += dx; rc->bottom += dy;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Increase size by \a dw horizontally and \a dh vertically.
|
||||||
|
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh)
|
||||||
|
{
|
||||||
|
rc->left -= dw; rc->top -= dh;
|
||||||
|
rc->right += dw; rc->bottom += dh;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Increase sizes on all sides by values of rectangle \a dr.
|
||||||
|
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr)
|
||||||
|
{
|
||||||
|
rc->left += dr->left; rc->top += dr->top;
|
||||||
|
rc->right += dr->right; rc->bottom += dr->bottom;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Vector ---------------------------------------------------------
|
||||||
|
|
||||||
|
//! Initialize a vector
|
||||||
|
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z)
|
||||||
|
{
|
||||||
|
vd->x= x; vd->y= y; vd->z= z;
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Add vectors: \b d = \b a + \b b;
|
||||||
|
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||||
|
{
|
||||||
|
vd->x= va->x + vb->x;
|
||||||
|
vd->y= va->y + vb->y;
|
||||||
|
vd->z= va->z + vb->z;
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Subtract vectors: \b d = \b a - \b b;
|
||||||
|
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||||
|
{
|
||||||
|
vd->x= va->x - vb->x;
|
||||||
|
vd->y= va->y - vb->y;
|
||||||
|
vd->z= va->z - vb->z;
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Multiply vectors elements: \b d = \b S(ax, ay, az) <20>\b b
|
||||||
|
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||||
|
{
|
||||||
|
vd->x= fxmul(va->x, vb->x);
|
||||||
|
vd->y= fxmul(va->y, vb->y);
|
||||||
|
vd->z= fxmul(va->z, vb->z);
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Scale vector: \b d = c*\b a
|
||||||
|
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c)
|
||||||
|
{
|
||||||
|
vd->x= fxmul(va->x, c);
|
||||||
|
vd->y= fxmul(va->y, c);
|
||||||
|
vd->z= fxmul(va->z, c);
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Dot-product: d = \b a <20>\b b
|
||||||
|
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb)
|
||||||
|
{
|
||||||
|
FIXED dot;
|
||||||
|
dot = fxmul(va->x, vb->x);
|
||||||
|
dot += fxmul(va->y, vb->y);
|
||||||
|
dot += fxmul(va->z, vb->z);
|
||||||
|
return dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Increment vector: \b d += \b b;
|
||||||
|
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb)
|
||||||
|
{ vd->x += vb->x; vd->y += vb->y; vd->z += vb->z; return vd; }
|
||||||
|
|
||||||
|
//! Decrease vector: \b d -= \b b;
|
||||||
|
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb)
|
||||||
|
{ vd->x -= vb->x; vd->y -= vb->y; vd->z -= vb->z; return vd; }
|
||||||
|
|
||||||
|
//! Multiply vectors elements: \b d = \b S(dx, dy, dz) <20>\b b
|
||||||
|
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb)
|
||||||
|
{
|
||||||
|
vd->x= fxmul(vd->x, vb->x);
|
||||||
|
vd->y= fxmul(vd->y, vb->y);
|
||||||
|
vd->z= fxmul(vd->z, vb->z);
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Scale vector: \b d = c*\b d
|
||||||
|
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c)
|
||||||
|
{
|
||||||
|
vd->x= fxmul(vd->x, c);
|
||||||
|
vd->y= fxmul(vd->y, c);
|
||||||
|
vd->z= fxmul(vd->z, c);
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
|
@ -14,7 +14,12 @@
|
||||||
#include "tonc_memmap.h"
|
#include "tonc_memmap.h"
|
||||||
#include "tonc_memdef.h"
|
#include "tonc_memdef.h"
|
||||||
#include "tonc_core.h"
|
#include "tonc_core.h"
|
||||||
|
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||||
|
#include "tonc_math_stub.h"
|
||||||
|
#else
|
||||||
#include "tonc_math.h"
|
#include "tonc_math.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// OBJECTS
|
// OBJECTS
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// Created by Wouter Groeneveld on 14/12/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||||
|
#define GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||||
|
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||||
|
#else
|
||||||
|
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class GBAVector {
|
||||||
|
private:
|
||||||
|
VECTOR v;
|
||||||
|
public:
|
||||||
|
GBAVector() : v({}) {}
|
||||||
|
GBAVector(VECTOR v) : v(v) {}
|
||||||
|
|
||||||
|
std::deque<VECTOR> bresenhamLineTo(VECTOR dest);
|
||||||
|
VECTOR rotateAsCenter(VECTOR point, uint angle);
|
||||||
|
|
||||||
|
std::string to_string() {
|
||||||
|
return "(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
|
@ -1,16 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Wouter Groeneveld on 14/12/18.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
|
||||||
#define GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
|
||||||
|
|
||||||
class Math {
|
|
||||||
public:
|
|
||||||
static std::deque<VECTOR> bresenhamLineBetween(VECTOR src, VECTOR dest);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
|
|
@ -7,7 +7,12 @@
|
||||||
|
|
||||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||||
|
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||||
|
#else
|
||||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||||
|
#endif
|
||||||
|
#include <libgba-sprite-engine/gbavector.h>
|
||||||
|
|
||||||
#define COLOR_MODE_16 0
|
#define COLOR_MODE_16 0
|
||||||
#define COLOR_MODE_256 1
|
#define COLOR_MODE_256 1
|
||||||
|
@ -92,6 +97,7 @@ public:
|
||||||
|
|
||||||
u32 getTileIndex() { return tileIndex; }
|
u32 getTileIndex() { return tileIndex; }
|
||||||
VECTOR getPos() { return {x, y}; }
|
VECTOR getPos() { return {x, y}; }
|
||||||
|
GBAVector getPosAsVector() { return GBAVector(getPos()); }
|
||||||
VECTOR getCenter() { return { x + w / 2, y + h / 2 }; }
|
VECTOR getCenter() { return { x + w / 2, y + h / 2 }; }
|
||||||
VECTOR getVelocity() { return { dx, dy}; }
|
VECTOR getVelocity() { return { dx, dy}; }
|
||||||
u32 getDx() { return dx; }
|
u32 getDx() { return dx; }
|
||||||
|
|
|
@ -2,10 +2,27 @@
|
||||||
// Created by Wouter Groeneveld on 14/12/18.
|
// Created by Wouter Groeneveld on 14/12/18.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <libgba-sprite-engine/math.h>
|
#include <libgba-sprite-engine/gbavector.h>
|
||||||
|
|
||||||
std::deque<VECTOR> Math::bresenhamLineBetween(VECTOR src, VECTOR dest) {
|
VECTOR GBAVector::rotateAsCenter(VECTOR point, uint angle) {
|
||||||
|
auto center = this->v;
|
||||||
|
s32 centerx = center.x, centery = center.y;
|
||||||
|
s32 defaultx = point.x, defaulty = point.y;
|
||||||
|
|
||||||
|
s32 cos = lu_cos(angle) >> 4;
|
||||||
|
s32 sin = lu_sin(angle) >> 4;
|
||||||
|
|
||||||
|
// affine matriches are 8.8 fixed point numbers, so shift all input 8 spaces up and forth
|
||||||
|
// possibilities: instead of between [-1.0, 1.0] it's between [-256, +256]
|
||||||
|
// 90° rotation in inversed y-axis needs to flip sin sign
|
||||||
|
return {
|
||||||
|
( cos * (defaultx - centerx) + sin * (defaulty - centery) + (centerx << 8)) >> 8,
|
||||||
|
(-sin * (defaultx - centerx) + cos * (defaulty - centery) + (centery << 8)) >> 8};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<VECTOR> GBAVector::bresenhamLineTo(VECTOR dest) {
|
||||||
// https://www.coranac.com/tonc/text/bitmaps.htm - Bresenham's line algorithm with fixed points
|
// https://www.coranac.com/tonc/text/bitmaps.htm - Bresenham's line algorithm with fixed points
|
||||||
|
VECTOR src = this->v;
|
||||||
VECTOR step, delta;
|
VECTOR step, delta;
|
||||||
|
|
||||||
std::deque<VECTOR> coords;
|
std::deque<VECTOR> coords;
|
|
@ -28,6 +28,7 @@ add_executable(unittest
|
||||||
allocatortest.cpp
|
allocatortest.cpp
|
||||||
palettetest.cpp
|
palettetest.cpp
|
||||||
real_data.h
|
real_data.h
|
||||||
|
../engine/src/gba/sin_lut.s
|
||||||
../engine/src/background/background.cpp
|
../engine/src/background/background.cpp
|
||||||
../engine/src/background/text_stream.cpp
|
../engine/src/background/text_stream.cpp
|
||||||
../engine/src/palette/palette_manager.cpp
|
../engine/src/palette/palette_manager.cpp
|
||||||
|
@ -35,7 +36,7 @@ add_executable(unittest
|
||||||
../engine/src/allocator.cpp
|
../engine/src/allocator.cpp
|
||||||
../engine/src/palette/combined_palette.cpp
|
../engine/src/palette/combined_palette.cpp
|
||||||
../engine/src/timer.cpp
|
../engine/src/timer.cpp
|
||||||
../engine/src/math.cpp
|
../engine/src/gbavector.cpp
|
||||||
timertest.cpp mathtest.cpp)
|
timertest.cpp gbavectortest.cpp)
|
||||||
|
|
||||||
target_link_libraries(unittest ${GTEST_LIBRARY}/build/libgtest.a ${GTEST_LIBRARY}/build/libgtest_main.a)
|
target_link_libraries(unittest ${GTEST_LIBRARY}/build/libgtest.a ${GTEST_LIBRARY}/build/libgtest_main.a)
|
||||||
|
|
|
@ -5,20 +5,54 @@
|
||||||
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <libgba-sprite-engine/math.h>
|
#include <libgba-sprite-engine/gbavector.h>
|
||||||
|
|
||||||
class MathSuite : public ::testing::Test {
|
class GBAVectorSuite : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
|
GBAVector vector;
|
||||||
|
VECTOR bottomHalf;
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
|
vector = GBAVector({120, 80});
|
||||||
|
bottomHalf = { 120, 200 };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Diagonal_ToTopRightCorner) {
|
// Angle in DEGREES for readability - converted in tonc_math_stub!
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {240, 0});
|
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_0_Degrees) {
|
||||||
|
auto result = vector.rotateAsCenter(bottomHalf, 0);
|
||||||
|
ASSERT_EQ(120, result.x);
|
||||||
|
ASSERT_EQ(200, result.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_90_Degrees) {
|
||||||
|
auto result = vector.rotateAsCenter(bottomHalf, 90);
|
||||||
|
ASSERT_EQ(240, result.x);
|
||||||
|
ASSERT_EQ(80, result.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_180_Degrees) {
|
||||||
|
auto result = vector.rotateAsCenter(bottomHalf, 180);
|
||||||
|
ASSERT_EQ(120, result.x);
|
||||||
|
ASSERT_EQ(-40, result.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_270_Degrees) {
|
||||||
|
auto result = vector.rotateAsCenter(bottomHalf, 270);
|
||||||
|
ASSERT_EQ(0, result.x);
|
||||||
|
ASSERT_EQ(80, result.y);
|
||||||
|
}
|
||||||
|
// ---- //
|
||||||
|
|
||||||
|
TEST_F(GBAVectorSuite, ToString) {
|
||||||
|
ASSERT_EQ(std::string("(120,80)"), vector.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToTopRightCorner) {
|
||||||
|
auto points = vector.bresenhamLineTo({240, 0});
|
||||||
ASSERT_EQ(121, points.size());
|
ASSERT_EQ(121, points.size());
|
||||||
VECTOR pt;
|
VECTOR pt;
|
||||||
|
|
||||||
|
@ -37,8 +71,8 @@ TEST_F(MathSuite, LineBetween_Diagonal_ToTopRightCorner) {
|
||||||
ASSERT_EQ(13, pt.y);
|
ASSERT_EQ(13, pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Diagonal_ToTopLeftCorner) {
|
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToTopLeftCorner) {
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {0, 0});
|
auto points = vector.bresenhamLineTo({0, 0});
|
||||||
ASSERT_EQ(121, points.size());
|
ASSERT_EQ(121, points.size());
|
||||||
VECTOR pt;
|
VECTOR pt;
|
||||||
|
|
||||||
|
@ -57,8 +91,8 @@ TEST_F(MathSuite, LineBetween_Diagonal_ToTopLeftCorner) {
|
||||||
ASSERT_EQ(13, pt.y);
|
ASSERT_EQ(13, pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Diagonal_ToBottomLeftCorner) {
|
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToBottomLeftCorner) {
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {0, 160});
|
auto points = vector.bresenhamLineTo({0, 160});
|
||||||
ASSERT_EQ(121, points.size());
|
ASSERT_EQ(121, points.size());
|
||||||
VECTOR pt;
|
VECTOR pt;
|
||||||
|
|
||||||
|
@ -77,8 +111,8 @@ TEST_F(MathSuite, LineBetween_Diagonal_ToBottomLeftCorner) {
|
||||||
ASSERT_EQ(147, pt.y);
|
ASSERT_EQ(147, pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Diagonal_ToBottomRightCorner) {
|
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToBottomRightCorner) {
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {240, 160});
|
auto points = vector.bresenhamLineTo({240, 160});
|
||||||
ASSERT_EQ(121, points.size());
|
ASSERT_EQ(121, points.size());
|
||||||
VECTOR pt;
|
VECTOR pt;
|
||||||
|
|
||||||
|
@ -97,8 +131,8 @@ TEST_F(MathSuite, LineBetween_Diagonal_ToBottomRightCorner) {
|
||||||
ASSERT_EQ(147, pt.y);
|
ASSERT_EQ(147, pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) {
|
TEST_F(GBAVectorSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) {
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {0, 80});
|
auto points = vector.bresenhamLineTo({0, 80});
|
||||||
ASSERT_EQ(121, points.size());
|
ASSERT_EQ(121, points.size());
|
||||||
for(int i = 0; i <= 120; i++) {
|
for(int i = 0; i <= 120; i++) {
|
||||||
auto &vec = points.front();
|
auto &vec = points.front();
|
||||||
|
@ -108,8 +142,8 @@ TEST_F(MathSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MathSuite, LineBetween_Vertical_FromCenterToHalfXFullY) {
|
TEST_F(GBAVectorSuite, LineBetween_Vertical_FromCenterToHalfXFullY) {
|
||||||
auto points = Math::bresenhamLineBetween({120, 80}, {120, 160});
|
auto points = vector.bresenhamLineTo({120, 160});
|
||||||
ASSERT_EQ(81, points.size());
|
ASSERT_EQ(81, points.size());
|
||||||
for(int i = 0; i <= (160 - 80); i++) {
|
for(int i = 0; i <= (160 - 80); i++) {
|
||||||
auto &vec = points.front();
|
auto &vec = points.front();
|
|
@ -14,7 +14,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SomePaletteManager() {
|
virtual ~SomePaletteManager() {
|
||||||
delete palette;
|
delete[] palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue