Skip to content

Instantly share code, notes, and snippets.

@OllieReynolds
Last active June 17, 2016 01:17
Show Gist options
  • Save OllieReynolds/f125dd2f1a5e5d7eea7fb8f52e0a57f0 to your computer and use it in GitHub Desktop.
Save OllieReynolds/f125dd2f1a5e5d7eea7fb8f52e0a57f0 to your computer and use it in GitHub Desktop.
#include <Windows.h>
#define GLM_SWIZZLE
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <ctime>
#include <algorithm>
#define WIDTH 80
#define HEIGHT 25
int currentScene = 0;
long long milliseconds_now() {
static LARGE_INTEGER s_frequency;
static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
if (s_use_qpc) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (1000LL * now.QuadPart) / s_frequency.QuadPart;
} else {
return GetTickCount();
}
}
bool hill(int x, int y, long long t, double timeFactor, float amplitude, float yOffset) {
int p1 = amplitude * sin(0.1 * x + (t * timeFactor)) + yOffset;
return y >= p1;
}
bool road(int x, int y, long long t, int start, int end) {
return y >= start && y <= end;
}
float calc_triangle_area(glm::vec2 a, glm::vec2 b, glm::vec2 c) {
float A = a.x * (b.y - c.y);
float B = b.x * (c.y - a.y);
float C = c.x * (a.y - b.y);
return abs((A + B + C) / 2);
}
float calc_polygon_area(glm::vec2* points) {
return 0.5 * abs(
points[0].x * points[1].y +
points[1].x * points[2].y +
points[2].x * points[3].y +
points[3].x * points[0].y -
points[1].x * points[0].y -
points[2].x * points[1].y -
points[3].x * points[2].y -
points[0].x * points[3].y
);
}
bool point_quad_intersect_fill(glm::vec2 p, glm::vec2* points) {
// Sum of areas △APD, △DPC, △CPB, △PBA must be less than
// area of quad for intersection to exist.
float tris =
calc_triangle_area(points[0], p, points[3]) +
calc_triangle_area(points[3], p, points[2]) +
calc_triangle_area(points[2], p, points[1]) +
calc_triangle_area(p, points[1], points[0]);
float quad = calc_polygon_area(points);
return tris <= quad;
}
bool point_quad_intersect_nofill(glm::vec2 p, glm::vec2* points) {
// Sum of areas △APD, △DPC, △CPB, △PBA must be less than
// area of quad for intersection to exist.
float tris =
calc_triangle_area(points[0], p, points[3]) +
calc_triangle_area(points[3], p, points[2]) +
calc_triangle_area(points[2], p, points[1]) +
calc_triangle_area(p, points[1], points[0]);
float quad = calc_polygon_area(points);
return tris == quad;
}
bool point_circle_intersect_fill(glm::vec2 p, glm::vec2 cP, float r) {
float dx = 0.5f * (cP.x - p.x);
float dy = cP.y - p.y;
float d = sqrt(dx * dx + dy * dy);
return d < r;
}
bool point_circle_intersect_nofill(glm::vec2 p, glm::vec2 cP, float r) {
float dx = 0.5f * (cP.x - p.x);
float dy = cP.y - p.y;
float d = sqrt(dx * dx + dy * dy);
return d > r - 0.25f
&& d < r + 0.25f;
}
bool occlude_view(glm::vec2 p, glm::vec2* points) {
return !point_quad_intersect_fill(p, points);
}
glm::vec2 rot_point(glm::vec2 p, float theta, glm::vec2 o) {
return glm::vec2(
cos(theta) * (p.x - o.x) - sin(theta) * (p.y - o.y) + o.x,
sin(theta) * (p.x - o.x) + cos(theta) * (p.y - o.y) + o.y
);
}
int main() {
glm::vec2 points[] = {
{0, 0}, // TOP-LEFT
{80, 0}, // TOP-RIGHT
{80, 25}, // BOTTOM-RIGHT
{0, 25} // BOTTOM-LEFT
};
CHAR_INFO cBuffer[WIDTH * HEIGHT];
SMALL_RECT wSize = {0, 0, WIDTH, HEIGHT};
SMALL_RECT wArea = {0, 0, WIDTH - 1, HEIGHT - 1};
HANDLE wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleWindowInfo(wHnd, TRUE, &wSize);
SetConsoleScreenBufferSize(wHnd, {WIDTH, HEIGHT});
long long start = milliseconds_now();
for (int i = 0; i < WIDTH * HEIGHT; i++) {
cBuffer[i].Char.AsciiChar = ' ';
cBuffer[i].Attributes = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
}
while (!GetAsyncKeyState(VK_ESCAPE)) {
long long elapsed = milliseconds_now() - start;
int seconds = elapsed / 1000;
if (GetAsyncKeyState(0x30)) {
currentScene = 0;
start = milliseconds_now();
}
else if (GetAsyncKeyState(0x31)) {
currentScene = 1;
start = milliseconds_now();
}
else if (GetAsyncKeyState(0x32)) {
currentScene = 2;
start = milliseconds_now();
}
else if (GetAsyncKeyState(0x33)) {
currentScene = 3;
start = milliseconds_now();
}
for (int y = 0; y < HEIGHT; ++y) {
for (int x = 0; x < WIDTH; ++x) {
switch (currentScene) {
case 0:
{
// FRONT LAYER
if (occlude_view(glm::vec2(x, y), points)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = ' ';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED;
} else if (hill(x, y, elapsed, 0.005, 12.5, 12.5)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '1';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_GREEN;
} else if (road(x, y, elapsed, 21, 24)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '~';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_BLUE;
} else if (hill(x, y, elapsed, 0.003, 12.5 * 0.66, 12.5)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '2';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_BLUE | FOREGROUND_GREEN;
} else if (road(x, y, elapsed, 17, 20)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '~';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_BLUE;
} else if (hill(x, y, elapsed, 0.001, 12.5 * 0.33, 12.5)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '3';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_GREEN;
} else {
cBuffer[x + WIDTH * y].Char.AsciiChar = ' ';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED;
}
// BACK LAYER
break;
}
case 1:
{
static float pointRadius = 2.f;
static glm::vec2 pointPositions[] = {
{15, 10},
{25, 10},
{35, 10}
};
float initialAltitude = 20;
float c = 2;
float _x = elapsed * 0.001f;
float PI = 3.141592;
bool drew = false;
for (int i = 0; i < 3; i++) {
float res = abs((initialAltitude / _x) * sin(((3 + i * PI) / c) * _x));
pointPositions[i].y = HEIGHT - res - pointRadius - 1;
pointPositions[i].x = (_x * (10.f * (i + 1)) + pointRadius) * 1.3;
if (point_circle_intersect_nofill(glm::vec2(x, y), pointPositions[i], pointRadius)) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '1';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE;
drew = true;
}
}
if (!drew) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '.';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED;
}
break;
}
case 2:
{
const int num_points = 6;
const float pointRadius = 6.f;
glm::vec2 startPosition = {40, 13};
glm::vec2 pointPositions[num_points] = {
{15, 10},
{25, 10},
{35, 10},
{45, 10},
{55, 10},
{65, 10},
};
bool drew = false;
for (int i = 0; i < num_points; i++) {
pointPositions[i].y += 2 * sin(elapsed * 0.005f + i) + 2;
if (point_circle_intersect_fill(glm::vec2(x, y), pointPositions[i], pointRadius)) {
if (i % 2 == 0) {
cBuffer[x + WIDTH * y].Char.AsciiChar = 'O';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | BACKGROUND_INTENSITY | BACKGROUND_BLUE;
} else {
cBuffer[x + WIDTH * y].Char.AsciiChar = 'O';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED;
}
drew = true;
}
}
if (!drew) {
cBuffer[x + WIDTH * y].Char.AsciiChar = '=';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_GREEN;
}
break;
}
case 3:
{
cBuffer[x + WIDTH * y].Char.AsciiChar = '|';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_GREEN | BACKGROUND_GREEN;
break;
}
default:
{
cBuffer[x + WIDTH * y].Char.AsciiChar = ' ';
cBuffer[x + WIDTH * y].Attributes = FOREGROUND_RED;
break;
}
}
}
}
WriteConsoleOutputA(wHnd, cBuffer, {WIDTH, HEIGHT}, {0, 0}, &wArea);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment