1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#include <X11/extensions/XShm.h>
#include <SDL/SDL.h>
struct VideoSDL : Video {
~VideoSDL() { term(); }
Display* display = nullptr;
SDL_Surface* screen = nullptr;
SDL_Surface* buffer = nullptr;
unsigned iwidth = 0;
unsigned iheight = 0;
struct {
uintptr_t handle = 0;
unsigned width = 0;
unsigned height = 0;
} settings;
auto cap(const string& name) -> bool {
if(name == Video::Handle) return true;
return false;
}
auto get(const string& name) -> any {
if(name == Video::Handle) return settings.handle;
return {};
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = value.get<uintptr_t>();
return true;
}
return false;
}
auto resize(unsigned width, unsigned height) -> void {
if(iwidth >= width && iheight >= height) return;
iwidth = max(width, iwidth);
iheight = max(height, iheight);
if(buffer) SDL_FreeSurface(buffer);
buffer = SDL_CreateRGBSurface(
SDL_SWSURFACE, iwidth, iheight, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
);
}
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
if(width != settings.width || height != settings.height) {
resize(settings.width = width, settings.height = height);
}
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
pitch = buffer->pitch;
return data = (uint32_t*)buffer->pixels;
}
auto unlock() -> void {
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
}
auto clear() -> void {
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
for(unsigned y = 0; y < iheight; y++) {
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
for(unsigned x = 0; x < iwidth; x++) *data++ = 0xff000000;
}
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
refresh();
}
auto refresh() -> void {
//ruby input is X8R8G8B8, top 8-bits are ignored.
//as SDL forces us to use a 32-bit buffer, we must set alpha to 255 (full opacity)
//to prevent blending against the window beneath when X window visual is 32-bits.
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
for(unsigned y = 0; y < settings.height; y++) {
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
for(unsigned x = 0; x < settings.width; x++) *data++ |= 0xff000000;
}
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
XWindowAttributes attributes;
XGetWindowAttributes(display, settings.handle, &attributes);
SDL_Rect src, dest;
src.x = 0;
src.y = 0;
src.w = settings.width;
src.h = settings.height;
dest.x = 0;
dest.y = 0;
dest.w = attributes.width;
dest.h = attributes.height;
SDL_SoftStretch(buffer, &src, screen, &dest);
SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
}
auto init() -> bool {
display = XOpenDisplay(0);
//todo: this causes a segfault inside SDL_SetVideoMode on FreeBSD (works under Linux)
char env[512];
sprintf(env, "SDL_WINDOWID=%ld", (long)settings.handle);
putenv(env);
SDL_InitSubSystem(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE);
XUndefineCursor(display, settings.handle);
buffer = 0;
iwidth = 0;
iheight = 0;
resize(settings.width = 256, settings.height = 256);
return true;
}
auto term() -> void {
XCloseDisplay(display);
SDL_FreeSurface(buffer);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
};
|