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