#include "raycaster.h"
#include "constants.h"
GLdouble degToRad(GLdouble a) {
return a * 3.14159 / 180;
}
float calculateWallDistance(GLfloat* positions, float rayAngle) {
float px = (positions[0] + 1.0f) / tileSize;
float py = (1.0f - positions[1]) / tileSize;
float rayDirX = sinf(degToRad(rayAngle));
float rayDirY = -cosf(degToRad(rayAngle));
int mapXpos = static_cast<int>(px);
int mapYpos = static_cast<int>(py);
float deltaDistX = (fabsf(rayDirX) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirX);
float deltaDistY = (fabsf(rayDirY) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirY);
int stepX, stepY;
float sideDistX, sideDistY;
if (rayDirX < 0) {
stepX = -1;
sideDistX = (px - mapXpos) * deltaDistX;
}
else {
stepX = 1;
sideDistX = (mapXpos + 1.0f - px) * deltaDistX;
}
if (rayDirY < 0) {
stepY = -1;
sideDistY = (py - mapYpos) * deltaDistY;
}
else {
stepY = 1;
sideDistY = (mapYpos + 1.0f - py) * deltaDistY;
}
bool hit = false;
int side = 0; // 0: x-side, 1: y-side
while (!hit) {
if (sideDistX < sideDistY) {
sideDistX += deltaDistX;
mapXpos += stepX;
side = 0;
}
else {
sideDistY += deltaDistY;
mapYpos += stepY;
side = 1;
}
if (mapXpos < 0 || mapXpos >= mapX || mapYpos < 0 || mapYpos >= mapY) {
return 1e30f; // No wall hit
}
if (map[mapYpos * mapX + mapXpos] == 1) {
hit = true;
}
}
float perpWallDist;
if (side == 0) {
perpWallDist = (sideDistX - deltaDistX);
}
else {
perpWallDist = (sideDistY - deltaDistY);
}
return perpWallDist;
}
void drawLine(Renderer& renderer, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, Renderer::ColorRGB color) {
GLfloat width = 0.0025f;
Renderer::QuadVertices quadVertices = {
x1 + width, y1 + width, // Top right
x2 + width, y2 - width, // Bottom right
x1 - width, y1 + width, // Top left
x2 - width, y2 - width // Bottom left
};
renderer.drawQuad(quadVertices, color, 0);
}
void drawMap(Renderer& renderer) {
for (int y = 0; y < mapY; y++) {
for (int x = 0; x < mapX; x++) {
if (map[y * mapX + x] == 1) {
GLfloat x0 = -1.0f + x * tileSize;
GLfloat y0 = 1.0f - y * tileSize;
GLfloat x1 = x0 + tileSize;
GLfloat y1 = y0 - tileSize;
Renderer::QuadVertices quadVertices = {
x1, y0,
x1, y1,
x0, y0,
x0, y1
};
Renderer::ColorRGB quadColor = Renderer::ColorRGB(0, 0, 0);
renderer.drawQuad(quadVertices, quadColor, 0);
}
}
}
}
GLfloat drawRaycastLine(Renderer& renderer, double rayAngle, double playerAngleX, double playerAngleY, GLfloat *positions) {
//player angle is direction of our player
//ray angle is angle at which we do raycast
float px = (positions[0] + 1.0f) / tileSize;
float py = (1.0f - positions[1]) / tileSize;
float rayDirX = sinf(degToRad(rayAngle));
float rayDirY = -cosf(degToRad(rayAngle));
int mapplayerAngle = static_cast<int>(px);
int mapYpos = static_cast<int>(py);
float deltaDistX = (fabsf(rayDirX) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirX);
float deltaDistY = (fabsf(rayDirY) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirY);
int stepX, stepY;
float sideDistX, sideDistY;
float perpWallDist;
if (rayDirX < 0) {
stepX = -1;
sideDistX = (px - mapplayerAngle) * deltaDistX;
}
else {
stepX = 1;
sideDistX = (mapplayerAngle + 1.0f - px) * deltaDistX;
}
if (rayDirY < 0) {
stepY = -1;
sideDistY = (py - mapYpos) * deltaDistY;
}
else {
stepY = 1;
sideDistY = (mapYpos + 1.0f - py) * deltaDistY;
}
bool hit = false;
int side = 0; // 0: x-side, 1: y-side
float rayLength = 0.0f;
while (!hit)
{
if (sideDistX < sideDistY) {
mapplayerAngle += stepX;
rayLength = sideDistX;
sideDistX += deltaDistX;
side = 0;
}
else {
mapYpos += stepY;
rayLength = sideDistY;
sideDistY += deltaDistY;
side = 1;
}
if (mapplayerAngle < 0 || mapplayerAngle >= mapX || mapYpos < 0 || mapYpos >= mapY) {
break;
}
if (map[mapYpos * mapX + mapplayerAngle] == 1) {
hit = true;
}
}
float hitX = px + rayDirX * rayLength; // positions for world
float hitY = py + rayDirY * rayLength;
float normHitX = hitX * tileSize - 1.0f; // positions for the map
float normHitY = 1.0f - hitY * tileSize;
if (side == 0) {
perpWallDist = (sideDistX - deltaDistX);
}
else {
perpWallDist = (sideDistY - deltaDistY);
}
float screenX = -1.0f + (rayAngle - (playerAngleX - (0.5 * RAY_NUM))) * angularSlice; // position on screen considering input angle
float lineHeight = 2.0f / perpWallDist * 0.5f; // height considering distance from camera
float lineStart = -lineHeight + (playerAngleY * 0.03f);
float lineEnd = lineHeight + (playerAngleY * 0.03f);
int wallColor = (side == 0) ? 200 : 150;
// draw wall line
renderer.drawQuad(
Renderer::QuadVertices{
screenX, lineStart,
screenX, lineEnd,
screenX + angularSlice, lineStart,
screenX + angularSlice, lineEnd
},
Renderer::ColorRGB(wallColor, 0, 0),
0
);
drawLine(renderer, positions[0], positions[1], normHitX, normHitY, Renderer::ColorRGB(0, 200, 0));
return perpWallDist;
}
bool drawPlayer(Renderer& renderer, float relativeAngle, float angleToOther, double playerAngleY, GLfloat *otherPlayerPositions, GLfloat * positions, int health)
{
if (fabs(relativeAngle) <= (RAY_NUM / 2)) {
//drawLine(positions[0], positions[1], otherPlayerPositions[0], otherPlayerPositions[1], shaderProgram, 3);
float playerDistance = (sqrt(pow((otherPlayerPositions[0] - positions[0]), 2) + pow((otherPlayerPositions[1] - positions[1]), 2))) / tileSize;
float angleToOtherDegrees = angleToOther * (180.0f / 3.14159f);
//float wallDistance = drawRaycastLine(renderer, angleToOtherDegrees, angleToOtherDegrees, positions);
float wallDistance = calculateWallDistance(positions, angleToOtherDegrees);
//cout << "wallDistance = " << wallDistance << " playerDistance = " << playerDistance << " angleToOtherDegrees = " << angleToOtherDegrees << endl;
if (playerDistance <= wallDistance)
{
float screenX = (relativeAngle / (RAY_NUM * 0.5f));
float CHARACTER_SIZE = (0.1f / playerDistance);
float Ystart = (0.6 / playerDistance) + (playerAngleY * 0.03f);
float Yend = (-0.9 / playerDistance) + (playerAngleY * 0.03f);
float Ystartbar = (0.8 / playerDistance) + (playerAngleY * 0.03f);
float Yendbar = (0.7 / playerDistance) + (playerAngleY * 0.03f);
float startPlus = Ystartbar + (0.008f);
float endPlus = Yendbar - (0.008f);
//onscreen player
renderer.drawQuad(
Renderer::QuadVertices{
screenX - CHARACTER_SIZE, Ystart,
screenX + CHARACTER_SIZE, Ystart,
screenX - CHARACTER_SIZE, Yend,
screenX + CHARACTER_SIZE, Yend
},
Renderer::ColorRGB(0, 0, 255),
2
);
// Health bar background
renderer.drawQuad(
Renderer::QuadVertices{
screenX - (2.05f * CHARACTER_SIZE), startPlus,
screenX + (2.05f * CHARACTER_SIZE), startPlus,
screenX - (2.05f * CHARACTER_SIZE), endPlus,
screenX + (2.05f * CHARACTER_SIZE), endPlus
},
Renderer::ColorRGB(0, 0, 0),
0
);
// Health bar
renderer.drawQuad(
Renderer::QuadVertices{
screenX - (2.0f * CHARACTER_SIZE), Ystartbar,
screenX + (2.0f * CHARACTER_SIZE), Ystartbar,
screenX - (2.0f * CHARACTER_SIZE), Yendbar,
screenX + (2.0f * CHARACTER_SIZE), Yendbar
},
Renderer::ColorRGB(0, 255, 0),
0
);
// Health bar current
renderer.drawQuad(
Renderer::QuadVertices{
screenX + (2.0f * CHARACTER_SIZE), Ystartbar,
screenX + (2.0f * CHARACTER_SIZE * (1.0f - static_cast<float>(health) * 2 / maxHealth)), Ystartbar,
screenX + (2.0f * CHARACTER_SIZE), Yendbar,
screenX + (2.0f * CHARACTER_SIZE * (1.0f - static_cast<float>(health) * 2 / maxHealth)), Yendbar
},
Renderer::ColorRGB(255, 0, 0),
0
);
// drawPlayerQuad
renderer.drawQuad(
Renderer::QuadVertices{
positions[0] + PLAYER_SIZE, positions[1] + PLAYER_SIZE,
positions[0] + PLAYER_SIZE, positions[1] - PLAYER_SIZE,
positions[0] - PLAYER_SIZE, positions[1] + PLAYER_SIZE,
positions[0] - PLAYER_SIZE, positions[1] - PLAYER_SIZE
},
Renderer::ColorRGB(0, 0, 255),
0
);
// drawCrosshair
renderer.drawQuad(
Renderer::QuadVertices{
0.01f, 0.01f,
0.01f, -0.01f,
-0.01f, 0.01f,
-0.01f, -0.01f
},
Renderer::ColorRGB(255, 255, 255),
0
);
return true;
}
}
return false;
}
void drawPlayerQuad(Renderer& renderer, GLfloat* positions, Renderer::ColorRGB color) {
Renderer::QuadVertices quadVertices = {
positions[0] + PLAYER_SIZE, positions[1] + PLAYER_SIZE,
positions[0] + PLAYER_SIZE, positions[1] - PLAYER_SIZE,
positions[0] - PLAYER_SIZE, positions[1] + PLAYER_SIZE,
positions[0] - PLAYER_SIZE, positions[1] - PLAYER_SIZE
};
renderer.drawQuad(quadVertices, color, 2);
}
void drawCrosshair(Renderer& renderer, Renderer::ColorRGB color) {
Renderer::QuadVertices quadVertices = {
0.01f, 0.01f, // Top right
0.01f, -0.01f, // Bottom right
-0.01f, 0.01f, // Top left
-0.01f, -0.01f // Bottom left
};
renderer.drawQuad(quadVertices, color, 2);
}