Last active
June 17, 2016 01:17
-
-
Save OllieReynolds/f125dd2f1a5e5d7eea7fb8f52e0a57f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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