-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
232 lines (188 loc) · 7.49 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN // the purposes of these defines is to reduce unnecessary includes via windows.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <windows.h>
#include <windowsx.h>
#include <gl/glew.h> // used to load function pointers for OpenGL.
#include <gl/wglew.h> // used for creating the modern OpenGL context.
#include "include/shader.h"
const int width = 1600;
const int height = 1200;
bool running = true;
HDC dc; // This tracks the "device context", a handle to the window.
HGLRC rc; // Represents a handle to a OpenGL context (rendering context, not the same as device context).
LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL createGLContext(HWND hwnd);
HWND createWindow(HINSTANCE instance, const wchar_t className[], int width, int height);
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nShowCmd) {
WNDCLASS wc = {0};
const wchar_t className[] = L"App Class";
wc.lpfnWndProc = windowProc;
wc.hInstance = hInstance;
wc.lpszClassName = className;
wc.hCursor = LoadCursor(0, IDC_ARROW);
if (!RegisterClass(&wc)) { // every windows window has to be associated with a window class.
MessageBoxA(0, "Failed to register class", "ERROR", 0);
return GetLastError();
}
HWND hwnd = createWindow(hInstance, className, width, height);
if (hwnd == NULL) {
MessageBoxA(0, "Failed to open window", "ERROR", 0);
return GetLastError();
}
ShowWindow(hwnd, nShowCmd);
SpirvData vertexShaderData = {0};
SpirvData fragmentShaderData = {0};
Shader shader;
if (!readBinaryFileIntoSpirvData("spirv/triangle_shader.vert.spv", &vertexShaderData)) {
MessageBoxA(0, "Unable to read vertex shader from file", "ERROR", 0);
return -1;
}
if (!readBinaryFileIntoSpirvData("spirv/triangle_shader.frag.spv", &fragmentShaderData)) {
MessageBoxA(0, "Unable to read fragment shader from file", "ERROR", 0);
return -1;
}
if (!compileShaders(&shader, &vertexShaderData, &fragmentShaderData)) {
MessageBoxA(0, "Unable to construct shader program", "ERROR", 0);
return -1;
}
float vertices[] = {
// x y z r g b
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
unsigned int vbo, vao;
glCreateVertexArrays(1, &vao);
glCreateBuffers(1, &vbo);
glNamedBufferStorage(vbo, sizeof(vertices), vertices, GL_DYNAMIC_STORAGE_BIT);
glVertexArrayVertexBuffer(vao, 0, vbo, 0, 6 * sizeof(float));
glEnableVertexArrayAttrib(vao, 0);
glEnableVertexArrayAttrib(vao, 1);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, false, 0);
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, false, 3 * sizeof(float));
glVertexArrayAttribBinding(vao, 0, 0);
glVertexArrayAttribBinding(vao, 1, 0);
while (running) {
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
running = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glClearColor(0.92f, 0.58f, 0.39f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader.program);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
SwapBuffers(dc);
}
return 0;
}
BOOL createGLContext(HWND hwnd) {
// if you are curious about these values "mean", they come from here:
// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setpixelformat
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // 32-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
16, // 16-bit stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
dc = GetDC(hwnd);
if (dc == NULL) return false;
int pf = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, pf, &pfd);
HGLRC tempContext = wglCreateContext(dc); // temp context which is needed to connect to OpenGL 3.2+ versions
wglMakeCurrent(dc, tempContext); // temp as well so we can call ->wgl<-createcontext...
GLenum err = glewInit();
if (GLEW_OK != err) {
return false;
}
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB,
4,
WGL_CONTEXT_MINOR_VERSION_ARB,
6,
WGL_CONTEXT_PROFILE_MASK_ARB,
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0,
0
};
rc = wglCreateContextAttribsARB(dc, 0, attribs); // it is at this call you need to have a placeholder context created.
wglMakeCurrent(NULL, NULL); // we can have a modern context, forget this one.
wglDeleteContext(tempContext);
if (!wglMakeCurrent(dc, rc)) return false;
int numExt = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
for (int i = 0; i < numExt; i++)
if (!strcmp((char*)glGetStringi(GL_EXTENSIONS, i), "GL_ARB_compatibility")) {
MessageBoxA(0, "If this prints ITS COMPATABILITY, NOT WANTED!", "INCORRECT PROFILE", 0);
return false;
}
glViewport(0, 0, width, height); // this fine to call here or before the message loop in main, it does not matter.
//MessageBoxA(0, (char*)glGetString(GL_VERSION), "OPENGL VERSION", 0); // optional to see the version retrieved
return true;
}
HWND createWindow(HINSTANCE instance, const wchar_t className[], int width, int height) {
HWND hwnd = CreateWindowEx(
0,
className,
L"App",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
0,
0,
instance,
0);
if (!hwnd) {
return NULL;
}
return hwnd;
}
LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_ACTIVATE: { // when the window is actived, create the context.
if (!createGLContext(hwnd)) {
MessageBoxA(hwnd, L"Failed to initialize OpenGL context", L"ERROR", 0);
PostQuitMessage(0);
}
}
case WM_CHAR: {
if (GetAsyncKeyState('Q')) { // destroy the context and close the window when the user presses 'Q'.
ReleaseDC(hwnd, dc);
wglDeleteContext(rc);
PostQuitMessage(0);
}
} break;
case WM_DESTROY: {
ReleaseDC(hwnd, dc);
wglDeleteContext(rc);
PostQuitMessage(0);
} break;
default: {
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
return 0;
}