Skip to content

Instantly share code, notes, and snippets.

@ishan9299
Created November 28, 2023 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ishan9299/3d100356237eb3f28be05cf4c6ad2918 to your computer and use it in GitHub Desktop.
Save ishan9299/3d100356237eb3f28be05cf4c6ad2918 to your computer and use it in GitHub Desktop.
main.c program to render and move 2d shapes.
#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