| #include <stdio.h>
|
| #include <stdlib.h>
|
| #include <string.h>
|
|
|
| #include <stdint.h>
|
| #include <stdlib.h>
|
| #include <stdarg.h>
|
| #include <errno.h>
|
|
|
| #include <unistd.h>
|
|
|
| #include <X11/Xlib.h>
|
| #include <X11/keysym.h>
|
| #include <X11/Xutil.h>
|
|
|
| #include "common.h"
|
| #include "doomkeys.h"
|
|
|
| #include "i_system.h"
|
| #include "m_argv.h"
|
| #include "d_main.h"
|
|
|
| #include "doomdef.h"
|
|
|
| static int video_initialized = 0;
|
|
|
| extern byte *screens[5];
|
|
|
| typedef struct Color {
|
| unsigned char b;
|
| unsigned char g;
|
| unsigned char r;
|
| unsigned char a;
|
| } Color;
|
|
|
| static Color current_palette[256];
|
| static char framebuffer[SCREENWIDTH*SCREENHEIGHT*4];
|
|
|
| static int window_w;
|
| static int window_h;
|
| static int offset_x;
|
|
|
| int multiply = 1;
|
|
|
| static long frame_num = 0;
|
|
|
| //static int mouse_captured = 0;
|
|
|
| XEvent X_event;
|
| Display *display;
|
| Window window;
|
| GC context;
|
| XImage *image;
|
|
|
| void I_ShutdownGraphics(void) {
|
| if (!video_initialized) return;
|
|
|
| // called from I_Quit also I_Error in i_system.c
|
|
|
| XDestroyImage(image);
|
| XCloseDisplay(display);
|
| }
|
|
|
| void I_StartFrame (void) {
|
| // called from d_main
|
|
|
| // er?
|
|
|
| /*if (WindowShouldClose()) I_Quit();*/
|
| }
|
| /*
|
| struct joystick_state {
|
| int axis1;
|
| int axis2;
|
| int buttons;
|
| };
|
|
|
| struct joystick_state poll_joystick() {
|
| struct joystick_state js = {0,0,0};
|
| if (!IsGamepadAvailable(0)) return js;
|
| float a1 = GetGamepadAxisMovement(0, 0);
|
| js.axis1 = a1 < -0.1 ? -1 : (a1 > 0.1 ? 1 : 0);
|
| float a2 = GetGamepadAxisMovement(0, 1);
|
| js.axis2 = a2 < -0.1 ? -1 : (a2 > 0.1 ? 1 : 0);
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_LEFT) ? 1 : 0;
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN) ? 2 : 0;
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_UP) ? 4 : 0;
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT) ? 8 : 0;
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_1) ? 16 : 0;
|
| js.buttons |= IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_1) ? 32 : 0;
|
| return js;
|
| }
|
|
|
| struct joystick_state joystate = {0,0,0};
|
| */
|
| int xlatekey()
|
| {
|
| int rc;
|
|
|
| switch(rc = XKeycodeToKeysym(display, X_event.xkey.keycode, 0))
|
| {
|
| case XK_Left: rc = KEY_LEFTARROW; break;
|
| case XK_Right: rc = KEY_RIGHTARROW; break;
|
| case XK_Down: rc = KEY_DOWNARROW; break;
|
| case XK_Up: rc = KEY_UPARROW; break;
|
| case XK_Escape: rc = KEY_ESCAPE; break;
|
| case XK_Return: rc = KEY_ENTER; break;
|
| case XK_Tab: rc = KEY_TAB; break;
|
| case XK_F1: rc = KEY_F1; break;
|
| case XK_F2: rc = KEY_F2; break;
|
| case XK_F3: rc = KEY_F3; break;
|
| case XK_F4: rc = KEY_F4; break;
|
| case XK_F5: rc = KEY_F5; break;
|
| case XK_F6: rc = KEY_F6; break;
|
| case XK_F7: rc = KEY_F7; break;
|
| case XK_F8: rc = KEY_F8; break;
|
| case XK_F9: rc = KEY_F9; break;
|
| case XK_F10: rc = KEY_F10; break;
|
| case XK_F11: rc = KEY_F11; break;
|
| case XK_F12: rc = KEY_F12; break;
|
|
|
| case XK_BackSpace:
|
| case XK_Delete: rc = KEY_BACKSPACE; break;
|
|
|
| case XK_Pause: rc = KEY_PAUSE; break;
|
|
|
| case XK_KP_Equal:
|
| case XK_equal: rc = KEY_EQUALS; break;
|
|
|
| case XK_KP_Subtract:
|
| case XK_minus: rc = KEY_MINUS; break;
|
|
|
| case XK_Shift_L:
|
| case XK_Shift_R:
|
| rc = KEY_RSHIFT;
|
| break;
|
|
|
| case XK_Control_L:
|
| case XK_Control_R:
|
| rc = KEY_RCTRL;
|
| break;
|
|
|
| case XK_Alt_L:
|
| case XK_Meta_L:
|
| case XK_Alt_R:
|
| case XK_Meta_R:
|
| rc = KEY_RALT;
|
| break;
|
|
|
| default:
|
| if (rc >= XK_space && rc <= XK_asciitilde)
|
| rc = rc - XK_space + ' ';
|
| if (rc >= 'A' && rc <= 'Z')
|
| rc = rc - 'A' + 'a';
|
| break;
|
| }
|
|
|
| return rc;
|
| }
|
|
|
| void I_GetEvent(void) {
|
| // was called from I_StartTic
|
| // get events and post them with D_PostEvent
|
| // also updated mousemoved
|
|
|
| event_t ev;
|
|
|
| /* cat mouse */
|
| /* Vector2 delta = GetMouseDelta();
|
| int motion = delta.x || delta.y;
|
| int button =
|
| IsMouseButtonPressed(0) ||
|
| IsMouseButtonPressed(1) ||
|
| IsMouseButtonPressed(2) ||
|
| IsMouseButtonReleased(0) ||
|
| IsMouseButtonReleased(1) ||
|
| IsMouseButtonReleased(2);
|
|
|
| if (mouse_captured && (button || motion)) {
|
| ev.type = ev_mouse;
|
| ev.data1 = IsMouseButtonDown(0) | (IsMouseButtonDown(1) ? 2 : 0) | (IsMouseButtonDown(2) ? 4 : 0);
|
| ev.data2 = (int)delta.x;
|
| ev.data3 = (int)-delta.y;
|
| D_PostEvent(&ev);
|
| }*/
|
|
|
| /* joy stick */
|
| /* struct joystick_state jcurrent = poll_joystick();
|
| int jchange =
|
| jcurrent.axis1 != joystate.axis1 ||
|
| jcurrent.axis2 != joystate.axis2 ||
|
| jcurrent.buttons != joystate.buttons;
|
| if(jchange) {
|
| joystate = jcurrent;
|
| ev.type = ev_joystick;
|
| ev.data3 = joystate.axis2;
|
| ev.data2 = joystate.axis1;
|
| ev.data1 = joystate.buttons;
|
| D_PostEvent(&ev);
|
| }*/
|
|
|
| /* kbd */
|
| if (XCheckWindowEvent(display,window,KeyPressMask |
|
| KeyReleaseMask,&X_event) != False)
|
| switch (X_event.xkey.type)
|
| {
|
| case KeyPress:
|
| ev.type = ev_keydown;
|
| ev.data1 = xlatekey();
|
| D_PostEvent(&ev);
|
| // fprintf(stderr, "k");
|
| break;
|
| case KeyRelease:
|
| ev.type = ev_keyup;
|
| ev.data1 = xlatekey();
|
| D_PostEvent(&ev);
|
| // fprintf(stderr, "ku");
|
| break;
|
| }
|
|
|
| /*if (rc==xlatekey()) { EnableCursor(); mouse_captured = false; }
|
| if (IsMouseButtonDown(1)) { DisableCursor(); mouse_captured = true; }*/
|
|
|
| }
|
|
|
| void I_StartTic (void) {
|
| // called from d_net, d_main
|
| // calls I_GetEvent repeatedly
|
|
|
| I_GetEvent();
|
| }
|
|
|
| void I_UpdateNoBlit (void) {
|
| // called from d_main
|
| }
|
|
|
| void I_FinishUpdate (void) {
|
| // called from d_main
|
| // copied image data from screens[0] into some shm image and synced
|
| // optionally expanding the picture 2x 3x ...
|
|
|
| Color *writing = framebuffer;
|
| for (int i = 0; i < SCREENWIDTH*SCREENHEIGHT; i++) {
|
| *writing++ = current_palette[screens[0][i]];
|
| }
|
|
|
| /* doesn't work. don't use */
|
| // scales the screen size before blitting it
|
| if (multiply == 2)
|
| {
|
| unsigned int *olineptrs[2];
|
| unsigned int *ilineptr;
|
| int x, y, i;
|
| unsigned int twoopixels;
|
| unsigned int twomoreopixels;
|
| unsigned int fouripixels;
|
|
|
| ilineptr = (unsigned int *) (screens[0]);
|
| for (i=0 ; i<2 ; i++)
|
| olineptrs[i] = (unsigned int *) &image->data[i*window_w];
|
|
|
| y = SCREENHEIGHT;
|
| while (y--)
|
| {
|
| x = SCREENWIDTH;
|
| do
|
| {
|
| fouripixels = *ilineptr++;
|
| twoopixels = (fouripixels & 0xff000000)
|
| | ((fouripixels>>8) & 0xffff00)
|
| | ((fouripixels>>16) & 0xff);
|
| twomoreopixels = ((fouripixels<<16) & 0xff000000)
|
| | ((fouripixels<<8) & 0xffff00)
|
| | (fouripixels & 0xff);
|
| #ifdef __BIG_ENDIAN__
|
| *olineptrs[0]++ = twoopixels;
|
| *olineptrs[1]++ = twoopixels;
|
| *olineptrs[0]++ = twomoreopixels;
|
| *olineptrs[1]++ = twomoreopixels;
|
| #else
|
| *olineptrs[0]++ = twomoreopixels;
|
| *olineptrs[1]++ = twomoreopixels;
|
| *olineptrs[0]++ = twoopixels;
|
| *olineptrs[1]++ = twoopixels;
|
| #endif
|
| } while (x-=4);
|
| olineptrs[0] += window_w/4;
|
| olineptrs[1] += window_w/4;
|
| }
|
|
|
| }
|
| else if (multiply == 3)
|
| {
|
| unsigned int *olineptrs[3];
|
| unsigned int *ilineptr;
|
| int x, y, i;
|
| unsigned int fouropixels[3];
|
| unsigned int fouripixels;
|
|
|
| ilineptr = (unsigned int *) (screens[0]);
|
| for (i=0 ; i<3 ; i++)
|
| olineptrs[i] = (unsigned int *) &image->data[i*window_w];
|
|
|
| y = SCREENHEIGHT;
|
| while (y--)
|
| {
|
| x = SCREENWIDTH;
|
| do
|
| {
|
| fouripixels = *ilineptr++;
|
| fouropixels[0] = (fouripixels & 0xff000000)
|
| | ((fouripixels>>8) & 0xff0000)
|
| | ((fouripixels>>16) & 0xffff);
|
| fouropixels[1] = ((fouripixels<<8) & 0xff000000)
|
| | (fouripixels & 0xffff00)
|
| | ((fouripixels>>8) & 0xff);
|
| fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
|
| | ((fouripixels<<8) & 0xff00)
|
| | (fouripixels & 0xff);
|
| #ifdef __BIG_ENDIAN__
|
| *olineptrs[0]++ = fouropixels[0];
|
| *olineptrs[1]++ = fouropixels[0];
|
| *olineptrs[2]++ = fouropixels[0];
|
| *olineptrs[0]++ = fouropixels[1];
|
| *olineptrs[1]++ = fouropixels[1];
|
| *olineptrs[2]++ = fouropixels[1];
|
| *olineptrs[0]++ = fouropixels[2];
|
| *olineptrs[1]++ = fouropixels[2];
|
| *olineptrs[2]++ = fouropixels[2];
|
| #else
|
| *olineptrs[0]++ = fouropixels[2];
|
| *olineptrs[1]++ = fouropixels[2];
|
| *olineptrs[2]++ = fouropixels[2];
|
| *olineptrs[0]++ = fouropixels[1];
|
| *olineptrs[1]++ = fouropixels[1];
|
| *olineptrs[2]++ = fouropixels[1];
|
| *olineptrs[0]++ = fouropixels[0];
|
| *olineptrs[1]++ = fouropixels[0];
|
| *olineptrs[2]++ = fouropixels[0];
|
| #endif
|
| } while (x-=4);
|
| olineptrs[0] += 2*window_w/4;
|
| olineptrs[1] += 2*window_w/4;
|
| olineptrs[2] += 2*window_w/4;
|
| }
|
|
|
| }
|
|
|
| XPutImage(display,window,context,image,0,0,0,0,window_w,window_h);
|
|
|
| I_Sleep(0.025); /* do? */
|
|
|
| frame_num++;
|
| }
|
|
|
| void I_ReadScreen (byte* scr) {
|
| // called from f_wipe to read the screen
|
| memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
|
| }
|
|
|
| void I_SetPalette (byte* palette) {
|
| // called from m_menu, d_main, st_stuff
|
| // to set the palette
|
|
|
| for (int i = 0; i < 256; i++) {
|
| current_palette[i].r = palette[3*i + 0];
|
| current_palette[i].g = palette[3*i + 1];
|
| current_palette[i].b = palette[3*i + 2];
|
| current_palette[i].a = 255;
|
| }
|
|
|
| }
|
|
|
| void I_InitGraphics(void) {
|
| // called from d_main
|
|
|
| // set up video backend and possibly override screen[0]
|
| // which is where rendering ultimately writes to
|
| // before FinishUpdate presents it, whatever is in screen[0]
|
|
|
| /* if (M_CheckParm("-fullscreen")) {
|
| int monitor = GetCurrentMonitor();
|
| window_h = GetMonitorHeight(monitor);
|
| window_w = window_h * 4 / 3;
|
| offset_x = GetMonitorWidth(monitor)/2 - window_w/2;
|
| SetWindowSize(window_w, window_h);
|
| ToggleBorderlessWindowed();
|
| }*/
|
| /*else {*/
|
| /*if (M_CheckParm("-1")) multiply = 1; useless */
|
| if (M_CheckParm("-2")) multiply = 2;
|
| else if (M_CheckParm("-3")) multiply = 3;
|
| /*else if (M_CheckParm("-4")) multiply = 4;
|
| else if (M_CheckParm("-5")) multiply = 5;
|
| else if (M_CheckParm("-10")) multiply = 10;*/ /* wtf */
|
| /* that'd be 3200x2400... you have a 4K capitalist mon or smth? */
|
|
|
| window_w = SCREENWIDTH * multiply;
|
| window_h = SCREENHEIGHT * multiply;
|
| offset_x = 0;
|
|
|
| /* based on Licar git.coom.tech/drummyfish/licar */
|
| display = XOpenDisplay(0);
|
| int screen = DefaultScreen(display);
|
|
|
| window = XCreateSimpleWindow(display,RootWindow(display,screen),10,10,
|
| window_w,window_h,1,
|
| BlackPixel(display,screen),WhitePixel(display,screen));
|
| XSizeHints *sizeHints = XAllocSizeHints();
|
| sizeHints->flags = PMaxSize | PMinSize;
|
| sizeHints->max_width = window_w;
|
| sizeHints->min_width = window_w;
|
| sizeHints->max_height = window_h;
|
| sizeHints->min_height = window_h;
|
| XSetWMNormalHints(display,window,sizeHints);
|
| XFree(sizeHints);
|
|
|
| XMapWindow(display,window);
|
|
|
| XSelectInput(display,window,KeyPressMask | KeyReleaseMask);
|
|
|
| context = DefaultGC(display,screen);
|
|
|
| XStoreName(display,window,"DOOM");
|
|
|
| /*
|
| Hardcoded constants here may perhaps cause trouble on some platforms, but
|
| doing X11 "the right way" would mean 1 billion lines of code, so fuck it.
|
| */
|
| image = XCreateImage(display,DefaultVisual(display,screen),
|
| /*DefaultDepth(display,screen)*/24,ZPixmap,0,framebuffer,
|
| window_w,window_h,8,0);
|
|
|
| /* forking autorepeat */
|
| XkbSetDetectableAutoRepeat(display,True,0);
|
|
|
| video_initialized = 1;
|
|
|
| // two obscure controllers I have
|
| /*SetGamepadMappings("03000000790000004e95000011010000,DragonRise Inc. NGC USB Gamepad,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:a4,rightx:a5,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,");
|
| SetGamepadMappings("03000000790000001100000010010000,!NNEXT Gamepad,a:b2,b:b1,x:b3,y:b0,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftx:a0,lefty:a1,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0");*/
|
| }
|