enum RaycastSide : Uint8
{
Top = 0,
Right,
Bottom,
Left
};
typedef struct s_raycastinfo_t
{
bool hit;
int x;
int y;
Uint8 texel;
float angle;
Vector start;
Vector end;
float distance;
RaycastSide side;
} RaycastInfo;
void Application::Raycast(RaycastInfo* info, const Vector start, const Vector dir)
{
if (info)
{
memset(info, NULL, sizeof(RaycastInfo));
float angle = atan2f(dir.y, dir.x);
if (angle < 0.0f)
{
angle += M_PI * 2.0f;
}
angle = fmod(angle, M_PI * 2.0f);
float angTan = tanf(angle);
bool isUp = (angle < 0.0f || angle > M_PI);
bool isRight = (angle > ((M_PI * 2.0f) * 0.75f) || angle < ((M_PI * 2.0f) * 0.25f));
/* Horizontal Intersection */
Vector horzEnd = Vector::Empty();
float hXa = (BLOCK_SIZE / (isUp ? -angTan : angTan));
float hYa = (BLOCK_SIZE * (isUp ? -1 : 1));
horzEnd.y = int(start.y / BLOCK_SIZE) * (BLOCK_SIZE) + (isUp ? -1 : BLOCK_SIZE);
horzEnd.x = start.x + (horzEnd.y - start.y) / angTan;
int hMx = 0;
int hMy = 0;
bool hHit = false;
while (true)
{
hMx = int(horzEnd.x) / BLOCK_SIZE;
hMy = int(horzEnd.y) / BLOCK_SIZE;
if (hMx < 0 || hMy < 0 || hMx >= mapWidth_ || hMy >= mapHeight_)
{
break;
}
else if (map_[(mapWidth_ * hMy) + hMx])
{
hHit = true;
break;
}
horzEnd.x += hXa;
horzEnd.y += hYa;
}
/* Vertical Intersection */
Vector vertEnd = Vector::Empty();
float vXa = (BLOCK_SIZE * (isRight ? 1 : -1));
float vYa = (BLOCK_SIZE * (isRight ? angTan : -angTan));
vertEnd.x = int(start.x / BLOCK_SIZE) * (BLOCK_SIZE) + (isRight ? BLOCK_SIZE : -1);
vertEnd.y = start.y + (vertEnd.x - start.x) * angTan;
int vMx = 0;
int vMy = 0;
bool vHit = false;
while (true)
{
vMx = int(vertEnd.x) / BLOCK_SIZE;
vMy = int(vertEnd.y) / BLOCK_SIZE;
if (vMx < 0 || vMy < 0 || vMx >= mapWidth_ || vMy >= mapHeight_)
{
break;
}
else if (map_[(mapWidth_ * vMy) + vMx])
{
vHit = true;
break;
}
vertEnd.x += vXa;
vertEnd.y += vYa;
}
/* Setup info object */
float vertDist = start.DistanceSquared(vertEnd);
float horzDist = start.DistanceSquared(horzEnd);
info->start = start;
info->angle = angle;
if (hHit && horzDist < vertDist)
{
info->end = horzEnd;
info->distance = sqrt(horzDist);
info->side = (isUp ? RaycastSide::Bottom : RaycastSide::Top);
info->x = hMx;
info->y = hMy;
info->texel = (hMx % BLOCK_SIZE);
info->hit = true;
}
else if (vHit)
{
info->end = vertEnd;
info->distance = sqrt(vertDist);
info->side = (isRight ? RaycastSide::Left : RaycastSide::Right);
info->x = vMx;
info->y = vMy;
info->texel = (vMy % BLOCK_SIZE);
info->hit = true;
}
else
{
info->end = start;
info->distance = 0.0f;
info->side = RaycastSide::Top;
info->x = INT_MAX;
info->y = INT_MAX;
info->texel = 0;
info->hit = false;
}
}
}
#pragma once
#ifndef _INCLUDE_VECTOR_H_
#define _INCLUDE_VECTOR_H_
#include "main.h"
class Vector
{
public:
float x, y;
/* =================== */
/* === Constructor === */
/* =================== */
Vector(void) :
x(0), y(0)
{
}
Vector(float x, float y) :
x(x), y(y)
{
}
Vector(const Vector& v) :
x(v.x), y(v.y)
{
}
~Vector(void)
{
}
static Vector Empty(void)
{
return Vector();
}
Vector Floor(void) const
{
Vector v;
v.x = floorf(this->x);
v.y = floorf(this->y);
return v;
}
Vector Ceil(void) const
{
Vector v;
v.x = ceilf(this->x);
v.y = ceilf(this->y);
return v;
}
/* =========================== */
/* === Calculation Methods === */
/* =========================== */
float Distance(const Vector& rhs) const
{
return sqrt(DistanceSquared(rhs));
}
float DistanceSquared(const Vector& rhs) const
{
Vector v = Subtract(rhs);
return ((v.x * v.x) + (v.y * v.y));
}
float Magnitude(void) const
{
return sqrtf((x * x) + (y * y));
}
Vector Normalized(void) const
{
Vector v(x, y);
float mag = v.Magnitude();
if (mag != 0.0f)
{
v.x /= mag;
v.y /= mag;
}
return v;
}
Vector& Normalize(void)
{
Set(Normalized());
return *this;
}
float Dot(const Vector& rhs) const
{
return ((x * rhs.x) + (y * rhs.y));
}
/* ====================== */
/* === Index Operator === */
/* ====================== */
float& operator[](int idx)
{
return (&this->x)[idx % 2];
}
/* =========================== */
/* === Assignment Operator === */
/* =========================== */
Vector& Set(const Vector& rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
Vector& Set(float rhs)
{
x = rhs;
y = rhs;
return *this;
}
Vector& Set(float rhsx, float rhsy)
{
x = rhsx;
y = rhsy;
return *this;
}
Vector& operator=(const Vector& rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
Vector& operator=(float rhs)
{
x = rhs;
y = rhs;
return *this;
}
/* ========================= */
/* === Addition Operator === */
/* ========================= */
Vector Add(const Vector& rhs) const
{
Vector v(x + rhs.x, y + rhs.y);
return v;
}
Vector Add(float rhs) const
{
Vector v(x + rhs, y + rhs);
return v;
}
Vector operator+(const Vector& rhs) const
{
return Add(rhs);
}
Vector operator+(float rhs) const
{
return Add(rhs);
}
Vector& operator+=(const Vector& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
Vector& operator+=(float rhs)
{
x += rhs;
y += rhs;
return *this;
}
/* ============================ */
/* === Subtraction Operator === */
/* ============================ */
Vector Subtract(const Vector& rhs) const
{
Vector v(x - rhs.x, y - rhs.y);
return v;
}
Vector Subtract(float rhs) const
{
Vector v(x - rhs, y - rhs);
return v;
}
Vector operator-(const Vector& rhs) const
{
return Subtract(rhs);
}
Vector operator-(float rhs) const
{
return Subtract(rhs);
}
Vector& operator-=(const Vector& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
Vector& operator-=(float rhs)
{
x -= rhs;
y -= rhs;
return *this;
}
/* ========================= */
/* === Division Operator === */
/* ========================= */
Vector Divide(const Vector& rhs) const
{
Vector v(x / rhs.x, y / rhs.y);
return v;
}
Vector Divide(float rhs) const
{
Vector v(x / rhs, y / rhs);
return v;
}
Vector operator/(const Vector& rhs) const
{
return Divide(rhs);
}
Vector operator/(float rhs) const
{
return Divide(rhs);
}
Vector& operator/=(const Vector& rhs)
{
x /= rhs.x;
y /= rhs.y;
return *this;
}
Vector& operator/=(float rhs)
{
x /= rhs;
y /= rhs;
return *this;
}
/* =============================== */
/* === Multiplication Operator === */
/* =============================== */
Vector Multiply(const Vector& rhs) const
{
Vector v(x * rhs.x, y * rhs.y);
return v;
}
Vector Multiply(float rhs) const
{
Vector v(x * rhs, y * rhs);
return v;
}
Vector operator*(const Vector& rhs) const
{
return Multiply(rhs);
}
Vector operator*(float rhs) const
{
return Multiply(rhs);
}
Vector& operator*=(const Vector& rhs)
{
x *= rhs.x;
y *= rhs.y;
return *this;
}
Vector& operator*=(float rhs)
{
x *= rhs;
y *= rhs;
return *this;
}
/* =========================== */
/* === Comparison Operator === */
/* =========================== */
bool operator==(const Vector& rhs) const
{
return (fabsf(x - rhs.x) < FLT_EPSILON && fabsf(y - rhs.y) < FLT_EPSILON);
}
bool operator==(const float rhs) const
{
return (fabsf(x - rhs) < FLT_EPSILON && fabsf(y - rhs) < FLT_EPSILON);
}
bool operator!=(const Vector& rhs) const
{
return (fabsf(x - rhs.x) > FLT_EPSILON || fabsf(y - rhs.y) > FLT_EPSILON);
}
bool operator!=(const float rhs) const
{
return (fabsf(x - rhs) > FLT_EPSILON || fabsf(y - rhs) > FLT_EPSILON);
}
};
#endif