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_input.h>
16#include <gf_log.h>
17#include <gf_draw.h>
18
19/* Standard */
20#include <string.h>
21#include <stdlib.h>
22
23#ifdef DO_SWAP_INTERVAL
24#ifndef GLX_MESA_swap_control
25#define GLX_MESA_swap_control 1
26typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
27typedef void (*PFNGLXSWAPINTERVALMESAPROC)(int);
28#endif
29
30#ifndef GLX_EXT_swap_control
31#define GLX_EXT_swap_control 1
32typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*, GLXDrawable, int);
33#endif
34
35#ifndef GLX_SGI_swap_control
36#define GLX_SGI_swap_control 1
37typedef void (*PFNGLXSWAPINTERVALSGIPROC)(int);
38#endif
39#endif
40
41void gf_draw_platform_begin(void) {}
42void gf_draw_platform_end(void) {}
43
44int gf_draw_platform_has_extension(gf_draw_t* draw, const char* query) {
45 const char* ext = NULL;
46 const char* ptr;
47 const int len = strlen(query);
48
49 glXMakeCurrent(draw->platform->display, draw->platform->window, draw->platform->context);
50
51 ext = glXQueryExtensionsString(draw->platform->display, DefaultScreen(draw->platform->display));
52 ptr = strstr(ext, query);
53 return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
54}
55
56gf_draw_platform_t* gf_draw_platform_create(gf_engine_t* engine, gf_draw_t* draw) {
57 int i = 0;
58 int attribs[64];
59 int screen;
60 Window root;
61 XVisualInfo* visual;
62 XSetWindowAttributes attr;
63 XSizeHints hints;
64 int interval = 0;
65 gf_draw_platform_t* platform = malloc(sizeof(*platform));
66 memset(platform, 0, sizeof(*platform));
67 platform->engine = engine;
68
69 platform->display = XOpenDisplay(NULL);
70 if(platform->display == NULL) {
71 gf_log_function(engine, "Failed to open display", "");
72 gf_draw_platform_destroy(platform);
73 return NULL;
74 }
75 attribs[i++] = GLX_RGBA;
76 attribs[i++] = GLX_DOUBLEBUFFER;
77
78 attribs[i++] = GLX_RED_SIZE;
79 attribs[i++] = 1;
80 attribs[i++] = GLX_GREEN_SIZE;
81 attribs[i++] = 1;
82 attribs[i++] = GLX_BLUE_SIZE;
83 attribs[i++] = 1;
84 attribs[i++] = GLX_DEPTH_SIZE;
85 attribs[i++] = 1;
86
87 attribs[i++] = None;
88
89 screen = DefaultScreen(platform->display);
90 root = RootWindow(platform->display, screen);
91
92 visual = glXChooseVisual(platform->display, screen, attribs);
93 if(visual == NULL) {
94 gf_log_function(engine, "Failed to get visual", "");
95 gf_draw_platform_destroy(platform);
96 return NULL;
97 }
98
99 attr.colormap = XCreateColormap(platform->display, root, visual->visual, AllocNone);
100 attr.event_mask = StructureNotifyMask | ExposureMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
101 platform->window = XCreateWindow(platform->display, root, draw->width, draw->height, draw->width, draw->height, 0, visual->depth, InputOutput, visual->visual, CWColormap | CWEventMask, &attr);
102
103 hints.x = draw->x;
104 hints.y = draw->y;
105 hints.width = draw->width;
106 hints.height = draw->height;
107 hints.flags = USSize | USPosition;
108 XSetNormalHints(platform->display, platform->window, &hints);
109 XSetStandardProperties(platform->display, platform->window, draw->title, "GoldFish", None, (char**)NULL, 0, &hints);
110
111 platform->wm_delete_window = XInternAtom(platform->display, "WM_DELETE_WINDOW", False);
112 XSetWMProtocols(platform->display, platform->window, &platform->wm_delete_window, 1);
113
114 platform->context = glXCreateContext(platform->display, visual, NULL, True);
115 if(platform->context == NULL) {
116 XFree(visual);
117 gf_log_function(engine, "Failed to get OpenGL context", "");
118 gf_draw_platform_destroy(platform);
119 return NULL;
120 }
121
122 XFree(visual);
123
124 XMapWindow(platform->display, platform->window);
125 glXMakeCurrent(platform->display, platform->window, platform->context);
126
127#ifdef DO_SWAP_INTERVAL
128 if(gf_draw_platform_has_extension(draw, "GLX_EXT_swap_control")) {
129 unsigned int tmp = -1;
130 PFNGLXSWAPINTERVALEXTPROC proc = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB("glXSwapIntervalEXT");
131 if(proc != NULL) {
132 proc(platform->display, platform->window, 1);
133 }
134 glXQueryDrawable(platform->display, platform->window, GLX_SWAP_INTERVAL_EXT, &tmp);
135 interval = tmp;
136 } else if(gf_draw_platform_has_extension(draw, "GLX_MESA_swap_control")) {
137 PFNGLXGETSWAPINTERVALMESAPROC proc = (PFNGLXGETSWAPINTERVALMESAPROC)glXGetProcAddressARB("glXGetSwapIntervalMESA");
138 PFNGLXSWAPINTERVALMESAPROC proc2 = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddressARB("glXSwapIntervalMESA");
139 if(proc2 != NULL) {
140 proc2(1);
141 }
142 interval = proc();
143 } else if(gf_draw_platform_has_extension(draw, "GLX_SGI_swap_control")) {
144 PFNGLXSWAPINTERVALSGIPROC proc = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB("glXSwapIntervalSGI");
145 proc(1);
146 interval = 1;
147 }
148 if(interval > 0) {
149 gf_log_function(engine, "Enabled VSync", "");
150 }
151#endif
152 return platform;
153}
154
155int gf_draw_platform_step(gf_draw_t* draw) {
156 int ret = 0;
157 glXMakeCurrent(draw->platform->display, draw->platform->window, draw->platform->context);
158 while(XPending(draw->platform->display) > 0) {
159 XEvent event;
160 XNextEvent(draw->platform->display, &event);
161 if(event.type == Expose) {
162 break;
163 } else if(event.type == MotionNotify) {
164 if(draw->input != NULL) {
165 draw->input->mouse_x = event.xmotion.x;
166 draw->input->mouse_y = event.xmotion.y;
167 }
168 } else if(event.type == ConfigureNotify) {
169 draw->x = event.xconfigure.x;
170 draw->y = event.xconfigure.y;
171 draw->width = event.xconfigure.width;
172 draw->height = event.xconfigure.height;
173 glXMakeCurrent(draw->platform->display, draw->platform->window, draw->platform->context);
174 gf_draw_reshape(draw);
175 } else if(event.type == ButtonPress) {
176 if(draw->input != NULL) {
177 if(event.xbutton.button == Button1) draw->input->mouse_flag |= GF_INPUT_MOUSE_LEFT_MASK;
178 if(event.xbutton.button == Button2) draw->input->mouse_flag |= GF_INPUT_MOUSE_MIDDLE_MASK;
179 if(event.xbutton.button == Button3) draw->input->mouse_flag |= GF_INPUT_MOUSE_RIGHT_MASK;
180 }
181 } else if(event.type == ButtonRelease) {
182 if(draw->input != NULL) {
183 if(event.xbutton.button == Button1) draw->input->mouse_flag ^= GF_INPUT_MOUSE_LEFT_MASK;
184 if(event.xbutton.button == Button2) draw->input->mouse_flag ^= GF_INPUT_MOUSE_MIDDLE_MASK;
185 if(event.xbutton.button == Button3) draw->input->mouse_flag ^= GF_INPUT_MOUSE_RIGHT_MASK;
186 }
187 } else if(event.type == ClientMessage) {
188 if(event.xclient.data.l[0] == draw->platform->wm_delete_window) {
189 draw->close = 1;
190 break;
191 }
192 }
193 }
194 if(ret == 0) {
195 gf_draw_driver_before(draw);
196 gf_draw_frame(draw);
197 gf_draw_driver_after(draw);
198
199 glXSwapBuffers(draw->platform->display, draw->platform->window);
200 }
201 return ret;
202}
203
204void gf_draw_platform_destroy(gf_draw_platform_t* platform) {
205 if(platform->context != NULL) {
206 glXMakeCurrent(platform->display, None, NULL);
207 glXDestroyContext(platform->display, platform->context);
208 }
209 if(platform->display != NULL) {
210 XDestroyWindow(platform->display, platform->window);
211 XCloseDisplay(platform->display);
212 }
213 gf_log_function(platform->engine, "Destroyed platform-dependent part of drawing driver", "");
214 free(platform);
215}
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.
#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