mirror of
https://github.com/ondra-novak/gates_of_skeldal.git
synced 2025-08-22 23:17:24 -04:00
revision of events
This commit is contained in:
parent
858c4384e8
commit
669f72908e
33 changed files with 661 additions and 382 deletions
|
@ -1,9 +1,28 @@
|
|||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
extern "C" {
|
||||
#include "error.h"
|
||||
}
|
||||
#include "platform.h"
|
||||
|
||||
|
||||
void display_error(const char *text) {
|
||||
std::cerr << "ERROR:" << text << std::endl;
|
||||
}
|
||||
|
||||
|
||||
static std::uint32_t gtick = get_game_tick_count();
|
||||
void send_log_impl(int task, const char *format, ...) {
|
||||
va_list args;
|
||||
char buff2[1000];
|
||||
va_start(args, format);
|
||||
auto reltik = get_game_tick_count() - gtick;
|
||||
double sec = reltik * 0.001;
|
||||
std::cerr << sec << "[" << task << "]";
|
||||
vsnprintf(buff2,1000,format, args);
|
||||
std::cerr << buff2 << std::endl;
|
||||
va_end(args);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
void display_error(const char *text);
|
||||
void send_log_impl(int task, const char *format, ...);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
struct TaskInfo {
|
||||
|
@ -13,6 +14,7 @@ struct TaskInfo {
|
|||
std::chrono::system_clock::time_point _wake_up_after = {};
|
||||
int wake_up_msg = -1;
|
||||
bool request_exit = false;
|
||||
bool exited = false;
|
||||
|
||||
TaskInfo(int id):id(id) {}
|
||||
};
|
||||
|
@ -32,41 +34,83 @@ static std::atomic<bool> resume_master_flag = {false};
|
|||
static TaskInfo *current_task_inst = NULL;
|
||||
static EVENT_MSG *cur_message = NULL;
|
||||
|
||||
struct MsgQueue {
|
||||
EVENT_MSG *msg;
|
||||
TaskInfo *sender;
|
||||
};
|
||||
|
||||
static std::queue<MsgQueue> msg_queue;
|
||||
|
||||
void flush_message_queue();
|
||||
|
||||
static void switch_to_task(TaskInfo *task) {
|
||||
if (task == current_task_inst) return;
|
||||
if (task == NULL) {
|
||||
TaskInfo *me = current_task_inst;
|
||||
current_task_inst = NULL;
|
||||
me->resume_flag = false;
|
||||
resume_master_flag = true;
|
||||
resume_master_flag.notify_all();
|
||||
me->resume_flag.wait(false);
|
||||
me->resume_flag = false;
|
||||
} else if (current_task_inst == NULL) {
|
||||
if (task->exited) return ;
|
||||
current_task_inst = task;
|
||||
resume_master_flag = false;
|
||||
task->resume_flag = true;
|
||||
task->resume_flag.notify_all();
|
||||
resume_master_flag.wait(false);
|
||||
resume_master_flag = false;
|
||||
flush_message_queue();
|
||||
} else {
|
||||
if (task->exited) return ;
|
||||
TaskInfo *me = current_task_inst;
|
||||
me->resume_flag = false;
|
||||
current_task_inst = task;
|
||||
task->resume_flag = true;
|
||||
task->resume_flag.notify_all();
|
||||
me->resume_flag.wait(false);
|
||||
me->resume_flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void clean_task_table() {
|
||||
for (auto iter = task_list.begin(); iter != task_list.end();) {
|
||||
if (iter->second->exited) {
|
||||
iter = task_list.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clean_up_current_task() {
|
||||
TaskInfo *me = current_task_inst;
|
||||
if (!me) return;
|
||||
int id = me->id;
|
||||
me->thr.detach();
|
||||
task_list.erase(id);
|
||||
me->exited = true;
|
||||
current_task_inst = NULL;
|
||||
resume_master_flag = true;
|
||||
resume_master_flag.notify_all();
|
||||
}
|
||||
|
||||
void flush_message_queue() {
|
||||
while (!msg_queue.empty()) {
|
||||
auto m = msg_queue.front();
|
||||
msg_queue.pop();
|
||||
for (auto &[id, task]: task_list) {
|
||||
if (task->wake_up_msg == m.msg->msg && task.get() != m.sender) {
|
||||
EVENT_MSG cpy;
|
||||
cpy.msg = m.msg->msg;
|
||||
va_copy(cpy.data, m.msg->data);
|
||||
cur_message = &cpy;
|
||||
switch_to_task(task.get());
|
||||
va_end(cpy.data);
|
||||
cur_message = NULL;
|
||||
}
|
||||
}
|
||||
clean_task_table();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int add_task(int stack,TaskerFunctionName fcname,...) {
|
||||
int id = get_new_task_id();
|
||||
auto st = task_list.emplace(id, std::make_unique<TaskInfo>(id));
|
||||
|
@ -75,6 +119,7 @@ int add_task(int stack,TaskerFunctionName fcname,...) {
|
|||
va_start(args, fcname);
|
||||
new_task->thr = std::thread([&]{
|
||||
new_task->resume_flag.wait(false);
|
||||
new_task->resume_flag = false;
|
||||
fcname(args);
|
||||
clean_up_current_task();
|
||||
});
|
||||
|
@ -93,17 +138,13 @@ char is_running(int id_num) {
|
|||
return id_num < 0 || task_list.find(id_num) != task_list.end();
|
||||
}
|
||||
void unsuspend_task(EVENT_MSG *msg) {
|
||||
for (auto &[id, task]: task_list) {
|
||||
if (task->wake_up_msg == msg->msg) {
|
||||
EVENT_MSG cpy;
|
||||
cpy.msg = msg->msg;
|
||||
va_copy(cpy.data, msg->data);
|
||||
cur_message = &cpy;
|
||||
switch_to_task(task.get());
|
||||
va_end(cpy.data);
|
||||
cur_message = NULL;
|
||||
}
|
||||
msg_queue.push({msg, current_task_inst});
|
||||
if (current_task_inst) {
|
||||
switch_to_task(NULL);
|
||||
} else {
|
||||
flush_message_queue();
|
||||
}
|
||||
|
||||
}
|
||||
void task_sleep(void) {
|
||||
if (current_task_inst) {
|
||||
|
@ -115,13 +156,14 @@ void task_sleep(void) {
|
|||
switch_to_task(task.get());
|
||||
}
|
||||
}
|
||||
clean_task_table();
|
||||
}
|
||||
}
|
||||
EVENT_MSG *task_wait_event(int32_t event_number) {
|
||||
if (current_task_inst == NULL) return NULL;
|
||||
current_task_inst->wake_up_msg = event_number;
|
||||
switch_to_task(NULL);
|
||||
return NULL;
|
||||
return cur_message;
|
||||
}
|
||||
int q_any_task() {
|
||||
return task_list.size();
|
||||
|
|
|
@ -26,9 +26,10 @@ char DXInit64(char inwindow,int zoom,int monitor, int refresh) {
|
|||
get_sdl_global_context().init_screen(mode, "Skeldal"); //todo allow change
|
||||
screen_buffer = std::make_unique<uint16_t[]>(screen_pitch*480);
|
||||
buffer2nd = std::make_unique<uint16_t[]>(screen_pitch*480);
|
||||
std::fill(screen_buffer.get(), screen_buffer.get()+screen_pitch*480,0);
|
||||
render_target = screen_buffer.get();
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DXCloseMode() {
|
||||
|
@ -77,7 +78,7 @@ void StripBlt(void *data, unsigned int startline, uint32_t width) {
|
|||
while (width--)
|
||||
{
|
||||
memcpy(start,data,640*2);
|
||||
data=(void *)(reinterpret_cast<char *>(data)+get_sdl_global_context().get_surface_pitch());
|
||||
data=(void *)(reinterpret_cast<short *>(data)+GetScreenPitch());
|
||||
start=start+GetScreenPitch();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
add_subdirectory(tests)
|
||||
|
||||
add_library(skeldal_sdl sdl_context.cpp BGraph2.cpp input.cpp sound.cpp)
|
||||
add_library(skeldal_sdl sdl_context.cpp BGraph2.cpp input.cpp sound.cpp)
|
||||
set_property(TARGET skeldal_sdl PROPERTY CXX_STANDARD 20)
|
||||
|
|
|
@ -15,14 +15,15 @@ void SetWheelMapping(char up, char down) { //todo
|
|||
|
||||
}
|
||||
|
||||
static MS_EVENT ms_event = {};
|
||||
|
||||
|
||||
|
||||
void get_ms_event(MS_EVENT *event) {
|
||||
*event = ms_event;
|
||||
*event = get_sdl_global_context().getMsEvent();
|
||||
}
|
||||
|
||||
void ShareCPU() {
|
||||
if (q_is_mastertask()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "sdl_context.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include "../platform.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
@ -44,6 +47,11 @@ SDLContext::SDLContext() {
|
|||
|
||||
void SDLContext::init_screen(DisplayMode mode, const char *title) {
|
||||
char buff[256];
|
||||
static Uint32 update_request_event = SDL_RegisterEvents(1);
|
||||
_update_request_event = update_request_event;
|
||||
|
||||
assert(!_render_thread.joinable());
|
||||
|
||||
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
|
@ -51,90 +59,137 @@ void SDLContext::init_screen(DisplayMode mode, const char *title) {
|
|||
width*=2;
|
||||
height*=2;
|
||||
}
|
||||
SDL_Window *window = SDL_CreateWindow(title,
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
width, height, SDL_WINDOW_RESIZABLE|(mode==fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0));
|
||||
|
||||
if (!window) {
|
||||
snprintf(buff, sizeof(buff), "SDL Error create window: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
|
||||
_window.reset(window);
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, 0);
|
||||
if (!renderer) {
|
||||
snprintf(buff,sizeof(buff), "Chyba při vytváření rendereru: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
_renderer.reset(renderer);
|
||||
// Vytvoření softwarového backbufferu (surface)
|
||||
SDL_Surface *backbuffer = SDL_CreateRGBSurfaceWithFormat(0, 640, 480, 16, SDL_PIXELFORMAT_RGB565);
|
||||
if (!backbuffer) {
|
||||
snprintf(buff,sizeof(buff), "Chyba při vytváření surface: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
_surface.reset(backbuffer);
|
||||
// Vytvoření textury pro zobrazení backbufferu
|
||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, 640, 480);
|
||||
if (!texture) {
|
||||
snprintf(buff, sizeof(buff), "Chyba při vytváření textury: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
_texture.reset(texture);
|
||||
|
||||
SDL_LockSurface(_surface.get());
|
||||
|
||||
if (!_timer_event) _timer_event = SDL_RegisterEvents(1);
|
||||
_fullscreen_mode = mode == fullscreen;
|
||||
|
||||
std::atomic<bool> done = false;
|
||||
std::exception_ptr e;
|
||||
_render_thread = std::jthread([&](std::stop_token stp){
|
||||
bool err = false;
|
||||
try {
|
||||
SDL_Window *window = SDL_CreateWindow(title,
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
width, height, SDL_WINDOW_RESIZABLE|(mode==fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0));
|
||||
|
||||
if (!window) {
|
||||
snprintf(buff, sizeof(buff), "SDL Error create window: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
|
||||
_window.reset(window);
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, 0);
|
||||
if (!renderer) {
|
||||
snprintf(buff,sizeof(buff), "Chyba při vytváření rendereru: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
_renderer.reset(renderer);
|
||||
// Vytvoření textury pro zobrazení backbufferu
|
||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, 640, 480);
|
||||
if (!texture) {
|
||||
snprintf(buff, sizeof(buff), "Chyba při vytváření textury: %s\n", SDL_GetError());
|
||||
throw std::runtime_error(buff);
|
||||
}
|
||||
_texture.reset(texture);
|
||||
} catch (...) {
|
||||
e = std::current_exception();
|
||||
err = true;
|
||||
}
|
||||
done = true;
|
||||
done.notify_all();
|
||||
if (!err) event_loop(stp);
|
||||
_texture.reset();
|
||||
_renderer.reset();
|
||||
_window.reset();
|
||||
});
|
||||
|
||||
done.wait(false);
|
||||
if (e) {
|
||||
_render_thread.join();
|
||||
std::rethrow_exception(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SDLContext::close_screen() {
|
||||
SDL_UnlockSurface(_surface.get());
|
||||
_texture.reset();
|
||||
_surface.reset();
|
||||
_renderer.reset();
|
||||
_window.reset();
|
||||
|
||||
_render_thread.request_stop();
|
||||
_render_thread.join();
|
||||
}
|
||||
|
||||
uint16_t* SDLContext::get_surface_addr() {
|
||||
return reinterpret_cast<uint16_t *>(_surface->pixels);
|
||||
void SDLContext::event_loop(std::stop_token stp) {
|
||||
|
||||
static Uint32 exit_loop_event = SDL_RegisterEvents(1);
|
||||
std::stop_callback stopcb(stp,[&]{
|
||||
SDL_Event event;
|
||||
event.type = exit_loop_event;
|
||||
SDL_PushEvent(&event);
|
||||
});
|
||||
|
||||
SDL_Event e;
|
||||
while (SDL_WaitEvent(&e)) {
|
||||
if (e.type == SDL_QUIT) {
|
||||
return;
|
||||
}
|
||||
if (e.type == exit_loop_event) {
|
||||
return;
|
||||
}
|
||||
if (e.type == _update_request_event) {
|
||||
update_screen();
|
||||
}
|
||||
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
if (e.key.keysym.sym == SDLK_RETURN && (e.key.keysym.mod & KMOD_ALT)) {
|
||||
_fullscreen_mode = !_fullscreen_mode;
|
||||
SDL_SetWindowFullscreen(_window.get(), _fullscreen_mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
}
|
||||
} else if (e.type == SDL_MOUSEMOTION) {
|
||||
int mouseX = e.motion.x;
|
||||
int mouseY = e.motion.y;
|
||||
int windowWidth;
|
||||
int windowHeight;
|
||||
SDL_GetWindowSize(_window.get(), &windowWidth, &windowHeight);
|
||||
float normalizedX = (float)mouseX / windowWidth;
|
||||
float normalizedY = (float)mouseY / windowHeight;
|
||||
ms_event.event = 1;
|
||||
ms_event.event_type = 1;
|
||||
ms_event.x = (int16_t)(640*normalizedX);
|
||||
ms_event.y = (int16_t)(480*normalizedY);
|
||||
} else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) {
|
||||
int button = e.button.button;
|
||||
int up = e.type == SDL_MOUSEBUTTONUP?1:0;
|
||||
ms_event.event = 1;
|
||||
ms_event.event_type = (1<<(2*button-1+up));
|
||||
switch (button) {
|
||||
default: break;
|
||||
case 1: ms_event.tl1 = !up; break;
|
||||
case 2: ms_event.tl2 = !up; break;
|
||||
case 3: ms_event.tl3 = !up; break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32_t SDLContext::get_surface_pitch() {
|
||||
return _surface->pitch;
|
||||
}
|
||||
|
||||
|
||||
void SDLContext::charge_timer() {
|
||||
_active_timer = SDL_AddTimer(1000/TIMERSPEED, [](Uint32 interval, void *param) -> Uint32 {
|
||||
SDLContext *me = reinterpret_cast<SDLContext *>(param);
|
||||
SDL_Event* event = (SDL_Event*)param;
|
||||
event->type = me->_timer_event;
|
||||
SDL_PushEvent(event);
|
||||
return 0;
|
||||
}, this);
|
||||
|
||||
}
|
||||
/*
|
||||
void SDLContext::pool_events() {
|
||||
if (!_active_timer.has_value()) charge_timer();
|
||||
SDL_RenderClear(_renderer.get());
|
||||
SDL_RenderCopy(_renderer.get(), _texture.get(), NULL, NULL);
|
||||
SDL_RenderPresent(_renderer.get());
|
||||
ms_event.event = 0;
|
||||
SDL_Event e;
|
||||
while (true) {
|
||||
if (SDL_WaitEvent(&e)) {
|
||||
if (e.type == SDL_QUIT) {
|
||||
_quit_requested = true;
|
||||
return;
|
||||
}
|
||||
if (e.type == _timer_event) {
|
||||
break;
|
||||
}
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
if (e.key.keysym.sym == SDLK_RETURN && (e.key.keysym.mod & KMOD_ALT)) {
|
||||
_fullscreen_mode = !_fullscreen_mode;
|
||||
SDL_SetWindowFullscreen(_window.get(), _fullscreen_mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
}
|
||||
} else if (e.type == SDL_MOUSEMOTION) {
|
||||
std::lock_guard _(_mx);
|
||||
int mouseX = e.motion.x;
|
||||
int mouseY = e.motion.y;
|
||||
int windowWidth;
|
||||
|
@ -147,6 +202,7 @@ void SDLContext::pool_events() {
|
|||
ms_event.x = (int16_t)(640*normalizedX);
|
||||
ms_event.y = (int16_t)(480*normalizedY);
|
||||
} else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) {
|
||||
std::lock_guard _(_mx);
|
||||
int button = e.button.button;
|
||||
int up = e.type == SDL_MOUSEBUTTONUP?1:0;
|
||||
ms_event.event = 1;
|
||||
|
@ -164,21 +220,46 @@ void SDLContext::pool_events() {
|
|||
}
|
||||
}
|
||||
charge_timer();
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
void SDLContext::present_rect(uint16_t *pixels, unsigned int pitch,
|
||||
unsigned int x, unsigned int y, unsigned int xs, unsigned ys) {
|
||||
|
||||
auto beg = pixels + y * pitch + y;
|
||||
|
||||
auto beg = pixels + y * pitch + x;
|
||||
SDL_Rect r = {static_cast<int>(x),
|
||||
static_cast<int>(y),
|
||||
static_cast<int>(xs),
|
||||
static_cast<int>(ys)};
|
||||
SDL_UpdateTexture(_texture.get(), &r, beg, pitch*2);
|
||||
SDL_RenderClear(_renderer.get());
|
||||
SDL_RenderCopy(_renderer.get(), _texture.get(), NULL, NULL);
|
||||
SDL_RenderPresent(_renderer.get());
|
||||
std::vector<short> data;
|
||||
data.resize(xs*ys);
|
||||
auto iter = data.begin();
|
||||
for (unsigned int yp = 0; yp <ys; ++yp) {
|
||||
iter = std::copy(beg, beg+xs,iter );
|
||||
beg+=pitch;
|
||||
}
|
||||
std::lock_guard _(_mx);
|
||||
if (_display_update_queue.empty()) {
|
||||
SDL_Event event;
|
||||
event.type = _update_request_event;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
_display_update_queue.push_back({std::move(r), std::move(data)});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SDLContext::update_screen() {
|
||||
{
|
||||
std::lock_guard _(_mx);
|
||||
for (const UpdateMsg &msg:_display_update_queue) {
|
||||
SDL_UpdateTexture(_texture.get(), &msg.rc, msg.data.data(), msg.rc.w*2);
|
||||
}
|
||||
_display_update_queue.clear();
|
||||
}
|
||||
SDL_RenderClear(_renderer.get());
|
||||
SDL_RenderCopy(_renderer.get(), _texture.get(), NULL, NULL);
|
||||
SDL_RenderPresent(_renderer.get());
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include <memory>
|
||||
#include <optional>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <mouse.h>
|
||||
|
||||
class SDLContext {
|
||||
|
@ -22,14 +24,15 @@ public:
|
|||
void close_screen();
|
||||
|
||||
|
||||
uint16_t *get_surface_addr();
|
||||
int32_t get_surface_pitch();
|
||||
|
||||
|
||||
void pool_events();
|
||||
|
||||
void present_rect(uint16_t *pixels, unsigned int pitch, unsigned int x, unsigned int y, unsigned int xs,unsigned ys);
|
||||
|
||||
MS_EVENT getMsEvent() {
|
||||
std::lock_guard _(_mx);
|
||||
MS_EVENT out = ms_event;
|
||||
ms_event.event = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
struct SDL_Deleter {
|
||||
|
@ -43,13 +46,26 @@ protected:
|
|||
|
||||
std::unique_ptr<SDL_Window, SDL_Deleter> _window;
|
||||
std::unique_ptr<SDL_Renderer, SDL_Deleter> _renderer;
|
||||
std::unique_ptr<SDL_Surface, SDL_Deleter> _surface;
|
||||
std::unique_ptr<SDL_Texture, SDL_Deleter> _texture;
|
||||
|
||||
std::optional<SDL_TimerID> _active_timer;
|
||||
Uint32 _timer_event = 0;
|
||||
std::jthread _render_thread;
|
||||
|
||||
bool _quit_requested = false;
|
||||
bool _fullscreen_mode = false;
|
||||
bool _present = false;
|
||||
void charge_timer();
|
||||
|
||||
void event_loop(std::stop_token stp);
|
||||
std::mutex _mx;
|
||||
|
||||
struct UpdateMsg {
|
||||
SDL_Rect rc;
|
||||
std::vector<short> data;
|
||||
};
|
||||
|
||||
std::vector<UpdateMsg> _display_update_queue;
|
||||
Uint32 _update_request_event;
|
||||
|
||||
void update_screen();
|
||||
|
||||
};
|
||||
|
|
|
@ -74,5 +74,10 @@ void DoneVideoSound(void *buffer) {
|
|||
|
||||
}
|
||||
|
||||
const char *device_name(int )
|
||||
{
|
||||
return "SDL sound device";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue