GoldFish Engine
Quite simple and lightweight game engine
Loading...
Searching...
No Matches
gf_draw.c
1#define GF_EXPOSE_DRAW_PLATFORM
2#define GF_EXPOSE_DRAW
3
4#include <gf_pre.h>
5
6/* External library */
7#include <gf_opengl.h>
8
9/* Interface */
10#include <gf_draw_platform.h>
11
12/* Engine */
13#include <gf_draw_driver.h>
14#include <gf_log.h>
15#include <gf_draw.h>
16
17/* Standard */
18#include <string.h>
19#include <stdlib.h>
20
21typedef const char*(APIENTRY* PFNWGLGETEXTENSIONSSTRINGARB)(HDC);
22#ifdef DO_SWAP_INTERVAL
23typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALPROC)(int);
24#endif
25
26void gf_draw_platform_begin(void) {}
27void gf_draw_platform_end(void) {}
28
29LRESULT CALLBACK gf_draw_platform_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
30 PAINTSTRUCT ps;
31 RECT rect;
32 gf_draw_t* draw = (gf_draw_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
33 switch(msg) {
34 case WM_PAINT:
35 BeginPaint(hWnd, &ps);
36 EndPaint(hWnd, &ps);
37 break;
38 case WM_SIZE:
39 if(draw->platform != NULL) {
40 GetClientRect(hWnd, &rect);
41 draw->x = rect.left;
42 draw->y = rect.top;
43 draw->width = rect.right - rect.left;
44 draw->height = rect.bottom - rect.top;
45 wglMakeCurrent(draw->platform->dc, draw->platform->glrc);
46 gf_draw_reshape(draw);
47 }
48 break;
49 case WM_CLOSE:
50 draw->close = 1;
51 break;
52 case WM_DESTROY:
53 PostQuitMessage(0);
54 break;
55 default:
56 return DefWindowProc(hWnd, msg, wp, lp);
57 }
58 return 0;
59}
60
61int gf_draw_platform_has_extension(gf_draw_t* draw, const char* query) {
62 const char* ext = NULL;
63 const char* ptr;
64 const int len = strlen(query);
65 PFNWGLGETEXTENSIONSSTRINGARB proc;
66
67 wglMakeCurrent(draw->platform->dc, draw->platform->glrc);
68
69 proc = (PFNWGLGETEXTENSIONSSTRINGARB)wglGetProcAddress("wglGetExtensionsStringARB");
70
71 if(proc != NULL) {
72 ext = proc(draw->platform->dc);
73 ptr = strstr(ext, query);
74 return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
75 }
76 return 0;
77}
78
79int gf_draw_platform_step(gf_draw_t* draw) {
80 MSG msg;
81 int ret = 0;
82 wglMakeCurrent(draw->platform->dc, draw->platform->glrc);
83 while(PeekMessage(&msg, draw->platform->window, 0, 0, PM_NOREMOVE)) {
84 if(GetMessage(&msg, draw->platform->window, 0, 0)) {
85 TranslateMessage(&msg);
86 DispatchMessage(&msg);
87 } else {
88 ret = 1;
89 break;
90 }
91 }
92 if(ret == 0) {
93 gf_draw_driver_before(draw);
94 gf_draw_frame(draw);
95 gf_draw_driver_after(draw);
96
97 SwapBuffers(draw->platform->dc);
98 }
99 return ret;
100}
101
102gf_draw_platform_t* gf_draw_platform_create(gf_engine_t* engine, gf_draw_t* draw) {
103 WNDCLASSEX wc;
104 PIXELFORMATDESCRIPTOR desc;
105#ifdef DO_SWAP_INTERVAL
106 PFNWGLSWAPINTERVALPROC wglSwapIntervalEXT;
107#endif
108 RECT rect;
109 int fmt;
110 DWORD style;
111 gf_draw_platform_t* platform = malloc(sizeof(*platform));
112 memset(platform, 0, sizeof(*platform));
113 platform->engine = engine;
114
115 platform->instance = (HINSTANCE)GetModuleHandle(NULL);
116 if(platform->instance == NULL) {
117 gf_log_function(engine, "Failed to get instance", "");
118 gf_draw_platform_destroy(platform);
119 return NULL;
120 }
121
122 wc.cbSize = sizeof(wc);
123 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
124 wc.lpfnWndProc = gf_draw_platform_proc;
125 wc.cbClsExtra = 0;
126 wc.cbWndExtra = 0;
127 wc.hInstance = platform->instance;
128 wc.hIcon = LoadIcon(platform->instance, "GAME");
129 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
130 wc.hbrBackground = NULL;
131 wc.lpszMenuName = NULL;
132 wc.lpszClassName = "goldfish";
133 wc.hIconSm = LoadIcon(platform->instance, "GAME");
134 if(!RegisterClassEx(&wc)) {
135 gf_log_function(engine, "Failed to register class", "");
136 gf_draw_platform_destroy(platform);
137 return NULL;
138 }
139
140 platform->window = CreateWindow("goldfish", draw->title, (WS_OVERLAPPEDWINDOW), draw->x, draw->y, draw->width, draw->height, NULL, 0, platform->instance, NULL);
141 if(platform->window == NULL) {
142 gf_log_function(engine, "Failed to create window", "");
143 gf_draw_platform_destroy(platform);
144 return NULL;
145 }
146
147 SetWindowLongPtr(platform->window, GWLP_USERDATA, (LONG_PTR)draw);
148
149 memset(&desc, 0, sizeof(desc));
150 desc.nSize = sizeof(desc);
151 desc.nVersion = 1;
152 desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
153 desc.iPixelType = PFD_TYPE_RGBA;
154 desc.cColorBits = 24;
155 desc.cAlphaBits = 8;
156 desc.cDepthBits = 32;
157
158 platform->dc = GetDC(platform->window);
159
160 fmt = ChoosePixelFormat(platform->dc, &desc);
161 SetPixelFormat(platform->dc, fmt, &desc);
162
163 platform->glrc = wglCreateContext(platform->dc);
164 if(platform->glrc == NULL) {
165 gf_log_function(engine, "Failed to create OpenGL context", "");
166 gf_draw_platform_destroy(platform);
167 return NULL;
168 }
169 wglMakeCurrent(platform->dc, platform->glrc);
170
171#ifdef DO_SWAP_INTERVAL
172 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALPROC)wglGetProcAddress("wglSwapIntervalEXT");
173 if(wglSwapIntervalEXT != NULL) {
174 gf_log_function(engine, "Enabled VSync", "");
175 wglSwapIntervalEXT(1);
176 }
177#endif
178
179 SetRect(&rect, 0, 0, draw->width, draw->height);
180 style = (DWORD)GetWindowLongPtr(platform->window, GWL_STYLE);
181 AdjustWindowRect(&rect, style, FALSE);
182 SetWindowPos(platform->window, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE);
183
184 ShowWindow(platform->window, SW_NORMAL);
185 UpdateWindow(platform->window);
186
187 return platform;
188}
189
190void gf_draw_platform_destroy(gf_draw_platform_t* platform) {
191 if(platform->glrc != NULL) {
192 wglMakeCurrent(NULL, NULL);
193 }
194 if(platform->dc != NULL) {
195 ReleaseDC(platform->window, platform->dc);
196 }
197 if(platform->glrc != NULL) {
198 wglDeleteContext(platform->glrc);
199 }
200 if(platform->window != NULL) {
201 DestroyWindow(platform->window);
202 }
203 gf_log_function(platform->engine, "Destroyed platform-dependent part of drawing driver", "");
204 free(platform);
205}
Drawing interface.
Drawing driver.
Platform-dependent part of drawing driver.
Logger.
#define gf_log_function(engine, fmt,...)
Output log with line number and function name.
Definition gf_log.h:26
OpenGL headers.
Required headers before anything.
Platform-dependent part of drawing driver.
Drawing interface.
Definition draw.h:101
int y
Y coord of window.
Definition draw.h:101
char title[128]
Window title.
Definition draw.h:101
int close
1 if it was requested to be closed, otherwise 0
Definition draw.h:101
gf_draw_platform_t * platform
Platform-dependent part of drawing driver.
Definition draw.h:101
int x
X coord of window.
Definition draw.h:101
int width
Width of window.
Definition draw.h:101
int height
Height of window.
Definition draw.h:101
Engine instance.
Definition core.h:44