bit engine
1#include "bite.h"
2
3#if defined(_WIN32)
4#include <windows.h>
5#ifndef WINDOWS_LEAN_AND_MEAN
6#define WINDOWS_LEAN_AND_MEAN 1
7#endif
8#include <gl/GL.h>
9#include <gl/GLU.h>
10#include <tchar.h>
11#elif defined(__EMSCRIPTEN__)
12#include <GLES2/gl2.h>
13#include <emscripten.h>
14#include <emscripten/html5.h>
15#include <time.h>
16#else
17#include <GL/gl.h>
18#include <GL/glx.h>
19#include <X11/Xlib.h>
20#include <X11/Xutil.h>
21#include <X11/XKBlib.h>
22#include <dlfcn.h>
23#include <time.h>
24#include <unistd.h>
25#endif
26
27#if defined(_WIN32)
28char keys[512] = {
29 [VK_BACK] = BITEK_BACKSPACE,
30 [VK_TAB] = BITEK_TAB,
31 [VK_RETURN] = BITEK_RETURN,
32 [VK_SHIFT] = BITEK_SHIFT,
33 [VK_CONTROL] = BITEK_CONTROL,
34
35 [VK_ESCAPE] = BITEK_ESCAPE,
36 [VK_SPACE] = BITEK_SPACE,
37 [VK_PRIOR] = BITEK_PAGEUP,
38 [VK_NEXT] = BITEK_PAGEDOWN,
39
40 [VK_LEFT] = BITEK_LEFT,
41 [VK_UP] = BITEK_UP,
42 [VK_RIGHT] = BITEK_RIGHT,
43 [VK_DOWN] = BITEK_DOWN,
44
45 [VK_END] = BITEK_END,
46 [VK_HOME] = BITEK_HOME,
47 [VK_INSERT] = BITEK_INSERT,
48 [VK_DELETE] = BITEK_DELETE,
49
50 [0x30] = BITEK_0,
51 [0x31] = BITEK_1,
52 [0x32] = BITEK_2,
53 [0x33] = BITEK_3,
54 [0x34] = BITEK_4,
55 [0x35] = BITEK_5,
56 [0x36] = BITEK_6,
57 [0x37] = BITEK_7,
58 [0x38] = BITEK_8,
59 [0x39] = BITEK_9,
60
61 [0x41] = BITEK_A,
62 [0x42] = BITEK_B,
63 [0x43] = BITEK_C,
64 [0x44] = BITEK_D,
65 [0x45] = BITEK_E,
66 [0x46] = BITEK_F,
67 [0x47] = BITEK_G,
68 [0x48] = BITEK_H,
69 [0x49] = BITEK_I,
70 [0x4A] = BITEK_J,
71 [0x4B] = BITEK_K,
72 [0x4C] = BITEK_L,
73 [0x4D] = BITEK_M,
74 [0x4E] = BITEK_N,
75 [0x4F] = BITEK_O,
76 [0x50] = BITEK_P,
77 [0x51] = BITEK_Q,
78 [0x52] = BITEK_R,
79 [0x53] = BITEK_S,
80 [0x54] = BITEK_T,
81 [0x55] = BITEK_U,
82 [0x56] = BITEK_V,
83 [0x57] = BITEK_W,
84 [0x58] = BITEK_X,
85 [0x59] = BITEK_Y,
86 [0x5A] = BITEK_Z,
87};
88#else
89char keys[] = {
90 [XK_BackSpace] = BITEK_BACKSPACE,
91 [XK_Tab] = BITEK_TAB,
92 [XK_Return] = BITEK_RETURN,
93 [XK_Escape] = BITEK_ESCAPE,
94 [XK_Delete] = BITEK_DELETE,
95 [XK_space] = BITEK_SPACE,
96 [XK_Alt_L] = BITEK_LALT,
97 [XK_Alt_R] = BITEK_RALT,
98 [XK_Shift_L] = BITEK_LSHIFT,
99 [XK_Shift_R] = BITEK_RSHIFT,
100 [XK_Control_L] = BITEK_LCONTROL,
101 [XK_Control_R] = BITEK_RCONTROL,
102 [XK_Super_L] = BITEK_LSUPER,
103 [XK_Super_R] = BITEK_RSUPER,
104
105 [XK_Left] = BITEK_LEFT,
106 [XK_Up] = BITEK_UP,
107 [XK_Right] = BITEK_RIGHT,
108 [XK_Down] = BITEK_DOWN,
109
110 [XK_Page_Up] = BITEK_PAGEUP,
111 [XK_Page_Down] = BITEK_PAGEDOWN,
112
113 [XK_End] = BITEK_END,
114 [XK_Home] = BITEK_HOME,
115
116 [XK_0] = BITEK_0,
117 [XK_1] = BITEK_1,
118 [XK_2] = BITEK_2,
119 [XK_3] = BITEK_3,
120 [XK_4] = BITEK_4,
121 [XK_5] = BITEK_5,
122 [XK_6] = BITEK_6,
123 [XK_7] = BITEK_7,
124 [XK_8] = BITEK_8,
125 [XK_9] = BITEK_9,
126
127 [XK_A] = BITEK_A,
128 [XK_B] = BITEK_B,
129 [XK_C] = BITEK_C,
130 [XK_D] = BITEK_D,
131 [XK_E] = BITEK_E,
132 [XK_F] = BITEK_F,
133 [XK_G] = BITEK_G,
134 [XK_H] = BITEK_H,
135 [XK_I] = BITEK_I,
136 [XK_J] = BITEK_J,
137 [XK_K] = BITEK_K,
138 [XK_L] = BITEK_L,
139 [XK_M] = BITEK_M,
140 [XK_N] = BITEK_N,
141 [XK_O] = BITEK_O,
142 [XK_P] = BITEK_P,
143 [XK_Q] = BITEK_Q,
144 [XK_R] = BITEK_R,
145 [XK_S] = BITEK_S,
146 [XK_T] = BITEK_T,
147 [XK_U] = BITEK_U,
148 [XK_V] = BITEK_V,
149 [XK_W] = BITEK_W,
150 [XK_X] = BITEK_X,
151 [XK_Y] = BITEK_Y,
152 [XK_Z] = BITEK_Z,
153
154 [XK_a] = BITEK_A,
155 [XK_b] = BITEK_B,
156 [XK_c] = BITEK_C,
157 [XK_d] = BITEK_D,
158 [XK_e] = BITEK_E,
159 [XK_f] = BITEK_F,
160 [XK_g] = BITEK_G,
161 [XK_h] = BITEK_H,
162 [XK_i] = BITEK_I,
163 [XK_j] = BITEK_J,
164 [XK_k] = BITEK_K,
165 [XK_l] = BITEK_L,
166 [XK_m] = BITEK_M,
167 [XK_n] = BITEK_N,
168 [XK_o] = BITEK_O,
169 [XK_p] = BITEK_P,
170 [XK_q] = BITEK_Q,
171 [XK_r] = BITEK_R,
172 [XK_s] = BITEK_S,
173 [XK_t] = BITEK_T,
174 [XK_u] = BITEK_U,
175 [XK_v] = BITEK_V,
176 [XK_w] = BITEK_W,
177 [XK_x] = BITEK_X,
178 [XK_y] = BITEK_Y,
179 [XK_z] = BITEK_Z,
180
181 [XK_KP_0] = BITEK_NUMPAD0,
182 [XK_KP_1] = BITEK_NUMPAD1,
183 [XK_KP_2] = BITEK_NUMPAD2,
184 [XK_KP_3] = BITEK_NUMPAD3,
185 [XK_KP_4] = BITEK_NUMPAD4,
186 [XK_KP_5] = BITEK_NUMPAD5,
187 [XK_KP_6] = BITEK_NUMPAD6,
188 [XK_KP_7] = BITEK_NUMPAD7,
189 [XK_KP_8] = BITEK_NUMPAD8,
190 [XK_KP_9] = BITEK_NUMPAD9,
191
192 [XK_F1] = BITEK_F1,
193 [XK_F2] = BITEK_F2,
194 [XK_F3] = BITEK_F3,
195 [XK_F4] = BITEK_F4,
196 [XK_F5] = BITEK_F5,
197 [XK_F6] = BITEK_F6,
198 [XK_F7] = BITEK_F7,
199 [XK_F8] = BITEK_F8,
200 [XK_F9] = BITEK_F9,
201 [XK_F10] = BITEK_F10,
202 [XK_F11] = BITEK_F11,
203 [XK_F12] = BITEK_F12,
204
205 [XK_minus] = BITEK_MINUS,
206 [XK_plus] = BITEK_PLUS,
207 [XK_less] = BITEK_LESS,
208 [XK_equal] = BITEK_EQUAL,
209 [XK_greater] = BITEK_GREATER,
210};
211#endif
212
213struct be_Shader {
214 GLuint handle;
215 GLint world_uniform, modelview_uniform;
216};
217
218struct be_Texture {
219 GLuint handle;
220 int width, height;
221 int filter[2];
222 int wrap[2];
223};
224
225struct be_Framebuffer {
226 GLuint handle;
227 be_Texture texture;
228};
229
230struct be_Window {
231 int x, y;
232 int width, height;
233#if defined(_WIN32)
234 HWND handle;
235 HDC dev_context;
236#elif defined(__EMSCRIPTEN__)
237#else
238 Display *display;
239 Window handle;
240 Colormap map;
241
242 GLXFBConfig fbconf;
243#endif
244};
245
246typedef struct be_Render be_Render;
247struct be_Render {
248#if defined(_WIN32)
249 HGLRC gl_context;
250#elif defined(__EMSCRIPTEN__)
251 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl_context;
252#else
253 GLXContext gl_context;
254#endif
255
256 int mode;
257 GLuint vao, vbo;
258};
259
260struct be_Context {
261 int running;
262 be_Window window;
263 be_Render render;
264 be_EventCallback callbacks[BITE_EVENTS];
265};
266
267static be_Context _context;
268
269static const be_Config _conf = {.window = {.title = "bitEngine " BITE_VERSION,
270 .width = 640,
271 .height = 380,
272 .flags = 0}};
273
274#if defined(_WIN32)
275typedef HGLRC WINAPI wglCreateContextAttribsARBProc(HDC hdc,
276 HGLRC hShareContext,
277 const int *attribList);
278wglCreateContextAttribsARBProc *wglCreateContextAttribsARB;
279#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
280#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
281#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
282#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
283#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
284
285typedef BOOL WINAPI wglChoosePixelFormatARBProc(
286 HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList,
287 UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
288wglChoosePixelFormatARBProc *wglChoosePixelFormatARB;
289
290// See
291// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt
292// for all values
293#define WGL_DRAW_TO_WINDOW_ARB 0x2001
294#define WGL_ACCELERATION_ARB 0x2003
295#define WGL_SUPPORT_OPENGL_ARB 0x2010
296#define WGL_DOUBLE_BUFFER_ARB 0x2011
297#define WGL_PIXEL_TYPE_ARB 0x2013
298#define WGL_COLOR_BITS_ARB 0x2014
299#define WGL_DEPTH_BITS_ARB 0x2022
300#define WGL_STENCIL_BITS_ARB 0x2023
301
302#define WGL_FULL_ACCELERATION_ARB 0x2027
303#define WGL_TYPE_RGBA_ARB 0x202B
304#elif defined(__EMSCRIPTEN__)
305#else
306typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig,
307 GLXContext, Bool,
308 const int *);
309#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
310#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
311#endif
312
313#define DEFINE_GL(ret, name, ...) \
314 typedef ret name##Proc(__VA_ARGS__); \
315 static name##Proc *name = 0
316
317#if !defined(__EMSCRIPTEN__)
318#define GL_VERSION 0x1F02
319#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
320
321/* data types */
322#define GL_BYTE 0x1400
323#define GL_UNSIGNED_BYTE 0x1401
324#define GL_SHORT 0x1402
325#define GL_UNSIGNED_SHORT 0x1403
326#define GL_INT 0x1404
327#define GL_UNSIGNED_INT 0x1405
328#define GL_FLOAT 0x1406
329#define GL_2_BYTES 0x1407
330#define GL_3_BYTES 0x1408
331#define GL_4_BYTES 0x1409
332#define GL_DOUBLE 0x140A
333
334/* Clear buffer bits */
335#define GL_DEPTH_BUFFER_BIT 0x00000100
336#define GL_ACCUM_BUFFER_BIT 0x00000200
337#define GL_STENCIL_BUFFER_BIT 0x00000400
338#define GL_COLOR_BUFFER_BIT 0x00004000
339
340#define GL_RGB 0x1907
341#define GL_RGBA 0x1908
342
343/* bgra */
344#define GL_BGR 0x80E0
345#define GL_BGRA 0x80E1
346
347/* Primitives */
348#define GL_POINTS 0x0000
349#define GL_LINES 0x0001
350#define GL_TRIANGLES 0x0004
351
352#define GL_ARRAY_BUFFER 0x8892
353#define GL_ELEMENT_ARRAY_BUFFER 0x8893
354
355#define GL_STREAM_DRAW 0x88E0
356#define GL_STREAM_READ 0x88E1
357#define GL_STREAM_COPY 0x88E2
358#define GL_STATIC_DRAW 0x88E4
359#define GL_STATIC_READ 0x88E5
360#define GL_STATIC_COPY 0x88E6
361#define GL_DYNAMIC_DRAW 0x88E8
362#define GL_DYNAMIC_READ 0x88E9
363#define GL_DYNAMIC_COPY 0x88EA
364
365#define GL_TEXTURE_2D 0x0DE1
366// #define GL_TEXTURE_MIN_FILTER 0x2800
367// #define GL_TEXTURE_MAG_FILTER 0x2801
368#define GL_TEXTURE_WRAP_S 0x2802
369#define GL_TEXTURE_WRAP_T 0x2803
370
371#define GL_NEAREST 0x2600
372#define GL_REPEAT 0x2901
373#define GL_CLAMP 0x2900
374
375#define GL_CLAMP_TO_EDGE 0x812F /* 1.2 */
376#define GL_CLAMP_TO_BORDER 0x812D /* 1.3 */
377
378// Core
379// DEFINE_GL(void, glClearColor, float, float, float, float);
380// DEFINE_GL(void, glClear, GLenum);
381
382// Transformation
383// DEFINE_GL(void, glViewport, GLint, GLint, GLint, GLint);
384
385// VAO
386DEFINE_GL(void, glGenVertexArrays, GLsizei, GLuint *); // glGenVertexArrays
387DEFINE_GL(void, glBindVertexArray, GLuint); // glBindVertexArray
388DEFINE_GL(void, glDeleteVertexArrays, GLsizei,
389 GLuint *); // glDeleteVertexArrays
390DEFINE_GL(void, glVertexAttribPointer, GLuint, GLint, GLuint, GLint, GLint,
391 const void *);
392DEFINE_GL(void, glEnableVertexAttribArray, GLuint);
393DEFINE_GL(void, glDisableVertexAttribArray, GLuint);
394
395// Buffers
396DEFINE_GL(void, glGenBuffers, GLsizei, GLuint *); // glGenBuffers
397DEFINE_GL(void, glBindBuffer, GLenum, GLuint); // glBindBuffer
398DEFINE_GL(void, glDeleteBuffers, GLsizei, GLuint *); // glDeleteBuffers
399DEFINE_GL(void, glBufferData, GLenum, GLsizei, const void *,
400 GLenum); // glBufferData(GLenum target, GLsizeptr size, const void*
401 // data, GLenum usage)
402DEFINE_GL(void, glBufferSubData, GLenum, GLsizei, GLsizei,
403 const void *); // glBufferSubData(GLenum target, GLintptr offset,
404 // GLsizeiptr, size, const void* data)
405
406// DEFINE_GL(void, glDrawArrays, GLenum, GLint, GLsizei); // glDrawArrays
407
408// SHADERS
409#define GL_FRAGMENT_SHADER 0x8B30
410#define GL_VERTEX_SHADER 0x8B31
411
412#define GL_COMPILE_STATUS 0x8B81
413#define GL_LINK_STATUS 0x8B82
414
415DEFINE_GL(GLuint, glCreateShader, GLenum); // glCreateShader
416DEFINE_GL(void, glShaderSource, GLuint, GLsizei, const char **,
417 const GLint *); // glShaderSource
418DEFINE_GL(void, glCompileShader, GLuint); // glCompileShader
419
420#define GL_LINK_STATUS 0x8B82
421DEFINE_GL(void, glGetShaderiv, GLuint, GLenum, GLint *); // glGetShaderiv
422const int t = GL_LINK_STATUS;
423DEFINE_GL(void, glGetShaderInfoLog, GLuint, GLsizei, GLsizei *,
424 char *); // glGetShaderInfoLog
425DEFINE_GL(void, glDeleteShader, GLuint); // glDeleteShader
426DEFINE_GL(GLuint, glCreateProgram, void); // glCreateProgram
427DEFINE_GL(void, glAttachShader, GLuint, GLuint); // glAttachShader
428DEFINE_GL(void, glLinkProgram, GLuint); // glLinkProgram
429DEFINE_GL(void, glGetProgramiv, GLuint, GLenum, GLint *); // glGetProgramiv
430DEFINE_GL(void, glGetProgramInfoLog, GLuint, GLsizei, GLsizei *,
431 char *); // glGetProgramInfoLog
432DEFINE_GL(void, glUseProgram, GLuint); // glUseProgram
433DEFINE_GL(void, glDeleteProgram, GLuint); // glUseProgram
434
435DEFINE_GL(void, glGetActiveUniform, GLuint, GLuint, GLint, GLint *, GLint *,
436 GLint *, char *);
437DEFINE_GL(GLint, glGetUniformLocation, GLuint, const char *);
438
439#define DEFINE_GL_UNIFORM(X, T) \
440 DEFINE_GL(void, glUniform1##X, GLuint, T); \
441 DEFINE_GL(void, glUniform2##X, GLint, T, T); \
442 DEFINE_GL(void, glUniform3##X, GLint, T, T, T); \
443 DEFINE_GL(void, glUniform4##X, GLint, T, T, T, T); \
444 DEFINE_GL(void, glUniform1##X##v, GLint, GLint, const T *); \
445 DEFINE_GL(void, glUniform2##X##v, GLint, GLint, const T *); \
446 DEFINE_GL(void, glUniform3##X##v, GLint, GLint, const T *); \
447 DEFINE_GL(void, glUniform4##X##v, GLint, GLint, const T *)
448
449// DEFINE_GL_UNIFORM(f, float);
450// DEFINE_GL_UNIFORM(i, GLint);
451
452DEFINE_GL(void, glUniformMatrix2fv, GLint, GLint, GLint, const float *);
453DEFINE_GL(void, glUniformMatrix3fv, GLint, GLint, GLint, const float *);
454DEFINE_GL(void, glUniformMatrix4fv, GLint, GLint, GLint, const float *);
455
456DEFINE_GL(GLint, glGetAttribLocation, GLuint, const char *);
457DEFINE_GL(void, glGetActiveAttribe, GLuint, GLuint, GLint, GLint *, GLint *,
458 GLuint *, char *);
459DEFINE_GL(void, glBindAttribLocation, GLuint, GLuint, const char *);
460
461#if defined(_WIN32)
462static HMODULE _gl_sym;
463#elif defined(__EMSCRIPTEN__)
464#else
465static void *_gl_sym;
466#ifndef RTLD_LAZY
467#define RTLD_LAZY 0x00001
468#endif
469#ifndef RTLD_GLOBAL
470#define RTLD_GLOBAL 0x00100
471#endif
472#endif
473
474static void *_get_proc(const char *name);
475BITE_RESULT _load_gl(void);
476void _setup_gl(void);
477void _close_gl(void);
478#endif
479
480BITE_RESULT _init_context(be_Context *ctx, const be_Config *conf);
481BITE_RESULT _init_window(be_Window *window, const be_Config *conf);
482BITE_RESULT _init_render(be_Render *render, const be_Window *window,
483 const be_Config *conf);
484void _poll_events(be_Context *ctx);
485
486#if defined(_WIN32)
487LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
488 be_Context *ctx = (be_Context *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
489 be_Event e;
490 e.type = 0;
491 be_EventCallback fn = NULL;
492 switch (msg) {
493 case WM_CREATE: return 0;
494 case WM_CLOSE: {
495 e.type = BITE_WINDOW_CLOSE;
496 } break;
497 case WM_DESTROY:
498 PostQuitMessage(0);
499 break;
500 case WM_SYSKEYDOWN:
501 case WM_KEYDOWN: {
502 e.type = BITE_KEY_PRESSED;
503 e.key.keycode = keys[(int)wParam];
504 } break;
505 case WM_SYSKEYUP:
506 case WM_KEYUP: {
507 e.type = BITE_KEY_RELEASED;
508 e.key.keycode = keys[(int)wParam];
509 printf("KeyPressed: %d\n", e.key.keycode);
510 } break;
511 default:
512 return DefWindowProc(hwnd, msg, wParam, lParam);
513 }
514
515 if (ctx)
516 fn = ctx->callbacks[e.type];
517 if (fn)
518 fn(ctx, &e);
519 printf("Teste\n");
520 return 0;
521}
522#endif
523
524void bite_simple_triangle(be_Context *ctx) {
525 glClearColor(0.3f, 0.4f, 0.4f, 1.f);
526 glClear(GL_COLOR_BUFFER_BIT);
527 // fprintf(stdout, "VAO: %d\n", ctx->render.vao);
528#if !defined(__EMSCRIPTEN__)
529 glBindVertexArray(ctx->render.vao);
530#else
531 glBindBuffer(GL_ARRAY_BUFFER, ctx->render.vbo);
532#endif
533 glDrawArrays(GL_TRIANGLES, 0, 3);
534#if !defined(__EMSCRIPTEN__)
535 glBindVertexArray(0);
536#else
537 glBindBuffer(GL_ARRAY_BUFFER, 0);
538#endif
539 // glBegin(GL_TRIANGLES);
540 // glColor3f(1.f, 0.f, 0.f);
541 // glVertex2f(0.f, 0.5f);
542 // glColor3f(0.f, 1.f, 0.f);
543 // glVertex2f(-0.5f, -0.5f);
544 // glColor3f(0.f, 0.f, 1.f);
545 // glVertex2f(0.5f, -0.5f);
546 // glEnd();
547}
548
549be_Config bite_init_config(const char *title, int w, int h) {
550 be_Config c = {0};
551 title = title != NULL ? title : "bitEngine " BITE_VERSION;
552 size_t len = strlen(title);
553 memcpy(c.window.title, title, len);
554 c.window.width = w;
555 c.window.height = h;
556 return c;
557}
558
559be_Context *bite_create(const be_Config *conf) {
560 conf = conf ? conf : &(_conf);
561 be_Context *ctx = malloc(sizeof(*ctx));
562 if (!ctx) {
563 fprintf(stderr, "Failed to alloc memory for context\n");
564 return NULL;
565 }
566 int mag, min;
567 // glGetIntegerv(GL_MAJOR_VERSION, &mag);
568 // glGetIntegerv(GL_MINOR_VERSION, &min);
569 // printf("OpenGL loaded: %d.%d\n", mag, min);
570 ctx->running = 1;
571 for (int i = 0; i < BITE_EVENTS; i++) {
572 ctx->callbacks[i] = NULL;
573 }
574 if (_init_context(ctx, conf) < 0) {
575 free(ctx);
576 return NULL;
577 }
578 const char *ver = (const char*)glGetString(GL_VERSION);
579 printf("OpenGL loaded: %s\n", ver);
580 return ctx;
581}
582
583void bite_destroy(be_Context *ctx) {
584 if (!ctx)
585 return;
586 be_Window *window = &(ctx->window);
587 be_Render *render = &(ctx->render);
588#if defined(_WIN32)
589 wglMakeCurrent(NULL, NULL);
590 wglDeleteContext(render->gl_context);
591 ReleaseDC(window->handle, window->dev_context);
592 DestroyWindow(window->handle);
593#elif defined(__EMSCRIPTEN__)
594 emscripten_webgl_destroy_context(render->gl_context);
595#else
596 glXDestroyContext(window->display, render->gl_context);
597 XDestroyWindow(window->display, window->handle);
598 XCloseDisplay(window->display);
599#endif
600 free(ctx);
601}
602
603void bite_register_callback(be_Context *ctx, int type,
604 be_EventCallback callback) {
605 if (!ctx)
606 return;
607 if (type < BITE_QUIT || type >= BITE_EVENTS)
608 return;
609 ctx->callbacks[type] = callback;
610}
611
612int bite_should_close(be_Context *ctx) {
613 if (!ctx)
614 return 1;
615 return !(ctx->running);
616}
617
618void bite_set_should_close(be_Context *ctx, int should_close) {
619 if (!ctx)
620 return;
621 ctx->running = !should_close;
622}
623
624void bite_poll_events(be_Context *ctx) {
625 if (!ctx)
626 return;
627 _poll_events(ctx);
628}
629
630void bite_swap(be_Context *ctx) {
631 if (!ctx)
632 return;
633 be_Window *window = &(ctx->window);
634#if defined(_WIN32)
635 SwapBuffers(window->dev_context);
636#elif defined(__EMSCRIPTEN__)
637 emscripten_webgl_commit_frame();
638#else
639 glXSwapBuffers(window->display, window->handle);
640#endif
641}
642
643/*********************
644 * Window
645 *********************/
646void bite_set_window_width(be_Context *ctx, int width) {}
647
648int bite_get_window_width(be_Context *ctx) {
649 if (!ctx)
650 return -1;
651 return ctx->window.width;
652}
653
654/*********************
655 * Render
656 *********************/
657
658static GLuint _compile_shader(GLenum type, const char *src) {
659 GLuint shader = glCreateShader(type);
660 glShaderSource(shader, 1, &src, NULL);
661 glCompileShader(shader);
662
663 int success;
664 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
665 if (!success) {
666 char info_log[512];
667 glGetShaderInfoLog(shader, 512, NULL, info_log);
668 fprintf(stderr, "Failed to compile shader: %s\n", info_log);
669 glDeleteShader(shader);
670 return 0;
671 }
672
673 return shader;
674}
675
676static GLuint _create_program(GLuint vert, GLuint frag) {
677#if 1
678 GLuint program = glCreateProgram();
679 glAttachShader(program, vert);
680 glAttachShader(program, frag);
681 glLinkProgram(program);
682
683 int success;
684 glGetProgramiv(program, GL_LINK_STATUS, &success);
685 if (!success) {
686 char info_log[512];
687 glGetProgramInfoLog(program, 512, NULL, info_log);
688 fprintf(stderr, "Failed to link program: %s\n", info_log);
689 glDeleteProgram(program);
690 return 0;
691 }
692
693 return program;
694#endif
695 return 0;
696}
697
698be_Texture *bite_create_texture(int width, int height, int format, void *data) {
699 be_Texture *texture = (be_Texture *)malloc(sizeof(*texture));
700 if (!texture) {
701 fprintf(stderr, "Failed to alloc memory for texture\n");
702 return NULL;
703 }
704 texture->filter[0] = GL_NEAREST;
705 texture->filter[1] = GL_NEAREST;
706 texture->wrap[0] = GL_CLAMP_TO_EDGE;
707 texture->wrap[1] = GL_CLAMP_TO_EDGE;
708 texture->width = width;
709 texture->height = height;
710
711 glGenTextures(1, &(texture->handle));
712 glBindTexture(GL_TEXTURE_2D, texture->handle);
713 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
714 GL_UNSIGNED_BYTE, data);
715
716 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture->filter[0]);
717 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture->filter[1]);
718 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture->wrap[0]);
719 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture->wrap[1]);
720 glBindTexture(GL_TEXTURE_2D, 0);
721 return texture;
722}
723
724be_Shader *bite_create_shader(const char *vert_src, const char *frag_src) {
725 be_Shader *shader = NULL;
726 GLuint vert, frag;
727 vert = _compile_shader(GL_VERTEX_SHADER, vert_src);
728 if (vert <= 0)
729 return shader;
730 frag = _compile_shader(GL_FRAGMENT_SHADER, frag_src);
731 if (frag <= 0)
732 return shader;
733
734 GLuint program = _create_program(vert, frag);
735 if (program <= 0)
736 return shader;
737 shader = malloc(sizeof(*shader));
738 shader->handle = program;
739
740 return shader;
741}
742
743void bite_render_clear_color(float r, float g, float b, float a) {
744 glClearColor(r, g, b, a);
745}
746
747void bite_render_clear(void) { glClear(GL_COLOR_BUFFER_BIT); }
748
749void bite_bind_framebuffer(be_Framebuffer *fbo) {
750#if 0
751 if (!fbo) glBindFramebuffer(GL_FRAMEBUFFER, 0);
752 else glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
753#endif
754}
755
756void bite_bind_texture(be_Texture *tex) {
757 if (!tex)
758 glBindTexture(GL_TEXTURE_2D, 0);
759 else
760 glBindTexture(GL_TEXTURE_2D, tex->handle);
761}
762
763void bite_use_shader(be_Shader *shader) {
764 if (!shader)
765 glUseProgram(0);
766 else
767 glUseProgram(shader->handle);
768}
769
770/*********************
771 * Timer
772 *********************/
773void bite_sleep(be_u64 ms) {
774#if defined(_WIN32)
775 Sleep(ms);
776#elif defined(__EMSCRIPTEN__)
777 emscripten_sleep((be_u32)ms);
778#else
779 sleep(ms / 1000);
780#endif
781}
782
783be_u64 bite_tick(void) {
784 be_u64 tick = 0;
785#if defined(_WIN32)
786 LARGE_INTEGER freq, count;
787 QueryPerformanceFrequency(&freq);
788 QueryPerformanceCounter(&count);
789 tick = (be_u64)(count.QuadPart * 1000.0 / freq.QuadPart);
790#else
791 struct timespec time;
792 clock_gettime(CLOCK_REALTIME, &time);
793 tick = time.tv_sec * 1000 + (time.tv_nsec / 1000000);
794#endif
795 return tick;
796}
797
798/*********************
799 * Internal
800 *********************/
801
802// static void init_opengl_extensions(be_Context* ctx);
803
804#if defined(_WIN32)
805static void init_opengl_extensions(void) {
806 WNDCLASSA window_class = {.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
807 .lpfnWndProc = DefWindowProcA,
808 .hInstance = GetModuleHandle(0),
809 .lpszClassName = "Dummy_WGL_window"};
810
811 if (!RegisterClassA(&window_class)) {
812 fprintf(stderr, "Failed to register dummy OpenGL window\n");
813 exit(EXIT_FAILURE);
814 }
815
816 HWND dummy_window =
817 CreateWindowExA(0, window_class.lpszClassName, "Dummy OpenGL Window", 0,
818 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
819 CW_USEDEFAULT, 0, 0, window_class.hInstance, 0);
820
821 if (!dummy_window) {
822 fprintf(stderr, "Failed to create dummy OpenGL window\n");
823 exit(EXIT_FAILURE);
824 }
825
826 HDC dummy_dc = GetDC(dummy_window);
827
828 PIXELFORMATDESCRIPTOR pfd = {.nSize = sizeof(pfd),
829 .nVersion = 1,
830 .iPixelType = PFD_TYPE_RGBA,
831 .dwFlags = PFD_DRAW_TO_WINDOW |
832 PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
833 .cColorBits = 32,
834 .cAlphaBits = 8,
835 .iLayerType = PFD_MAIN_PLANE,
836 .cDepthBits = 24,
837 .cStencilBits = 8};
838
839 int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
840 if (!pixel_format) {
841 fprintf(stderr, "Failed to find a suitable format\n");
842 exit(EXIT_FAILURE);
843 }
844 if (!SetPixelFormat(dummy_dc, pixel_format, &pfd)) {
845 fprintf(stderr, "Failed to set the pixel format\n");
846 exit(EXIT_FAILURE);
847 }
848
849 HGLRC dummy_context = wglCreateContext(dummy_dc);
850 if (!dummy_context) {
851 fprintf(stderr, "Failed to create dummy OpenGL context\n");
852 exit(EXIT_FAILURE);
853 }
854
855 if (!wglMakeCurrent(dummy_dc, dummy_context)) {
856 fprintf(stderr, "Failed to activate dummy OpenGL context\n");
857 exit(EXIT_FAILURE);
858 }
859 wglCreateContextAttribsARB =
860 (wglCreateContextAttribsARBProc *)wglGetProcAddress(
861 "wglCreateContextAttribsARB");
862 wglChoosePixelFormatARB = (wglChoosePixelFormatARBProc *)wglGetProcAddress(
863 "wglChoosePixelFormatARB");
864
865 printf("functions: %p %p\n", wglCreateContextAttribsARB,
866 wglChoosePixelFormatARB);
867
868 wglMakeCurrent(dummy_dc, 0);
869 wglDeleteContext(dummy_context);
870 ReleaseDC(dummy_window, dummy_dc);
871 DestroyWindow(dummy_window);
872}
873#else
874static BITE_BOOL is_extension_supported(const char *extList,
875 const char *extension) {
876 const char *start;
877 const char *where, *terminator;
878
879 /* Extension names should not have spaces. */
880 where = strchr(extension, ' ');
881 if (where || *extension == '\0')
882 return BITE_FALSE;
883
884 /* It takes a bit of care to be fool-proof about parsing the
885 OpenGL extensions string. Don't be fooled by sub-strings,
886 etc. */
887 for (start = extList;;) {
888 where = strstr(start, extension);
889
890 if (!where)
891 break;
892
893 terminator = where + strlen(extension);
894
895 if (where == start || *(where - 1) == ' ')
896 if (*terminator == ' ' || *terminator == '\0')
897 return BITE_TRUE;
898
899 start = terminator;
900 }
901 return BITE_FALSE;
902}
903#endif
904
905BITE_RESULT _init_context(be_Context *ctx, const be_Config *conf) {
906 if (_init_window(&(ctx->window), conf) != BITE_OK)
907 return BITE_ERROR;
908#if defined(_WIN32)
909 SetWindowLongPtr(ctx->window.handle, GWLP_USERDATA, (LONG_PTR)ctx);
910#endif
911 if (_init_render(&(ctx->render), &(ctx->window), conf) != BITE_OK)
912 return BITE_ERROR;
913 be_Render *render = &(ctx->render);
914
915 float vertices[] = {0.f, 0.5f, 1.f, 0.f, 0.f, 1.f, -0.5f, -0.5f, 0.f,
916 1.f, 0.f, 1.f, 0.5f, -0.5f, 0.f, 0.f, 1.f, 1.f};
917
918#if !defined(__EMSCRIPTEN__)
919 glGenVertexArrays(1, &(render->vao));
920 glBindVertexArray(render->vao);
921#endif
922 glGenBuffers(1, &(render->vbo));
923 glBindBuffer(GL_ARRAY_BUFFER, render->vbo);
924 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
925
926 glEnableVertexAttribArray(0);
927 glEnableVertexAttribArray(1);
928 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
929 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
930 (void *)(2 * sizeof(float)));
931 // glBindBuffer(GL_ARRAY_BUFFER, 0);
932#if !defined(__EMSCRIPTEN__)
933 glBindVertexArray(0);
934#endif
935 return BITE_OK;
936}
937
938BITE_RESULT _init_window(be_Window *window, const be_Config *conf) {
939#if defined(_WIN32)
940 HWND handle;
941 HMODULE hInstance = GetModuleHandle(0);
942
943 const TCHAR windowClass[] = _T("bitEngine");
944
945 WNDCLASSEX wc;
946 wc.cbSize = sizeof(WNDCLASSEX);
947 wc.style = CS_HREDRAW | CS_VREDRAW;
948 wc.lpfnWndProc = WindowProc;
949 wc.cbClsExtra = 0;
950 wc.cbWndExtra = 0;
951 wc.hInstance = hInstance;
952 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
953 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
954 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
955 wc.lpszMenuName = NULL;
956 wc.lpszClassName = windowClass;
957 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
958
959 if (!RegisterClassEx(&wc)) {
960 MessageBox(NULL, _T("Call to RegisterClassEx failed"), _T("bitEngine"),
961 NULL);
962 return BITE_ERROR;
963 }
964
965 handle = CreateWindow(windowClass, conf->window.title, WS_OVERLAPPEDWINDOW,
966 CW_USEDEFAULT, CW_USEDEFAULT, conf->window.width,
967 conf->window.height, NULL, NULL, hInstance, NULL);
968 if (!handle) {
969 MessageBox(NULL, _T("Class to CreateWindow failed"), _T("bitEngine"), NULL);
970 return BITE_ERROR;
971 }
972 window->handle = handle;
973 window->dev_context = GetDC(handle);
974
975 ShowWindow(handle, SW_SHOWDEFAULT);
976 UpdateWindow(handle);
977#elif (__EMSCRIPTEN__)
978#else
979 Display *dpy;
980 Window handle;
981 dpy = XOpenDisplay(NULL);
982 if (dpy == NULL) {
983 fprintf(stderr, "Could not open X11 display\n");
984 return BITE_ERROR;
985 }
986 int scrId = DefaultScreen(dpy);
987
988 static int visual_attribs[] = {
989 GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
990 GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
991 GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8,
992 GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_DOUBLEBUFFER, True,
993 // GLX_SAMPLE_BUFFERS , 1,
994 // GLX_SAMPLES , 4,
995 None};
996
997 GLint major, minor;
998 glXQueryVersion(dpy, &major, &minor);
999 if ((major == 1 && minor < 3) || (major < 1)) {
1000 fprintf(stderr, "Invalid GLX version\n");
1001 XCloseDisplay(dpy);
1002 return BITE_ERROR;
1003 }
1004
1005 int fbcount;
1006 GLXFBConfig *fbc = glXChooseFBConfig(dpy, scrId, visual_attribs, &fbcount);
1007 if (!fbc) {
1008 fprintf(stderr, "Failed to retrieve a framebuffer config\n");
1009 return BITE_ERROR;
1010 }
1011
1012 int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
1013
1014 int i;
1015 for (i = 0; i < fbcount; ++i) {
1016 XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, fbc[i]);
1017 if (vi) {
1018 int samp_buf, samples;
1019 glXGetFBConfigAttrib(dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
1020 glXGetFBConfigAttrib(dpy, fbc[i], GLX_SAMPLES, &samples);
1021
1022 // printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
1023 // " SAMPLES = %d\n",
1024 // i, vi -> visualid, samp_buf, samples );
1025
1026 if (best_fbc < 0 || samp_buf && samples > best_num_samp)
1027 best_fbc = i, best_num_samp = samples;
1028 if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp)
1029 worst_fbc = i, worst_num_samp = samples;
1030 }
1031 XFree(vi);
1032 }
1033 GLXFBConfig bestFbc = fbc[best_fbc];
1034 XFree(fbc);
1035
1036 XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, bestFbc);
1037 XSetWindowAttributes swa;
1038 Colormap map;
1039 swa.colormap =
1040 XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);
1041 swa.background_pixmap = None;
1042 swa.border_pixel = 0;
1043 swa.event_mask = ExposureMask | StructureNotifyMask;
1044
1045 handle =
1046 XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, conf->window.width,
1047 conf->window.height, 0, vi->depth, InputOutput, vi->visual,
1048 CWBorderPixel | CWColormap | CWEventMask, &swa);
1049
1050 if (!handle) {
1051 fprintf(stderr, "Failed to create X11 window\n");
1052 return BITE_ERROR;
1053 }
1054
1055 XFree(vi);
1056 XSelectInput(dpy, handle, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask);
1057 XClearWindow(dpy, handle);
1058 XStoreName(dpy, handle, conf->window.title);
1059 XMapWindow(dpy, handle);
1060
1061 window->handle = handle;
1062 window->display = dpy;
1063 window->map = swa.colormap;
1064 window->fbconf = bestFbc;
1065#endif
1066 window->width = conf->window.width;
1067 window->height = conf->window.height;
1068 return BITE_OK;
1069}
1070
1071BITE_RESULT _init_render(be_Render *render, const be_Window *window,
1072 const be_Config *conf) {
1073#if defined(_WIN32)
1074 init_opengl_extensions();
1075 HDC hdc = window->dev_context;
1076 int pixel_format_attribs[] = {WGL_DRAW_TO_WINDOW_ARB,
1077 GL_TRUE,
1078 WGL_SUPPORT_OPENGL_ARB,
1079 GL_TRUE,
1080 WGL_DOUBLE_BUFFER_ARB,
1081 GL_TRUE,
1082 WGL_ACCELERATION_ARB,
1083 WGL_FULL_ACCELERATION_ARB,
1084 WGL_PIXEL_TYPE_ARB,
1085 WGL_TYPE_RGBA_ARB,
1086 WGL_COLOR_BITS_ARB,
1087 32,
1088 WGL_DEPTH_BITS_ARB,
1089 24,
1090 WGL_STENCIL_BITS_ARB,
1091 8,
1092 0,
1093 0};
1094
1095 int pixel_format;
1096 UINT num_formats;
1097 wglChoosePixelFormatARB(hdc, pixel_format_attribs, 0, 1, &pixel_format,
1098 &num_formats);
1099 if (!num_formats) {
1100 MessageBox(NULL, _T("Failed to set Modern OpenGL pixel format"),
1101 _T("bitEngine"), NULL);
1102 DestroyWindow(window->handle);
1103 return BITE_ERROR;
1104 }
1105
1106 PIXELFORMATDESCRIPTOR pfd;
1107 DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd);
1108 if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
1109 MessageBox(NULL, _T("Failed to set Modern OpenGL pixel format\n"),
1110 _T("bitEngine"), NULL);
1111 DestroyWindow(window->handle);
1112 return BITE_ERROR;
1113 }
1114
1115 int gl_attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
1116 3,
1117 WGL_CONTEXT_MINOR_VERSION_ARB,
1118 0,
1119 WGL_CONTEXT_PROFILE_MASK_ARB,
1120 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
1121 0,
1122 0};
1123
1124 HGLRC hglrc = wglCreateContextAttribsARB(hdc, 0, gl_attribs);
1125 if (!hglrc) {
1126 MessageBox(NULL, _T("Failed to create Modern OpenGL context"),
1127 _T("bitEngine"), NULL);
1128 DestroyWindow(window->handle);
1129 return BITE_ERROR;
1130 }
1131 wglMakeCurrent(hdc, hglrc);
1132
1133 if (_load_gl() != BITE_OK) {
1134 MessageBox(NULL, _T("Failed to init OpenGL loader"), _T("bitEngine"), NULL);
1135 DestroyWindow(window->handle);
1136 return BITE_ERROR;
1137 }
1138 _setup_gl();
1139 _close_gl();
1140#elif defined(__EMSCRIPTEN__)
1141 EmscriptenWebGLContextAttributes attr;
1142 emscripten_webgl_init_context_attributes(&attr);
1143 attr.alpha = 0;
1144 render->gl_context = emscripten_webgl_create_context("#canvas", &attr);
1145 emscripten_webgl_make_context_current(render->gl_context);
1146#else
1147 Display *dpy = window->display;
1148 int scrId = DefaultScreen(dpy);
1149 const char *glxExts = glXQueryExtensionsString(dpy, scrId);
1150 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
1151 glXCreateContextAttribsARB =
1152 (glXCreateContextAttribsARBProc)glXGetProcAddressARB(
1153 (const GLubyte *)"glXCreateContextAttribsARB");
1154
1155 GLXContext ctx = 0;
1156
1157 if (!glXCreateContextAttribsARB) {
1158 fprintf(stderr, "Failed to load glXCreateContextAttribsARB(), loading "
1159 "legacy OpenGL context\n");
1160 ctx = glXCreateNewContext(dpy, window->fbconf, GLX_RGBA_TYPE, 0, True);
1161 } else {
1162 int context_attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB,
1163 2,
1164 GLX_CONTEXT_MINOR_VERSION_ARB,
1165 1,
1166 GLX_CONTEXT_PROFILE_MASK_ARB,
1167 GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
1168 None};
1169
1170 ctx = glXCreateContextAttribsARB(dpy, window->fbconf, 0, True,
1171 context_attribs);
1172 XSync(dpy, False);
1173 if (!ctx) {
1174 fprintf(stderr, "Failed to create 3.0 OpenGL context\n");
1175 XDestroyWindow(dpy, window->handle);
1176 XFreeColormap(dpy, window->map);
1177 XCloseDisplay(dpy);
1178 return BITE_ERROR;
1179 }
1180 glXMakeCurrent(dpy, window->handle, ctx);
1181 render->gl_context = ctx;
1182 if (_load_gl() != BITE_OK) {
1183 fprintf(stderr, "Failed to init OpenGL loader\n");
1184 XDestroyWindow(dpy, window->handle);
1185 XFreeColormap(dpy, window->map);
1186 XCloseDisplay(dpy);
1187 return BITE_ERROR;
1188 }
1189 _setup_gl();
1190 _close_gl();
1191 }
1192#endif
1193 return BITE_OK;
1194}
1195
1196#if 0
1197int _init_context(be_Context* ctx, const be_Config* conf) {
1198#if defined(_WIN32)
1199 HWND handle;
1200 HMODULE hInstance = GetModuleHandle(0);
1201
1202 const TCHAR windowClass[] = _T("bitEngine");
1203
1204 WNDCLASSEX wc;
1205 wc.cbSize = sizeof(WNDCLASSEX);
1206 wc.style = CS_HREDRAW | CS_VREDRAW;
1207 wc.lpfnWndProc = WindowProc;
1208 wc.cbClsExtra = 0;
1209 wc.cbWndExtra = 0;
1210 wc.hInstance = hInstance;
1211 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1212 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1213 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
1214 wc.lpszMenuName = NULL;
1215 wc.lpszClassName = windowClass;
1216 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
1217
1218 if (!RegisterClassEx(&wc)) {
1219 MessageBox(NULL,
1220 _T("Call to RegisterClassEx failed"),
1221 _T("bit Engine"),
1222 NULL);
1223 fprintf(stderr, "Error code: %d\n", GetLastError());
1224 return -1;
1225 }
1226
1227 handle = CreateWindow(
1228 windowClass,
1229 conf->window.title,
1230 WS_OVERLAPPEDWINDOW,
1231 CW_USEDEFAULT, CW_USEDEFAULT,
1232 conf->window.width, conf->window.height,
1233 NULL, NULL, hInstance, ctx
1234 );
1235 if (!handle) {
1236 MessageBox(NULL,
1237 _T("Call to CreateWindow failed"),
1238 _T("bit Engine"),
1239 NULL);
1240 fprintf(stderr, "Error code: %d\n", GetLastError());
1241 return -1;
1242 }
1243 SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)ctx);
1244
1245 HDC hdc = GetDC(handle);
1246
1247 init_opengl_extensions();
1248
1249 int pixel_format_attribs[] = {
1250 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
1251 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
1252 WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
1253 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
1254 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
1255 WGL_COLOR_BITS_ARB, 32,
1256 WGL_DEPTH_BITS_ARB, 24,
1257 WGL_STENCIL_BITS_ARB, 8,
1258 0
1259 };
1260
1261 int pixel_format;
1262 UINT num_formats;
1263 wglChoosePixelFormatARB(hdc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats);
1264 if (!num_formats) {
1265 fprintf(stderr, "Failed to set Modern OpenGL pixel format\n");
1266 DestroyWindow(handle);
1267 return -1;
1268 }
1269
1270 PIXELFORMATDESCRIPTOR pfd;
1271 DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd);
1272 if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
1273 fprintf(stderr, "Failed to set Modern OpenGL pixel format\n");
1274 DestroyWindow(handle);
1275 return -1;
1276 }
1277
1278 int gl_attribs[] = {
1279 WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
1280 WGL_CONTEXT_MINOR_VERSION_ARB, 1,
1281 WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1282 0
1283 };
1284
1285 HGLRC hglrc = wglCreateContextAttribsARB(hdc, 0, gl_attribs);
1286 if (!hglrc) {
1287 fprintf(stderr, "Failed to create Modern OpenGL context\n");
1288 DestroyWindow(handle);
1289 return -1;
1290 }
1291 wglMakeCurrent(hdc, hglrc);
1292
1293 // ctx = malloc(sizeof(*ctx));
1294 be_Window* window = &(ctx->window);
1295 window->handle = handle;
1296 window->dev_context = hdc;
1297
1298 ShowWindow(handle, SW_SHOWDEFAULT);
1299 UpdateWindow(handle);
1300#elif defined(__EMSCRIPTEN__)
1301 be_Window* window = &(ctx->window);
1302 EmscriptenWebGLContextAttributes attr;
1303 emscripten_webgl_init_context_attributes(&attr);
1304 attr.alpha = 0;
1305 ctx->window.handle = emscripten_webgl_create_context("#canvas", &attr);
1306 emscripten_webgl_make_context_current(window->handle);
1307#else
1308 Display* dpy;
1309 Window handle;
1310 Screen* scr;
1311 int scrId;
1312 dpy = XOpenDisplay(NULL);
1313 if (dpy == NULL) {
1314 fprintf(stderr, "Could not open X11 display\n");
1315 return -1;
1316 }
1317 scr = DefaultScreenOfDisplay(dpy);
1318 scrId = DefaultScreen(dpy);
1319
1320 GLint majorGLX, minorGLX;
1321 glXQueryVersion(dpy, &majorGLX, &minorGLX);
1322 if (majorGLX <= 1 && minorGLX < 2) {
1323 fprintf(stderr, "GLX 1.2 or greater is required\n");
1324 XCloseDisplay(dpy);
1325 return -1;
1326 } else {
1327 fprintf(stdout, "GLX version: %d.%d\n", majorGLX, minorGLX);
1328 }
1329
1330 GLint glxAttribs[] = {
1331 GLX_RGBA,
1332 GLX_DOUBLEBUFFER,
1333 GLX_DEPTH_SIZE, 24,
1334 GLX_STENCIL_SIZE, 8,
1335 GLX_RED_SIZE, 8,
1336 GLX_GREEN_SIZE, 8,
1337 GLX_BLUE_SIZE, 8,
1338 GLX_SAMPLE_BUFFERS, 0,
1339 GLX_SAMPLES, 0,
1340 None
1341 };
1342 XVisualInfo* visual = glXChooseVisual(dpy, scrId, glxAttribs);
1343 if (!visual) {
1344 fprintf(stderr, "Failed to create correct visual window\n");
1345 XCloseDisplay(dpy);
1346 return -1;
1347 }
1348
1349 XSetWindowAttributes windowAttribs;
1350 windowAttribs.border_pixel = BlackPixel(dpy, scrId);
1351 windowAttribs.background_pixel = WhitePixel(dpy, scrId);
1352 windowAttribs.override_redirect = 1;
1353 windowAttribs.colormap = XCreateColormap(dpy, RootWindow(dpy, scrId), visual->visual, AllocNone);
1354 windowAttribs.event_mask = ExposureMask;
1355
1356 handle = XCreateWindow(dpy, RootWindowOfScreen(scr), 0, 0, conf->window.width, conf->window.height, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &windowAttribs);
1357 if (!handle) {
1358 fprintf(stderr, "Failed to create X11 window\n");
1359 XCloseDisplay(dpy);
1360 return -1;
1361 }
1362 GLXContext context = glXCreateContext(dpy, visual, NULL, GL_TRUE);
1363 if (!context) {
1364 fprintf(stderr, "Failed to create GLX context\n");
1365 XDestroyWindow(dpy, handle);
1366 XCloseDisplay(dpy);
1367 return -1;
1368 }
1369 glXMakeCurrent(dpy, handle, context);
1370 be_Window* window = &(ctx->window);
1371 window->display = dpy;
1372 window->handle = handle;
1373 window->glContext = context;
1374 XSelectInput(dpy, handle, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask);
1375 XClearWindow(dpy, handle);
1376 XMapRaised(dpy, handle);
1377 XStoreName(dpy, handle, conf->window.title);
1378#endif
1379
1380 if (_init_gl(ctx) != BITE_OK) {
1381 fprintf(stderr, "Failed to init OpenGL loader\n");
1382 return NULL;
1383 }
1384 _setup_gl();
1385 _close_gl();
1386
1387
1388 ctx->window.width = conf->window.width;
1389 ctx->window.height = conf->window.height;
1390 return BITE_OK;
1391}
1392#endif
1393void _poll_events(be_Context *ctx) {
1394#if defined(_WIN32)
1395 MSG message;
1396 if (GetMessage(&message, NULL, 0, 0)) {
1397 TranslateMessage(&message);
1398 DispatchMessage(&message);
1399 }
1400#elif defined(__EMSCRIPTEN__)
1401#else
1402 XEvent ev;
1403 be_Window *window = &(ctx->window);
1404 while (XPending(window->display)) {
1405 XNextEvent(window->display, &ev);
1406 be_Event e = {0};
1407 be_EventCallback fn = NULL;
1408 switch (ev.type) {
1409 case ClientMessage: {
1410 if (ev.xclient.data.l[0] ==
1411 XInternAtom(window->display, "WM_DELETE_WINDOW", 0)) {
1412 e.type = BITE_WINDOW_CLOSE;
1413 }
1414 } break;
1415 case DestroyNotify: {
1416 e.type = BITE_QUIT;
1417 } break;
1418 case ConfigureNotify: {
1419 XConfigureEvent xce = ev.xconfigure;
1420 if ((xce.x != window->x) || (xce.y != window->y)) {
1421 window->x = xce.x;
1422 window->y = xce.y;
1423 e.type = BITE_WINDOW_MOVE;
1424 e.window.x = xce.x;
1425 e.window.y = xce.y;
1426 e.window.handle = window;
1427 }
1428 if ((xce.width != window->width) || (xce.height != window->height)) {
1429 window->width = xce.width;
1430 window->height = xce.height;
1431 e.type = BITE_WINDOW_RESIZE;
1432 e.window.x = xce.width;
1433 e.window.y = xce.height;
1434 e.window.handle = window;
1435 }
1436 } break;
1437 case KeyPress: {
1438 e.type = BITE_KEY_PRESSED;
1439 int code = ev.xkey.keycode;
1440 int keysym = XkbKeycodeToKeysym(
1441 ctx->window.display,
1442 ev.xkey.keycode,
1443 0,
1444 ev.xkey.state & ShiftMask ? 1 : 0
1445 );
1446 e.key.keycode = keys[keysym];
1447 printf("KeyPress: %d %d %d\n", keysym, ev.xkey.keycode, e.key.keycode);
1448 } break;
1449 case KeyRelease: {
1450 e.type = BITE_KEY_RELEASED;
1451 int keysym = XkbKeycodeToKeysym(
1452 ctx->window.display,
1453 ev.xkey.keycode,
1454 0,
1455 ev.xkey.state & ShiftMask ? 1 : 0
1456 );
1457 e.key.keycode = keys[keysym];
1458 } break;
1459 }
1460 fn = ctx->callbacks[e.type];
1461 if (fn)
1462 fn(ctx, &e);
1463 }
1464#endif
1465}
1466
1467// OpenGL loader
1468
1469#if !defined(__APPLE__) && !defined(__HAIKU__)
1470void *(*_proc_address)(const char *);
1471#endif
1472
1473#define GET_GL_PROC(name) name = (name##Proc *)_get_proc(#name)
1474
1475void *_get_proc(const char *);
1476
1477BITE_RESULT _load_gl(void) {
1478#if defined(_WIN32)
1479 _gl_sym = LoadLibrary("opengl32.dll");
1480 if (_gl_sym == NULL) {
1481 fprintf(stderr, "Failed to load OpenGL32.dll\n");
1482 return BITE_ERROR;
1483 }
1484 _proc_address =
1485 (void *(*)(const char *))GetProcAddress(_gl_sym, "wglGetProcAddress");
1486#elif defined(__EMSCRIPTEN__)
1487#else
1488#if defined(__APPLE__)
1489 const char *names[] = {
1490 "../Frameworks/OpenGL.framework/OpenGL",
1491 "/Library/Frameworks/OpenGL.framework/Opengl",
1492 "/System/Library/Frameworks/OpenGL.framework/OpenGL",
1493 "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL",
1494 NULL,
1495 };
1496#else
1497 const char *names[] = {
1498 "libGL.so.1",
1499 "libGL.so",
1500 NULL,
1501 };
1502#endif
1503 int index;
1504 for (index = 0; names[index] != NULL; ++index) {
1505 _gl_sym = dlopen(names[index], RTLD_LAZY | RTLD_GLOBAL);
1506 if (_gl_sym != NULL) {
1507#if defined(__APPLE__) || defined(__HAIKU__)
1508 return BITE_OK;
1509#else
1510 _proc_address =
1511 (void *(*)(const char *))dlsym(_gl_sym, "glXGetProcAddress");
1512 return _proc_address != NULL ? BITE_OK : BITE_ERROR;
1513#endif
1514 break;
1515 }
1516 }
1517#endif
1518 return BITE_OK;
1519}
1520
1521#if !defined(__EMSCRIPTEN__)
1522void _close_gl(void) {
1523 if (_gl_sym != NULL) {
1524#if defined(_WIN32)
1525 FreeLibrary(_gl_sym);
1526#else
1527 dlclose(_gl_sym);
1528#endif
1529 _gl_sym = NULL;
1530 }
1531}
1532
1533void _setup_gl(void) {
1534 const char *version = (const char*)glGetString(GL_VERSION);
1535 const char *glsl = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
1536 if (!version) {
1537 fprintf(stderr, "Failed to get OpenGL version\n");
1538 }
1539 const char *prefixes[] = {"OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ",
1540 NULL};
1541
1542 if (version) {
1543 const char *ver = version;
1544 for (int i = 0; prefixes[i] != NULL; i++) {
1545 if (strncmp(ver, prefixes[i], strlen(prefixes[i])) == 0) {
1546 ver += strlen(prefixes[i]);
1547 fprintf(stdout, "Using OpenGL ES\n");
1548 }
1549 }
1550 }
1551
1552 fprintf(stderr, "OpenGL: %s\n", version);
1553
1554 GET_GL_PROC(glGenVertexArrays);
1555 GET_GL_PROC(glBindVertexArray);
1556 GET_GL_PROC(glDeleteVertexArrays);
1557
1558 GET_GL_PROC(glVertexAttribPointer);
1559 GET_GL_PROC(glEnableVertexAttribArray);
1560 GET_GL_PROC(glDisableVertexAttribArray);
1561
1562 GET_GL_PROC(glGenBuffers);
1563 GET_GL_PROC(glBindBuffer);
1564 GET_GL_PROC(glDeleteBuffers);
1565 GET_GL_PROC(glBufferData);
1566 GET_GL_PROC(glBufferSubData);
1567
1568 GET_GL_PROC(glCreateShader);
1569 GET_GL_PROC(glShaderSource);
1570 GET_GL_PROC(glCompileShader);
1571 GET_GL_PROC(glGetShaderiv);
1572 GET_GL_PROC(glGetShaderInfoLog);
1573 GET_GL_PROC(glDeleteShader);
1574 GET_GL_PROC(glCreateProgram);
1575 GET_GL_PROC(glAttachShader);
1576 GET_GL_PROC(glLinkProgram);
1577 GET_GL_PROC(glGetProgramiv);
1578 GET_GL_PROC(glGetProgramInfoLog);
1579 GET_GL_PROC(glUseProgram);
1580 GET_GL_PROC(glDeleteProgram);
1581}
1582
1583static inline void *_get_proc(const char *name) {
1584 void *sym = NULL;
1585 if (_gl_sym == NULL)
1586 return sym;
1587#if !defined(__APPLE__) && !defined(__HAIKU__)
1588 if (_proc_address != NULL)
1589 sym = _proc_address(name);
1590#endif
1591 if (sym == NULL) {
1592#if defined(_WIN32) || defined(__CYGWWIN__)
1593 sym = (void *)GetProcAddress(_gl_sym, name);
1594#else
1595 sym = (void *)dlsym(_gl_sym, name);
1596#endif
1597 }
1598 fprintf(stderr, "%s: %p\n", name, sym);
1599 return sym;
1600}
1601#endif