125 lines
2.7 KiB
C++
125 lines
2.7 KiB
C++
#include <iostream>
|
|
|
|
#include "../Video.h"
|
|
|
|
#include "Events.h"
|
|
|
|
#define WINDOW_WIDTH 1280
|
|
#define WINDOW_HEIGHT 800
|
|
|
|
Video video;
|
|
|
|
Video::Video() {
|
|
// TODO
|
|
}
|
|
|
|
Video::~Video() {
|
|
Exit();
|
|
}
|
|
|
|
inline void writePixel(SDL_Surface *surface, unsigned x, unsigned y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
auto row = reinterpret_cast<Uint32*>(static_cast<Uint8*>(surface->pixels) + y * surface->pitch);
|
|
row[x] = SDL_MapRGBA(surface->format, r, g, b, a);
|
|
}
|
|
|
|
void Video::Enter() {
|
|
_window = SDL_CreateWindow("game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 800, SDL_WINDOW_SHOWN);
|
|
if (!_window) {
|
|
std::cerr << "Error creating SDL window: " << SDL_GetError() << std::endl;
|
|
abort();
|
|
}
|
|
|
|
_windowSurface = SDL_GetWindowSurface(_window);
|
|
_fb = SDL_CreateRGBSurfaceWithFormat(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_PIXELFORMAT_ARGB8888);
|
|
}
|
|
|
|
void Video::Exit() {
|
|
if (_fb) SDL_FreeSurface(_fb);
|
|
_fb = nullptr;
|
|
|
|
SDL_DestroyWindow(_window);
|
|
}
|
|
|
|
void Video::SetMode(uint8_t mode) {
|
|
// Ignored
|
|
}
|
|
|
|
uint8_t Video::GetMode() {
|
|
// Fixed
|
|
return 0x13;
|
|
}
|
|
|
|
void Video::SetPaletteEntry(uint8_t index, PaletteEntry entry) {
|
|
SetPaletteEntry(index, &entry);
|
|
}
|
|
|
|
Video::PaletteEntry Video::GetPaletteEntry(uint8_t index) {
|
|
PaletteEntry entry;
|
|
GetPaletteEntry(index, &entry);
|
|
return entry;
|
|
}
|
|
|
|
void Video::SetPaletteEntry(uint8_t index, PaletteEntry *entry) {
|
|
_palette[index] = *entry;
|
|
}
|
|
|
|
void Video::GetPaletteEntry(uint8_t index, PaletteEntry *entry) {
|
|
*entry = _palette[index];
|
|
}
|
|
|
|
void *Video::GetFB() {
|
|
return _renderBuffer;
|
|
}
|
|
|
|
void Video::WaitForVerticalSync() {
|
|
auto targetTime = _lastUpdate + std::chrono::microseconds(14286);
|
|
auto currentTime = std::chrono::steady_clock::now();
|
|
|
|
while (currentTime < targetTime) {
|
|
currentTime = std::chrono::steady_clock::now();
|
|
}
|
|
_lastUpdate = currentTime;
|
|
}
|
|
|
|
void Video::UpdateRect(const Rect &rect) {
|
|
// Merge rect if it overlaps with an existing rect
|
|
for (auto i = 0; i < _updateRectIndex; i++) {
|
|
auto &r = _updatedRects[i];
|
|
if (r.overlaps(rect)) {
|
|
r += rect;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Add a new rect to the list
|
|
_updatedRects[_updateRectIndex++] = rect;
|
|
}
|
|
|
|
void Video::Flip() {
|
|
SDL_LockSurface(_fb);
|
|
|
|
for (auto i = 0; i <= MAX_UPDATE_RECT_INDEX; i++) {
|
|
auto &rect = _updatedRects[i];
|
|
rect.clamp(0, 0, _fb->w, _fb->h);
|
|
|
|
for (auto y = rect.y1; y < rect.y2; y++) {
|
|
for (auto x = rect.x1; x < rect.x2; x++) {
|
|
auto &paletteEntry = _palette[_renderBuffer[y * SCREEN_WIDTH + x]];
|
|
|
|
writePixel(_fb, x, y, paletteEntry.r, paletteEntry.g, paletteEntry.b, 255);
|
|
}
|
|
}
|
|
}
|
|
SDL_UnlockSurface(_fb);
|
|
|
|
SDL_Rect srcRect{0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
SDL_Rect dstRect{0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
|
|
|
|
SDL_BlitScaled(_fb, &srcRect, _windowSurface, &dstRect);
|
|
SDL_UpdateWindowSurface(_window);
|
|
|
|
_updateRectIndex = 0;
|
|
|
|
events.poll();
|
|
}
|