In order to get OpenGL support these libraries often use libEGL, so I implemented that first.
This also allows us to use platform-independent code for creating an OpenGL context.
Here is an example program that uses libEGL. It works on both KOS and Linux.
Code: Select all
#include <stdio.h>
#include <string.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#define CLEANUP(n) { ret = (n); goto cleanup; }
static EGLint const gl_config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 0,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};
static int init_egl(EGLDisplay * dest_egl_display, EGLSurface * dest_egl_surface, EGLNativeDisplayType display, EGLNativeWindowType surface) {
int ret = 0;
EGLConfig egl_config;
EGLContext egl_context;
EGLDisplay egl_display;
EGLSurface egl_surface;
EGLint n;
egl_display = eglGetDisplay(display);
if(egl_display == EGL_NO_DISPLAY) {
CLEANUP(1);
}
if(!eglInitialize(egl_display, 0, 0)) {
CLEANUP(2);
}
/* Advertised on Dreamcast, may also be used on Linux without X11/Wayland
if(!strstr(eglQueryString(egl_display, EGL_EXTENSIONS), "EGL_KHR_surfaceless_opengl")) {
CLEANUP(3);
}
*/
printf("EGL Version \"%s\"\n", eglQueryString(egl_display, EGL_VERSION));
printf("EGL Vendor \"%s\"\n", eglQueryString(egl_display, EGL_VENDOR));
printf("EGL Extensions \"%s\"\n", eglQueryString(egl_display, EGL_EXTENSIONS));
if(!eglBindAPI(EGL_OPENGL_API)) {
CLEANUP(4);
}
if(!eglChooseConfig(egl_display, gl_config_attribs, &egl_config, 1, &n) || n != 1) {
CLEANUP(5);
}
egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, 0);
if(!egl_context) {
CLEANUP(6);
}
egl_surface = eglCreateWindowSurface(egl_display, egl_config, surface, 0);
if(egl_surface == EGL_NO_SURFACE) {
CLEANUP(7);
}
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
eglSwapBuffers(egl_display, egl_surface);
*dest_egl_display = egl_display;
*dest_egl_surface = egl_surface;
cleanup:
return ret;
}
int main(int argc, char ** argv) {
EGLDisplay egl_display;
EGLSurface egl_surface;
int ret = init_egl(&egl_display, &egl_surface, EGL_DEFAULT_DISPLAY, 0);
if(ret) {
printf("Cannot init EGL, error %u, egl error %0x\n", ret, (unsigned)eglGetError());
return 1;
}
for(;;) {
glClearColor(1.f, 1.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(egl_display, egl_surface);
}
return 0;
}
But because OpenGL needs to swap buffers somehow and we don't have a graphics driver that supports a framebuffer etc. and I don't want to complicate things, I suggest we add a non-standard function glSwapBuffersKOS instead (just a rename of glutSwapBuffers in libGL). Then libEGL can call libGL's glSwapBuffersKOS.
The current example code with glutSwapBuffers is non-standard glut, it doesn't even have a main loop, doesn't use glut for input processing, etc. so I think for porting glut code to Dreamcast it's kind of useless and should be rewritten to use glSwapBuffersKOS instead, or ultimately use proper glut code, when the glut library is done (I've made good progress on this, it's easy with libEGL in place).
The only worry I have is that users use glutSwapBuffers right now and they would be surprised about their program not compiling anymore (not link, the glut.h header would be removed from libGL). All they'd need to do is rename the function, though.
Alternatively we could add the function to gl.h with __attribute__ ((deprecated)) and make it call glSwapBuffersKOS properly. Then I think libglut could #undef glutSwapBuffers and provide one of its own.
There's also glutCopyBufferToTexture which is non-standard, but it doesn't name clash so I'm not too worried about it. That said, it has been replaced by standards-conformant frame buffer objects in OpenGL, so I think it's not needed anymore.
Thoughts?