RyanHub – file viewer
filename: src/raycaster.cpp
branch: main
back to repo
#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);
}