#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
class Vertex
{
public:
float x;
float y;
float z;
};
struct CONSOLE_FONT
{
DWORD index;
COORD dim;
};
enum class COLOR
{
FG_BLACK = 0x0000,
FG_DARK_BLUE = 0x0001,
FG_DARK_GREEN = 0x0002,
FG_DARK_CYAN = 0x0003,
FG_DARK_RED = 0x0004,
FG_DARK_MAGENTA = 0x0005,
FG_DARK_YELLOW = 0x0006,
FG_GREY = 0x0007,
FG_DARK_GREY = 0x0008,
FG_BLUE = 0x0009,
FG_GREEN = 0x000A,
FG_CYAN = 0x000B,
FG_RED = 0x000C,
FG_MAGENTA = 0x000D,
FG_YELLOW = 0x000E,
FG_WHITE = 0x000F,
BG_BLACK = 0x0000,
BG_DARK_BLUE = 0x0010,
BG_DARK_GREEN = 0x0020,
BG_DARK_CYAN = 0x0030,
BG_DARK_RED = 0x0040,
BG_DARK_MAGENTA = 0x0050,
BG_DARK_YELLOW = 0x0060,
BG_GREY = 0x0070,
BG_DARK_GREY = 0x0080,
BG_BLUE = 0x0090,
BG_GREEN = 0x00A0,
BG_CYAN = 0x00B0,
BG_RED = 0x00C0,
BG_MAGENTA = 0x00D0,
BG_YELLOW = 0x00E0,
BG_WHITE = 0x00F0,
};
void Draw_Text(CHAR_INFO* screen_buffer, string text, float sx, float sy, int character_screen_width, int character_screen_height, COLOR color);
int main();
int keystate;
Vertex vertex_list[4];
Vertex temp_list[4];
Vertex local_list[4];
Vertex camera_list[4];
Vertex perspective_list[4];
Vertex screen_list[4];
Vertex angle;
Vertex cam;
void Draw_Text(CHAR_INFO* screen_buffer, string text, float sx, float sy, int character_screen_width, int character_screen_height, COLOR color)
{
if (sx >= character_screen_width - 1) sx = 0.0f;
for (int x = 0; x < static_cast<int>(text.length()); x++)
{
if (sx >= 0 && sx < character_screen_width && sy >= 0 && sy < character_screen_height)
{
screen_buffer[static_cast<int>(sy) * character_screen_width + static_cast<int>(sx + x)].Char.UnicodeChar = text[x];
screen_buffer[static_cast<int>(sy) * character_screen_width + static_cast<int>(sx + x)].Attributes = static_cast<WORD>(color);
}
}
}
void Draw_Bresenham_Line(CHAR_INFO* screen_buffer, int x1, int y1, int x2, int y2, int character_screen_width, int character_screen_height, COLOR color)
{
int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
dx = x2 - x1;
dy = y2 - y1;
dx1 = static_cast<int>(fabs(dx));
dy1 = static_cast<int>(fabs(dy));
px = 2 * dy1 - dx1;
py = 2 * dx1 - dy1;
if (dy1 <= dx1)
{
if (dx >= 0)
{
x = x1;
y = y1;
xe = x2;
}
else
{
x = x2;
y = y2;
xe = x1;
}
if (x >= 0 && x < character_screen_width && y >= 0 && y < character_screen_height)
{
screen_buffer[y * character_screen_width + x].Char.UnicodeChar = ' ';
screen_buffer[y * character_screen_width + x].Attributes = static_cast<WORD>(color);
}
for (i = 0; x < xe; i++)
{
x = x + 1;
if (px < 0)
{
px = px + 2 * dy1;
}
else
{
if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0))
{
y = y + 1;
}
else
{
y = y - 1;
}
px = px + 2 * (dy1 - dx1);
}
if (x >= 0 && x < character_screen_width && y >= 0 && y < character_screen_height)
{
screen_buffer[y * character_screen_width + x].Char.UnicodeChar = ' ';
screen_buffer[y * character_screen_width + x].Attributes = static_cast<WORD>(color);
}
}
}
else
{
if (dy >= 0)
{
x = x1;
y = y1;
ye = y2;
}
else
{
x = x2;
y = y2;
ye = y1;
}
if (x >= 0 && x < character_screen_width && y >= 0 && y < character_screen_height)
{
screen_buffer[y * character_screen_width + x].Char.UnicodeChar = ' ';
screen_buffer[y * character_screen_width + x].Attributes = static_cast<WORD>(color);
}
for (i = 0; y < ye; i++)
{
y = y + 1;
if (py <= 0)
{
py = py + 2 * dx1;
}
else
{
if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0))
{
x = x + 1;
}
else
{
x = x - 1;
}
py = py + 2 * (dx1 - dy1);
}
if (x >= 0 && x < character_screen_width && y >= 0 && y < character_screen_height)
{
screen_buffer[y * character_screen_width + x].Char.UnicodeChar = ' ';
screen_buffer[y * character_screen_width + x].Attributes = static_cast<WORD>(color);
}
}
}
}
int main()
{
const float PI = 3.14159265358979f;
const float RADIAN = PI / 180.0f;
const float FOV = 90.0f;
vertex_list[0].x = -50.0f; vertex_list[0].y = 50.0f; vertex_list[0].z = 0.0f;
vertex_list[1].x = 50.0f; vertex_list[1].y = 50.0f; vertex_list[1].z = 0.0f;
vertex_list[2].x = -50.0f; vertex_list[2].y = -50.0f; vertex_list[2].z = 0.0f;
vertex_list[3].x = 50.0f; vertex_list[3].y = -50.0f; vertex_list[3].z = 0.0f;
//// Get console font size
//CONSOLE_FONT fonts = {};
//fonts.dim = GetConsoleFontSize(console, fonts.index);
//int fontw = fonts.dim.x;
//int fonth = fonts.dim.y;
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
cfi.nFont = 0;
cfi.dwFontSize.X = 20;
cfi.dwFontSize.Y = 20;
cfi.FontFamily = FF_DONTCARE;
cfi.FontWeight = FW_NORMAL;
int screen_width = 1280;
int screen_height = 720;
int character_screen_width = static_cast<int>(floor((screen_width) / (cfi.dwFontSize.X)));
int character_screen_height = static_cast<int>(floor((screen_height - 39) / (cfi.dwFontSize.Y))) + 1;
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
COORD NewSBSize;
GetConsoleScreenBufferInfo(console, &SBInfo);
NewSBSize.X = SBInfo.srWindow.Right - SBInfo.srWindow.Left + 1;
NewSBSize.Y = SBInfo.srWindow.Bottom - SBInfo.srWindow.Top + 1;
SetConsoleScreenBufferSize(console, NewSBSize);
// Setup Console window
SMALL_RECT m_rectWindow = { 0, 0, (short)character_screen_width - 1, (short)character_screen_height - 1 };
SetConsoleActiveScreenBuffer(console);
SetCurrentConsoleFontEx(console, false, &cfi);
// Resize Console window
RECT r;
GetWindowRect(GetConsoleWindow(), &r); //stores the console's current dimensions
MoveWindow(GetConsoleWindow(), r.left, r.top, screen_width, screen_height, TRUE);
// Setup screen buffer
CHAR_INFO* screen_buffer = new CHAR_INFO[character_screen_width * character_screen_height];
// Make key cursor invisible
CONSOLE_CURSOR_INFO cursor_info;
GetConsoleCursorInfo(console, &cursor_info);
cursor_info.bVisible = false; // set the cursor visibility
SetConsoleCursorInfo(console, &cursor_info);
// Set key cursor to beginning
SetConsoleCursorPosition(console, { 0, 0 });
cam.x = 0.0f;
cam.y = 0.0f;
cam.z = 400.0f;
while (true)
{
angle.x = 0.0f;
angle.y += 0.1f;
angle.z = 0.0f;
for (int i = 0; i < 4; i++)
{
temp_list[i].x = vertex_list[i].x * (cosf(angle.y * RADIAN) * cosf(angle.z * RADIAN)) + vertex_list[i].y * ((sinf(angle.x * RADIAN) * sinf(angle.y * RADIAN) * cosf(angle.z * RADIAN)) + (cosf(angle.x * RADIAN) * -sinf(angle.z * RADIAN))) + vertex_list[i].z * (cosf(angle.x * RADIAN) * sinf(angle.y * RADIAN) * cosf(angle.z * RADIAN)) + (-sinf(angle.x * RADIAN) * -sinf(angle.z * RADIAN));
temp_list[i].y = vertex_list[i].x * (cosf(angle.y * RADIAN) * sinf(angle.z * RADIAN)) + vertex_list[i].y * ((sinf(angle.x * RADIAN) * sinf(angle.y * RADIAN) * sinf(angle.z * RADIAN)) + (cosf(angle.x * RADIAN) * cosf(angle.z * RADIAN))) + vertex_list[i].z * (cosf(angle.x * RADIAN) * sinf(angle.y * RADIAN) * sinf(angle.z * RADIAN)) + (-sinf(angle.x * RADIAN) * cosf(angle.z * RADIAN));
temp_list[i].z = vertex_list[i].x * (-sinf(angle.y * RADIAN)) + vertex_list[i].y * (sinf(angle.x * RADIAN) * cosf(angle.y * RADIAN)) + vertex_list[i].z * (cosf(angle.x * RADIAN) * cosf(angle.y * RADIAN));
local_list[i] = temp_list[i];
}
if (GetAsyncKeyState('W'))
keystate |= 0x1;
else
keystate &= ~0x1;
if (GetAsyncKeyState('S'))
keystate |= 0x2;
else
keystate &= ~0x2;
if (GetAsyncKeyState('A'))
keystate |= 0x4;
else
keystate &= ~0x4;
if (GetAsyncKeyState('D'))
keystate |= 0x8;
else
keystate &= ~0x8;
if (keystate & 0x1) cam.z -= 0.5f;
if (keystate & 0x2) cam.z += 0.5f;
if (keystate & 0x4) cam.x -= 0.5f;
if (keystate & 0x8) cam.x += 0.5f;
wchar_t buffer[256];
swprintf_s(buffer, 256, L"3D: %f, %f", cam.x, cam.z);
SetConsoleTitle(buffer);
// Clear screen
memset(screen_buffer, 0, sizeof(CHAR_INFO) * character_screen_width * character_screen_height);
Draw_Text(screen_buffer, "Press W, S, A, and D keys to move around", 0, 0, character_screen_width, character_screen_height, COLOR::FG_WHITE);
float aspect = 16.0f / 9.0f;
float distance = tanf(PI * (FOV / 2.0f) / 180.0f);
for (int i = 0; i < 4; i++)
{
camera_list[i].x = local_list[i].x + cam.x;
camera_list[i].y = local_list[i].y + cam.y;
camera_list[i].z = local_list[i].z + cam.z;
if (camera_list[i].z > 0.0f)
{
perspective_list[i].x = distance * camera_list[i].x / camera_list[i].z;
perspective_list[i].y = distance * camera_list[i].y * aspect / camera_list[i].z;
perspective_list[i].z = 0.0f;
}
float alpha = 0.5f * character_screen_width - 0.5f;
float beta = 0.5f * character_screen_height - 0.5f;
screen_list[i].x = alpha + alpha * perspective_list[i].x;
screen_list[i].y = beta - beta * perspective_list[i].y;
screen_list[i].z = 0.0f;
}
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[0].x), static_cast<int>(screen_list[0].y), static_cast<int>(screen_list[1].x), static_cast<int>(screen_list[1].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[1].x), static_cast<int>(screen_list[1].y), static_cast<int>(screen_list[2].x), static_cast<int>(screen_list[2].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[2].x), static_cast<int>(screen_list[2].y), static_cast<int>(screen_list[0].x), static_cast<int>(screen_list[0].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[1].x), static_cast<int>(screen_list[1].y), static_cast<int>(screen_list[2].x), static_cast<int>(screen_list[2].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[2].x), static_cast<int>(screen_list[2].y), static_cast<int>(screen_list[3].x), static_cast<int>(screen_list[3].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
Draw_Bresenham_Line(screen_buffer, static_cast<int>(screen_list[3].x), static_cast<int>(screen_list[3].y), static_cast<int>(screen_list[1].x), static_cast<int>(screen_list[1].y), character_screen_width, character_screen_height, COLOR::BG_WHITE);
// Draw buffer to Console Window
WriteConsoleOutput(console, screen_buffer, { (short)character_screen_width, (short)character_screen_height }, { 0,0 }, &m_rectWindow);
}
return 0;
}