#ifndef PLAY96_HPP
#define PLAY96_HPP
#include "play96.h"
#include <stdexcept>
#include <string>
namespace play96 {
struct Color {
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char alpha = 255;
};
enum class MouseButton : size_t {
Left = PLAY96_MOUSE_LEFT,
Right = PLAY96_MOUSE_RIGHT,
Middle = PLAY96_MOUSE_MIDDLE,
Button4 = PLAY96_MOUSE_BUTTON4,
Button5 = PLAY96_MOUSE_BUTTON5,
};
enum class InputDevice : unsigned {
None = PLAY96_DEVICE_NONE,
Joypad = PLAY96_DEVICE_JOYPAD,
Mouse = PLAY96_DEVICE_MOUSE,
Keyboard = PLAY96_DEVICE_KEYBOARD,
};
class Session {
public:
Session(const char* core_path, const char* cartridge_path) {
check(play96_create(core_path, cartridge_path, &session_));
}
~Session() { play96_destroy(session_); }
Session(const Session&) = delete;
Session& operator=(const Session&) = delete;
Session(Session&& other) noexcept : session_(other.session_) { other.session_ = nullptr; }
Session& operator=(Session&& other) noexcept {
if (this != &other) {
play96_destroy(session_);
session_ = other.session_;
other.session_ = nullptr;
}
return *this;
}
void run_frame() { check(play96_run_frame(session_)); }
void run_frames(size_t frames) { check(play96_run_frames(session_, frames)); }
void set_button(unsigned port, unsigned button, bool pressed) { check(play96_set_button(session_, port, button, pressed)); }
void clear_buttons(unsigned port = 0) { check(play96_clear_buttons(session_, port)); }
void set_controller_device(unsigned port, InputDevice device) {
check(play96_set_controller_device(session_, port, static_cast<play96_input_device>(device)));
}
void set_key(uint32_t keycode, bool pressed) { check(play96_set_key(session_, keycode, pressed)); }
void clear_keys() { check(play96_clear_keys(session_)); }
void set_mouse_delta(int16_t x, int16_t y) { check(play96_set_mouse_delta(session_, x, y)); }
void set_mouse_button(MouseButton button, bool pressed) {
check(play96_set_mouse_button(session_, static_cast<size_t>(button), pressed));
}
void clear_mouse_buttons() { check(play96_clear_mouse_buttons(session_)); }
void set_mouse_wheel(int16_t vertical, int16_t horizontal = 0) {
check(play96_set_mouse_wheel(session_, vertical, horizontal));
}
unsigned width() const { return play96_framebuffer_width(session_); }
unsigned height() const { return play96_framebuffer_height(session_); }
uint32_t pixel_xrgb(unsigned x, unsigned y) const { return play96_pixel_xrgb(session_, x, y); }
void assert_pixel(unsigned x, unsigned y, Color color) const {
check(play96_assert_pixel(session_, x, y, {color.red, color.green, color.blue, color.alpha}));
}
void assert_pixel_xrgb(unsigned x, unsigned y, uint32_t color) const { check(play96_assert_pixel_xrgb(session_, x, y, color)); }
const int16_t* audio_samples() const { return play96_audio_samples(session_); }
size_t audio_sample_count() const { return play96_audio_sample_count(session_); }
size_t audio_frame_count() const { return play96_audio_frame_count(session_); }
double audio_sample_rate() const { return play96_audio_sample_rate(session_); }
uint64_t audio_hash() const { return play96_audio_hash(session_); }
void assert_audio_sample(size_t frame, size_t channel, int16_t expected, uint16_t tolerance = 0) const {
check(play96_assert_audio_sample(session_, frame, channel, expected, tolerance));
}
void assert_audio_hash(uint64_t expected) const { check(play96_assert_audio_hash(session_, expected)); }
void save_state(const char* path) { check(play96_save_state(session_, path)); }
void load_state(const char* path) { check(play96_load_state(session_, path)); }
void write_png(const char* path) const { check(play96_write_png(session_, path)); }
private:
static void check(const char* error) {
if (error) throw std::runtime_error(error);
}
play96_session* session_ = nullptr;
};
}
#endif