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