Created
November 28, 2023 06:06
-
-
Save ishan9299/3d100356237eb3f28be05cf4c6ad2918 to your computer and use it in GitHub Desktop.
main.c program to render and move 2d shapes.
This file contains hidden or 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> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <xinput.h> | |
#define SWAP(T, x, y) do {T t = x; x = y; y = t;} while(0) | |
#define MIN(x, y) ((x) < (y) ? x : y); | |
bool window_running = true; | |
unsigned int bitmap_width = 800; | |
unsigned int bitmap_height = 600; | |
static BITMAPINFO bitmap_info; | |
static HBITMAP bitmap; | |
static HDC device_context; | |
static unsigned int *bitmap_memory; | |
struct vec2i32 { | |
int x; | |
int y; | |
}; | |
// NOTE(not-set): write an algorithm to make sure winding order is counter clockwise. | |
int IsInsideTriangle(struct vec2i32 a, struct vec2i32 b, struct vec2i32 c) { | |
// NOTE(not-set): make sure the winding order of the vertices is counter clockwise | |
int result = ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x)); | |
return result; | |
} | |
void plotPixel(int x, int y, unsigned int color) { | |
for (int Y = 0; Y < bitmap_height; Y++) { | |
for (int X = 0; X < bitmap_width; X++) { | |
if ((x == X) && (y == Y)) { | |
bitmap_memory[(Y * bitmap_width) + X] = color; | |
} | |
} | |
} | |
} | |
void plotLine(struct vec2i32 v1, struct vec2i32 v2) | |
{ | |
int x0 = v1.x; | |
int y0 = v1.y; | |
int x1 = v2.x; | |
int y1 = v2.y; | |
int steep = 0; | |
if (abs(y1 - y0) < abs(x1 - x0)) { | |
if (x1 < x0) { | |
SWAP(int, x0, x1); | |
SWAP(int, y0, y1); | |
} | |
} else { | |
steep = 1; | |
SWAP(int, x0, y0); | |
SWAP(int, x1, y1); | |
if (y1 < y0) { | |
SWAP(int, x0, x1); | |
SWAP(int, y0, y1); | |
} | |
if (x1 < x0) { | |
SWAP(int, x0, x1); | |
SWAP(int, y0, y1); | |
} | |
} | |
int deltaY = y1 - y0; | |
int deltaX = x1 - x0; | |
int increment = 1; | |
if (deltaY < 0) { | |
increment = -1; | |
deltaY = -deltaY; | |
} | |
int decisionParam = (2 * deltaY) - deltaX; | |
int y = y0; | |
for (int X = x0; X <= x1; X++) { | |
if (steep == 1) { | |
plotPixel(y, X, 0xffffffff); | |
} else { | |
plotPixel(X, y, 0xffffffff); | |
} | |
if (decisionParam > 0) { | |
y = y + increment; | |
decisionParam = decisionParam + (2 * (deltaY - deltaX)); | |
} else { | |
decisionParam = decisionParam + (2 * deltaY); | |
} | |
} | |
} | |
void plotTriangle(struct vec2i32 v1, | |
struct vec2i32 v2, | |
struct vec2i32 v3) { | |
plotLine(v1, v2); | |
plotLine(v2, v3); | |
plotLine(v1, v3); | |
} | |
void plotFilledTriangle(struct vec2i32 v1, | |
struct vec2i32 v2, | |
struct vec2i32 v3) { | |
if (v1.y < v2.y) { | |
SWAP(int, v1.y, v2.y); | |
SWAP(int, v1.x, v2.x); | |
} | |
if (v1.y < v3.y) { | |
SWAP(int, v1.y, v3.y); | |
SWAP(int, v1.x, v3.x); | |
} | |
if (v2.y < v3.y) { | |
SWAP(int, v2.y, v3.y); | |
SWAP(int, v2.x, v3.x); | |
} | |
int maxY = v1.y; | |
int minY = v3.y; | |
if (v3.x < v2.x) { | |
SWAP(int, v2.x, v3.x); | |
SWAP(int, v2.y, v3.y); | |
} | |
int minX = v2.x; | |
int maxX = v3.x; | |
if (v1.x > v3.x) { | |
maxX = v1.x; | |
} | |
for (int Y = minY; Y <= maxY; Y++) { | |
for (int X = minX; X <= maxX; X++) { | |
struct vec2i32 p = { | |
.x = X, | |
.y = Y, | |
}; | |
int result1 = IsInsideTriangle(v1, v2, p); | |
int result2 = IsInsideTriangle(v2, v3, p); | |
int result3 = IsInsideTriangle(v3, v1, p); | |
char buffer[256]; | |
int j = sprintf(buffer, | |
"r1: %d, r2: %d, r3: %d\n", | |
result1, result2, result3); | |
if (result1 > 0 && result2 > 0 && result3 > 0) { | |
bitmap_memory[(Y * bitmap_width) + X] = 0xffffffff; | |
} | |
} | |
} | |
} | |
void plotFilledRect(struct vec2i32 topLeft, struct vec2i32 bottomRight) { | |
int height = bottomRight.y - topLeft.y; | |
int width = bottomRight.x - topLeft.x; | |
int x1 = topLeft.x; | |
int y1 = topLeft.y; | |
int x2 = topLeft.x; | |
int y2 = topLeft.y + height; | |
int x3 = bottomRight.x; | |
int y3 = bottomRight.y; | |
int x4 = bottomRight.x; | |
int y4 = bottomRight.y - height; | |
for(int Y = topLeft.y; Y < bottomRight.y; Y++) { | |
for (int X = topLeft.x; X < bottomRight.x; X++) { | |
bitmap_memory[(Y * bitmap_width) + X] = 0xffffffff; | |
} | |
} | |
} | |
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, | |
WPARAM wParam, LPARAM lParam); | |
int WINAPI wWinMain(HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
PWSTR pCmdLine, int nCmdShow) { | |
const char *class_name = "Window Class"; | |
WNDCLASSEX window_class = {0}; | |
window_class.cbSize = sizeof(WNDCLASSEX); | |
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
window_class.lpfnWndProc = WindowProc; | |
window_class.hInstance = hInstance; | |
window_class.lpszClassName = class_name; | |
bitmap_info.bmiHeader.biSize = sizeof(bitmap_info.bmiHeader); | |
bitmap_info.bmiHeader.biPlanes = 1; | |
bitmap_info.bmiHeader.biBitCount = 32; | |
bitmap_info.bmiHeader.biCompression = BI_RGB; | |
device_context = CreateCompatibleDC(0); | |
if(!RegisterClassEx(&window_class)) { | |
return 0; | |
} | |
HWND window_handle = CreateWindowEx(0, class_name, | |
"Windows Program", | |
WS_OVERLAPPEDWINDOW, | |
CW_USEDEFAULT, CW_USEDEFAULT, | |
CW_USEDEFAULT, CW_USEDEFAULT, | |
NULL, NULL, hInstance, NULL); | |
if (window_handle == NULL) { | |
return 0; | |
} | |
ShowWindow(window_handle, nCmdShow); | |
UpdateWindow(window_handle); | |
MSG msg = {0}; | |
int x_offset = 0; | |
int y_offset = 0; | |
while (window_running) | |
{ | |
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | |
if (msg.message == WM_QUIT) { | |
window_running = false; | |
} | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
if (bitmap_memory) { | |
ZeroMemory(bitmap_memory, (bitmap_width * bitmap_height)); | |
} | |
unsigned int dwResult; | |
for (DWORD i=0; i< XUSER_MAX_COUNT; i++ ) | |
{ | |
XINPUT_STATE controller_state; | |
ZeroMemory(&controller_state, sizeof(XINPUT_STATE) ); | |
// Simply get the state of the controller from XInput. | |
dwResult = XInputGetState( i, &controller_state ); | |
if( dwResult == ERROR_SUCCESS ) | |
{ | |
// Controller is connected | |
XINPUT_GAMEPAD *pad = &controller_state.Gamepad; | |
int controller_up = (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP); | |
int controller_down = (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN); | |
int controller_left = (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT); | |
int controller_right = (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT); | |
int controller_start = (pad->wButtons & XINPUT_GAMEPAD_START); | |
int controller_back = (pad->wButtons & XINPUT_GAMEPAD_BACK); | |
int controller_lthumb = (pad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB); | |
int controller_rthumb = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB); | |
int controller_lshoulder = (pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER); | |
int controller_rshoulder = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER); | |
int controller_a = (pad->wButtons & XINPUT_GAMEPAD_A); | |
int controller_b = (pad->wButtons & XINPUT_GAMEPAD_B); | |
int controller_x = (pad->wButtons & XINPUT_GAMEPAD_X); | |
int controller_y = (pad->wButtons & XINPUT_GAMEPAD_Y); | |
int stick_x = pad->sThumbLX; | |
int stick_y = pad->sThumbLY; | |
if (controller_right) { | |
x_offset += 2; | |
} | |
if (controller_left) { | |
x_offset -= 2; | |
} | |
if (controller_up) { | |
y_offset -= 0; | |
} | |
if (controller_down) { | |
y_offset += 2; | |
} | |
} | |
else | |
{ | |
// Controller is not connected | |
} | |
} | |
struct vec2i32 topLeft = { | |
.x = 80 + x_offset, | |
.y = 80 + y_offset, | |
}; | |
struct vec2i32 bottomRight = { | |
.x = 130 + x_offset, | |
.y = 130 + y_offset, | |
}; | |
char s[256]; | |
sprintf(s, "coordinates [topLeft]: [%d, %d] [bottomRight]: [%d, %d]\n", | |
topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); | |
OutputDebugStringA(s); | |
plotFilledRect(topLeft, bottomRight); | |
InvalidateRect(window_handle, NULL, FALSE); | |
UpdateWindow(window_handle); | |
} | |
return 0; | |
} | |
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, | |
WPARAM wParam, LPARAM lParam) | |
{ | |
LRESULT result; | |
PAINTSTRUCT paint; | |
switch(uMsg) { | |
case WM_PAINT: { | |
HDC paint_device_context = BeginPaint(hwnd, &paint); | |
BitBlt(paint_device_context, paint.rcPaint.left, | |
paint.rcPaint.top, | |
paint.rcPaint.right - paint.rcPaint.left, | |
paint.rcPaint.bottom - paint.rcPaint.top, | |
device_context, paint.rcPaint.left, paint.rcPaint.top, | |
SRCCOPY); | |
EndPaint(hwnd, &paint); | |
break; | |
} | |
case WM_DESTROY: { | |
PostQuitMessage(0); | |
break; | |
} | |
case WM_SIZE: { | |
bitmap_info.bmiHeader.biWidth = LOWORD(lParam); | |
bitmap_info.bmiHeader.biHeight = -HIWORD(lParam); | |
bitmap_width = bitmap_info.bmiHeader.biWidth; | |
bitmap_height = -bitmap_info.bmiHeader.biHeight; | |
if (bitmap) DeleteObject(bitmap); | |
bitmap = CreateDIBSection(0, &bitmap_info, DIB_RGB_COLORS, (void **)&bitmap_memory, 0, 0); | |
SelectObject(device_context, bitmap); | |
} | |
default: { | |
result = DefWindowProc(hwnd, uMsg, wParam, lParam); | |
break; | |
} | |
} | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment