File: sdl.cpp

package info (click to toggle)
higan 106-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster
  • size: 9,640 kB
  • sloc: cpp: 108,736; ansic: 809; makefile: 22; sh: 7
file content (132 lines) | stat: -rw-r--r-- 3,717 bytes parent folder | download
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
#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() { initialize(); }
  ~VideoSDL() { terminate(); }

  auto ready() -> bool { return _ready; }

  auto context() -> uintptr { return _context; }

  auto setContext(uintptr context) -> bool {
    if(_context == context) return true;
    _context = context;
    return initialize();
  }

  auto clear() -> void {
    if(!ready()) return;
    if(SDL_MUSTLOCK(_buffer)) SDL_LockSurface(_buffer);
    for(uint y : range(_bufferHeight)) {
      uint32_t* data = (uint32_t*)_buffer->pixels + y * (_buffer->pitch >> 2);
      for(uint x : range(_bufferWidth)) *data++ = 0xff000000;
    }
    if(SDL_MUSTLOCK(_buffer)) SDL_UnlockSurface(_buffer);
    output();
  }

  auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
    if(!ready()) return false;
    if(width != _width || height != _height) resize(_width = width, _height = height);
    if(SDL_MUSTLOCK(_buffer)) SDL_LockSurface(_buffer);
    pitch = _buffer->pitch;
    return data = (uint32_t*)_buffer->pixels;
  }

  auto unlock() -> void {
    if(!ready()) return;
    if(SDL_MUSTLOCK(_buffer)) SDL_UnlockSurface(_buffer);
  }

  auto output() -> void {
    if(!ready()) return;

    //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(uint y : range(_height)) {
      uint32_t* data = (uint32_t*)_buffer->pixels + y * (_buffer->pitch >> 2);
      for(uint x : range(_width)) *data++ |= 0xff000000;
    }
    if(SDL_MUSTLOCK(_buffer)) SDL_UnlockSurface(_buffer);

    XWindowAttributes attributes;
    XGetWindowAttributes(_display, _context, &attributes);

    SDL_Rect source;
    SDL_Rect target;

    source.x = 0;
    source.y = 0;
    source.w = _width;
    source.h = _height;

    target.x = 0;
    target.y = 0;
    target.w = attributes.width;
    target.h = attributes.height;

    SDL_SoftStretch(_buffer, &source, _screen, &target);
    SDL_UpdateRect(_screen, target.x, target.y, target.w, target.h);
  }

private:
  auto initialize() -> bool {
    terminate();
    if(!_context) return false;

    _display = XOpenDisplay(0);

    char env[512];
    sprintf(env, "SDL_WINDOWID=%ld", (long)_context);
    putenv(env);

    SDL_InitSubSystem(SDL_INIT_VIDEO);
    _screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE);
    XUndefineCursor(_display, _context);

    _buffer = nullptr;
    _bufferWidth = 0;
    _bufferHeight = 0;
    resize(_width = 256, _height = 256);

    return _ready = true;
  }

  auto terminate() -> void {
    _ready = false;
    if(_buffer) SDL_FreeSurface(_buffer), _buffer = nullptr;
    if(_screen) SDL_QuitSubSystem(SDL_INIT_VIDEO), _screen = nullptr;
    if(_display) XCloseDisplay(_display), _display = nullptr;
  }

  auto resize(uint width, uint height) -> void {
    if(_bufferWidth >= width && _bufferHeight >= height) return;

    _bufferWidth = max(width, _bufferWidth);
    _bufferHeight = max(height, _bufferHeight);

    if(_buffer) SDL_FreeSurface(_buffer);
    _buffer = SDL_CreateRGBSurface(
      SDL_SWSURFACE, _bufferWidth, _bufferHeight, 32,
      0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
    );
  }

  bool _ready = false;
  uintptr _context = 0;

  Display* _display = nullptr;
  SDL_Surface* _screen = nullptr;
  SDL_Surface* _buffer = nullptr;
  uint _bufferWidth = 0;
  uint _bufferHeight = 0;
  uint _width = 0;
  uint _height = 0;
};