Created
August 19, 2016 22:10
Star
You must be signed in to star a gist
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
//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