Skip to content

Instantly share code, notes, and snippets.

@albertelwin
Created August 19, 2016 22:10
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save albertelwin/5c2f4d9de337b1b707850462be986aed to your computer and use it in GitHub Desktop.
//NOTE: MSVC 2013 command line build
//cl -nologo -EHa- -Gm- -GR- -fp:fast -Oi -WX -W4 -wd4996 -wd4100 -wd4189 -wd4127 -wd4201 -wd4101 -wd4505 -MTd -Od -Z7 tear.cpp user32.lib gdi32.lib winmm.lib opengl32.lib -link -incremental:no -opt:ref
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#undef near
#undef far
#ifndef _WINMM_
#define WINMMAPI DECLSPEC_IMPORT
#else
#define WINMMAPI
#endif
typedef UINT MMRESULT;
extern "C" {
WINMMAPI MMRESULT WINAPI timeBeginPeriod(_In_ UINT uPeriod);
}
#include <cmath>
#include <stddef.h>
#include <stdio.h>
typedef unsigned int u32;
typedef int i32;
typedef float f32;
#include <GL/gl.h>
#define GL_ARRAY_BUFFER 0x8892
#define GL_STATIC_DRAW 0x88E4
#define GL_VERTEX_SHADER 0x8B31
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_FRAMEBUFFER 0x8D40
typedef ptrdiff_t GLsizeiptr;
typedef char GLchar;
typedef void (APIENTRY * PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); PFNGLATTACHSHADERPROC glAttachShader;
typedef void (APIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); PFNGLBINDBUFFERPROC glBindBuffer;
typedef void (APIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array); PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
typedef void (APIENTRY * PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
typedef void (APIENTRY * PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); PFNGLBUFFERDATAPROC glBufferData;
typedef void (APIENTRY * PFNGLCOMPILESHADERPROC) (GLuint shader); PFNGLCOMPILESHADERPROC glCompileShader;
typedef GLuint (APIENTRY * PFNGLCREATEPROGRAMPROC) (void); PFNGLCREATEPROGRAMPROC glCreateProgram;
typedef GLuint (APIENTRY * PFNGLCREATESHADERPROC) (GLenum type); PFNGLCREATESHADERPROC glCreateShader;
typedef void (APIENTRY * PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
typedef void (APIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); PFNGLGENBUFFERSPROC glGenBuffers;
typedef void (APIENTRY * PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
typedef GLint (APIENTRY * PFNGLGETUNIFORMLOCATIONPROC) (u32 program, const GLchar *name); PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
typedef void (APIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program); PFNGLLINKPROGRAMPROC glLinkProgram;
typedef void (APIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); PFNGLSHADERSOURCEPROC glShaderSource;
typedef void (APIENTRY * PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
typedef void (APIENTRY * PFNGLUSEPROGRAMPROC) (GLuint program); PFNGLUSEPROGRAMPROC glUseProgram;
typedef void (APIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
extern "C" {
//NOTE: Enables dedicated Nvidia GPU!!
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
struct Win32State {
u32 client_width;
u32 client_height;
u32 running;
u32 focus;
};
static Win32State global_win32_state;
HGLRC win32_create_gl_context(HWND window, HDC device_context) {
PIXELFORMATDESCRIPTOR pixel_format = {};
pixel_format.nSize = sizeof(pixel_format);
pixel_format.nVersion = 1;
pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pixel_format.iPixelType = PFD_TYPE_RGBA;
pixel_format.cColorBits = 32;
pixel_format.cDepthBits = 24;
pixel_format.cStencilBits = 8;
i32 pixel_format_index = ChoosePixelFormat(device_context, &pixel_format);
DescribePixelFormat(device_context, pixel_format_index, sizeof(pixel_format), &pixel_format);
SetPixelFormat(device_context, pixel_format_index, &pixel_format);
HGLRC gl_context = wglCreateContext(device_context);
if(wglMakeCurrent(device_context, gl_context)) {
glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress("glBindVertexArray");
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebuffer");
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress("glGenVertexArrays");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv");
glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if(wglSwapIntervalEXT) {
wglSwapIntervalEXT(1);
}
}
return gl_context;
}
LRESULT CALLBACK win32_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) {
LRESULT result = 0;
switch(message) {
case WM_CLOSE:
case WM_DESTROY: {
global_win32_state.running = false;
break;
}
case WM_ACTIVATEAPP: {
global_win32_state.focus = (w_param == 1);
break;
}
case WM_SIZE: {
global_win32_state.client_width = l_param & 0x0000FFFF;
global_win32_state.client_height = (l_param >> 16) & 0x0000FFFF;
break;
}
case WM_PAINT: {
PAINTSTRUCT paint;
HDC device_context = BeginPaint(window, &paint);
EndPaint(window, &paint);
break;
}
default: {
result = DefWindowProcA(window, message, w_param, l_param);
break;
}
}
return result;
}
int CALLBACK WinMain(HINSTANCE h_inst, HINSTANCE h_prev_inst, LPSTR cmd_line, int cmd_show) {
WNDCLASSA window_class = {};
window_class.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
window_class.lpfnWndProc = win32_proc;
window_class.hInstance = GetModuleHandleA(0);
window_class.hCursor = LoadCursorA(0, IDC_ARROW);
window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
window_class.lpszClassName = "Win32Class";
LARGE_INTEGER perf_freq;
QueryPerformanceFrequency(&perf_freq);
timeBeginPeriod(1);
LARGE_INTEGER begin_perf_count;
QueryPerformanceCounter(&begin_perf_count);
if(RegisterClassA(&window_class)) {
Win32State * win32_state = &global_win32_state;
// win32_state->client_width = 640, win32_state->client_height = 360;
// win32_state->client_width = 1280, win32_state->client_height = 720;
win32_state->client_width = 1920, win32_state->client_height = 1080;
u32 window_flags = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
RECT window_rect = {};
window_rect.left = 0;
window_rect.top = 0;
window_rect.right = win32_state->client_width;
window_rect.bottom = win32_state->client_height;
AdjustWindowRect(&window_rect, window_flags, false);
u32 window_width = (u32)(window_rect.right - window_rect.left);
u32 window_height = (u32)(window_rect.bottom - window_rect.top);
HWND window = CreateWindowExA(0, window_class.lpszClassName, "Win32Window", window_flags, window_rect.left + 1, 0, window_width, window_height, 0, 0, window_class.hInstance, 0);
HDC device_context = GetDC(window);
HGLRC gl_context = win32_create_gl_context(window, device_context);
char * gl_version = (char *)glGetString(GL_VERSION);
u32 vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
char * VS = "#version 330\nin vec3 i_position; uniform mat4 u_transform; void main() { gl_Position = u_transform * vec4(i_position, 1.0); }";
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &VS, 0);
glCompileShader(vs);
char * FS = "#version 330\nuniform vec4 u_base_color; out vec4 o_color; void main() { o_color = vec4(1.0); }";
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &FS, 0);
glCompileShader(fs);
u32 program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
u32 u_transform = glGetUniformLocation(program, "u_transform");
f32 quad[] = {
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 0.0f,
1.0f,-1.0f, 0.0f,
};
u32 v_buf;
glGenBuffers(1, &v_buf);
glBindBuffer(GL_ARRAY_BUFFER, v_buf);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
u32 frame_count = 0;
f32 time = 0.0f;
WINDOWPLACEMENT window_placement = { sizeof(window_placement) };
win32_state->running = true;
while(win32_state->running) {
MSG message;
while(PeekMessageA(&message, 0, 0, 0, PM_REMOVE)) {
switch(message.message) {
case WM_QUIT: {
win32_state->running = false;
break;
}
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP: {
u32 vk_code = (u32)message.wParam;
if(vk_code == VK_ESCAPE) {
win32_state->running = false;
}
u32 is_down = (message.lParam & (1 << 31)) == 0;
u32 alt = message.lParam & (1 << 29);
if(is_down && alt) {
if(vk_code == VK_F4) {
win32_state->running = false;
}
if(vk_code == VK_RETURN) {
DWORD style = GetWindowLong(window, GWL_STYLE);
if(style & WS_OVERLAPPEDWINDOW) {
MONITORINFO mi = { sizeof(mi) };
if(GetWindowPlacement(window, &window_placement) && GetMonitorInfo(MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY), &mi)) {
SetWindowLong(window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(window, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
else {
SetWindowLong(window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
SetWindowPlacement(window, &window_placement);
SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
}
break;
}
default: {
TranslateMessage(&message);
DispatchMessageA(&message);
break;
}
}
}
f32 clear_color = 0.0f;
// if(gfx_state->frame_count % 2 == 0) {
// clear_color = 1.0f;
// }
glClearColor(clear_color, clear_color, clear_color, 0.0f);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, win32_state->client_width, win32_state->client_height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, v_buf);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
f32 scale[3] = { 0.05f, 1.0f, 0.01f };
f32 transform[16] = {
scale[0], 0.0f, 0.0f, sin(time),
0.0f, scale[1], 0.0f, 0.0f,
0.0f, 0.0f, scale[2], 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
glUniformMatrix4fv(u_transform, 1, GL_TRUE, transform);
glDrawArrays(GL_TRIANGLES, 0, 6);
SwapBuffers(device_context);
LARGE_INTEGER end_perf_count;
QueryPerformanceCounter(&end_perf_count);
LONGLONG dt_i64 = ((end_perf_count.QuadPart - begin_perf_count.QuadPart) * 1000000) / perf_freq.QuadPart;
f32 dt = (f32)(dt_i64 / 1000000.0);
frame_count++;
time += dt;
begin_perf_count = end_perf_count;
char gl_str_buf[256];
sprintf(gl_str_buf, "OpenGL %s - %f", gl_version, dt);
SetWindowTextA(window, gl_str_buf);
}
wglMakeCurrent(0, 0);
wglDeleteContext(gl_context);
ReleaseDC(window, device_context);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment