Initial commit
|
|
@ -0,0 +1,6 @@
|
|||
.idea
|
||||
*.o
|
||||
*.gbm
|
||||
gbmconv
|
||||
game.exe
|
||||
game.img
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
HOSTCXX:=$(CXX)
|
||||
|
||||
ifeq ($(TARGET),SDL)
|
||||
# SDL
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
LD=g++
|
||||
STRIP=strip
|
||||
|
||||
SDL_INCLUDE=$(shell pkg-config --cflags sdl2)
|
||||
SDL_LIBS=$(shell pkg-config --libs sdl2)
|
||||
|
||||
CFLAGS=-g -DBUILD_SDL $(SDL_INCLUDE)
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
LDFLAGS=
|
||||
LDLIBS=$(SDL_LIBS) -lstdc++
|
||||
EXE=game
|
||||
EXTRA_FILES=
|
||||
SYSTEM=SDL
|
||||
else ifeq ($(TARGET),SDLWIN)
|
||||
# SDL on Windows
|
||||
CC=i686-w64-mingw32-gcc
|
||||
CXX=i686-w64-mingw32-g++
|
||||
LD=i686-w64-mingw32-g++
|
||||
STRIP=i686-w64-mingw32-strip
|
||||
|
||||
SDL_INCLUDE=-I../SDL2-2.32.10/i686-w64-mingw32/include/SDL2
|
||||
SDL_LDFLAGS=-L../SDL2-2.32.10/i686-w64-mingw32/lib
|
||||
SDL_LIBS=-lmingw32 -lSDL2main -lSDL2
|
||||
|
||||
CFLAGS=-g -DBUILD_SDL $(SDL_INCLUDE) -m32
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
LDFLAGS=$(SDL_LDFLAGS) -mwindows
|
||||
LDLIBS=$(SDL_LIBS) -lstdc++
|
||||
EXE=game.exe
|
||||
EXTRA_FILES=../SDL2-2.32.10/i686-w64-mingw32/bin/SDL2.dll
|
||||
EXTRA_FILES+=/usr/lib/gcc/i686-w64-mingw32/10-win32/libgcc_s_dw2-1.dll
|
||||
EXTRA_FILES+=/usr/lib/gcc/i686-w64-mingw32/10-win32/libstdc++-6.dll
|
||||
SYSTEM=SDL
|
||||
else ifeq ($(TARGET),SDLWIN64)
|
||||
# SDL on Windows
|
||||
CC=x86_64-w64-mingw32-gcc
|
||||
CXX=x86_64-w64-mingw32-g++
|
||||
LD=x86_64-w64-mingw32-g++
|
||||
STRIP=x86_64-w64-mingw32-strip
|
||||
|
||||
SDL_INCLUDE=-I../SDL2-2.32.10/x86_64-w64-mingw32/include/SDL2
|
||||
SDL_LDFLAGS=-L../SDL2-2.32.10/x86_64-w64-mingw32/lib
|
||||
SDL_LIBS=-lmingw32 -lSDL2main -lSDL2
|
||||
|
||||
CFLAGS=-g -DBUILD_SDL $(SDL_INCLUDE) -m64
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
LDFLAGS=$(SDL_LDFLAGS) -mwindows
|
||||
LDLIBS=$(SDL_LIBS) -lstdc++
|
||||
EXE=game.exe
|
||||
EXTRA_FILES=../SDL2-2.32.10/x86_64-w64-mingw32/bin/SDL2.dll
|
||||
EXTRA_FILES+=/mingw64/bin/libgcc_s_seh-1.dll
|
||||
EXTRA_FILES+=/mingw64/bin/libstdc++-6.dll
|
||||
SYSTEM=SDL
|
||||
else
|
||||
# DOS
|
||||
CC=/usr/local/djgpp/bin/i586-pc-msdosdjgpp-gcc
|
||||
CXX=/usr/local/djgpp/bin/i586-pc-msdosdjgpp-g++
|
||||
LD=/usr/local/djgpp/bin/i586-pc-msdosdjgpp-g++
|
||||
STRIP=i586-pc-msdosdjgpp-strip
|
||||
|
||||
CFLAGS=-O3 -march=i486
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
LDFLAGS=
|
||||
LDLIBS=
|
||||
EXE=game.exe
|
||||
DPMI_HOST=CWSDPMI.EXE
|
||||
EXTRA_FILES=install.bat $(DPMI_HOST)
|
||||
SYSTEM=DOS
|
||||
endif
|
||||
|
||||
OBJ=main.o
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard graphics/*.cpp))
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard audio/*.cpp))
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard util/*.cpp))
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard scenes/*.cpp))
|
||||
|
||||
ifeq ($(SYSTEM),SDL)
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard system/sdl/*.cpp))
|
||||
else ifeq ($(SYSTEM),DOS)
|
||||
OBJ+=$(patsubst %.cpp,%.o,$(wildcard system/dos/*.cpp))
|
||||
else
|
||||
$(error Unknown SYSTEM variable:$(SYSTEM))
|
||||
endif
|
||||
|
||||
CONVERTER_CXX=$(HOSTCXX)
|
||||
CONVERTER_EXE=gbmconv
|
||||
CONVERTER_SRC=converter.cpp
|
||||
CONVERTER_SRC+=graphics/Bitmap.cpp
|
||||
CONVERTER_SRC+=util/Files.cpp util/Bmp.cpp util/Gbm.cpp
|
||||
|
||||
COMPILED_GFX_ASSETS=assets/font1.gbm assets/cow.gbm assets/witch.gbm
|
||||
GFX_ASSETS=assets/bg.bmp $(COMPILED_GFX_ASSETS)
|
||||
MUSIC_ASSETS=assets/rain.rad assets/getup.rad assets/spiral.rad
|
||||
|
||||
RELEASE_FILES=$(EXE) $(GFX_ASSETS) $(MUSIC_ASSETS) $(EXTRA_FILES)
|
||||
|
||||
FLOPPY_IMG=game.img
|
||||
|
||||
.PHONY: all clean release debug assets floppy
|
||||
|
||||
all: $(CONVERTER_EXE) $(EXE)
|
||||
|
||||
clean: ; rm -rf $(OBJ) $(EXE) $(CONVERTER_EXE) $(FLOPPY_IMG) $(COMPILED_GFX_ASSETS) release debug
|
||||
|
||||
release: all assets; $(STRIP) $(EXE) && upx $(EXE); mkdir -p release; cp -Rv $(RELEASE_FILES) release/
|
||||
|
||||
debug: all assets; mkdir -p debug; cp -Rv $(RELEASE_FILES) debug/
|
||||
|
||||
floppy: release; dd if=/dev/zero of=$(FLOPPY_IMG) bs=512 count=2880 && mkfs.fat -F12 $(FLOPPY_IMG) && mcopy -i $(FLOPPY_IMG) -s release/* ::
|
||||
|
||||
$(CONVERTER_EXE): $(CONVERTER_SRC); $(CONVERTER_CXX) -o $@ $(CONVERTER_SRC)
|
||||
|
||||
$(EXE): $(OBJ); $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LDLIBS)
|
||||
|
||||
%.o : %.c ; $(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o : %.cpp ; $(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
assets: $(CONVERTER_EXE) $(GFX_ASSETS)
|
||||
|
||||
%.gbm : %.bmp %_m.bmp $(CONVERTER_EXE) ; ./$(CONVERTER_EXE) $@ $^
|
||||
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,35 @@
|
|||
#include "Audio.h"
|
||||
#include "../util/Files.h"
|
||||
|
||||
#include "AudioPlayer.h"
|
||||
|
||||
Audio::Audio() {
|
||||
}
|
||||
|
||||
Audio::Audio(const char *path) {
|
||||
loadFromFile(path);
|
||||
}
|
||||
|
||||
Audio::~Audio() {
|
||||
unload();
|
||||
}
|
||||
|
||||
bool Audio::isValid() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
void Audio::loadFromFile(const char *path) {
|
||||
unload();
|
||||
_length = Files::allocateBufferAndLoadFromFile(path, &_data);
|
||||
}
|
||||
|
||||
void Audio::unload() {
|
||||
if (_data) {
|
||||
if (audioPlayer.isPlaying(*this)) {
|
||||
audioPlayer.stopAudio(*this);
|
||||
}
|
||||
Files::deleteBuffer(_data);
|
||||
_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef GAME_AUDIO_H
|
||||
#define GAME_AUDIO_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class Audio {
|
||||
Audio();
|
||||
explicit Audio(const char *path);
|
||||
~Audio();
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
void loadFromFile(const char* path);
|
||||
void unload();
|
||||
private:
|
||||
friend class AudioPlayer;
|
||||
[[nodiscard]] void *getData() const { return _data; }
|
||||
size_t _length{0};
|
||||
void *_data{nullptr};
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_AUDIO_H
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
#include "AudioPlayer.h"
|
||||
|
||||
#include "../system/Opl.h"
|
||||
#include "../system/Timer.h"
|
||||
|
||||
AudioPlayer audioPlayer;
|
||||
|
||||
void radPlayerWriteReg(void *p, uint16_t reg, uint8_t data) {
|
||||
auto player = static_cast<AudioPlayer *>(p);
|
||||
player->writeOpl(reg, data);
|
||||
}
|
||||
|
||||
void audioPlayerOnTimer() {
|
||||
audioPlayer.onTimer();
|
||||
}
|
||||
|
||||
AudioPlayer::AudioPlayer() {
|
||||
timer.setCallback(audioPlayerOnTimer);
|
||||
}
|
||||
|
||||
AudioPlayer::~AudioPlayer() {
|
||||
timer.setCallback(nullptr);
|
||||
}
|
||||
|
||||
void AudioPlayer::playMusic(Music &music) {
|
||||
stopMusic();
|
||||
|
||||
_currentMusic = &music;
|
||||
_musicPlayer.Init(_currentMusic->getData(), radPlayerWriteReg, this);
|
||||
|
||||
auto hz = _musicPlayer.GetHertz();
|
||||
if (hz < 0) {
|
||||
stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
// Start music playback
|
||||
timer.setFrequency(hz);
|
||||
resumeMusic();
|
||||
}
|
||||
|
||||
void AudioPlayer::stopMusic() {
|
||||
if (!_currentMusic) return;
|
||||
|
||||
_musicPlayer.Stop();
|
||||
_paused = true;
|
||||
_currentMusic = nullptr;
|
||||
}
|
||||
|
||||
void AudioPlayer::pauseMusic() {
|
||||
_paused = true;
|
||||
}
|
||||
|
||||
void AudioPlayer::resumeMusic() {
|
||||
if (!_currentMusic) return;
|
||||
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
void AudioPlayer::playAudio(Audio &audio, int priority, int flags) {
|
||||
if (priority > AUDIO_MAX_PRIORITY) priority = AUDIO_MAX_PRIORITY;
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool AudioPlayer::isPlaying(const Audio &audio) {
|
||||
for (auto &channel : _channels) {
|
||||
if (channel.audio == &audio) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioPlayer::stopAudio(Audio &audio) {
|
||||
for (auto &channel : _channels) {
|
||||
if (channel.audio == &audio) {
|
||||
channel.audio = nullptr;
|
||||
channel.loop = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::stopAllAudio() {
|
||||
for (auto &channel : _channels) {
|
||||
channel.audio = nullptr;
|
||||
channel.loop = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::generateSamples(uint8_t *buffer, size_t size) {
|
||||
}
|
||||
|
||||
bool AudioPlayer::isPlaying(const Music &music) const {
|
||||
return _currentMusic == &music;
|
||||
}
|
||||
|
||||
void AudioPlayer::writeOpl(uint16_t reg, uint8_t data) const {
|
||||
Opl::write(reg, data);
|
||||
}
|
||||
|
||||
void AudioPlayer::onTimer() {
|
||||
if (_paused) return;
|
||||
if (!_currentMusic) return;
|
||||
|
||||
_musicPlayer.Update();
|
||||
}
|
||||
|
||||
void AudioPlayer::generateSamples() {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef GAME_AUDIOPLAYER_H
|
||||
#define GAME_AUDIOPLAYER_H
|
||||
|
||||
#include "Audio.h"
|
||||
#include "Music.h"
|
||||
#include "rad20player.h"
|
||||
|
||||
#define AUDIO_CHANNELS 8
|
||||
#define AUDIO_MAX_PRIORITY 7
|
||||
|
||||
#define AUDIO_PLAY_LOOP 0x01
|
||||
#define AUDIO_PLAY_FIXED_PRIORITY 0x02
|
||||
|
||||
class AudioPlayer {
|
||||
public:
|
||||
AudioPlayer();
|
||||
|
||||
~AudioPlayer();
|
||||
|
||||
void playMusic(Music &music);
|
||||
|
||||
void stopMusic();
|
||||
|
||||
void pauseMusic();
|
||||
|
||||
void resumeMusic();
|
||||
|
||||
void playAudio(Audio &audio, int priority, int flags = 0);
|
||||
|
||||
bool isPlaying(const Audio & audio);
|
||||
|
||||
void stopAudio(Audio &audio);
|
||||
|
||||
void stopAllAudio();
|
||||
|
||||
void generateSamples(uint8_t *buffer, size_t size);
|
||||
private:
|
||||
friend class Music;
|
||||
friend void radPlayerWriteReg(void *p, uint16_t reg, uint8_t data);
|
||||
friend void audioPlayerOnTimer();
|
||||
|
||||
RADPlayer _musicPlayer;
|
||||
Music *_currentMusic{nullptr};
|
||||
bool _paused{true};
|
||||
|
||||
struct {
|
||||
Audio *audio{nullptr};
|
||||
bool loop{false};
|
||||
} _channels[AUDIO_CHANNELS];
|
||||
|
||||
[[nodiscard]] bool isPlaying(const Music &music) const;
|
||||
void writeOpl(uint16_t reg, uint8_t data) const;
|
||||
void onTimer();
|
||||
|
||||
void generateSamples();
|
||||
|
||||
void copySamples();
|
||||
};
|
||||
|
||||
extern AudioPlayer audioPlayer;
|
||||
|
||||
#endif //GAME_AUDIOPLAYER_H
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include "Music.h"
|
||||
|
||||
#include "AudioPlayer.h"
|
||||
#include "../util/Files.h"
|
||||
|
||||
Music::Music() {
|
||||
}
|
||||
|
||||
Music::Music(const char *path) {
|
||||
loadFromFile(path);
|
||||
}
|
||||
|
||||
Music::~Music() {
|
||||
unload();
|
||||
}
|
||||
|
||||
bool Music::isValid() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
void Music::loadFromFile(const char *path) {
|
||||
unload();
|
||||
_length = Files::allocateBufferAndLoadFromFile(path, &_data);
|
||||
}
|
||||
|
||||
void Music::unload() {
|
||||
if (_data) {
|
||||
if (audioPlayer.isPlaying(*this)) {
|
||||
audioPlayer.stopMusic();
|
||||
}
|
||||
Files::deleteBuffer(_data);
|
||||
_length = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef GAME_MUSIC_H
|
||||
#define GAME_MUSIC_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class Music {
|
||||
public:
|
||||
Music();
|
||||
explicit Music(const char *path);
|
||||
~Music();
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
void loadFromFile(const char* path);
|
||||
void unload();
|
||||
private:
|
||||
friend class AudioPlayer;
|
||||
[[nodiscard]] void *getData() const { return _data; }
|
||||
size_t _length{0};
|
||||
void *_data{nullptr};
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_MUSIC_H
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
#ifndef RAD20PLAYER_H
|
||||
#define RAD20PLAYER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//==================================================================================================
|
||||
// RAD player class.
|
||||
//==================================================================================================
|
||||
class RADPlayer {
|
||||
|
||||
// Various constants
|
||||
enum {
|
||||
kTracks = 100,
|
||||
kChannels = 9,
|
||||
kTrackLines = 64,
|
||||
kRiffTracks = 10,
|
||||
kInstruments = 127,
|
||||
|
||||
cmPortamentoUp = 0x1,
|
||||
cmPortamentoDwn = 0x2,
|
||||
cmToneSlide = 0x3,
|
||||
cmToneVolSlide = 0x5,
|
||||
cmVolSlide = 0xA,
|
||||
cmSetVol = 0xC,
|
||||
cmJumpToLine = 0xD,
|
||||
cmSetSpeed = 0xF,
|
||||
cmIgnore = ('I' - 55),
|
||||
cmMultiplier = ('M' - 55),
|
||||
cmRiff = ('R' - 55),
|
||||
cmTranspose = ('T' - 55),
|
||||
cmFeedback = ('U' - 55),
|
||||
cmVolume = ('V' - 55),
|
||||
};
|
||||
|
||||
enum e_Source {
|
||||
SNone, SRiff, SIRiff,
|
||||
};
|
||||
|
||||
enum {
|
||||
fKeyOn = 1 << 0,
|
||||
fKeyOff = 1 << 1,
|
||||
fKeyedOn = 1 << 2,
|
||||
};
|
||||
|
||||
struct CInstrument {
|
||||
uint8_t Feedback[2];
|
||||
uint8_t Panning[2];
|
||||
uint8_t Algorithm;
|
||||
uint8_t Detune;
|
||||
uint8_t Volume;
|
||||
uint8_t RiffSpeed;
|
||||
uint8_t * Riff;
|
||||
uint8_t Operators[4][5];
|
||||
};
|
||||
|
||||
struct CEffects {
|
||||
int8_t PortSlide;
|
||||
int8_t VolSlide;
|
||||
uint16_t ToneSlideFreq;
|
||||
uint8_t ToneSlideOct;
|
||||
uint8_t ToneSlideSpeed;
|
||||
int8_t ToneSlideDir;
|
||||
};
|
||||
|
||||
struct CChannel {
|
||||
uint8_t LastInstrument;
|
||||
CInstrument * Instrument;
|
||||
uint8_t Volume;
|
||||
uint8_t DetuneA;
|
||||
uint8_t DetuneB;
|
||||
uint8_t KeyFlags;
|
||||
uint16_t CurrFreq;
|
||||
int8_t CurrOctave;
|
||||
CEffects FX;
|
||||
struct CRiff {
|
||||
CEffects FX;
|
||||
uint8_t * Track;
|
||||
uint8_t * TrackStart;
|
||||
uint8_t Line;
|
||||
uint8_t Speed;
|
||||
uint8_t SpeedCnt;
|
||||
int8_t TransposeOctave;
|
||||
int8_t TransposeNote;
|
||||
uint8_t LastInstrument;
|
||||
} Riff, IRiff;
|
||||
};
|
||||
|
||||
public:
|
||||
RADPlayer() : Initialised(false) {}
|
||||
void Init(const void *tune, void (*opl3)(void *, uint16_t, uint8_t), void *arg);
|
||||
void Stop();
|
||||
bool Update();
|
||||
int GetHertz() const { return Hertz; }
|
||||
int GetPlayTimeInSeconds() const { return PlayTime / Hertz; }
|
||||
int GetTunePos() const { return Order; }
|
||||
int GetTuneLength() const { return OrderListSize; }
|
||||
int GetTuneLine() const { return Line; }
|
||||
void SetMasterVolume(int vol) { MasterVol = vol; }
|
||||
int GetMasterVolume() const { return MasterVol; }
|
||||
int GetSpeed() const { return Speed; }
|
||||
|
||||
#if RAD_DETECT_REPEATS
|
||||
uint32_t ComputeTotalTime();
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool UnpackNote(uint8_t *&s, uint8_t &last_instrument);
|
||||
uint8_t * GetTrack();
|
||||
uint8_t * SkipToLine(uint8_t *trk, uint8_t linenum, bool chan_riff = false);
|
||||
void PlayLine();
|
||||
void PlayNote(int channum, int8_t notenum, int8_t octave, uint16_t instnum, uint8_t cmd = 0, uint8_t param = 0, e_Source src = SNone, int op = 0);
|
||||
void LoadInstrumentOPL3(int channum);
|
||||
void PlayNoteOPL3(int channum, int8_t octave, int8_t note);
|
||||
void ResetFX(CEffects *fx);
|
||||
void TickRiff(int channum, CChannel::CRiff &riff, bool chan_riff);
|
||||
void ContinueFX(int channum, CEffects *fx);
|
||||
void SetVolume(int channum, uint8_t vol);
|
||||
void GetSlideDir(int channum, CEffects *fx);
|
||||
void LoadInstMultiplierOPL3(int channum, int op, uint8_t mult);
|
||||
void LoadInstVolumeOPL3(int channum, int op, uint8_t vol);
|
||||
void LoadInstFeedbackOPL3(int channum, int which, uint8_t fb);
|
||||
void Portamento(uint16_t channum, CEffects *fx, int8_t amount, bool toneslide);
|
||||
void Transpose(int8_t note, int8_t octave);
|
||||
void SetOPL3(uint16_t reg, uint8_t val) {
|
||||
OPL3Regs[reg] = val;
|
||||
OPL3(OPL3Arg, reg, val);
|
||||
}
|
||||
uint8_t GetOPL3(uint16_t reg) const {
|
||||
return OPL3Regs[reg];
|
||||
}
|
||||
|
||||
void (*OPL3)(void *, uint16_t, uint8_t);
|
||||
void * OPL3Arg;
|
||||
CInstrument Instruments[kInstruments];
|
||||
CChannel Channels[kChannels];
|
||||
uint32_t PlayTime;
|
||||
#if RAD_DETECT_REPEATS
|
||||
uint32_t OrderMap[4];
|
||||
bool Repeating;
|
||||
#endif
|
||||
int16_t Hertz;
|
||||
uint8_t * OrderList;
|
||||
uint8_t * Tracks[kTracks];
|
||||
uint8_t * Riffs[kRiffTracks][kChannels];
|
||||
uint8_t * Track;
|
||||
bool Initialised;
|
||||
uint8_t Speed;
|
||||
uint8_t OrderListSize;
|
||||
uint8_t SpeedCnt;
|
||||
uint8_t Order;
|
||||
uint8_t Line;
|
||||
int8_t Entrances;
|
||||
uint8_t MasterVol;
|
||||
int8_t LineJump;
|
||||
uint8_t OPL3Regs[512];
|
||||
|
||||
// Values exported by UnpackNote()
|
||||
int8_t NoteNum;
|
||||
int8_t OctaveNum;
|
||||
uint8_t InstNum;
|
||||
uint8_t EffectNum;
|
||||
uint8_t Param;
|
||||
bool LastNote;
|
||||
|
||||
static const int8_t NoteSize[];
|
||||
static const uint16_t ChanOffsets3[9], Chn2Offsets3[9];
|
||||
static const uint16_t NoteFreq[];
|
||||
static const uint16_t OpOffsets3[9][4];
|
||||
static const bool AlgCarriers[7][4];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include <cstdio>
|
||||
|
||||
#include "util/Bmp.h"
|
||||
#include "util/Gbm.h"
|
||||
|
||||
void usage() {
|
||||
printf("Usage: gbmconv <gbm output file> <source bitmap> <source mask bitmap>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 4) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *gbmPath = argv[1];
|
||||
char *bmpPath = argv[2];
|
||||
char *maskBmpPath = argv[3];
|
||||
|
||||
auto bitmap = Bmp::loadFromFile(bmpPath);
|
||||
if (bitmap.GetWidth() == 0 || bitmap.GetHeight() == 0) {
|
||||
printf("Unable to load source bitmap\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto maskBitmap = Bmp::loadFromFile(maskBmpPath);
|
||||
if (maskBitmap.GetWidth() == 0 || maskBitmap.GetHeight() == 0) {
|
||||
printf("Unable to load mask bitmap\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (maskBitmap.GetWidth() != bitmap.GetWidth() || maskBitmap.GetHeight() != bitmap.GetHeight()) {
|
||||
printf("Mask bitmap must be the same size as the source bitmap\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a combined bitmap where the most significant bit is a transparency bit
|
||||
auto combined = Bitmap(bitmap.GetWidth(), bitmap.GetHeight());
|
||||
for (auto y = 0u; y < bitmap.GetHeight(); y++) {
|
||||
for (auto x = 0u; x < bitmap.GetWidth(); x++) {
|
||||
auto isTransparent = (maskBitmap.GetPixel(x, y) == 0);
|
||||
auto pv = (isTransparent ? 0x80 : 0x00) | (bitmap.GetPixel(x, y) & 0x7f);
|
||||
combined.SetPixel(x, y, pv);
|
||||
}
|
||||
}
|
||||
for (auto i = 0u; i < 256; i++) {
|
||||
combined.SetPaletteEntry(i, bitmap.GetPaletteEntry(i));
|
||||
}
|
||||
|
||||
Gbm::writeToFile(gbmPath, combined);
|
||||
printf("Wrote %s\n", gbmPath);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#include "Bitmap.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
Bitmap::~Bitmap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(const Bitmap &other) {
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
Bitmap & Bitmap::operator=(const Bitmap &other) {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(Bitmap &&other) noexcept {
|
||||
moveFrom(std::move(other));
|
||||
}
|
||||
|
||||
Bitmap & Bitmap::operator=(Bitmap &&other) noexcept {
|
||||
moveFrom(std::move(other));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(uint16_t width, uint16_t height)
|
||||
: _width(width), _height(height), _data(new uint8_t[width * height]) {
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(uint16_t width, uint16_t height, uint8_t *data) : Bitmap(width, height) {
|
||||
memcpy(_data, data, width * height);
|
||||
}
|
||||
|
||||
void Bitmap::SetPaletteEntry(uint8_t index, Video::PaletteEntry entry) {
|
||||
_pal[index] = entry;
|
||||
}
|
||||
|
||||
Video::PaletteEntry Bitmap::GetPaletteEntry(uint8_t index) const {
|
||||
return _pal[index];
|
||||
}
|
||||
|
||||
void Bitmap::clear() {
|
||||
delete[] _data;
|
||||
_data = nullptr;
|
||||
_width = _height = 0;
|
||||
}
|
||||
|
||||
void Bitmap::copyFrom(const Bitmap &other) {
|
||||
_width = other._width;
|
||||
_height = other._height;
|
||||
_data = new uint8_t[_width * _height];
|
||||
for (auto i = 0; i < 256; i++) _pal[i] = other._pal[i];
|
||||
|
||||
memcpy(_data, other._data, _width * _height);
|
||||
}
|
||||
|
||||
void Bitmap::moveFrom(Bitmap &&other) noexcept {
|
||||
// Clear existing data
|
||||
clear();
|
||||
|
||||
// Copy data from other
|
||||
_data = other._data;
|
||||
_width = other._width;
|
||||
_height = other._height;
|
||||
for (auto i = 0; i < 256; i++) _pal[i] = other._pal[i];
|
||||
|
||||
// Clear other
|
||||
other._data = nullptr;
|
||||
other._width = other._height = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef GAME_BITMAP_H
|
||||
#define GAME_BITMAP_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../system/Video.h"
|
||||
|
||||
class Bitmap {
|
||||
public:
|
||||
Bitmap() = default;
|
||||
|
||||
~Bitmap();
|
||||
|
||||
Bitmap(const Bitmap& other);
|
||||
Bitmap& operator=(const Bitmap& other);
|
||||
|
||||
Bitmap(Bitmap &&other) noexcept ;
|
||||
Bitmap& operator=(Bitmap &&other) noexcept;
|
||||
|
||||
Bitmap(uint16_t width, uint16_t height);
|
||||
|
||||
Bitmap(uint16_t width, uint16_t height, uint8_t* data);
|
||||
|
||||
[[nodiscard]] uint8_t GetPixel(uint16_t x, uint16_t y) const {
|
||||
return _data[y * _width + x];
|
||||
}
|
||||
|
||||
void SetPixel(uint16_t x, uint16_t y, uint8_t value) {
|
||||
_data[y * _width + x] = value;
|
||||
}
|
||||
|
||||
uint8_t &operator[](uint32_t offset) {
|
||||
return _data[offset];
|
||||
}
|
||||
|
||||
const uint8_t &operator[](uint32_t offset) const {
|
||||
return _data[offset];
|
||||
}
|
||||
|
||||
void SetPaletteEntry(uint8_t index, Video::PaletteEntry entry);
|
||||
|
||||
[[nodiscard]] Video::PaletteEntry GetPaletteEntry(uint8_t index) const;
|
||||
|
||||
[[nodiscard]] uint16_t GetWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t GetHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
uint16_t _width{0};
|
||||
uint16_t _height{0};
|
||||
uint8_t *_data{nullptr};
|
||||
|
||||
Video::PaletteEntry _pal[256]{};
|
||||
|
||||
void copyFrom(const Bitmap& other);
|
||||
void moveFrom(Bitmap&& other) noexcept;
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_BITMAP_H
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef GAME_FONT_H
|
||||
#define GAME_FONT_H
|
||||
|
||||
#include "Bitmap.h"
|
||||
|
||||
class Font {
|
||||
public:
|
||||
Font(Bitmap *bitmap, unsigned w, unsigned h, unsigned minCode = 32, unsigned maxCode = 127)
|
||||
: _font(bitmap), _w(w), _h(h), _minCode(minCode), _maxCode(maxCode) {
|
||||
_charsPerRow = _font->GetWidth() / _w;
|
||||
}
|
||||
|
||||
void renderCharAlpha(int c, int x, int y, uint8_t color, uint8_t *fb, unsigned fbWidth, unsigned fbHeight) {
|
||||
if (c < _minCode || c > _maxCode) return;
|
||||
c -= _minCode;
|
||||
|
||||
auto bitmapX = (c % _charsPerRow) * _w;
|
||||
auto bitmapY = (c / _charsPerRow) * _h;
|
||||
|
||||
for (auto charY = 0; charY < _h; charY++) {
|
||||
if (y + charY < 0) continue;
|
||||
if (y + charY >= fbHeight) break;
|
||||
auto yOffset = (y + charY) * fbWidth;
|
||||
|
||||
for (auto charX = 0; charX < _w; charX++) {
|
||||
if (x + charX < 0) continue;
|
||||
if (x + charX >= fbWidth) break;
|
||||
|
||||
auto pv = _font->GetPixel(bitmapX + charX, bitmapY + charY);
|
||||
if (pv & 0x80) continue;
|
||||
|
||||
fb[yOffset + x + charX] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderChar(int c, int x, int y, uint8_t fgColor, uint8_t bgColor, uint8_t *fb, unsigned fbWidth, unsigned fbHeight) {
|
||||
if (c < _minCode || c > _maxCode) return;
|
||||
c -= _minCode;
|
||||
|
||||
auto bitmapX = (c % _charsPerRow) * _w;
|
||||
auto bitmapY = (c / _charsPerRow) * _h;
|
||||
|
||||
for (auto charY = 0; charY < _h; charY++) {
|
||||
if (y + charY < 0) continue;
|
||||
if (y + charY >= fbHeight) break;
|
||||
auto yOffset = (y + charY) * fbWidth;
|
||||
|
||||
for (auto charX = 0; charX < _w; charX++) {
|
||||
if (x + charX < 0) continue;
|
||||
if (x + charX >= fbWidth) break;
|
||||
|
||||
auto pv = _font->GetPixel(bitmapX + charX, bitmapY + charY) & 0x80 ? bgColor : fgColor;
|
||||
fb[yOffset + x + charX] = pv;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
Bitmap *_font;
|
||||
unsigned _w, _h;
|
||||
unsigned _minCode;
|
||||
unsigned _maxCode;
|
||||
unsigned _charsPerRow{0};
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_FONT_H
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef GAME_RECT_H
|
||||
#define GAME_RECT_H
|
||||
|
||||
struct Rect {
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
void clamp(int minX, int minY, int maxX, int maxY) {
|
||||
if (x1 < minX) x1 = minX;
|
||||
if (x2 > maxX) x2 = maxX;
|
||||
if (y1 < minY) y1 = minY;
|
||||
if (y2 > maxY) y2 = maxY;
|
||||
}
|
||||
|
||||
void sort() {
|
||||
if (x1 > x2) {
|
||||
auto x = x1;
|
||||
x1 = x2;
|
||||
x2 = x;
|
||||
}
|
||||
if (y1 > y2) {
|
||||
auto y = y1;
|
||||
y1 = y2;
|
||||
y2 = y;
|
||||
}
|
||||
}
|
||||
|
||||
Rect &operator+=(const Rect &other) {
|
||||
if (other.x1 < x1) x1 = other.x1;
|
||||
if (other.x2 > x2) x2 = other.x2;
|
||||
if (other.y1 < y1) y1 = other.y1;
|
||||
if (other.y2 > y2) y2 = other.y2;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool contains(int x, int y) const {
|
||||
return x >= x1 && y >= y1 && x < x2 && y < y2;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool overlaps(const Rect &other) const {
|
||||
return !(other.x1 > x2 || other.x2 < x1 || other.y1 > y2 || other.y2 < y1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GAME_RECT_H
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef GAME_SPRITE_H
|
||||
#define GAME_SPRITE_H
|
||||
#include "Bitmap.h"
|
||||
|
||||
#define SPR_SUBPX_TO_PX(v) ((v) >= 0 ? ((v) >> 8) : -((-(v)) >> 8))
|
||||
#define SPR_PX_TO_SUBPX(v) ((v) >= 0 ? ((v) << 8) : -((-(v)) << 8))
|
||||
|
||||
class Sprite {
|
||||
public:
|
||||
virtual ~Sprite() = default;
|
||||
|
||||
virtual void Tick() = 0;
|
||||
|
||||
[[nodiscard]] virtual int GetWidth() const {
|
||||
return _w;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual int GetHeight() const {
|
||||
return _h;
|
||||
}
|
||||
|
||||
[[nodiscard]] int GetX() const {
|
||||
return SPR_SUBPX_TO_PX(_sx);
|
||||
}
|
||||
|
||||
[[nodiscard]] int GetY() const {
|
||||
return SPR_SUBPX_TO_PX(_sy);
|
||||
}
|
||||
|
||||
void SetX(int x) {
|
||||
_sx = x >= 0 ? (x << 8) : -((-x) << 8);
|
||||
}
|
||||
|
||||
void SetY(int y) {
|
||||
_sy = y >= 0 ? (y << 8) : -((-y) << 8);
|
||||
}
|
||||
|
||||
[[nodiscard]] Rect GetRect() const {
|
||||
auto x = SPR_SUBPX_TO_PX(_sx), y = SPR_SUBPX_TO_PX(_sy);
|
||||
return { x, y, x + _w, y + _h };
|
||||
}
|
||||
|
||||
void SetPalette(uint8_t palette) { _palette = palette << 4; }
|
||||
|
||||
[[nodiscard]] uint8_t GetPalette() const { return _palette >> 4; }
|
||||
|
||||
[[nodiscard]] Bitmap *GetBitmap() const { return _bitmap; }
|
||||
|
||||
[[nodiscard]] unsigned GetYOffset() const { return _frame * _h; }
|
||||
|
||||
[[nodiscard]] bool isMirroredX() const { return _mirrorX; }
|
||||
|
||||
[[nodiscard]] bool isMirroredY() const { return _mirrorY; }
|
||||
|
||||
protected:
|
||||
Sprite() = default;
|
||||
|
||||
Bitmap *_bitmap{nullptr};
|
||||
uint8_t _palette{0};
|
||||
int _sx{0}, _sy{0};
|
||||
int _w{0}, _h{0};
|
||||
unsigned _frame{0};
|
||||
bool _mirrorX{false};
|
||||
bool _mirrorY{false};
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_SPRITE_H
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
mkdir C:\game\
|
||||
xcopy *.* C:\game\
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#include <SDL_main.h>
|
||||
#endif
|
||||
|
||||
#include "audio/AudioPlayer.h"
|
||||
#include "audio/Music.h"
|
||||
#include "system/Timer.h"
|
||||
#include "system/Video.h"
|
||||
#include "graphics/Bitmap.h"
|
||||
#include "graphics/Font.h"
|
||||
|
||||
#include "scenes/Scene.h"
|
||||
#include "system/init.h"
|
||||
#include "system/Keyboard.h"
|
||||
#include "util/Gbm.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
volatile bool showFps = true;
|
||||
volatile bool running = true;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
System::init();
|
||||
|
||||
srand(time(nullptr));
|
||||
|
||||
DefaultLog.log("Loading music\n");
|
||||
Music music("spiral.rad");
|
||||
if (!music.isValid()) {
|
||||
printf("Unable to load song\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DefaultLog.log("Playing music\n");
|
||||
audioPlayer.playMusic(music);
|
||||
|
||||
DefaultLog.log("Changing video mode\n");
|
||||
video.Enter();
|
||||
|
||||
// Run scenes
|
||||
auto fb = static_cast<uint8_t *>(video.GetFB());
|
||||
|
||||
unsigned fps{0};
|
||||
unsigned frameCount{0};
|
||||
uint32_t fpsTick{0};
|
||||
char fpsDigits[4]{'0', '0', '0', 0};
|
||||
auto fontBitmap = Gbm::loadFromFile("font1.gbm");
|
||||
Font font(&fontBitmap, 7, 9, 32, 127);
|
||||
|
||||
keyboard.setKeyDownHandler([] (unsigned char key) {
|
||||
DefaultLog.log("KeyDown %u (%s)\n", key, keyboard.getKeyName(key));
|
||||
});
|
||||
keyboard.setKeyUpHandler([] (unsigned char key) {
|
||||
DefaultLog.log("KeyUp %u (%s)\n", key, keyboard.getKeyName(key));
|
||||
switch (key) {
|
||||
case KeyEscape:
|
||||
running = false;
|
||||
break;
|
||||
case KeyF:
|
||||
showFps = !showFps;
|
||||
video.UpdateRect({0, 0, 21, 9 });
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
});
|
||||
keyboard.setKeyRepeatHandler([](unsigned char key) {
|
||||
DefaultLog.log("KeyRepeat %u (%s)\n", key, keyboard.getKeyName(key));
|
||||
});
|
||||
|
||||
while (running) {
|
||||
const auto scene = Scenes::getCurrentScene();
|
||||
|
||||
scene->run();
|
||||
|
||||
// Render fps
|
||||
++frameCount;
|
||||
auto ticks = timer.getTicks();
|
||||
if (ticks > fpsTick + 50) {
|
||||
fpsTick = ticks;
|
||||
fps = frameCount;
|
||||
frameCount = 0;
|
||||
fpsDigits[0] = '0' + (fps / 100) % 10;
|
||||
fpsDigits[1] = '0' + (fps / 10) % 10;
|
||||
fpsDigits[2] = '0' + fps % 10;
|
||||
}
|
||||
|
||||
if (showFps) {
|
||||
font.renderChar(fpsDigits[0], 0, 0, 242, 0, fb, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
font.renderChar(fpsDigits[1], 7, 0, 242, 0, fb, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
font.renderChar(fpsDigits[2], 14, 0, 242, 0, fb, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
video.UpdateRect({0, 0, 21, 9 });
|
||||
}
|
||||
|
||||
// Wait for vertical retrace and then copy render buffer to screen
|
||||
video.WaitForVerticalSync();
|
||||
video.Flip();
|
||||
}
|
||||
|
||||
audioPlayer.stopMusic();
|
||||
|
||||
System::terminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
#include "GameScene.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../system/Keyboard.h"
|
||||
#include "../system/Timer.h"
|
||||
#include "../system/Video.h"
|
||||
#include "../util/Bmp.h"
|
||||
#include "../util/Gbm.h"
|
||||
#include "../util/Log.h"
|
||||
|
||||
class TestSprite : public Sprite {
|
||||
public:
|
||||
enum { Width = 20, Height = 16, Frames = 12 };
|
||||
|
||||
explicit TestSprite(Bitmap *image) {
|
||||
_bitmap = image;
|
||||
_w = Width;
|
||||
_h = Height;
|
||||
SetX(10 + rand() % (SCREEN_WIDTH - 20 - Width));
|
||||
SetY(10 + rand() % (SCREEN_HEIGHT - 20 - Height));
|
||||
|
||||
int velXSign = ((rand() & 1) << 1) - 1;
|
||||
int velYSign = ((rand() & 1) << 1) - 1;
|
||||
_vx = (rand() % 128 + 64) * velXSign;
|
||||
_vy = (rand() % 128 + 64) * velYSign;
|
||||
}
|
||||
|
||||
void Tick() override {
|
||||
if (++_ticks >= 15) {
|
||||
_ticks = 0;
|
||||
if (++_frame >= Frames) {
|
||||
_frame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto newX = _sx + _vx;
|
||||
if (newX < 0) {
|
||||
newX = -newX;
|
||||
_vx = -_vx;
|
||||
} else if (newX >= MaxX) {
|
||||
auto d = newX - MaxX;
|
||||
newX = MaxX - d - 1;
|
||||
_vx = -_vx;
|
||||
}
|
||||
_mirrorX = (_vx < 0);
|
||||
|
||||
auto newY = _sy + _vy;
|
||||
if (newY < 0) {
|
||||
newY = -newY;
|
||||
_vy = -_vy;
|
||||
} else if (newY >= MaxY) {
|
||||
auto d = newY - MaxY;
|
||||
newY = MaxY - d - 1;
|
||||
_vy = -_vy;
|
||||
}
|
||||
|
||||
_sx = newX;
|
||||
_sy = newY;
|
||||
}
|
||||
|
||||
protected:
|
||||
int _vx{0}, _vy{0};
|
||||
unsigned _ticks{0};
|
||||
const int MaxX = (SCREEN_WIDTH - Width) << 8;
|
||||
const int MaxY = (SCREEN_HEIGHT - Height) << 8;
|
||||
};
|
||||
|
||||
class PlayerSprite : public Sprite {
|
||||
public:
|
||||
enum { Width = 24, Height = 32, Frames = 4, Speed = 480 };
|
||||
|
||||
explicit PlayerSprite(Bitmap *image) {
|
||||
_bitmap = image;
|
||||
_w = Width;
|
||||
_h = Height;
|
||||
SetX(20);
|
||||
SetY((SCREEN_HEIGHT - Height) / 2);
|
||||
}
|
||||
|
||||
void Tick() override {
|
||||
if (++_ticks >= 15) {
|
||||
_ticks = 0;
|
||||
if (++_animationStep >= Frames) {
|
||||
_animationStep = 0;
|
||||
}
|
||||
|
||||
_frame = _animationMap[_animationStep];
|
||||
}
|
||||
|
||||
if (keyboard.keyState[KeyLeft]) {
|
||||
_sx -= Speed;
|
||||
if (_sx < 0) _sx = 0;
|
||||
}
|
||||
if (keyboard.keyState[KeyRight]) {
|
||||
_sx += Speed;
|
||||
if (_sx > MaxX) _sx = MaxX;
|
||||
}
|
||||
if (keyboard.keyState[KeyUp]) {
|
||||
_sy -= Speed;
|
||||
if (_sy < 0) _sy = 0;
|
||||
}
|
||||
if (keyboard.keyState[KeyDown]) {
|
||||
_sy += Speed;
|
||||
if (_sy > MaxY) _sy = MaxY;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned _ticks{0};
|
||||
unsigned _animationStep = 0;
|
||||
const int MaxX = (SCREEN_WIDTH - Width) << 8;
|
||||
const int MaxY = (SCREEN_HEIGHT - Height) << 8;
|
||||
const unsigned _animationMap[4] = {
|
||||
0, 1, 2, 1
|
||||
};
|
||||
};
|
||||
|
||||
GameScene::GameScene() {
|
||||
|
||||
}
|
||||
|
||||
GameScene::~GameScene() {
|
||||
}
|
||||
|
||||
void GameScene::run() {
|
||||
if (_firstFrame) {
|
||||
Rect bgRect{0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||
for (auto y = 0; y < SCREEN_HEIGHT; y++) {
|
||||
auto yOffset = y * SCREEN_WIDTH;
|
||||
for (auto x = 0; x < SCREEN_WIDTH; x++) {
|
||||
_fb[yOffset + x] = _bg.GetPixel(x, y);
|
||||
}
|
||||
}
|
||||
video.UpdateRect(bgRect);
|
||||
_firstFrame = false;
|
||||
}
|
||||
|
||||
// Redraw background
|
||||
for (auto &sprite : _sprites) {
|
||||
clearSprite(sprite);
|
||||
}
|
||||
clearSprite(_playerSprite);
|
||||
|
||||
// Update and paint all sprites after update
|
||||
for (auto &sprite : _sprites) {
|
||||
sprite->Tick();
|
||||
drawSprite(sprite);
|
||||
}
|
||||
|
||||
_playerSprite->Tick();
|
||||
drawSprite(_playerSprite);
|
||||
}
|
||||
|
||||
void GameScene::enter() {
|
||||
DefaultLog.log("Entering GameScene\n");
|
||||
_fb = static_cast<uint8_t *>(video.GetFB());
|
||||
|
||||
_cow = Gbm::loadFromFile("cow.gbm");
|
||||
_witch = Gbm::loadFromFile("witch.gbm");
|
||||
_bg = Bmp::loadFromFile("bg.bmp");
|
||||
|
||||
_playerSprite = new PlayerSprite(&_witch);
|
||||
_playerSprite->SetPalette(14);
|
||||
|
||||
for (auto &sprite : _sprites) {
|
||||
sprite = new TestSprite(&_cow);
|
||||
sprite->SetPalette(15);
|
||||
}
|
||||
|
||||
// Load bg palette
|
||||
for (auto i = 0u; i < 64; i++) {
|
||||
video.SetPaletteEntry(i, _bg.GetPaletteEntry(i));
|
||||
}
|
||||
|
||||
// Load sprite palette
|
||||
for (auto i = 0u; i < 16; i++) {
|
||||
video.SetPaletteEntry(i + 240, _cow.GetPaletteEntry(i));
|
||||
}
|
||||
|
||||
// Load player sprite palette
|
||||
for (auto i = 0u; i < 16; i++) {
|
||||
video.SetPaletteEntry(i + 224, _witch.GetPaletteEntry(i));
|
||||
}
|
||||
|
||||
_firstFrame = true;
|
||||
}
|
||||
|
||||
void GameScene::exit() {
|
||||
DefaultLog.log("Exiting GameScene\n");
|
||||
|
||||
for (auto &sprite : _sprites) {
|
||||
delete sprite;
|
||||
}
|
||||
|
||||
delete _playerSprite;
|
||||
|
||||
_cow.clear();
|
||||
_bg.clear();
|
||||
_witch.clear();
|
||||
}
|
||||
|
||||
void GameScene::clearSprite(Sprite *sprite) {
|
||||
auto rect = sprite->GetRect();
|
||||
rect.clamp(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
for (auto y = rect.y1; y < rect.y2; y++) {
|
||||
auto yOffset = y * SCREEN_WIDTH;
|
||||
|
||||
for (auto x = rect.x1; x < rect.x2; x++) {
|
||||
_fb[yOffset + x] = _bg.GetPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
video.UpdateRect(rect);
|
||||
}
|
||||
|
||||
void GameScene::drawSprite(Sprite *sprite) {
|
||||
auto rect = sprite->GetRect();
|
||||
rect.clamp(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
auto rx = rect.x1;
|
||||
auto ry = rect.y1;
|
||||
auto rx2 = rect.x2;
|
||||
auto ry2 = rect.y2;
|
||||
|
||||
auto paletteOffset = sprite->GetPalette() << 4;
|
||||
auto bitmap = sprite->GetBitmap();
|
||||
auto syoff = sprite->GetYOffset();
|
||||
|
||||
if (sprite->isMirroredY()) {
|
||||
for (auto y = ry; y < ry2; y++) {
|
||||
auto yOffset = y * SCREEN_WIDTH;
|
||||
auto offy = ry2 - y - 1;
|
||||
|
||||
if (sprite->isMirroredX()) {
|
||||
for (auto x = rx; x < rx2; x++) {
|
||||
auto offx = rx2 - x - 1;
|
||||
|
||||
auto pv = bitmap->GetPixel(offx, offy + syoff);
|
||||
|
||||
if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset;
|
||||
}
|
||||
} else {
|
||||
for (auto x = rx; x < rx2; x++) {
|
||||
auto offx = x - rx;
|
||||
|
||||
auto pv = bitmap->GetPixel(offx, offy + syoff);
|
||||
|
||||
if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto y = ry; y < ry2; y++) {
|
||||
auto yOffset = y * SCREEN_WIDTH;
|
||||
auto offy = y -ry;
|
||||
|
||||
if (sprite->isMirroredX()) {
|
||||
for (auto x = rx; x < rx2; x++) {
|
||||
auto offx = rx2 - x - 1;
|
||||
|
||||
auto pv = bitmap->GetPixel(offx, offy + syoff);
|
||||
|
||||
if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset;
|
||||
}
|
||||
} else {
|
||||
for (auto x = rx; x < rx2; x++) {
|
||||
auto offx = x - rx;
|
||||
|
||||
auto pv = bitmap->GetPixel(offx, offy + syoff);
|
||||
|
||||
if (!(pv & 0x80)) _fb[yOffset + x] = (pv & 0x7f) + paletteOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
video.UpdateRect(rect);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef GAME_GAMESCENE_H
|
||||
#define GAME_GAMESCENE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Scene.h"
|
||||
#include "../graphics/Bitmap.h"
|
||||
#include "../graphics/Sprite.h"
|
||||
|
||||
#define MAX_OBJECTS 16
|
||||
|
||||
class GameScene : public Scene {
|
||||
public:
|
||||
GameScene();
|
||||
~GameScene() override;
|
||||
|
||||
void run() override;
|
||||
|
||||
void enter() override;
|
||||
|
||||
void exit() override;
|
||||
private:
|
||||
uint8_t *_fb{nullptr};
|
||||
|
||||
Bitmap _bg;
|
||||
Bitmap _cow;
|
||||
Bitmap _witch;
|
||||
Sprite *_playerSprite;
|
||||
Sprite *_sprites[MAX_OBJECTS]{nullptr};
|
||||
bool _firstFrame = true;
|
||||
|
||||
void clearSprite(Sprite *sprite);
|
||||
void drawSprite(Sprite *sprite);
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_GAMESCENE_H
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#include "IntroScene.h"
|
||||
|
||||
void IntroScene::run() {
|
||||
Scenes::setScene(Scenes::MainMenuScene);
|
||||
}
|
||||
|
||||
void IntroScene::enter() {
|
||||
}
|
||||
|
||||
void IntroScene::exit() {
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef GAME_INTROSCENE_H
|
||||
#define GAME_INTROSCENE_H
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
|
||||
class IntroScene : public Scene {
|
||||
public:
|
||||
IntroScene() = default;
|
||||
~IntroScene() override = default;
|
||||
|
||||
void run() override;
|
||||
|
||||
void enter() override;
|
||||
|
||||
void exit() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_INTROSCENE_H
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#include "MainMenuScene.h"
|
||||
|
||||
void MainMenuScene::run() {
|
||||
Scenes::setScene(Scenes::GameScene);
|
||||
}
|
||||
|
||||
void MainMenuScene::enter() {
|
||||
}
|
||||
|
||||
void MainMenuScene::exit() {
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef GAME_MAINMENUSCENE_H
|
||||
#define GAME_MAINMENUSCENE_H
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
|
||||
class MainMenuScene : public Scene {
|
||||
public:
|
||||
MainMenuScene() = default;
|
||||
~MainMenuScene() override = default;
|
||||
|
||||
void run() override;
|
||||
|
||||
void enter() override;
|
||||
|
||||
void exit() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_MAINMENUSCENE_H
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include "Scene.h"
|
||||
|
||||
#include "GameScene.h"
|
||||
#include "IntroScene.h"
|
||||
#include "MainMenuScene.h"
|
||||
|
||||
namespace Scenes {
|
||||
static ::IntroScene introScene{};
|
||||
static ::MainMenuScene mainMenuScene{};
|
||||
static ::GameScene gameScene{};
|
||||
|
||||
SceneId currentSceneId = IntroScene;
|
||||
Scene *sceneList[] = {
|
||||
&introScene,
|
||||
&mainMenuScene,
|
||||
&gameScene
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef GAME_SCENE_H
|
||||
#define GAME_SCENE_H
|
||||
|
||||
#include "../graphics/Rect.h"
|
||||
|
||||
class Scene {
|
||||
public:
|
||||
virtual ~Scene() = default;
|
||||
virtual void run() = 0;
|
||||
virtual void enter() = 0;
|
||||
virtual void exit() = 0;
|
||||
|
||||
protected:
|
||||
Scene() = default;
|
||||
};
|
||||
|
||||
|
||||
namespace Scenes {
|
||||
enum SceneId {
|
||||
IntroScene,
|
||||
MainMenuScene,
|
||||
GameScene,
|
||||
};
|
||||
|
||||
extern SceneId currentSceneId;
|
||||
extern Scene *sceneList[];
|
||||
|
||||
inline SceneId setScene(SceneId scene) {
|
||||
auto previousSceneId = currentSceneId;
|
||||
sceneList[currentSceneId]->exit();
|
||||
currentSceneId = scene;
|
||||
sceneList[currentSceneId]->enter();
|
||||
return previousSceneId;
|
||||
}
|
||||
|
||||
inline Scene *getCurrentScene() { return sceneList[currentSceneId]; }
|
||||
inline SceneId getCurrentSceneId() { return currentSceneId; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //GAME_SCENE_H
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#ifdef BUILD_SDL
|
||||
#include "sdl/Keyboard.h"
|
||||
#else
|
||||
#include "dos/Keyboard.h"
|
||||
#endif
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef GAME_OPL_H
|
||||
#define GAME_OPL_H
|
||||
#include <cstdint>
|
||||
|
||||
namespace Opl {
|
||||
void write(uint16_t reg, uint8_t data);
|
||||
}
|
||||
|
||||
#endif //GAME_OPL_H
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GAME_PIC_H
|
||||
#define GAME_PIC_H
|
||||
|
||||
#include "../util/Asm.h"
|
||||
|
||||
namespace Pic {
|
||||
static void clearInterrupt() {
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //GAME_PIC_H
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef GAME_SOUNDBLASTER_H
|
||||
#define GAME_SOUNDBLASTER_H
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
#include <dpmi.h>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
|
||||
#define SB_BUFFER_SIZE 1024
|
||||
#define SB_BUFFERS 32
|
||||
#define SB_DMA_BUFFER_SIZE (SB_BUFFER_SIZE * 4)
|
||||
|
||||
class SoundBlaster {
|
||||
public:
|
||||
SoundBlaster();
|
||||
~SoundBlaster();
|
||||
|
||||
private:
|
||||
friend void soundblasterIsr();
|
||||
void onInterrupt();
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
_go32_dpmi_seginfo _dmaBuffer{};
|
||||
uint8_t (*_buffers)[SB_BUFFER_SIZE]{};
|
||||
uint8_t _dmaPage{0};
|
||||
uint16_t _dmaOffset{0};
|
||||
unsigned _nextBufferReadIndex{0};
|
||||
unsigned _nextBufferWriteIndex{0};
|
||||
#endif
|
||||
};
|
||||
|
||||
extern SoundBlaster soundblaster;
|
||||
|
||||
#endif //GAME_SOUNDBLASTER_H
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef TICKS_H
|
||||
#define TICKS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
#include <dpmi.h>
|
||||
#endif
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
using Callback = void (*)();
|
||||
|
||||
Timer();
|
||||
|
||||
~Timer();
|
||||
|
||||
void setFrequency(uint16_t freq);
|
||||
|
||||
void setDivider(uint16_t div);
|
||||
|
||||
Callback setCallback(Callback);
|
||||
|
||||
[[nodiscard]] uint32_t getTicks() const;
|
||||
|
||||
[[nodiscard]] uint16_t getFrequency() const;
|
||||
|
||||
private:
|
||||
friend void timerISR();
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
_go32_dpmi_seginfo _oldIsr{}, _newIsr{};
|
||||
#endif
|
||||
|
||||
uint32_t _ticks{0};
|
||||
uint32_t _elapsed{0};
|
||||
uint16_t _div{0};
|
||||
uint16_t _freq{0};
|
||||
|
||||
void (*_callback)(){nullptr};
|
||||
|
||||
void update();
|
||||
};
|
||||
|
||||
extern Timer timer;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef VIDEO_H
|
||||
#define VIDEO_H
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#include <SDL.h>
|
||||
#include <chrono>
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include "../graphics/Rect.h"
|
||||
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 200
|
||||
#define MAX_UPDATE_RECT_INDEX 255
|
||||
|
||||
class Video {
|
||||
public:
|
||||
struct PaletteEntry {
|
||||
uint8_t r{0}, g{0}, b{0};
|
||||
};
|
||||
|
||||
Video();
|
||||
~Video();
|
||||
|
||||
void Enter();
|
||||
void Exit();
|
||||
|
||||
void SetPaletteEntry(uint8_t index, PaletteEntry entry);
|
||||
PaletteEntry GetPaletteEntry(uint8_t index);
|
||||
|
||||
void SetPaletteEntry(uint8_t index, PaletteEntry *entry);
|
||||
void GetPaletteEntry(uint8_t index, PaletteEntry *entry);
|
||||
|
||||
void *GetFB();
|
||||
|
||||
void WaitForVerticalSync();
|
||||
|
||||
void UpdateRect(const Rect &rect);
|
||||
void Flip();
|
||||
private:
|
||||
uint8_t _oldMode{0};
|
||||
PaletteEntry _oldPalette[256]{};
|
||||
#ifdef BUILD_SDL
|
||||
SDL_Window *_window;
|
||||
SDL_Surface *_windowSurface;
|
||||
SDL_Surface *_fb;
|
||||
PaletteEntry _palette[256]{};
|
||||
std::chrono::steady_clock::time_point _lastUpdate{std::chrono::steady_clock::now()};
|
||||
#else
|
||||
uint8_t *_fb{nullptr};
|
||||
#endif
|
||||
uint8_t _renderBuffer[SCREEN_WIDTH*SCREEN_HEIGHT]{};
|
||||
Rect _updatedRects[MAX_UPDATE_RECT_INDEX+1];
|
||||
unsigned _updateRectIndex{0};
|
||||
|
||||
void SetMode(uint8_t mode);
|
||||
uint8_t GetMode();
|
||||
};
|
||||
|
||||
extern Video video;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
#include "../Keyboard.h"
|
||||
|
||||
#include <go32.h>
|
||||
|
||||
#include "../Pic.h"
|
||||
|
||||
#define PIC
|
||||
#define KEYB_DATA 0x60
|
||||
|
||||
Keyboard keyboard;
|
||||
|
||||
static const char *keyNames[] = {
|
||||
"<unknown:00>",
|
||||
"KeyEscape", // = 0x01,
|
||||
"Key1", // = 0x02,
|
||||
"Key2", // = 0x03,
|
||||
"Key3", // = 0x04,
|
||||
"Key4", // = 0x05,
|
||||
"Key5", // = 0x06,
|
||||
"Key6", // = 0x07,
|
||||
"Key7", // = 0x08,
|
||||
"Key8", // = 0x09,
|
||||
"Key9", // = 0x0a,
|
||||
"Key0", // = 0x0b,
|
||||
"KeyMinus", // = 0x0c,
|
||||
"KeyEqual", // = 0x0d,
|
||||
"KeyBackspace", // = 0x0e,
|
||||
"KeyTab", // = 0x0f,
|
||||
|
||||
"KeyQ", // = 0x10,
|
||||
"KeyW", // = 0x11,
|
||||
"KeyE", // = 0x12,
|
||||
"KeyR", // = 0x13,
|
||||
"KeyT", // = 0x14,
|
||||
"KeyY", // = 0x15,
|
||||
"KeyU", // = 0x16,
|
||||
"KeyI", // = 0x17,
|
||||
"KeyO", // = 0x18,
|
||||
"KeyP", // = 0x19,
|
||||
"KeyBracketLeft", // = 0x1a,
|
||||
"KeyBracketRight", // = 0x1b,
|
||||
"KeyEnter", // = 0x1c,
|
||||
"KeyLeftCtrl", // = 0x1d,
|
||||
"KeyA", // = 0x1e,
|
||||
"KeyS", // = 0x1f,
|
||||
|
||||
"KeyD", // = 0x20,
|
||||
"KeyF", // = 0x21,
|
||||
"KeyG", // = 0x22,
|
||||
"KeyH", // = 0x23,
|
||||
"KeyJ", // = 0x24,
|
||||
"KeyK", // = 0x25,
|
||||
"KeyL", // = 0x26,
|
||||
"KeySemicolon", // = 0x27,
|
||||
"KeyApostrophe", // = 0x28,
|
||||
"KeyBacktick", // = 0x29,
|
||||
"KeyLeftShift", // = 0x2a,
|
||||
"KeyBackslash", // = 0x2b,
|
||||
"KeyZ", // = 0x2c,
|
||||
"KeyX", // = 0x2d,
|
||||
"KeyC", // = 0x2e,
|
||||
"KeyV", // = 0x2f,
|
||||
|
||||
"KeyB", // = 0x30,
|
||||
"KeyN", // = 0x31,
|
||||
"KeyM", // = 0x32,
|
||||
"KeyComma", // = 0x33,
|
||||
"KeyPeriod", // = 0x34,
|
||||
"KeySlash", // = 0x35,
|
||||
"KeyRightShift", // = 0x36,
|
||||
"KeyKeypadMultiply", // = 0x37,
|
||||
"KeyLeftAlt", // = 0x38,
|
||||
"KeySpace", // = 0x39,
|
||||
"KeyCapsLock", // = 0x3a,
|
||||
"KeyF1", // = 0x3b,
|
||||
"KeyF2", // = 0x3c,
|
||||
"KeyF3", // = 0x3d,
|
||||
"KeyF4", // = 0x3e,
|
||||
"KeyF5", // = 0x3f,
|
||||
|
||||
"KeyF6", // = 0x40,
|
||||
"KeyF7", // = 0x41,
|
||||
"KeyF8", // = 0x42,
|
||||
"KeyF9", // = 0x43,
|
||||
"KeyF10", // = 0x44,
|
||||
"KeyNumLock", // = 0x45,
|
||||
"KeyScrollLock", // = 0x46,
|
||||
"KeyKeypad7", // = 0x47,
|
||||
"KeyKeypad8", // = 0x48,
|
||||
"KeyKeypad9", // = 0x49,
|
||||
"KeyKeypadMinus", // = 0x4a,
|
||||
"KeyKeypad4", // = 0x4b,
|
||||
"KeyKeypad5", // = 0x4c,
|
||||
"KeyKeypad6", // = 0x4d,
|
||||
"KeyKeypadPlus", // = 0x4e,
|
||||
"KeyKeypad1", // = 0x4f,
|
||||
|
||||
"KeyKeypad2", // = 0x50,
|
||||
"KeyKeypad3", // = 0x51,
|
||||
"KeyKeypad0", // = 0x52,
|
||||
"KeyKeypadPeriod", // = 0x53,
|
||||
"<unknown:54>",
|
||||
"<unknown:55>",
|
||||
"<unknown:56>",
|
||||
"KeyF11", // = 0x57,
|
||||
"KeyF12", // = 0x58,
|
||||
"<unknown:59>",
|
||||
"<unknown:5a>",
|
||||
"<unknown:5b>",
|
||||
"<unknown:5c>",
|
||||
"<unknown:5d>",
|
||||
"<unknown:5e>",
|
||||
"<unknown:5f>",
|
||||
|
||||
"<unknown:60>",
|
||||
"<unknown:61>",
|
||||
"<unknown:62>",
|
||||
"<unknown:63>",
|
||||
"<unknown:64>",
|
||||
"<unknown:65>",
|
||||
"<unknown:66>",
|
||||
"<unknown:67>",
|
||||
"<unknown:68>",
|
||||
"<unknown:69>",
|
||||
"<unknown:6a>",
|
||||
"<unknown:6b>",
|
||||
"<unknown:6c>",
|
||||
"<unknown:6d>",
|
||||
"<unknown:6e>",
|
||||
"<unknown:6f>",
|
||||
|
||||
"<unknown:70>",
|
||||
"<unknown:71>",
|
||||
"<unknown:72>",
|
||||
"<unknown:73>",
|
||||
"<unknown:74>",
|
||||
"<unknown:75>",
|
||||
"<unknown:76>",
|
||||
"<unknown:77>",
|
||||
"<unknown:78>",
|
||||
"<unknown:79>",
|
||||
"<unknown:7a>",
|
||||
"<unknown:7b>",
|
||||
"<unknown:7c>",
|
||||
"<unknown:7d>",
|
||||
"<unknown:7e>",
|
||||
"<unknown:7f>",
|
||||
|
||||
"<unknown:80>",
|
||||
"<unknown:81>",
|
||||
"<unknown:82>",
|
||||
"<unknown:83>",
|
||||
"<unknown:84>",
|
||||
"<unknown:85>",
|
||||
"<unknown:86>",
|
||||
"<unknown:87>",
|
||||
"<unknown:88>",
|
||||
"<unknown:89>",
|
||||
"<unknown:8a>",
|
||||
"<unknown:8b>",
|
||||
"<unknown:8c>",
|
||||
"<unknown:8d>",
|
||||
"<unknown:8e>",
|
||||
"<unknown:8f>",
|
||||
|
||||
"KeyMediaPrev", // = 0x90,
|
||||
"<unknown:91>",
|
||||
"<unknown:92>",
|
||||
"<unknown:93>",
|
||||
"<unknown:94>",
|
||||
"<unknown:95>",
|
||||
"<unknown:96>",
|
||||
"<unknown:97>",
|
||||
"<unknown:98>",
|
||||
"KeyMediaNext", // = 0x99,
|
||||
"<unknown:9a>",
|
||||
"<unknown:9b>",
|
||||
"KeyKeypadEnter", // = 0x9c,
|
||||
"KeyRightControl", // = 0x9d,
|
||||
"<unknown:9e>",
|
||||
"<unknown:9f>",
|
||||
|
||||
"KeyMediaMute", // = 0xa0,
|
||||
"KeyMediaCalculator", // = 0xa1,
|
||||
"KeyMediaPlay", // = 0xa2,
|
||||
"<unknown:a3>",
|
||||
"KeyMediaStop", // = 0xa4,
|
||||
"<unknown:a5>",
|
||||
"<unknown:a6>",
|
||||
"<unknown:a7>",
|
||||
"<unknown:a8>",
|
||||
"<unknown:a9>",
|
||||
"<unknown:aa>",
|
||||
"<unknown:ab>",
|
||||
"<unknown:ac>",
|
||||
"<unknown:ad>",
|
||||
"KeyMediaVolumeDown", // = 0xae,
|
||||
"<unknown:af>",
|
||||
|
||||
"KeyMediaVolumeUp", // = 0xb0,
|
||||
"<unknown:b1>",
|
||||
"KeyMediaWww", // = 0xb2,
|
||||
"<unknown:b3>",
|
||||
"<unknown:b4>",
|
||||
"KeyKeypadDivide", // = 0xb5,
|
||||
"<unknown:b6>",
|
||||
"<unknown:b7>",
|
||||
"KeyRightAlt", // = 0xb8,
|
||||
"<unknown:b9>",
|
||||
"<unknown:ba>",
|
||||
"<unknown:bb>",
|
||||
"<unknown:bc>",
|
||||
"<unknown:bd>",
|
||||
"<unknown:be>",
|
||||
"<unknown:bf>",
|
||||
|
||||
"<unknown:c0>",
|
||||
"<unknown:c1>",
|
||||
"<unknown:c2>",
|
||||
"<unknown:c3>",
|
||||
"<unknown:c4>",
|
||||
"<unknown:c5>",
|
||||
"<unknown:c6>",
|
||||
"KeyHome", // = 0xc7,
|
||||
"KeyUp", // = 0xc8,
|
||||
"KeyPageUp", // = 0xc9,
|
||||
"<unknown:ca>",
|
||||
"KeyLeft", // = 0xcb,
|
||||
"<unknown:cc>",
|
||||
"KeyRight", // = 0xcd,
|
||||
"<unknown:ce>",
|
||||
"KeyEnd", // = 0xcf,
|
||||
|
||||
"KeyDown", // = 0xd0,
|
||||
"KeyPageDown", // = 0xd1,
|
||||
"KeyInsert", // = 0xd2,
|
||||
"KeyDelete", // = 0xd3,
|
||||
"<unknown:d4>",
|
||||
"<unknown:d5>",
|
||||
"<unknown:d6>",
|
||||
"<unknown:d7>",
|
||||
"<unknown:d8>",
|
||||
"<unknown:d9>",
|
||||
"<unknown:da>",
|
||||
"KeyLeftGui", // = 0xdb,
|
||||
"KeyRightGui", // = 0xdc,
|
||||
"KeyApps", // = 0xdd,
|
||||
"KeyAcpiPower", // = 0xde,
|
||||
"KeyAcpiSleep", // = 0xdf,
|
||||
|
||||
"<unknown:e0>",
|
||||
"<unknown:e1>",
|
||||
"<unknown:e2>",
|
||||
"KeyAcpiWake", // = 0xe3,
|
||||
"<unknown:e4>",
|
||||
"KeyMediaWwwSearch", // = 0xe5,
|
||||
"KeyMediaWwwFavorites", // = 0xe6,
|
||||
"KeyMediaWwwRefresh", // = 0xe7,
|
||||
"KeyMediaWwwStop", // = 0xe8,
|
||||
"KeyMediaWwwForward", // = 0xe9,
|
||||
"KeyMediaWwwBack", // = 0xea,
|
||||
"KeyMediaMyComputer", // = 0xeb,
|
||||
"KeyMediaEmail", // = 0xec,
|
||||
"KeyMediaSelect", // = 0xed,
|
||||
"<unknown:ee>",
|
||||
"<unknown:ef>",
|
||||
|
||||
"<unknown:f0>",
|
||||
"<unknown:f1>",
|
||||
"<unknown:f2>",
|
||||
"<unknown:f3>",
|
||||
"<unknown:f4>",
|
||||
"<unknown:f5>",
|
||||
"<unknown:f6>",
|
||||
"<unknown:f7>",
|
||||
"<unknown:f8>",
|
||||
"<unknown:f9>",
|
||||
"<unknown:fa>",
|
||||
"<unknown:fb>",
|
||||
"<unknown:fc>",
|
||||
"<unknown:fd>",
|
||||
"KeyPrint", // = 0xfe,
|
||||
"KeyPause", // = 0xff,
|
||||
};
|
||||
|
||||
void keyboardIsr() {
|
||||
keyboard.Isr();
|
||||
}
|
||||
|
||||
Keyboard::Keyboard() {
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(9, &_oldIsr);
|
||||
|
||||
_newIsr.pm_offset = (int)keyboardIsr;
|
||||
_newIsr.pm_selector = _go32_my_cs();
|
||||
_go32_dpmi_allocate_iret_wrapper(&_newIsr);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(9, &_newIsr);
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard() {
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(9, &_oldIsr);
|
||||
_go32_dpmi_free_iret_wrapper(&_newIsr);
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyUpHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyUpHandler;
|
||||
_keyUpHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyDownHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyDownHandler;
|
||||
_keyDownHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyRepeatHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyRepeatHandler;
|
||||
_keyRepeatHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
const char *Keyboard::getKeyName(unsigned char keyCode) {
|
||||
return keyNames[keyCode];
|
||||
}
|
||||
|
||||
void Keyboard::Isr() {
|
||||
auto code = inb(KEYB_DATA);
|
||||
switch (_state) {
|
||||
case Start:
|
||||
if (code == 0xe0) {
|
||||
_state = Extended;
|
||||
break;
|
||||
}
|
||||
if (code == 0xe1) {
|
||||
_state = PauseBegin;
|
||||
break;
|
||||
}
|
||||
if (code & 0x80) {
|
||||
_state = Start;
|
||||
keyUp(code & 0x7f);
|
||||
} else {
|
||||
_state = Start;
|
||||
keyDown(code & 0x7f);
|
||||
}
|
||||
break;
|
||||
case Extended:
|
||||
if (code == 0x2a) {
|
||||
_state = PrintPressed1;
|
||||
break;
|
||||
}
|
||||
if (code == 0xb7) {
|
||||
_state = PrintReleased1;
|
||||
break;
|
||||
}
|
||||
if (code & 0x80) {
|
||||
_state = Start;
|
||||
keyUp(0x80 + (code & 0x7f));
|
||||
} else {
|
||||
_state = Start;
|
||||
keyDown(0x80 + code);
|
||||
}
|
||||
break;
|
||||
case PauseBegin:
|
||||
if (code == 0x1d) {
|
||||
_state = PausePressed1;
|
||||
break;
|
||||
}
|
||||
if (code == 0x9d) {
|
||||
_state = PauseReleased1;
|
||||
break;
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PausePressed1:
|
||||
if (code == 45) {
|
||||
keyDown(KeyPause);
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PauseReleased1:
|
||||
if (code == 0xc5) {
|
||||
keyUp(KeyPause);
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PrintPressed1:
|
||||
if (code == 0xe0) {
|
||||
_state = PrintPressed2;
|
||||
break;
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PrintPressed2:
|
||||
if (code == 0x37) {
|
||||
keyDown(KeyPrint);
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PrintReleased1:
|
||||
if (code == 0xe0) {
|
||||
_state = PrintReleased2;
|
||||
break;
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
case PrintReleased2:
|
||||
if (code == 0xaa) {
|
||||
keyUp(KeyPrint);
|
||||
}
|
||||
_state = Start;
|
||||
break;
|
||||
}
|
||||
|
||||
Pic::clearInterrupt();
|
||||
}
|
||||
|
||||
void Keyboard::keyDown(unsigned char c) {
|
||||
if (keyState[c]) {
|
||||
if (_keyRepeatHandler) _keyRepeatHandler(c);
|
||||
} else {
|
||||
keyState[c] = true;
|
||||
if (_keyDownHandler) _keyDownHandler(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::keyUp(unsigned char c) {
|
||||
keyState[c] = false;
|
||||
if (_keyUpHandler) _keyUpHandler(c);
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#ifndef GAME_KEYBOARD_H
|
||||
#define GAME_KEYBOARD_H
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
#include <dpmi.h>
|
||||
#endif
|
||||
|
||||
#define KEY_MAX 256
|
||||
|
||||
enum {
|
||||
KeyEscape = 0x01,
|
||||
Key1 = 0x02,
|
||||
Key2 = 0x03,
|
||||
Key3 = 0x04,
|
||||
Key4 = 0x05,
|
||||
Key5 = 0x06,
|
||||
Key6 = 0x07,
|
||||
Key7 = 0x08,
|
||||
Key8 = 0x09,
|
||||
Key9 = 0x0a,
|
||||
Key0 = 0x0b,
|
||||
KeyMinus = 0x0c,
|
||||
KeyEqual = 0x0d,
|
||||
KeyBackspace = 0x0e,
|
||||
KeyTab = 0x0f,
|
||||
KeyQ = 0x10,
|
||||
KeyW = 0x11,
|
||||
KeyE = 0x12,
|
||||
KeyR = 0x13,
|
||||
KeyT = 0x14,
|
||||
KeyY = 0x15,
|
||||
KeyU = 0x16,
|
||||
KeyI = 0x17,
|
||||
KeyO = 0x18,
|
||||
KeyP = 0x19,
|
||||
KeyBracketLeft = 0x1a,
|
||||
KeyBracketRight = 0x1b,
|
||||
KeyEnter = 0x1c,
|
||||
KeyLeftCtrl = 0x1d,
|
||||
KeyA = 0x1e,
|
||||
KeyS = 0x1f,
|
||||
KeyD = 0x20,
|
||||
KeyF = 0x21,
|
||||
KeyG = 0x22,
|
||||
KeyH = 0x23,
|
||||
KeyJ = 0x24,
|
||||
KeyK = 0x25,
|
||||
KeyL = 0x26,
|
||||
KeySemicolon = 0x27,
|
||||
KeyApostrophe = 0x28,
|
||||
KeyBacktick = 0x29,
|
||||
KeyLeftShift = 0x2a,
|
||||
KeyBackslash = 0x2b,
|
||||
KeyZ = 0x2c,
|
||||
KeyX = 0x2d,
|
||||
KeyC = 0x2e,
|
||||
KeyV = 0x2f,
|
||||
KeyB = 0x30,
|
||||
KeyN = 0x31,
|
||||
KeyM = 0x32,
|
||||
KeyComma = 0x33,
|
||||
KeyPeriod = 0x34,
|
||||
KeySlash = 0x35,
|
||||
KeyRightShift = 0x36,
|
||||
KeyKeypadMultiply = 0x37,
|
||||
KeyLeftAlt = 0x38,
|
||||
KeySpace = 0x39,
|
||||
KeyCapsLock = 0x3a,
|
||||
KeyF1 = 0x3b,
|
||||
KeyF2 = 0x3c,
|
||||
KeyF3 = 0x3d,
|
||||
KeyF4 = 0x3e,
|
||||
KeyF5 = 0x3f,
|
||||
KeyF6 = 0x40,
|
||||
KeyF7 = 0x41,
|
||||
KeyF8 = 0x42,
|
||||
KeyF9 = 0x43,
|
||||
KeyF10 = 0x44,
|
||||
KeyNumLock = 0x45,
|
||||
KeyScrollLock = 0x46,
|
||||
KeyKeypad7 = 0x47,
|
||||
KeyKeypad8 = 0x48,
|
||||
KeyKeypad9 = 0x49,
|
||||
KeyKeypadMinus = 0x4a,
|
||||
KeyKeypad4 = 0x4b,
|
||||
KeyKeypad5 = 0x4c,
|
||||
KeyKeypad6 = 0x4d,
|
||||
KeyKeypadPlus = 0x4e,
|
||||
KeyKeypad1 = 0x4f,
|
||||
KeyKeypad2 = 0x50,
|
||||
KeyKeypad3 = 0x51,
|
||||
KeyKeypad0 = 0x52,
|
||||
KeyKeypadPeriod = 0x53,
|
||||
KeyF11 = 0x57,
|
||||
KeyF12 = 0x58,
|
||||
KeyMediaPrev = 0x90,
|
||||
KeyMediaNext = 0x99,
|
||||
KeyKeypadEnter = 0x9c,
|
||||
KeyRightControl = 0x9d,
|
||||
KeyMediaMute = 0xa0,
|
||||
KeyMediaCalculator = 0xa1,
|
||||
KeyMediaPlay = 0xa2,
|
||||
KeyMediaStop = 0xa4,
|
||||
KeyMediaVolumeDown = 0xae,
|
||||
KeyMediaVolumeUp = 0xb0,
|
||||
KeyMediaWww = 0xb2,
|
||||
KeyKeypadDivide = 0xb5,
|
||||
KeyRightAlt = 0xb8,
|
||||
KeyHome = 0xc7,
|
||||
KeyUp = 0xc8,
|
||||
KeyPageUp = 0xc9,
|
||||
KeyLeft = 0xcb,
|
||||
KeyRight = 0xcd,
|
||||
KeyEnd = 0xcf,
|
||||
KeyDown = 0xd0,
|
||||
KeyPageDown = 0xd1,
|
||||
KeyInsert = 0xd2,
|
||||
KeyDelete = 0xd3,
|
||||
KeyLeftGui = 0xdb,
|
||||
KeyRightGui = 0xdc,
|
||||
KeyApps = 0xdd,
|
||||
KeyAcpiPower = 0xde,
|
||||
KeyAcpiSleep = 0xdf,
|
||||
KeyAcpiWake = 0xe3,
|
||||
KeyMediaWwwSearch = 0xe5,
|
||||
KeyMediaWwwFavorites = 0xe6,
|
||||
KeyMediaWwwRefresh = 0xe7,
|
||||
KeyMediaWwwStop = 0xe8,
|
||||
KeyMediaWwwForward = 0xe9,
|
||||
KeyMediaWwwBack = 0xea,
|
||||
KeyMediaMyComputer = 0xeb,
|
||||
KeyMediaEmail = 0xec,
|
||||
KeyMediaSelect = 0xed,
|
||||
KeyPrint = 0xfe,
|
||||
KeyPause = 0xff,
|
||||
};
|
||||
|
||||
class Keyboard {
|
||||
public:
|
||||
using KeyHandleFunction = void (*)(unsigned char);
|
||||
|
||||
Keyboard();
|
||||
~Keyboard();
|
||||
|
||||
KeyHandleFunction setKeyUpHandler(KeyHandleFunction handler);
|
||||
KeyHandleFunction setKeyDownHandler(KeyHandleFunction handler);
|
||||
KeyHandleFunction setKeyRepeatHandler(KeyHandleFunction handler);
|
||||
|
||||
bool keyState[KEY_MAX]{};
|
||||
|
||||
const char *getKeyName(unsigned char keyCode);
|
||||
private:
|
||||
friend void keyboardIsr();
|
||||
void Isr();
|
||||
enum State {
|
||||
Start,
|
||||
Extended,
|
||||
PauseBegin,
|
||||
PausePressed1,
|
||||
PauseReleased1,
|
||||
PrintPressed1,
|
||||
PrintPressed2,
|
||||
PrintReleased1,
|
||||
PrintReleased2,
|
||||
};
|
||||
State _state;
|
||||
KeyHandleFunction _keyDownHandler{nullptr}, _keyUpHandler{nullptr}, _keyRepeatHandler{nullptr};
|
||||
|
||||
void keyDown(unsigned char c);
|
||||
|
||||
void keyUp(unsigned char c);
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
#else
|
||||
_go32_dpmi_seginfo _oldIsr, _newIsr;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern Keyboard keyboard;
|
||||
|
||||
#endif //GAME_KEYBOARD_H
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#include "../Opl.h"
|
||||
#include "../../util/Asm.h"
|
||||
|
||||
#define OPL_REG 0x388
|
||||
|
||||
namespace Opl {
|
||||
void write(uint16_t reg, uint8_t data) {
|
||||
if (reg >= 0x100) {
|
||||
outb(OPL_REG + 2, reg & 0xff);
|
||||
outb(OPL_REG + 3, data);
|
||||
} else {
|
||||
outb(OPL_REG, reg);
|
||||
outb(OPL_REG + 1, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include "../SoundBlaster.h"
|
||||
|
||||
#include <go32.h>
|
||||
|
||||
SoundBlaster soundblaster;
|
||||
|
||||
void soundblasterIsr() {
|
||||
soundblaster.onInterrupt();
|
||||
}
|
||||
|
||||
SoundBlaster::SoundBlaster() {
|
||||
// Allocate twice the amount needed and select one half depending on whether it crosses a 64k boundary
|
||||
_dmaBuffer.size = (SB_DMA_BUFFER_SIZE + 15) >> (4-1);
|
||||
_go32_dpmi_allocate_dos_memory(&_dmaBuffer);
|
||||
|
||||
auto physFirst = (_dmaBuffer.rm_segment << 4) + _dmaBuffer.rm_offset;
|
||||
auto physSecond = physFirst + SB_DMA_BUFFER_SIZE;
|
||||
auto pageFirst = physFirst >> 16;
|
||||
auto pageSecond = physSecond >> 16;
|
||||
|
||||
if (pageFirst == pageSecond) {
|
||||
// Use first half
|
||||
_buffers = reinterpret_cast<decltype(_buffers)>(physFirst);
|
||||
_dmaPage = pageFirst;
|
||||
_dmaOffset = physFirst & 0xFFFF;
|
||||
} else {
|
||||
// Use second half
|
||||
_buffers = reinterpret_cast<decltype(_buffers)>(physSecond);
|
||||
_dmaPage = pageSecond;
|
||||
_dmaOffset = physSecond & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
SoundBlaster::~SoundBlaster() {
|
||||
_go32_dpmi_free_dos_memory(&_dmaBuffer);
|
||||
}
|
||||
|
||||
void SoundBlaster::onInterrupt() {
|
||||
// No data available - should not happen, but let's force generate a block
|
||||
if (_nextBufferReadIndex == _nextBufferWriteIndex) {
|
||||
generateSamples();
|
||||
}
|
||||
|
||||
dosmemput(_buffers, SB_BUFFER_SIZE, (_dmaBuffer.rm_segment << 4) + _nextBufferReadIndex * SB_BUFFER_SIZE);
|
||||
_nextBufferReadIndex = (_nextBufferReadIndex + 1) & 3;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#include <go32.h>
|
||||
|
||||
#include "../Timer.h"
|
||||
|
||||
#include "../Pic.h"
|
||||
#include "../../util/Asm.h"
|
||||
|
||||
#define PIT_FREQ 1193181
|
||||
#define PIT_MODE_CH0 0x00
|
||||
#define PIT_MODE_CH1 0x40
|
||||
#define PIT_MODE_CH2 0x80
|
||||
#define PIT_MODE_ACCESS_LO 0x10
|
||||
#define PIT_MODE_ACCESS_HI 0x20
|
||||
#define PIT_MODE_ACCESS_LOHI 0x30
|
||||
#define PIT_MODE_M0 0x00
|
||||
#define PIT_MODE_M1 0x02
|
||||
#define PIT_MODE_M2 0x04
|
||||
#define PIT_MODE_M3 0x06
|
||||
#define PIT_MODE_M4 0x08
|
||||
#define PIT_MODE_M5 0x0a
|
||||
#define PIT_MODE_BIN 0x00
|
||||
#define PIT_MODE_BCD 0x01
|
||||
|
||||
#define PIT_REG_CH0 0x40
|
||||
#define PIT_REG_CH1 0x41
|
||||
#define PIT_REG_CH2 0x42
|
||||
#define PIT_REG_MODE 0x43
|
||||
|
||||
Timer timer;
|
||||
|
||||
void timerISR() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
Timer::Timer() {
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(8, &_oldIsr);
|
||||
|
||||
_newIsr.pm_offset = reinterpret_cast<int>(timerISR);
|
||||
_newIsr.pm_selector = _go32_my_cs();
|
||||
_go32_dpmi_allocate_iret_wrapper(&_newIsr);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(8, &_newIsr);
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
setDivider(65535);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(8, &_oldIsr);
|
||||
_go32_dpmi_free_iret_wrapper(&_newIsr);
|
||||
}
|
||||
|
||||
void Timer::update() {
|
||||
_ticks++;
|
||||
|
||||
if (_callback) _callback();
|
||||
|
||||
_elapsed += _div;
|
||||
if (_elapsed >= 65535) {
|
||||
_elapsed -= 65535;
|
||||
// TODO call old isr
|
||||
// Documentation is kind of nonexistant so we will not call the handler for now
|
||||
Pic::clearInterrupt();
|
||||
} else {
|
||||
Pic::clearInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Timer::getTicks() const {
|
||||
return _ticks;
|
||||
}
|
||||
|
||||
uint16_t Timer::getFrequency() const {
|
||||
return _freq;
|
||||
}
|
||||
|
||||
void Timer::setFrequency(uint16_t freq) {
|
||||
_freq = freq;
|
||||
setDivider(PIT_FREQ / freq);
|
||||
}
|
||||
|
||||
void Timer::setDivider(uint16_t div) {
|
||||
auto wasEnabled = interruptsEnabled();
|
||||
disableInterrupts();
|
||||
|
||||
_div = div;
|
||||
|
||||
// Update PIT frequency
|
||||
outb(PIT_REG_MODE, PIT_MODE_CH0|PIT_MODE_ACCESS_LOHI|PIT_MODE_M2|PIT_MODE_BIN);
|
||||
outb(PIT_REG_CH0, _div & 0xff);
|
||||
outb(PIT_REG_CH0, (_div >> 8) & 0xff);
|
||||
|
||||
if (wasEnabled) enableInterrupts();
|
||||
}
|
||||
|
||||
Timer::Callback Timer::setCallback(Timer::Callback callback) {
|
||||
auto oldCallback = _callback;
|
||||
_callback = callback;
|
||||
return oldCallback;
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#include <dos.h>
|
||||
#include <sys/nearptr.h>
|
||||
|
||||
#include "../Video.h"
|
||||
#include "../../util/Asm.h"
|
||||
#include "../../util/Log.h"
|
||||
|
||||
#define VGA_DAC_ADDR_RD 0x3c7
|
||||
#define VGA_DAC_ADDR_WR 0x3c8
|
||||
#define VGA_DAC_DATA 0x3c9
|
||||
#define VGA_EXT_INPUT_STATUS 0x3da
|
||||
#define VGA_EXT_INPUT_STATUS_VRETRACE 8
|
||||
|
||||
Video video;
|
||||
|
||||
Video::Video() {
|
||||
__djgpp_nearptr_enable();
|
||||
|
||||
// Store current video mode
|
||||
_oldMode = GetMode();
|
||||
|
||||
// Store current palette
|
||||
for (auto i = 0; i < 256; i++) {
|
||||
GetPaletteEntry(i, &_oldPalette[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
Exit();
|
||||
}
|
||||
|
||||
void Video::Enter() {
|
||||
SetMode(0x13);
|
||||
}
|
||||
|
||||
void Video::Exit() {
|
||||
// Restore old palette
|
||||
for (auto i = 0; i < 256; i++) {
|
||||
SetPaletteEntry(i, &_oldPalette[i]);
|
||||
}
|
||||
|
||||
// Restore old video mode
|
||||
SetMode(_oldMode);
|
||||
}
|
||||
|
||||
void Video::SetMode(uint8_t mode) {
|
||||
union REGS regs;
|
||||
regs.h.ah = 0x00;
|
||||
regs.h.al = mode;
|
||||
int86(0x10, ®s, ®s);
|
||||
|
||||
//__djgpp_nearptr_enable();
|
||||
switch (mode) {
|
||||
default:
|
||||
case 0x13:
|
||||
_fb = (uint8_t *)(0xA0000 + __djgpp_conventional_base);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Video::GetMode() {
|
||||
union REGS regs;
|
||||
regs.h.ah = 0x0f;
|
||||
regs.h.al = 0;
|
||||
int86(0x10, ®s, ®s);
|
||||
|
||||
return regs.h.al;
|
||||
}
|
||||
|
||||
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) {
|
||||
outb(VGA_DAC_ADDR_WR, index);
|
||||
outb(VGA_DAC_DATA, entry->r >> 2);
|
||||
outb(VGA_DAC_DATA, entry->g >> 2);
|
||||
outb(VGA_DAC_DATA, entry->b >> 2);
|
||||
}
|
||||
|
||||
void Video::GetPaletteEntry(uint8_t index, PaletteEntry *entry) {
|
||||
outb(VGA_DAC_ADDR_RD, index);
|
||||
entry->r = inb(VGA_DAC_DATA);
|
||||
entry->g = inb(VGA_DAC_DATA);
|
||||
entry->b = inb(VGA_DAC_DATA);
|
||||
}
|
||||
|
||||
void *Video::GetFB() {
|
||||
return _renderBuffer;
|
||||
}
|
||||
|
||||
void Video::WaitForVerticalSync() {
|
||||
auto state = inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE;
|
||||
if (!state) {
|
||||
// We started before a retrace, so wait until it begins
|
||||
while (!(inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE)) {}
|
||||
}
|
||||
// Wait until it ends
|
||||
while (inb(VGA_EXT_INPUT_STATUS) & VGA_EXT_INPUT_STATUS_VRETRACE);
|
||||
}
|
||||
|
||||
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() {
|
||||
for (auto i = 0; i <= MAX_UPDATE_RECT_INDEX; i++) {
|
||||
auto &rect = _updatedRects[i];
|
||||
for (auto y = rect.y1; y <= rect.y2; y++) {
|
||||
auto yOffset = y * SCREEN_WIDTH;
|
||||
|
||||
for (auto x = rect.x1; x <= rect.x2; x++) {
|
||||
_fb[yOffset + x] = _renderBuffer[yOffset + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_updateRectIndex = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#include "../init.h"
|
||||
|
||||
namespace System {
|
||||
void init() {
|
||||
|
||||
}
|
||||
|
||||
void terminate() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef GAME_INIT_H
|
||||
#define GAME_INIT_H
|
||||
|
||||
namespace System {
|
||||
void init();
|
||||
void terminate();
|
||||
}
|
||||
|
||||
#endif //GAME_INIT_H
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#include <SDL.h>
|
||||
#include "Events.h"
|
||||
|
||||
#include "Keyboard.h"
|
||||
|
||||
Events events;
|
||||
|
||||
void Events::poll() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
// TODO handle events
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
// TODO
|
||||
exit(0);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
keyboard.keyDown(event.key.keysym.sym);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
keyboard.keyUp(event.key.keysym.sym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef GAME_EVENTS_H
|
||||
#define GAME_EVENTS_H
|
||||
|
||||
class Events {
|
||||
public:
|
||||
Events() = default;
|
||||
~Events() = default;
|
||||
|
||||
void poll();
|
||||
};
|
||||
|
||||
extern Events events;
|
||||
|
||||
#endif //GAME_EVENTS_H
|
||||
|
|
@ -0,0 +1,821 @@
|
|||
#include <SDL.h>
|
||||
#include "../Keyboard.h"
|
||||
|
||||
Keyboard keyboard;
|
||||
|
||||
// TODO map unknown key codes
|
||||
uint8_t mapSdlKeycode(SDL_Keycode keyCode) {
|
||||
switch (keyCode) {
|
||||
case SDLK_UNKNOWN:
|
||||
return KeyUnknown;
|
||||
case SDLK_RETURN:
|
||||
return KeyUnknown;
|
||||
case SDLK_ESCAPE:
|
||||
return KeyEscape;
|
||||
case SDLK_BACKSPACE:
|
||||
return KeyBackspace;
|
||||
case SDLK_TAB:
|
||||
return KeyTab;
|
||||
case SDLK_SPACE:
|
||||
return KeySpace;
|
||||
case SDLK_EXCLAIM:
|
||||
return KeyUnknown;
|
||||
case SDLK_QUOTEDBL:
|
||||
return KeyUnknown;
|
||||
case SDLK_HASH:
|
||||
return KeyUnknown;
|
||||
case SDLK_PERCENT:
|
||||
return KeyUnknown;
|
||||
case SDLK_DOLLAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_AMPERSAND:
|
||||
return KeyUnknown;
|
||||
case SDLK_QUOTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_LEFTPAREN:
|
||||
return KeyUnknown;
|
||||
case SDLK_RIGHTPAREN:
|
||||
return KeyUnknown;
|
||||
case SDLK_ASTERISK:
|
||||
return KeyUnknown;
|
||||
case SDLK_PLUS:
|
||||
return KeyUnknown;
|
||||
case SDLK_COMMA:
|
||||
return KeyUnknown;
|
||||
case SDLK_MINUS:
|
||||
return KeyUnknown;
|
||||
case SDLK_PERIOD:
|
||||
return KeyUnknown;
|
||||
case SDLK_SLASH:
|
||||
return KeyUnknown;
|
||||
case SDLK_0:
|
||||
return Key0;
|
||||
case SDLK_1:
|
||||
return Key1;
|
||||
case SDLK_2:
|
||||
return Key2;
|
||||
case SDLK_3:
|
||||
return Key3;
|
||||
case SDLK_4:
|
||||
return Key4;
|
||||
case SDLK_5:
|
||||
return Key5;
|
||||
case SDLK_6:
|
||||
return Key6;
|
||||
case SDLK_7:
|
||||
return Key7;
|
||||
case SDLK_8:
|
||||
return Key8;
|
||||
case SDLK_9:
|
||||
return Key9;
|
||||
case SDLK_COLON:
|
||||
return KeyUnknown;
|
||||
case SDLK_SEMICOLON:
|
||||
return KeyUnknown;
|
||||
case SDLK_LESS:
|
||||
return KeyUnknown;
|
||||
case SDLK_EQUALS:
|
||||
return KeyUnknown;
|
||||
case SDLK_GREATER:
|
||||
return KeyUnknown;
|
||||
case SDLK_QUESTION:
|
||||
return KeyUnknown;
|
||||
case SDLK_AT:
|
||||
return KeyUnknown;
|
||||
case SDLK_LEFTBRACKET:
|
||||
return KeyUnknown;
|
||||
case SDLK_BACKSLASH:
|
||||
return KeyUnknown;
|
||||
case SDLK_RIGHTBRACKET:
|
||||
return KeyUnknown;
|
||||
case SDLK_CARET:
|
||||
return KeyUnknown;
|
||||
case SDLK_UNDERSCORE:
|
||||
return KeyUnknown;
|
||||
case SDLK_BACKQUOTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_a:
|
||||
return KeyA;
|
||||
case SDLK_b:
|
||||
return KeyB;
|
||||
case SDLK_c:
|
||||
return KeyC;
|
||||
case SDLK_d:
|
||||
return KeyD;
|
||||
case SDLK_e:
|
||||
return KeyE;
|
||||
case SDLK_f:
|
||||
return KeyF;
|
||||
case SDLK_g:
|
||||
return KeyG;
|
||||
case SDLK_h:
|
||||
return KeyG;
|
||||
case SDLK_i:
|
||||
return KeyI;
|
||||
case SDLK_j:
|
||||
return KeyJ;
|
||||
case SDLK_k:
|
||||
return KeyK;
|
||||
case SDLK_l:
|
||||
return KeyL;
|
||||
case SDLK_m:
|
||||
return KeyM;
|
||||
case SDLK_n:
|
||||
return KeyN;
|
||||
case SDLK_o:
|
||||
return KeyO;
|
||||
case SDLK_p:
|
||||
return KeyP;
|
||||
case SDLK_q:
|
||||
return KeyQ;
|
||||
case SDLK_r:
|
||||
return KeyR;
|
||||
case SDLK_s:
|
||||
return KeyS;
|
||||
case SDLK_t:
|
||||
return KeyT;
|
||||
case SDLK_u:
|
||||
return KeyU;
|
||||
case SDLK_v:
|
||||
return KeyV;
|
||||
case SDLK_w:
|
||||
return KeyW;
|
||||
case SDLK_x:
|
||||
return KeyX;
|
||||
case SDLK_y:
|
||||
return KeyY;
|
||||
case SDLK_z:
|
||||
return KeyZ;
|
||||
case SDLK_CAPSLOCK:
|
||||
return KeyCapsLock;
|
||||
case SDLK_F1:
|
||||
return KeyF1;
|
||||
case SDLK_F2:
|
||||
return KeyF2;
|
||||
case SDLK_F3:
|
||||
return KeyF3;
|
||||
case SDLK_F4:
|
||||
return KeyF4;
|
||||
case SDLK_F5:
|
||||
return KeyF5;
|
||||
case SDLK_F6:
|
||||
return KeyF6;
|
||||
case SDLK_F7:
|
||||
return KeyF7;
|
||||
case SDLK_F8:
|
||||
return KeyF8;
|
||||
case SDLK_F9:
|
||||
return KeyF9;
|
||||
case SDLK_F10:
|
||||
return KeyF10;
|
||||
case SDLK_F11:
|
||||
return KeyF11;
|
||||
case SDLK_F12:
|
||||
return KeyF12;
|
||||
case SDLK_PRINTSCREEN:
|
||||
return KeyPrint;
|
||||
case SDLK_SCROLLLOCK:
|
||||
return KeyScrollLock;
|
||||
case SDLK_PAUSE:
|
||||
return KeyPause;
|
||||
case SDLK_INSERT:
|
||||
return KeyInsert;
|
||||
case SDLK_HOME:
|
||||
return KeyHome;
|
||||
case SDLK_PAGEUP:
|
||||
return KeyPageUp;
|
||||
case SDLK_DELETE:
|
||||
return KeyDelete;
|
||||
case SDLK_END:
|
||||
return KeyEnd;
|
||||
case SDLK_PAGEDOWN:
|
||||
return KeyPageDown;
|
||||
case SDLK_RIGHT:
|
||||
return KeyRight;
|
||||
case SDLK_LEFT:
|
||||
return KeyLeft;
|
||||
case SDLK_DOWN:
|
||||
return KeyDown;
|
||||
case SDLK_UP:
|
||||
return KeyUp;
|
||||
case SDLK_NUMLOCKCLEAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_DIVIDE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MULTIPLY:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MINUS:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_PLUS:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_ENTER:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_1:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_2:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_3:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_4:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_5:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_6:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_7:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_8:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_9:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_0:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_PERIOD:
|
||||
return KeyUnknown;
|
||||
case SDLK_APPLICATION:
|
||||
return KeyUnknown;
|
||||
case SDLK_POWER:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_EQUALS:
|
||||
return KeyUnknown;
|
||||
case SDLK_F13:
|
||||
return KeyUnknown;
|
||||
case SDLK_F14:
|
||||
return KeyUnknown;
|
||||
case SDLK_F15:
|
||||
return KeyUnknown;
|
||||
case SDLK_F16:
|
||||
return KeyUnknown;
|
||||
case SDLK_F17:
|
||||
return KeyUnknown;
|
||||
case SDLK_F18:
|
||||
return KeyUnknown;
|
||||
case SDLK_F19:
|
||||
return KeyUnknown;
|
||||
case SDLK_F20:
|
||||
return KeyUnknown;
|
||||
case SDLK_F21:
|
||||
return KeyUnknown;
|
||||
case SDLK_F22:
|
||||
return KeyUnknown;
|
||||
case SDLK_F23:
|
||||
return KeyUnknown;
|
||||
case SDLK_F24:
|
||||
return KeyUnknown;
|
||||
case SDLK_EXECUTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_HELP:
|
||||
return KeyUnknown;
|
||||
case SDLK_MENU:
|
||||
return KeyUnknown;
|
||||
case SDLK_SELECT:
|
||||
return KeyUnknown;
|
||||
case SDLK_STOP:
|
||||
return KeyUnknown;
|
||||
case SDLK_AGAIN:
|
||||
return KeyUnknown;
|
||||
case SDLK_UNDO:
|
||||
return KeyUnknown;
|
||||
case SDLK_CUT:
|
||||
return KeyUnknown;
|
||||
case SDLK_COPY:
|
||||
return KeyUnknown;
|
||||
case SDLK_PASTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_FIND:
|
||||
return KeyUnknown;
|
||||
case SDLK_MUTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_VOLUMEUP:
|
||||
return KeyUnknown;
|
||||
case SDLK_VOLUMEDOWN:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_COMMA:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_EQUALSAS400:
|
||||
return KeyUnknown;
|
||||
case SDLK_ALTERASE:
|
||||
return KeyUnknown;
|
||||
case SDLK_SYSREQ:
|
||||
return KeyUnknown;
|
||||
case SDLK_CANCEL:
|
||||
return KeyUnknown;
|
||||
case SDLK_CLEAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_PRIOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_RETURN2:
|
||||
return KeyUnknown;
|
||||
case SDLK_SEPARATOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_OUT:
|
||||
return KeyUnknown;
|
||||
case SDLK_OPER:
|
||||
return KeyUnknown;
|
||||
case SDLK_CLEARAGAIN:
|
||||
return KeyUnknown;
|
||||
case SDLK_CRSEL:
|
||||
return KeyUnknown;
|
||||
case SDLK_EXSEL:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_00:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_000:
|
||||
return KeyUnknown;
|
||||
case SDLK_THOUSANDSSEPARATOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_DECIMALSEPARATOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_CURRENCYUNIT:
|
||||
return KeyUnknown;
|
||||
case SDLK_CURRENCYSUBUNIT:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_LEFTPAREN:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_RIGHTPAREN:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_LEFTBRACE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_RIGHTBRACE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_TAB:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_BACKSPACE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_A:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_B:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_C:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_D:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_E:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_F:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_XOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_POWER:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_PERCENT:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_LESS:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_GREATER:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_AMPERSAND:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_DBLAMPERSAND:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_VERTICALBAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_DBLVERTICALBAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_COLON:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_HASH:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_SPACE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_AT:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_EXCLAM:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMSTORE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMRECALL:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMCLEAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMADD:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMSUBTRACT:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMMULTIPLY:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_MEMDIVIDE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_PLUSMINUS:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_CLEAR:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_CLEARENTRY:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_BINARY:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_OCTAL:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_DECIMAL:
|
||||
return KeyUnknown;
|
||||
case SDLK_KP_HEXADECIMAL:
|
||||
return KeyUnknown;
|
||||
case SDLK_LCTRL:
|
||||
return KeyLeftCtrl;
|
||||
case SDLK_LSHIFT:
|
||||
return KeyLeftShift;
|
||||
case SDLK_LALT:
|
||||
return KeyLeftAlt;
|
||||
case SDLK_LGUI:
|
||||
return KeyUnknown;
|
||||
case SDLK_RCTRL:
|
||||
return KeyRightControl;
|
||||
case SDLK_RSHIFT:
|
||||
return KeyRightShift;
|
||||
case SDLK_RALT:
|
||||
return KeyRightAlt;
|
||||
case SDLK_RGUI:
|
||||
return KeyUnknown;
|
||||
case SDLK_MODE:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIONEXT:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOPREV:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOSTOP:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOPLAY:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOMUTE:
|
||||
return KeyUnknown;
|
||||
case SDLK_MEDIASELECT:
|
||||
return KeyUnknown;
|
||||
case SDLK_WWW:
|
||||
return KeyUnknown;
|
||||
case SDLK_MAIL:
|
||||
return KeyUnknown;
|
||||
case SDLK_CALCULATOR:
|
||||
return KeyUnknown;
|
||||
case SDLK_COMPUTER:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_SEARCH:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_HOME:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_BACK:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_FORWARD:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_STOP:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_REFRESH:
|
||||
return KeyUnknown;
|
||||
case SDLK_AC_BOOKMARKS:
|
||||
return KeyUnknown;
|
||||
case SDLK_BRIGHTNESSDOWN:
|
||||
return KeyUnknown;
|
||||
case SDLK_BRIGHTNESSUP:
|
||||
return KeyUnknown;
|
||||
case SDLK_DISPLAYSWITCH:
|
||||
return KeyUnknown;
|
||||
case SDLK_KBDILLUMTOGGLE:
|
||||
return KeyUnknown;
|
||||
case SDLK_KBDILLUMDOWN:
|
||||
return KeyUnknown;
|
||||
case SDLK_KBDILLUMUP:
|
||||
return KeyUnknown;
|
||||
case SDLK_EJECT:
|
||||
return KeyUnknown;
|
||||
case SDLK_SLEEP:
|
||||
return KeyUnknown;
|
||||
case SDLK_APP1:
|
||||
return KeyUnknown;
|
||||
case SDLK_APP2:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOREWIND:
|
||||
return KeyUnknown;
|
||||
case SDLK_AUDIOFASTFORWARD:
|
||||
return KeyUnknown;
|
||||
default: ;
|
||||
}
|
||||
|
||||
return KeyUnknown;
|
||||
}
|
||||
|
||||
static const char *keyNames[] = {
|
||||
"<unknown:00>",
|
||||
"KeyEscape", // = 0x01,
|
||||
"Key1", // = 0x02,
|
||||
"Key2", // = 0x03,
|
||||
"Key3", // = 0x04,
|
||||
"Key4", // = 0x05,
|
||||
"Key5", // = 0x06,
|
||||
"Key6", // = 0x07,
|
||||
"Key7", // = 0x08,
|
||||
"Key8", // = 0x09,
|
||||
"Key9", // = 0x0a,
|
||||
"Key0", // = 0x0b,
|
||||
"KeyMinus", // = 0x0c,
|
||||
"KeyEqual", // = 0x0d,
|
||||
"KeyBackspace", // = 0x0e,
|
||||
"KeyTab", // = 0x0f,
|
||||
|
||||
"KeyQ", // = 0x10,
|
||||
"KeyW", // = 0x11,
|
||||
"KeyE", // = 0x12,
|
||||
"KeyR", // = 0x13,
|
||||
"KeyT", // = 0x14,
|
||||
"KeyY", // = 0x15,
|
||||
"KeyU", // = 0x16,
|
||||
"KeyI", // = 0x17,
|
||||
"KeyO", // = 0x18,
|
||||
"KeyP", // = 0x19,
|
||||
"KeyBracketLeft", // = 0x1a,
|
||||
"KeyBracketRight", // = 0x1b,
|
||||
"KeyEnter", // = 0x1c,
|
||||
"KeyLeftCtrl", // = 0x1d,
|
||||
"KeyA", // = 0x1e,
|
||||
"KeyS", // = 0x1f,
|
||||
|
||||
"KeyD", // = 0x20,
|
||||
"KeyF", // = 0x21,
|
||||
"KeyG", // = 0x22,
|
||||
"KeyH", // = 0x23,
|
||||
"KeyJ", // = 0x24,
|
||||
"KeyK", // = 0x25,
|
||||
"KeyL", // = 0x26,
|
||||
"KeySemicolon", // = 0x27,
|
||||
"KeyApostrophe", // = 0x28,
|
||||
"KeyBacktick", // = 0x29,
|
||||
"KeyLeftShift", // = 0x2a,
|
||||
"KeyBackslash", // = 0x2b,
|
||||
"KeyZ", // = 0x2c,
|
||||
"KeyX", // = 0x2d,
|
||||
"KeyC", // = 0x2e,
|
||||
"KeyV", // = 0x2f,
|
||||
|
||||
"KeyB", // = 0x30,
|
||||
"KeyN", // = 0x31,
|
||||
"KeyM", // = 0x32,
|
||||
"KeyComma", // = 0x33,
|
||||
"KeyPeriod", // = 0x34,
|
||||
"KeySlash", // = 0x35,
|
||||
"KeyRightShift", // = 0x36,
|
||||
"KeyKeypadMultiply", // = 0x37,
|
||||
"KeyLeftAlt", // = 0x38,
|
||||
"KeySpace", // = 0x39,
|
||||
"KeyCapsLock", // = 0x3a,
|
||||
"KeyF1", // = 0x3b,
|
||||
"KeyF2", // = 0x3c,
|
||||
"KeyF3", // = 0x3d,
|
||||
"KeyF4", // = 0x3e,
|
||||
"KeyF5", // = 0x3f,
|
||||
|
||||
"KeyF6", // = 0x40,
|
||||
"KeyF7", // = 0x41,
|
||||
"KeyF8", // = 0x42,
|
||||
"KeyF9", // = 0x43,
|
||||
"KeyF10", // = 0x44,
|
||||
"KeyNumLock", // = 0x45,
|
||||
"KeyScrollLock", // = 0x46,
|
||||
"KeyKeypad7", // = 0x47,
|
||||
"KeyKeypad8", // = 0x48,
|
||||
"KeyKeypad9", // = 0x49,
|
||||
"KeyKeypadMinus", // = 0x4a,
|
||||
"KeyKeypad4", // = 0x4b,
|
||||
"KeyKeypad5", // = 0x4c,
|
||||
"KeyKeypad6", // = 0x4d,
|
||||
"KeyKeypadPlus", // = 0x4e,
|
||||
"KeyKeypad1", // = 0x4f,
|
||||
|
||||
"KeyKeypad2", // = 0x50,
|
||||
"KeyKeypad3", // = 0x51,
|
||||
"KeyKeypad0", // = 0x52,
|
||||
"KeyKeypadPeriod", // = 0x53,
|
||||
"<unknown:54>",
|
||||
"<unknown:55>",
|
||||
"<unknown:56>",
|
||||
"KeyF11", // = 0x57,
|
||||
"KeyF12", // = 0x58,
|
||||
"<unknown:59>",
|
||||
"<unknown:5a>",
|
||||
"<unknown:5b>",
|
||||
"<unknown:5c>",
|
||||
"<unknown:5d>",
|
||||
"<unknown:5e>",
|
||||
"<unknown:5f>",
|
||||
|
||||
"<unknown:60>",
|
||||
"<unknown:61>",
|
||||
"<unknown:62>",
|
||||
"<unknown:63>",
|
||||
"<unknown:64>",
|
||||
"<unknown:65>",
|
||||
"<unknown:66>",
|
||||
"<unknown:67>",
|
||||
"<unknown:68>",
|
||||
"<unknown:69>",
|
||||
"<unknown:6a>",
|
||||
"<unknown:6b>",
|
||||
"<unknown:6c>",
|
||||
"<unknown:6d>",
|
||||
"<unknown:6e>",
|
||||
"<unknown:6f>",
|
||||
|
||||
"<unknown:70>",
|
||||
"<unknown:71>",
|
||||
"<unknown:72>",
|
||||
"<unknown:73>",
|
||||
"<unknown:74>",
|
||||
"<unknown:75>",
|
||||
"<unknown:76>",
|
||||
"<unknown:77>",
|
||||
"<unknown:78>",
|
||||
"<unknown:79>",
|
||||
"<unknown:7a>",
|
||||
"<unknown:7b>",
|
||||
"<unknown:7c>",
|
||||
"<unknown:7d>",
|
||||
"<unknown:7e>",
|
||||
"<unknown:7f>",
|
||||
|
||||
"<unknown:80>",
|
||||
"<unknown:81>",
|
||||
"<unknown:82>",
|
||||
"<unknown:83>",
|
||||
"<unknown:84>",
|
||||
"<unknown:85>",
|
||||
"<unknown:86>",
|
||||
"<unknown:87>",
|
||||
"<unknown:88>",
|
||||
"<unknown:89>",
|
||||
"<unknown:8a>",
|
||||
"<unknown:8b>",
|
||||
"<unknown:8c>",
|
||||
"<unknown:8d>",
|
||||
"<unknown:8e>",
|
||||
"<unknown:8f>",
|
||||
|
||||
"KeyMediaPrev", // = 0x90,
|
||||
"<unknown:91>",
|
||||
"<unknown:92>",
|
||||
"<unknown:93>",
|
||||
"<unknown:94>",
|
||||
"<unknown:95>",
|
||||
"<unknown:96>",
|
||||
"<unknown:97>",
|
||||
"<unknown:98>",
|
||||
"KeyMediaNext", // = 0x99,
|
||||
"<unknown:9a>",
|
||||
"<unknown:9b>",
|
||||
"KeyKeypadEnter", // = 0x9c,
|
||||
"KeyRightControl", // = 0x9d,
|
||||
"<unknown:9e>",
|
||||
"<unknown:9f>",
|
||||
|
||||
"KeyMediaMute", // = 0xa0,
|
||||
"KeyMediaCalculator", // = 0xa1,
|
||||
"KeyMediaPlay", // = 0xa2,
|
||||
"<unknown:a3>",
|
||||
"KeyMediaStop", // = 0xa4,
|
||||
"<unknown:a5>",
|
||||
"<unknown:a6>",
|
||||
"<unknown:a7>",
|
||||
"<unknown:a8>",
|
||||
"<unknown:a9>",
|
||||
"<unknown:aa>",
|
||||
"<unknown:ab>",
|
||||
"<unknown:ac>",
|
||||
"<unknown:ad>",
|
||||
"KeyMediaVolumeDown", // = 0xae,
|
||||
"<unknown:af>",
|
||||
|
||||
"KeyMediaVolumeUp", // = 0xb0,
|
||||
"<unknown:b1>",
|
||||
"KeyMediaWww", // = 0xb2,
|
||||
"<unknown:b3>",
|
||||
"<unknown:b4>",
|
||||
"KeyKeypadDivide", // = 0xb5,
|
||||
"<unknown:b6>",
|
||||
"<unknown:b7>",
|
||||
"KeyRightAlt", // = 0xb8,
|
||||
"<unknown:b9>",
|
||||
"<unknown:ba>",
|
||||
"<unknown:bb>",
|
||||
"<unknown:bc>",
|
||||
"<unknown:bd>",
|
||||
"<unknown:be>",
|
||||
"<unknown:bf>",
|
||||
|
||||
"<unknown:c0>",
|
||||
"<unknown:c1>",
|
||||
"<unknown:c2>",
|
||||
"<unknown:c3>",
|
||||
"<unknown:c4>",
|
||||
"<unknown:c5>",
|
||||
"<unknown:c6>",
|
||||
"KeyHome", // = 0xc7,
|
||||
"KeyUp", // = 0xc8,
|
||||
"KeyPageUp", // = 0xc9,
|
||||
"<unknown:ca>",
|
||||
"KeyLeft", // = 0xcb,
|
||||
"<unknown:cc>",
|
||||
"KeyRight", // = 0xcd,
|
||||
"<unknown:ce>",
|
||||
"KeyEnd", // = 0xcf,
|
||||
|
||||
"KeyDown", // = 0xd0,
|
||||
"KeyPageDown", // = 0xd1,
|
||||
"KeyInsert", // = 0xd2,
|
||||
"KeyDelete", // = 0xd3,
|
||||
"<unknown:d4>",
|
||||
"<unknown:d5>",
|
||||
"<unknown:d6>",
|
||||
"<unknown:d7>",
|
||||
"<unknown:d8>",
|
||||
"<unknown:d9>",
|
||||
"<unknown:da>",
|
||||
"KeyLeftGui", // = 0xdb,
|
||||
"KeyRightGui", // = 0xdc,
|
||||
"KeyApps", // = 0xdd,
|
||||
"KeyAcpiPower", // = 0xde,
|
||||
"KeyAcpiSleep", // = 0xdf,
|
||||
|
||||
"<unknown:e0>",
|
||||
"<unknown:e1>",
|
||||
"<unknown:e2>",
|
||||
"KeyAcpiWake", // = 0xe3,
|
||||
"<unknown:e4>",
|
||||
"KeyMediaWwwSearch", // = 0xe5,
|
||||
"KeyMediaWwwFavorites", // = 0xe6,
|
||||
"KeyMediaWwwRefresh", // = 0xe7,
|
||||
"KeyMediaWwwStop", // = 0xe8,
|
||||
"KeyMediaWwwForward", // = 0xe9,
|
||||
"KeyMediaWwwBack", // = 0xea,
|
||||
"KeyMediaMyComputer", // = 0xeb,
|
||||
"KeyMediaEmail", // = 0xec,
|
||||
"KeyMediaSelect", // = 0xed,
|
||||
"<unknown:ee>",
|
||||
"<unknown:ef>",
|
||||
|
||||
"<unknown:f0>",
|
||||
"<unknown:f1>",
|
||||
"<unknown:f2>",
|
||||
"<unknown:f3>",
|
||||
"<unknown:f4>",
|
||||
"<unknown:f5>",
|
||||
"<unknown:f6>",
|
||||
"<unknown:f7>",
|
||||
"<unknown:f8>",
|
||||
"<unknown:f9>",
|
||||
"<unknown:fa>",
|
||||
"<unknown:fb>",
|
||||
"<unknown:fc>",
|
||||
"<unknown:fd>",
|
||||
"KeyPrint", // = 0xfe,
|
||||
"KeyPause", // = 0xff,
|
||||
};
|
||||
|
||||
void keyboardIsr() {
|
||||
keyboard.Isr();
|
||||
}
|
||||
|
||||
Keyboard::Keyboard() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyUpHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyUpHandler;
|
||||
_keyUpHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyDownHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyDownHandler;
|
||||
_keyDownHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
Keyboard::KeyHandleFunction Keyboard::setKeyRepeatHandler(KeyHandleFunction handler) {
|
||||
auto oldHandler = _keyRepeatHandler;
|
||||
_keyRepeatHandler = handler;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
const char *Keyboard::getKeyName(unsigned char keyCode) {
|
||||
return keyNames[keyCode];
|
||||
}
|
||||
|
||||
void Keyboard::Isr() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Keyboard::keyDown(SDL_Keycode keyCode) {
|
||||
auto c = mapSdlKeycode(keyCode);
|
||||
if (keyState[c]) {
|
||||
if (_keyRepeatHandler) _keyRepeatHandler(c);
|
||||
} else {
|
||||
keyState[c] = true;
|
||||
if (_keyDownHandler) _keyDownHandler(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::keyUp(SDL_Keycode keyCode) {
|
||||
auto c = mapSdlKeycode(keyCode);
|
||||
keyState[c] = false;
|
||||
if (_keyUpHandler) _keyUpHandler(c);
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
#ifndef GAME_KEYBOARD_H
|
||||
#define GAME_KEYBOARD_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#define KEY_MAX 256
|
||||
|
||||
enum {
|
||||
KeyUnknown = 0x00,
|
||||
KeyEscape = 0x01,
|
||||
Key1 = 0x02,
|
||||
Key2 = 0x03,
|
||||
Key3 = 0x04,
|
||||
Key4 = 0x05,
|
||||
Key5 = 0x06,
|
||||
Key6 = 0x07,
|
||||
Key7 = 0x08,
|
||||
Key8 = 0x09,
|
||||
Key9 = 0x0a,
|
||||
Key0 = 0x0b,
|
||||
KeyMinus = 0x0c,
|
||||
KeyEqual = 0x0d,
|
||||
KeyBackspace = 0x0e,
|
||||
KeyTab = 0x0f,
|
||||
KeyQ = 0x10,
|
||||
KeyW = 0x11,
|
||||
KeyE = 0x12,
|
||||
KeyR = 0x13,
|
||||
KeyT = 0x14,
|
||||
KeyY = 0x15,
|
||||
KeyU = 0x16,
|
||||
KeyI = 0x17,
|
||||
KeyO = 0x18,
|
||||
KeyP = 0x19,
|
||||
KeyBracketLeft = 0x1a,
|
||||
KeyBracketRight = 0x1b,
|
||||
KeyEnter = 0x1c,
|
||||
KeyLeftCtrl = 0x1d,
|
||||
KeyA = 0x1e,
|
||||
KeyS = 0x1f,
|
||||
KeyD = 0x20,
|
||||
KeyF = 0x21,
|
||||
KeyG = 0x22,
|
||||
KeyH = 0x23,
|
||||
KeyJ = 0x24,
|
||||
KeyK = 0x25,
|
||||
KeyL = 0x26,
|
||||
KeySemicolon = 0x27,
|
||||
KeyApostrophe = 0x28,
|
||||
KeyBacktick = 0x29,
|
||||
KeyLeftShift = 0x2a,
|
||||
KeyBackslash = 0x2b,
|
||||
KeyZ = 0x2c,
|
||||
KeyX = 0x2d,
|
||||
KeyC = 0x2e,
|
||||
KeyV = 0x2f,
|
||||
KeyB = 0x30,
|
||||
KeyN = 0x31,
|
||||
KeyM = 0x32,
|
||||
KeyComma = 0x33,
|
||||
KeyPeriod = 0x34,
|
||||
KeySlash = 0x35,
|
||||
KeyRightShift = 0x36,
|
||||
KeyKeypadMultiply = 0x37,
|
||||
KeyLeftAlt = 0x38,
|
||||
KeySpace = 0x39,
|
||||
KeyCapsLock = 0x3a,
|
||||
KeyF1 = 0x3b,
|
||||
KeyF2 = 0x3c,
|
||||
KeyF3 = 0x3d,
|
||||
KeyF4 = 0x3e,
|
||||
KeyF5 = 0x3f,
|
||||
KeyF6 = 0x40,
|
||||
KeyF7 = 0x41,
|
||||
KeyF8 = 0x42,
|
||||
KeyF9 = 0x43,
|
||||
KeyF10 = 0x44,
|
||||
KeyNumLock = 0x45,
|
||||
KeyScrollLock = 0x46,
|
||||
KeyKeypad7 = 0x47,
|
||||
KeyKeypad8 = 0x48,
|
||||
KeyKeypad9 = 0x49,
|
||||
KeyKeypadMinus = 0x4a,
|
||||
KeyKeypad4 = 0x4b,
|
||||
KeyKeypad5 = 0x4c,
|
||||
KeyKeypad6 = 0x4d,
|
||||
KeyKeypadPlus = 0x4e,
|
||||
KeyKeypad1 = 0x4f,
|
||||
KeyKeypad2 = 0x50,
|
||||
KeyKeypad3 = 0x51,
|
||||
KeyKeypad0 = 0x52,
|
||||
KeyKeypadPeriod = 0x53,
|
||||
KeyF11 = 0x57,
|
||||
KeyF12 = 0x58,
|
||||
KeyMediaPrev = 0x90,
|
||||
KeyMediaNext = 0x99,
|
||||
KeyKeypadEnter = 0x9c,
|
||||
KeyRightControl = 0x9d,
|
||||
KeyMediaMute = 0xa0,
|
||||
KeyMediaCalculator = 0xa1,
|
||||
KeyMediaPlay = 0xa2,
|
||||
KeyMediaStop = 0xa4,
|
||||
KeyMediaVolumeDown = 0xae,
|
||||
KeyMediaVolumeUp = 0xb0,
|
||||
KeyMediaWww = 0xb2,
|
||||
KeyKeypadDivide = 0xb5,
|
||||
KeyRightAlt = 0xb8,
|
||||
KeyHome = 0xc7,
|
||||
KeyUp = 0xc8,
|
||||
KeyPageUp = 0xc9,
|
||||
KeyLeft = 0xcb,
|
||||
KeyRight = 0xcd,
|
||||
KeyEnd = 0xcf,
|
||||
KeyDown = 0xd0,
|
||||
KeyPageDown = 0xd1,
|
||||
KeyInsert = 0xd2,
|
||||
KeyDelete = 0xd3,
|
||||
KeyLeftGui = 0xdb,
|
||||
KeyRightGui = 0xdc,
|
||||
KeyApps = 0xdd,
|
||||
KeyAcpiPower = 0xde,
|
||||
KeyAcpiSleep = 0xdf,
|
||||
KeyAcpiWake = 0xe3,
|
||||
KeyMediaWwwSearch = 0xe5,
|
||||
KeyMediaWwwFavorites = 0xe6,
|
||||
KeyMediaWwwRefresh = 0xe7,
|
||||
KeyMediaWwwStop = 0xe8,
|
||||
KeyMediaWwwForward = 0xe9,
|
||||
KeyMediaWwwBack = 0xea,
|
||||
KeyMediaMyComputer = 0xeb,
|
||||
KeyMediaEmail = 0xec,
|
||||
KeyMediaSelect = 0xed,
|
||||
KeyPrint = 0xfe,
|
||||
KeyPause = 0xff,
|
||||
};
|
||||
|
||||
class Keyboard {
|
||||
public:
|
||||
using KeyHandleFunction = void (*)(unsigned char);
|
||||
|
||||
Keyboard();
|
||||
~Keyboard();
|
||||
|
||||
KeyHandleFunction setKeyUpHandler(KeyHandleFunction handler);
|
||||
KeyHandleFunction setKeyDownHandler(KeyHandleFunction handler);
|
||||
KeyHandleFunction setKeyRepeatHandler(KeyHandleFunction handler);
|
||||
|
||||
bool keyState[KEY_MAX]{};
|
||||
|
||||
const char *getKeyName(unsigned char keyCode);
|
||||
private:
|
||||
friend class Events;
|
||||
|
||||
friend void keyboardIsr();
|
||||
void Isr();
|
||||
enum State {
|
||||
Start,
|
||||
Extended,
|
||||
PauseBegin,
|
||||
PausePressed1,
|
||||
PauseReleased1,
|
||||
PrintPressed1,
|
||||
PrintPressed2,
|
||||
PrintReleased1,
|
||||
PrintReleased2,
|
||||
};
|
||||
State _state;
|
||||
KeyHandleFunction _keyDownHandler{nullptr}, _keyUpHandler{nullptr}, _keyRepeatHandler{nullptr};
|
||||
|
||||
void keyDown(SDL_Keycode c);
|
||||
|
||||
void keyUp(SDL_Keycode c);
|
||||
|
||||
};
|
||||
|
||||
extern Keyboard keyboard;
|
||||
|
||||
#endif //GAME_KEYBOARD_H
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include "../Opl.h"
|
||||
|
||||
namespace Opl {
|
||||
void write(uint16_t reg, uint8_t data) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include "../SoundBlaster.h"
|
||||
|
||||
SoundBlaster soundblaster;
|
||||
|
||||
void soundblasterIsr() {
|
||||
soundblaster.onInterrupt();
|
||||
}
|
||||
|
||||
SoundBlaster::SoundBlaster() {
|
||||
|
||||
}
|
||||
|
||||
SoundBlaster::~SoundBlaster() {
|
||||
}
|
||||
|
||||
void SoundBlaster::onInterrupt() {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include <SDL.h>
|
||||
|
||||
#include "../Timer.h"
|
||||
|
||||
Timer timer;
|
||||
|
||||
SDL_TimerID timerId;
|
||||
|
||||
void timerISR() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
Timer::Timer() {
|
||||
_freq = 50;
|
||||
timerId = SDL_AddTimer(1000/_freq, [] (Uint32, void*) -> Uint32 {
|
||||
timerISR();
|
||||
return 1000 / timer.getFrequency();
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
SDL_RemoveTimer(timerId);
|
||||
}
|
||||
|
||||
void Timer::update() {
|
||||
// TODO
|
||||
_ticks++;
|
||||
}
|
||||
|
||||
uint32_t Timer::getTicks() const {
|
||||
return _ticks;
|
||||
}
|
||||
|
||||
void Timer::setFrequency(uint16_t freq) {
|
||||
_freq = freq;
|
||||
// TODO
|
||||
}
|
||||
|
||||
uint16_t Timer::getFrequency() const {
|
||||
return _freq;
|
||||
}
|
||||
|
||||
void Timer::setDivider(uint16_t div) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Timer::Callback Timer::setCallback(Timer::Callback callback) {
|
||||
auto oldCallback = _callback;
|
||||
_callback = callback;
|
||||
return oldCallback;
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
#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();
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#include "../init.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "../Video.h"
|
||||
|
||||
namespace System {
|
||||
void init() {
|
||||
if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0) {
|
||||
std::cerr << "Error initializing SDL: " << SDL_GetError() << std::endl;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void terminate() {
|
||||
video.Exit();
|
||||
SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef ASM_H
|
||||
#define ASM_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
static inline uint8_t inb(uint16_t port) {
|
||||
uint8_t value;
|
||||
asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint16_t inw(uint16_t port) {
|
||||
uint16_t value;
|
||||
asm volatile ("inw %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint32_t inl(uint16_t port) {
|
||||
uint32_t value;
|
||||
asm volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t value) {
|
||||
asm volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline void outw(uint16_t port, uint16_t value) {
|
||||
asm volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline void outl(uint16_t port, uint32_t value) {
|
||||
asm volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline void enableInterrupts() {
|
||||
asm volatile ("sti": : :"memory");
|
||||
}
|
||||
|
||||
static inline void disableInterrupts() {
|
||||
asm volatile ("cli": : :"memory");
|
||||
}
|
||||
|
||||
static inline uint32_t eflags() {
|
||||
uint32_t value;
|
||||
asm volatile ( "pushf\n\t"
|
||||
"popl %0"
|
||||
: "=g"(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline bool interruptsEnabled() {
|
||||
return (eflags() & (1u << 9u)) != 0;
|
||||
}
|
||||
|
||||
static void pmInterruptCall(unsigned short selector, unsigned long offset) {
|
||||
__asm__ __volatile__ (
|
||||
"pushf\n" // Push EFLAGS
|
||||
"mov %0, %%ax\n" // Load the segment selector into AX
|
||||
"mov %%ax, %%ds\n" // Move it to DS (or another segment register)
|
||||
"call *%1\n" // Perform the indirect far call using the offset
|
||||
: // No output operands
|
||||
: "r" (selector), "r" (offset) // Input operands
|
||||
: "%ax" // Clobbered register
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#include "Bmp.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "Files.h"
|
||||
|
||||
namespace Bmp {
|
||||
Bitmap loadFromMemory(void *buf, size_t len) {
|
||||
if (len < sizeof (BmpFileHeader) + sizeof (BmpInfoHeader)) return {};
|
||||
|
||||
auto fileHeader = reinterpret_cast<BmpFileHeader *>(buf);
|
||||
auto infoHeader = reinterpret_cast<BmpInfoHeader *>(fileHeader + 1);
|
||||
|
||||
if (fileHeader->signature != 0x4d42) {
|
||||
printf("Invalid signature\n");
|
||||
return {};
|
||||
}
|
||||
if (len < fileHeader->fileSize) {
|
||||
printf("File too small\n");
|
||||
return {};
|
||||
}
|
||||
if (infoHeader->headerSize != 40) {
|
||||
printf("Invalid header size\n");
|
||||
return {};
|
||||
}
|
||||
if (infoHeader->width < 0 || infoHeader->height < 0 || infoHeader->planes != 1) {
|
||||
printf("Invalid width/height/bit planes\n");
|
||||
|
||||
return {};
|
||||
}
|
||||
if (infoHeader->bitsPerPixel != 1 && infoHeader->bitsPerPixel != 4 && infoHeader->bitsPerPixel != 8) {
|
||||
printf("Unsupported bpp %u\n", infoHeader->bitsPerPixel);
|
||||
|
||||
return {};
|
||||
}
|
||||
if (infoHeader->compression != BmpInfoHeader::CompressionType::Rgb) {
|
||||
printf("Unsupported compression\n");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO check imageSize
|
||||
|
||||
Bitmap bitmap(infoHeader->width, infoHeader->height);
|
||||
|
||||
// Read color table
|
||||
auto colorTable = reinterpret_cast<uint8_t *>(infoHeader + 1);
|
||||
for (auto i = 0; i < infoHeader->colorsUsed; i++) {
|
||||
Video::PaletteEntry paletteEntry;
|
||||
paletteEntry.b = colorTable[4 * i + 0];
|
||||
paletteEntry.g = colorTable[4 * i + 1];
|
||||
paletteEntry.r = colorTable[4 * i + 2];
|
||||
bitmap.SetPaletteEntry(i, paletteEntry);
|
||||
}
|
||||
|
||||
// Read pixel data
|
||||
auto data = static_cast<uint8_t *>(buf) + fileHeader->offset;
|
||||
auto rowLength = infoHeader->width;
|
||||
if (infoHeader->bitsPerPixel == 1) rowLength = (rowLength + 7) >> 3;
|
||||
else if (infoHeader->bitsPerPixel == 4) rowLength = (rowLength + 1) >> 1;
|
||||
auto stride = (rowLength + 3) >> 2 << 2;
|
||||
for (auto y = 0u; y < infoHeader->height; y++) {
|
||||
for (auto x = 0u; x < infoHeader->width; x++) {
|
||||
uint8_t pv = 0;
|
||||
switch (infoHeader->bitsPerPixel) {
|
||||
case 1: {
|
||||
const auto byte = data[(infoHeader->height - y - 1) * stride + (x >> 3)];
|
||||
auto pixelOffset = x & 7;
|
||||
pv = (byte >> (7 - pixelOffset)) & 1;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
const auto byte = data[(infoHeader->height - y - 1) * stride + (x >> 1)];
|
||||
pv = x & 1 ? byte & 0xf : byte >> 4;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
pv = data[(infoHeader->height - y - 1) * stride + x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
bitmap.SetPixel(x, y, pv);
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
Bitmap loadFromFile(const char* path) {
|
||||
void *data;
|
||||
auto len = Files::allocateBufferAndLoadFromFile(path, &data);
|
||||
auto bitmap = loadFromMemory(data, len);
|
||||
Files::deleteBuffer(data);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef GAME_BMPLOADER_H
|
||||
#define GAME_BMPLOADER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include "../graphics/Bitmap.h"
|
||||
|
||||
namespace Bmp {
|
||||
struct BmpFileHeader {
|
||||
uint16_t signature;
|
||||
uint32_t fileSize;
|
||||
uint16_t reserved1;
|
||||
uint16_t reserved2;
|
||||
uint32_t offset;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct BmpInfoHeader {
|
||||
uint32_t headerSize;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint16_t planes;
|
||||
uint16_t bitsPerPixel;
|
||||
uint32_t compression;
|
||||
uint32_t imageSize;
|
||||
uint32_t horizontalResolution;
|
||||
uint32_t verticalResolution;
|
||||
uint32_t colorsUsed;
|
||||
uint32_t colorsImportant;
|
||||
|
||||
enum CompressionType {
|
||||
Rgb = 0,
|
||||
Rle8,
|
||||
Rle4,
|
||||
Bitfields,
|
||||
Jpeg,
|
||||
Png,
|
||||
Alphabitfields,
|
||||
Cmyk,
|
||||
CmykRle8,
|
||||
CmykRle4,
|
||||
};
|
||||
} __attribute__((__packed__));
|
||||
|
||||
Bitmap loadFromMemory(void *buf, size_t len);
|
||||
Bitmap loadFromFile(const char* path);
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_BMPLOADER_H
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#include "Files.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
size_t Files::allocateBufferAndLoadFromFile(const char *path, void **bufferPointer) {
|
||||
auto fp = fopen(path, "rb");
|
||||
if (!fp) {
|
||||
*bufferPointer = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
auto data = new unsigned char[len];
|
||||
fread(data, 1, len, fp);
|
||||
fclose(fp);
|
||||
|
||||
*bufferPointer = data;
|
||||
return len;
|
||||
}
|
||||
|
||||
void Files::deleteBuffer(void *buffer) {
|
||||
delete[] static_cast<unsigned char*>(buffer);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef GAME_FILES_H
|
||||
#define GAME_FILES_H
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Files {
|
||||
size_t allocateBufferAndLoadFromFile(const char *path, void **bufferPointer);
|
||||
void deleteBuffer(void *);
|
||||
}
|
||||
|
||||
#endif //GAME_FILES_H
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#include "Gbm.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "Files.h"
|
||||
|
||||
#define GBM_SIGNATURE 0x204d4247
|
||||
|
||||
Bitmap Gbm::loadFromMemory(const void *data, size_t size) {
|
||||
// Check for minimum
|
||||
if (size < sizeof (uint32_t) + sizeof (uint16_t) + sizeof (uint16_t) + 16 * 3) return {};
|
||||
|
||||
auto gbm = static_cast<const GbmHeader *>(data);
|
||||
|
||||
if (gbm->signature != GBM_SIGNATURE) return {};
|
||||
if (gbm->width == 0 || gbm->height == 0) return {};
|
||||
|
||||
Bitmap bitmap(gbm->width, gbm->height);
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
bitmap.SetPaletteEntry(i, {gbm->palette[i].r, gbm->palette[i].g, gbm->palette[i].b});
|
||||
}
|
||||
|
||||
for (auto y = 0; y < gbm->height; y++) {
|
||||
for (auto x = 0; x < gbm->width; x++) {
|
||||
auto pv = gbm->data[y * gbm->width + x];
|
||||
bitmap.SetPixel(x, y, pv);
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
Bitmap Gbm::loadFromFile(const char *path) {
|
||||
void *data;
|
||||
auto len = Files::allocateBufferAndLoadFromFile(path, &data);
|
||||
auto bitmap = loadFromMemory(data, len);
|
||||
Files::deleteBuffer(data);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
void Gbm::writeToFile(const char *path, const Bitmap &bitmap) {
|
||||
auto fp = fopen(path, "wb");
|
||||
if (!fp) return;
|
||||
|
||||
// Write signature
|
||||
uint32_t signature = GBM_SIGNATURE;
|
||||
fwrite(&signature, 4, 1, fp);
|
||||
uint16_t width = bitmap.GetWidth(), height = bitmap.GetHeight();
|
||||
fwrite(&width, 2, 1, fp);
|
||||
fwrite(&height, 2, 1, fp);
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
auto entry = bitmap.GetPaletteEntry(i);
|
||||
auto r = entry.r, g = entry.g, b = entry.b;
|
||||
fwrite(&r, 1, 1, fp);
|
||||
fwrite(&g, 1, 1, fp);
|
||||
fwrite(&b, 1, 1, fp);
|
||||
}
|
||||
|
||||
for (auto y = 0; y < height; y++) {
|
||||
for (auto x = 0; x < width; x++) {
|
||||
auto pv = bitmap.GetPixel(x, y);
|
||||
fwrite(&pv, 1, 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef GAME_GBM_H
|
||||
#define GAME_GBM_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "../graphics/Bitmap.h"
|
||||
|
||||
namespace Gbm {
|
||||
struct GbmHeader {
|
||||
uint32_t signature;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} __attribute__((__packed__)) palette[16];
|
||||
uint8_t data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
Bitmap loadFromMemory(const void *data, size_t size);
|
||||
Bitmap loadFromFile(const char *path);
|
||||
|
||||
void writeToFile(const char *path, const Bitmap &bitmap);
|
||||
};
|
||||
|
||||
|
||||
#endif //GAME_GBM_H
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#include "Log.h"
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
Log DefaultLog("log.txt");
|
||||
|
||||
Log::Log(const char *path) {
|
||||
fp = fopen(path, "w");
|
||||
}
|
||||
|
||||
Log::~Log() {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void Log::log(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(fp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fflush(fp);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef GAME_LOG_H
|
||||
#define GAME_LOG_H
|
||||
#include <cstdio>
|
||||
|
||||
class Log {
|
||||
public:
|
||||
Log(const char *path);
|
||||
~Log();
|
||||
|
||||
void log(const char *fmt, ...);
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
extern Log DefaultLog;
|
||||
|
||||
|
||||
#endif //GAME_LOG_H
|
||||