#include #include #include #include #include #include "Display.h" #include #include #include #include #include #include #include #include #include #include // apt-get install libx11-dev namespace { // static int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, None}; // static int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, GLX_DOUBLEBUFFER, None}; uint32_t screen_width; uint32_t screen_height; Kore::WindowMode windowMode; uint32_t width; uint32_t height; bool bcmHostStarted = false; EGLDisplay display; EGLSurface surface; EGLContext context; DISPMANX_ELEMENT_HANDLE_T dispman_element; GLboolean doubleBuffer = GL_TRUE; void fatalError(const char *message) { printf("main: %s\n", message); exit(1); } int getbit(uint32_t *bits, uint32_t bit) { return (bits[bit / 32] >> (bit % 32)) & 1; } void enable_bit(uint32_t *bits, uint32_t bit) { bits[bit / 32] |= 1u << (bit % 32); } void disable_bit(uint32_t *bits, uint32_t bit) { bits[bit / 32] &= ~(1u << (bit % 32)); } void set_bit(uint32_t *bits, uint32_t bit, int value) { if (value) enable_bit(bits, bit); else disable_bit(bits, bit); } struct InputDevice { int fd; uint16_t keys; uint32_t key_state[(KEY_MAX - 1) / 32 + 1]; }; const int inputDevicesCount = 16; InputDevice inputDevices[inputDevicesCount]; Display *dpy; void openXWindow(int x, int y, int width, int height) { dpy = XOpenDisplay(NULL); XSetWindowAttributes winAttr; winAttr.event_mask = StructureNotifyMask; Window w = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, width, height, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWEventMask, &winAttr); XMapWindow(dpy, w); XFlush(dpy); // TODO: Figure this out /*Atom atom = XInternAtom(dpy, "_NET_FRAME_EXTENTS", True); Atom atom2; int f; unsigned long n, b; XEvent e; unsigned char *data = 0; while (XGetWindowProperty(dpy, w, atom, 0, 4, False, AnyPropertyType, &atom2, &f, &n, &b, &data) != Success || n != 4 || b != 0) { XNextEvent(dpy, &e); } long* extents = (long*) data; //printf ("Got frame extents: left %ld right %ld top %ld bottom %ld\n", // extents[0], extents[1], extents[2], extents[3]); */ XMoveWindow(dpy, w, x - 1, y - 30); // extents[2]); XFlush(dpy); } void setScreenSize() { if (!bcmHostStarted) { bcm_host_init(); bcmHostStarted = true; } if (screen_width == 0 || screen_height == 0) { int32_t success = 0; success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height); assert(success >= 0); } } } namespace Kore { namespace Display { void enumDisplayMonitors(DeviceInfo screens[], int &displayCounter) { displayCounter = 1; } } } void Kore::System::setup() {} bool Kore::System::isFullscreen() { // TODO (DK) return false; } // TODO (DK) the whole glx stuff should go into Graphics/OpenGL? // -then there would be a better separation between window + context setup int createWindow(const char *title, int x, int y, int width, int height, Kore::WindowMode windowMode, int targetDisplay, int depthBufferBits, int stencilBufferBits) { if (!bcmHostStarted) { bcm_host_init(); bcmHostStarted = true; } ::windowMode = windowMode; ::width = width; ::height = height; // uint32_t screen_width = 640; // uint32_t screen_height = 480; EGLBoolean result; EGLint num_config; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE}; static const EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; EGLConfig config; display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(display != EGL_NO_DISPLAY); glCheckErrors(); result = eglInitialize(display, NULL, NULL); assert(EGL_FALSE != result); glCheckErrors(); result = eglChooseConfig(display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); glCheckErrors(); result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); glCheckErrors(); context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); assert(context != EGL_NO_CONTEXT); glCheckErrors(); setScreenSize(); if (windowMode == Kore::WindowModeFullscreen) { dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = screen_width; dst_rect.height = screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = screen_width << 16; src_rect.height = screen_height << 16; } else { dst_rect.x = x; dst_rect.y = y; #ifdef KINC_RASPBERRY_PI_SCALING dst_rect.width = screen_width; dst_rect.height = screen_height; #else dst_rect.width = width; dst_rect.height = height; #endif src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; } dispman_display = vc_dispmanx_display_open(0 /* LCD */); dispman_update = vc_dispmanx_update_start(0); VC_DISPMANX_ALPHA_T alpha = {}; alpha.flags = (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS); alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, (DISPMANX_TRANSFORM_T)0 /*transform*/); nativewindow.element = dispman_element; if (windowMode == Kore::WindowModeFullscreen) { nativewindow.width = screen_width; nativewindow.height = screen_height; } else { nativewindow.width = width; nativewindow.height = height; #ifndef KINC_RASPBERRY_PI_SCALING openXWindow(x, y, width, height); #endif } vc_dispmanx_update_submit_sync(dispman_update); glCheckErrors(); surface = eglCreateWindowSurface(display, config, &nativewindow, NULL); assert(surface != EGL_NO_SURFACE); glCheckErrors(); result = eglMakeCurrent(display, surface, surface, context); assert(EGL_FALSE != result); glCheckErrors(); // input char name[64]; for (int i = 0; i < inputDevicesCount; ++i) { sprintf(name, "/dev/input/event%d", i); // PIGU_device_info_t info; // if(PIGU_detect_device(name, &info) < 0) uint32_t events[(KEY_MAX - 1) / 32 + 1]; inputDevices[i].fd = open(name, O_RDONLY | O_NONBLOCK); if (inputDevices[i].fd < 0) continue; char deviceName[128]; ioctl(inputDevices[i].fd, EVIOCGNAME(sizeof(deviceName)), deviceName); printf("Found a device. %s\n", deviceName); uint32_t types[EV_MAX]; memset(types, 0, sizeof(types)); ioctl(inputDevices[i].fd, EVIOCGBIT(0, EV_MAX), types); int keycount = 0; if (getbit(types, EV_KEY)) { // count events memset(events, 0, sizeof(events)); ioctl(inputDevices[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), events); int j = 0; for (; j < BTN_MISC; ++j) if (getbit(events, j)) keycount++; /*j = BTN_MOUSE; // skip misc buttons for(;j=16) continue; buttons.map[buttons.count] = j-BTN_MOUSE; buttons.count++; } for(;j=16) continue; buttons.map[buttons.count] = j-BTN_JOYSTICK; buttons.count++; } for(;j=16) continue; buttons.map[buttons.count] = j-BTN_GAMEPAD; buttons.count++; }*/ } } return 0; } namespace Kore { namespace System { int windowCount() { return 1; } int windowWidth(int id) { if (windowMode == Kore::WindowModeFullscreen) { return screen_width; } else { return width; } } int windowHeight(int id) { if (windowMode == Kore::WindowModeFullscreen) { return screen_height; } else { return height; } } int desktopWidth() { setScreenSize(); return screen_width; } int desktopHeight() { setScreenSize(); return screen_height; } int initWindow(WindowOptions options) { char buffer[1024] = {0}; strcat(buffer, name()); if (options.title != nullptr) { strcat(buffer, options.title); } int id = createWindow(buffer, options.x == -1 ? screen_width / 2 - options.width / 2 : options.x, options.y == -1 ? screen_height / 2 - options.height / 2 : options.y, options.width, options.height, options.mode, options.targetDisplay, options.rendererOptions.depthBufferBits, options.rendererOptions.stencilBufferBits); Graphics4::init(id, options.rendererOptions.depthBufferBits, options.rendererOptions.stencilBufferBits); return id; } void *windowHandle(int id) { return nullptr; } } } namespace Kore { namespace System { int currentDeviceId = -1; int currentDevice() { return currentDeviceId; } void setCurrentDevice(int id) { currentDeviceId = id; } } } bool Kore::System::handleMessages() { for (int i = 0; i < inputDevicesCount; ++i) { int eventcount = 0; if (inputDevices[i].fd < 0) continue; input_event event; ssize_t readsize = read(inputDevices[i].fd, &event, sizeof(event)); while (readsize >= 0) { set_bit(inputDevices[i].key_state, event.code, event.value); #define KEY(linuxkey, korekey, keychar) \ case linuxkey: \ if (event.value == 1) \ Kore::Keyboard::the()->_keydown(korekey); \ else if (event.value == 0) \ Kore::Keyboard::the()->_keyup(korekey); \ break; switch (event.code) { KEY(KEY_RIGHT, KeyRight, ' ') KEY(KEY_LEFT, KeyLeft, ' ') KEY(KEY_UP, KeyUp, ' ') KEY(KEY_DOWN, KeyDown, ' ') KEY(KEY_SPACE, KeySpace, ' ') KEY(KEY_BACKSPACE, KeyBackspace, ' ') KEY(KEY_TAB, KeyTab, ' ') // KEY(KEY_ENTER, KeyEnter, ' ') KEY(KEY_LEFTSHIFT, KeyShift, ' ') KEY(KEY_RIGHTSHIFT, KeyShift, ' ') KEY(KEY_LEFTCTRL, KeyControl, ' ') KEY(KEY_RIGHTCTRL, KeyControl, ' ') KEY(KEY_LEFTALT, KeyAlt, ' ') KEY(KEY_RIGHTALT, KeyAlt, ' ') KEY(KEY_DELETE, KeyDelete, ' ') KEY(KEY_A, KeyA, 'a') KEY(KEY_B, KeyB, 'b') KEY(KEY_C, KeyC, 'c') KEY(KEY_D, KeyD, 'd') KEY(KEY_E, KeyE, 'e') KEY(KEY_F, KeyF, 'f') KEY(KEY_G, KeyG, 'g') KEY(KEY_H, KeyH, 'h') KEY(KEY_I, KeyI, 'i') KEY(KEY_J, KeyJ, 'j') KEY(KEY_K, KeyK, 'k') KEY(KEY_L, KeyL, 'l') KEY(KEY_M, KeyM, 'm') KEY(KEY_N, KeyN, 'n') KEY(KEY_O, KeyO, 'o') KEY(KEY_P, KeyP, 'p') KEY(KEY_Q, KeyQ, 'q') KEY(KEY_R, KeyR, 'r') KEY(KEY_S, KeyS, 's') KEY(KEY_T, KeyT, 't') KEY(KEY_U, KeyU, 'u') KEY(KEY_V, KeyV, 'v') KEY(KEY_W, KeyW, 'w') KEY(KEY_X, KeyX, 'x') KEY(KEY_Y, KeyY, 'y') KEY(KEY_Z, KeyZ, 'z') KEY(KEY_1, Key1, '1') KEY(KEY_2, Key2, '2') KEY(KEY_3, Key3, '3') KEY(KEY_4, Key4, '4') KEY(KEY_5, Key5, '5') KEY(KEY_6, Key6, '6') KEY(KEY_7, Key7, '7') KEY(KEY_8, Key8, '8') KEY(KEY_9, Key9, '9') KEY(KEY_0, Key0, '0') } #undef KEY // printf("Code %d Value %d\n", event.code, event.value); readsize = read(inputDevices[i].fd, &event, sizeof(event)); } } #ifndef KINC_RASPBERRY_PI_SCALING if (windowMode != Kore::WindowModeFullscreen) { while (XPending(dpy) > 0) { XEvent event; XNextEvent(dpy, &event); printf("Got an X event.\n"); switch (event.type) { case ConfigureNotify: DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); VC_RECT_T dst_rect; VC_RECT_T src_rect; dst_rect.x = event.xconfigure.x; dst_rect.y = event.xconfigure.y; dst_rect.width = width; dst_rect.height = height; src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; vc_dispmanx_element_change_attributes(update, dispman_element, 0, 0, 255, &dst_rect, &src_rect, 0, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_update_submit_sync(update); } } } #endif return true; } const char *Kore::System::systemId() { return "Pi"; } void Kore::System::makeCurrent(int contextId) { if (currentDeviceId == contextId) { return; } #if !defined(NDEBUG) // log(Info, "Kore/System | context switch from %i to %i", currentDeviceId, contextId); #endif currentDeviceId = contextId; } void Kore::Graphics4::clearCurrent() {} void Kore::System::clearCurrent() { #if !defined(NDEBUG) // log(Info, "Kore/System | context clear"); #endif currentDeviceId = -1; Graphics4::clearCurrent(); } void Kore::System::swapBuffers(int contextId) { eglSwapBuffers(display, surface); } void Kore::System::destroyWindow(int id) { // TODO (DK) implement me } void Kore::System::changeResolution(int width, int height, bool fullscreen) {} void Kore::System::setTitle(const char *title) {} void Kore::System::setKeepScreenOn(bool on) {} void Kore::System::showWindow() {} void Kore::System::showKeyboard() {} void Kore::System::hideKeyboard() {} void Kore::System::loadURL(const char *url) {} void Kore::System::vibrate(int ms) {} const char *Kore::System::language() { return "en"; } namespace { char save[2000]; bool saveInitialized = false; } const char *Kore::System::savePath() { if (!saveInitialized) { strcpy(save, "ΔΆ~/."); strcat(save, name()); strcat(save, "/"); saveInitialized = true; } return save; } namespace { const char *videoFormats[] = {"ogv", nullptr}; } const char **Kore::System::videoFormats() { return ::videoFormats; } #include #include double Kore::System::frequency() { return 1000000.0; } Kore::System::ticks Kore::System::timestamp() { timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000000 + static_cast(now.tv_usec); } extern int kore(int argc, char **argv); int main(int argc, char **argv) { kore(argc, argv); }