Last active
November 6, 2022 06:59
-
-
Save RealNeGate/62efdbd9175f63840f9bad9fe6ea9d3d 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
// Reject modernity, return to wrinkly ass GL shit | |
#if !defined(_WIN32) | |
#error "Fuck you" | |
#endif | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#define _USE_MATH_DEFINES | |
#include <math.h> | |
#define NOMINMAX | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <GL/gl.h> | |
#define STB_TRUETYPE_IMPLEMENTATION | |
#include "stb_truetype.h" | |
#include "dyn_array.h" | |
#pragma comment(lib, "opengl32.lib") | |
#pragma comment(lib, "gdi32.lib") | |
#pragma comment(lib, "user32.lib") | |
// no need for do while crap if it's an expression :p | |
// it's basically an assert but it doesn't get vaporized | |
#define CHECK(x) ((x) ? (void)0 : abort()) | |
enum { | |
BITMAP_W = 512, BITMAP_H = 512 | |
}; | |
typedef struct { | |
uint64_t user_id; // 0 is self | |
const char* content; | |
} Message; | |
typedef struct { | |
float x, y; | |
} Point; | |
typedef struct { | |
float x, y, w, h; | |
} Rect; | |
typedef struct { | |
float curr, target; | |
} Scrollbar; | |
static DynArray(Message) messages; | |
static float font_size; | |
static unsigned char ttf_buffer[1<<20]; | |
static unsigned char temp_bitmap[BITMAP_W * BITMAP_H]; | |
static stbtt_packedchar cdata[128]; | |
static GLuint ftex; | |
static int mouse_scroll; | |
static Point mouse_pos; | |
static void update_scroll(Scrollbar* s, float dt, float min, float max) { | |
if (s->target > max) s->target = max; | |
if (s->target < min) s->target = min; | |
s->curr += (s->target - s->curr) * (1.0f - expf(-10.0f * dt)); | |
} | |
static bool rect_contains(const Rect* a, const Point* b) { | |
return (b->x >= a->x && b->y >= a->y && b->x < (a->x + a->w) && b->y < (a->y + a->h)); | |
} | |
static LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) { | |
if (msg == WM_DESTROY) { | |
PostQuitMessage(0); | |
return 0; | |
} else if (msg == WM_MOUSEWHEEL) { | |
mouse_scroll = GET_WHEEL_DELTA_WPARAM(wparam) < 0 ? -1 : 1; | |
return 0; | |
} | |
return DefWindowProcW(wnd, msg, wparam, lparam); | |
} | |
static void set_color(void fn(float, float, float, float), uint32_t color) { | |
fn( | |
((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, | |
((color >> 0) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f | |
); | |
} | |
static void draw_rect(uint32_t color, float x, float y, float w, float h) { | |
float x1 = x + w; | |
float y1 = y + h; | |
glBegin(GL_QUADS); | |
set_color(glColor4f, color); | |
glVertex2f(x, y), glVertex2f(x1, y); | |
glVertex2f(x1, y1), glVertex2f(x, y1); | |
glEnd(); | |
} | |
static void draw_text(uint32_t color, float x, float y, const char* text) { | |
glEnable(GL_TEXTURE_2D); | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
glBindTexture(GL_TEXTURE_2D, ftex); | |
glBegin(GL_QUADS); | |
set_color(glColor4f, color); | |
float xx = x, yy = 0.0f; | |
for (; *text; text++) { | |
if (*text >= 32 && *text < 128) { | |
stbtt_aligned_quad q; | |
stbtt_GetPackedQuad(cdata, BITMAP_W, BITMAP_H, *text, &xx, &yy, &q, 1); | |
q.x0 = ceilf(q.x0); | |
q.x1 = ceilf(q.x1); | |
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,y-q.y0); | |
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,y-q.y0); | |
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,y-q.y1); | |
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,y-q.y1); | |
} | |
} | |
glEnd(); | |
glBindTexture(GL_TEXTURE_2D, 0); | |
glDisable(GL_BLEND); | |
glDisable(GL_TEXTURE_2D); | |
} | |
static void draw_circle(uint32_t color, float x, float y, float w, float h, float angle_start, float angle_range) { | |
enum { RINGS = 32 }; | |
uint32_t fade_end = (color & ~0xFF000000) | 0x20000000; | |
float radius_x = w*0.5f, center_x = x + radius_x; | |
float radius_y = h*0.5f, center_y = y + radius_y; | |
float step = angle_range / RINGS; | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
// draw ring around the circle that's fading so we can pretend there's smooth edges | |
glBegin(GL_TRIANGLE_STRIP); | |
for (int i = 0; i < RINGS + 1; i++) { | |
float rad = angle_start + (i*step), c = cosf(rad), s = sinf(rad); | |
set_color(glColor4f, color); | |
glVertex2f(center_x + c*radius_x*1.0f, center_y + s*radius_y*1.0f); | |
set_color(glColor4f, fade_end); | |
glVertex2f(center_x + c*(radius_x+1.0f), center_y + s*(radius_y+1.0f)); | |
} | |
glEnd(); | |
glBegin(GL_TRIANGLE_FAN); | |
set_color(glColor4f, color); | |
glVertex2f(center_x, center_y); | |
for (int i = 0; i < RINGS + 1; i++) { | |
float rad = angle_start + (i*step), c = cosf(rad), s = sinf(rad); | |
glVertex2f(center_x + c*radius_x, center_y + s*radius_y); | |
} | |
glEnd(); | |
glDisable(GL_BLEND); | |
} | |
static void draw_rounded_rect(uint32_t color, float x, float y, float w, float h) { | |
float corner = h; | |
draw_circle(color, x, y + 1.0f, corner, corner - 2.0f, 0.5f*M_PI, M_PI); | |
draw_rect(color, x + corner*0.5f, y, w - corner, corner); | |
draw_circle(color, x + w - corner, y + 1.0f, corner, corner - 2.0f, 1.5f*M_PI, M_PI); | |
} | |
static float measure_text_w(const char* text) { | |
float xx = 0.0f, yy = 0.0f; | |
for (; *text; text++) { | |
if (*text >= 32 && *text < 128) { | |
stbtt_aligned_quad q; | |
stbtt_GetPackedQuad(cdata, BITMAP_W, BITMAP_H, *text, &xx, &yy, &q, 1); | |
} | |
} | |
return xx; | |
} | |
static void draw_text_button(uint32_t color, float x, float y, float h, const char* text) { | |
float text_w = measure_text_w(text); | |
float w = text_w + 20.0f, corner = h * 0.5f; | |
// rounded rect | |
draw_circle(color, x, y + 1.0f, corner * 2.0f, (corner*2.0f) - 2.0f, 0.5f*M_PI, M_PI); | |
draw_rect(color, x + corner, y, w, h); | |
draw_circle(color, x + w, y + 1.0f, corner * 2.0f, (corner*2.0f) - 2.0f, 1.5f*M_PI, M_PI); | |
draw_text(0xFFFFFFFF, x + corner + 10.0f, y + (corner - 8.0f), text); | |
} | |
static void draw_circle_text_button(uint32_t color, float x, float y, float diameter, const char* text) { | |
float text_w = measure_text_w(text); | |
draw_circle(color, x, y, diameter, diameter, 0.0f, 2.0f*M_PI); | |
draw_text(0xFFFFFFFF, x + diameter*0.5f - text_w*0.5f, y + diameter*0.5f - font_size*0.25f, text); | |
} | |
int main() { | |
WNDCLASSEXW wc = { | |
.cbSize = sizeof(wc), | |
.lpfnWndProc = WindowProc, | |
.hInstance = GetModuleHandleA(NULL), | |
.lpszClassName = L"MINE", | |
.hCursor = LoadCursor(NULL, IDC_ARROW), | |
}; | |
CHECK(RegisterClassExW(&wc)); | |
HWND window = CreateWindowExW( | |
WS_EX_APPWINDOW, L"MINE", L"Da square", WS_OVERLAPPEDWINDOW, | |
CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, NULL, NULL, wc.hInstance, NULL | |
); | |
CHECK(window); | |
ShowWindow(window, SW_SHOW); | |
SetFocus(window); | |
// WGL shit | |
HDC dc = GetDC(window); | |
PIXELFORMATDESCRIPTOR pfd = { | |
.nSize = sizeof(pfd), | |
.nVersion = 1, | |
.iPixelType = PFD_TYPE_RGBA, | |
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, | |
.cColorBits = 32, | |
.cAlphaBits = 8, | |
.iLayerType = PFD_MAIN_PLANE | |
}; | |
int pixel_format; | |
CHECK(pixel_format = ChoosePixelFormat(dc, &pfd)); | |
CHECK(SetPixelFormat(dc, pixel_format, &pfd)); | |
HGLRC glctx; | |
CHECK(glctx = wglCreateContext(dc)); | |
CHECK(wglMakeCurrent(dc, glctx)); | |
set_color(glClearColor, 0xFF1C1B1F); | |
{ | |
font_size = 36.0; | |
FILE* f = fopen("assets/OpenSans-SemiBold.ttf", "rb"); | |
fread(ttf_buffer, 1, 1<<20, f); | |
stbtt_pack_context pc; | |
stbtt_PackBegin(&pc, temp_bitmap, BITMAP_W, BITMAP_H, 0, 1, NULL); | |
stbtt_PackSetOversampling(&pc, 1, 1); | |
stbtt_PackFontRange(&pc, ttf_buffer, 0, font_size, 32, 96, cdata + 32); | |
stbtt_PackEnd(&pc); | |
// can free ttf_buffer at this point | |
glGenTextures(1, &ftex); | |
glBindTexture(GL_TEXTURE_2D, ftex); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_W, BITMAP_H, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); | |
// can free temp_bitmap at this point | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glBindTexture(GL_TEXTURE_2D, 0); | |
fclose(f); | |
} | |
messages = dyn_array_create(Message); | |
dyn_array_put(messages, (Message){ 0, "Hey!" }); | |
dyn_array_put(messages, (Message){ 0, "Ok really not gonna answer" }); | |
dyn_array_put(messages, (Message){ 1, "Fuck you" }); | |
dyn_array_put(messages, (Message){ 1, "I hate you and your grandma" }); | |
dyn_array_put(messages, (Message){ 0, "My grandma's dead" }); | |
dyn_array_put(messages, (Message){ 1, "And?" }); | |
LARGE_INTEGER now, start_time, frequency; | |
QueryPerformanceFrequency(&frequency); | |
QueryPerformanceCounter(&start_time); | |
for (;;) { | |
// da pump | |
mouse_scroll = 0; | |
MSG msg; | |
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { | |
if (msg.message == WM_QUIT) goto exit; | |
TranslateMessage(&msg); | |
DispatchMessageW(&msg); | |
} | |
// Get time delta | |
LARGE_INTEGER now; | |
QueryPerformanceCounter(&now); | |
float dt = (now.QuadPart - start_time.QuadPart) / (double) frequency.QuadPart; | |
start_time = now; | |
RECT rect; | |
GetClientRect(window, &rect); | |
int w = rect.right - rect.left, h = rect.bottom - rect.top; | |
POINT mp; | |
GetCursorPos(&mp); | |
ScreenToClient(window, &mp); | |
mouse_pos = (Point){ mp.x, h - mp.y }; | |
glViewport(0, 0, w, h); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glOrtho(0, w, 0, h, -1, 1); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
#if 1 | |
float dp = 96.0f / 160.0f; | |
// User list | |
float split = w * 0.2f; | |
{ | |
static Scrollbar user_list_scroll; | |
update_scroll(&user_list_scroll, dt, 0.0f, 300.0f); | |
Rect r = { 0.0f, 0.0f, split, h }; | |
glPushMatrix(); | |
glTranslatef(0.0f, user_list_scroll.curr, 0.0f); | |
float line_height = 104.0f*dp; | |
for (int i = 0; i < 15; i++) { | |
float top = (h - 16.0f*dp) - (line_height * i); | |
float x = 16.0f*dp; | |
char ch[2] = { 'A' + i }; | |
draw_circle_text_button(0xFF004787, x, top - 72.0f*dp, 72.0f*dp, ch); | |
{ | |
float x2 = x + (72.0f + 16.0f)*dp; | |
draw_rect(0xFF222426, x2, top - (36.0f - 8.0f)*dp, 168.0f*dp, 24.0f*dp); | |
draw_rect(0xFF222426, x2, top - (72.0f - 8.0f)*dp, 72.0f*dp, 24.0f*dp); | |
} | |
// draw separator | |
draw_rect(0xFF43474E, 16.0f*dp, top - 88.0f*dp, split - (32.0f*dp), 1.0f); | |
} | |
glPopMatrix(); | |
if (rect_contains(&r, &mouse_pos)) { | |
// user list hot now, we can scroll | |
user_list_scroll.target -= mouse_scroll*100.0f; | |
// draw_rect(0xFF00FF00, r.x, r.y, r.w, r.h); | |
} | |
} | |
draw_rect(0xFF43474E, split, 0.0f, 1.0f, h); | |
// Message view | |
{ | |
float msg_view_x = split + 32.0f*dp; | |
float msg_view_y = (32.0f+96.0f+32.0f)*dp; | |
float msg_view_w = (w - 32.0f*dp) - msg_view_x; | |
float msg_view_h = (h - 32.0f*dp) - msg_view_y; | |
// draw_rect(0xFFFF0000, msg_view_x, msg_view_y, msg_view_w, msg_view_h); | |
float msg_h = 104.0f*dp; | |
float right = msg_view_x + msg_view_w; | |
float current = msg_view_y + msg_view_h; | |
dyn_array_for(i, messages) { | |
Message* msg = &messages[i]; | |
float msg_w = measure_text_w(msg->content) + 20.0f + (88.0f*dp); | |
float msg_x = msg->user_id == 0 ? msg_view_x : (right - msg_w); | |
current -= msg_h; | |
draw_text_button(0xFF004787, msg_x, current, 88.0f*dp, msg->content); | |
// draw_rect(0xFF0000FF, msg_x, current, msg_w, font_size*0.5f); | |
} | |
} | |
// Text field and send button | |
{ | |
float field_w = w - (split + 96.0f*dp + 96.0f*dp); | |
float x = split + 32.0f*dp; | |
draw_rounded_rect(0xFF222426, x, 32.0f*dp, field_w, 96.0f*dp); | |
x += field_w + (32.0f*dp); | |
draw_circle(0xFF004787, x, 32.0f*dp, 96.0f*dp, 96.0f*dp, 0.0f, 2.0f*M_PI); | |
} | |
#else | |
draw_rect(0xFFE6E1E5, 0.0f, 0.0f, 400.0f, 200.0f); | |
draw_text(0xFF000000, 20.0f, 20.0f, "Hello, World!"); | |
draw_circle(0xFF004A77, 500.0f, 500.0f, 100.0f, 100.0f, 0.0f, 2.0f * M_PI); | |
draw_rounded_rect(0xFF004A77, 700.0f, 300.0f, 103.0f, 43.0f); | |
draw_text_button(0xFF386A20, 700.0f, 350.0f, "Enabled"); | |
for (int i = 0; i < 4; i++) { | |
draw_circle_text_button(0xFF6750A4, 950.0f, 300.0f + (i * 56.0f), 43.0f, "A"); | |
} | |
#endif | |
// draw_circle(0xFF6750A4, mouse_pos.x - 5.0f, mouse_pos.y - 5.0f, 10.0f, 10.0f, 0.0f, 2.0f * M_PI); | |
SwapBuffers(dc); | |
} | |
exit: | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment