Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine_callbackXmp.cpp":
- #include "_kit_shared.hpp"
- namespace kit {
- static inline void applyFadeXmp(_SoundEngineOpaque* opq,
- smp_ptr buffer, u32 buffer_len)
- {
- f32 fDelta = opq->fadeDelta;
- f32 fVolume = opq->fadeVolumeXmp;
- u32 i = 0; //this index is shared, as the loops can jump to others at will
- //FADING OUT
- if(opq->fadeOutXmp){ _FadeOut:;
- if(opq->streamIsMono){ //mono fade out
- for(; i<buffer_len; ++i){
- if(!opq->fadeOutXmp) goto _FadeIn;
- buffer._s16[i] = (s16)(buffer._s16[i]*fVolume);
- fVolume -= fDelta;
- if(fVolume < 0.0f) fVolume = 0.0f;
- }
- } else { //stereo fade out
- for(; i<buffer_len; ++i){
- if(!opq->fadeOutXmp) goto _FadeIn;
- buffer._s16s[i] *= fVolume;
- fVolume -= fDelta;
- if(fVolume < 0.0f) fVolume = 0.0f;
- }
- }
- //stop music if fade out finishes
- if(fVolume <= 0.0f){
- xmp_end_player(opq->xmpCtx);
- opq->xmpPlaying = false;
- }
- //FADING IN
- } else if(fVolume < 1.0f){ _FadeIn:;
- if(opq->streamIsMono){ //mono fade out
- for(; i<buffer_len; ++i){
- if(opq->fadeOutXmp) goto _FadeOut;
- else if(fVolume >= 1.0f){ fVolume = 1.0f; break; }
- buffer._s16[i] = (s16)(buffer._s16[i]*fVolume);
- fVolume += fDelta;
- }
- } else {
- for(; i<buffer_len; ++i){ //stereo fade out
- if(opq->fadeOutXmp) goto _FadeOut;
- else if(fVolume >= 1.0f){ fVolume = 1.0f; break; }
- buffer._s16s[i] *= fVolume;
- fVolume += fDelta;
- }
- }
- }
- opq->fadeVolumeXmp = fVolume; //update fade volume to new value
- }
- //this is a ThreadFunction that uses a _SoundEngineOpaque* as its userdata.
- //the SoundEngine's mutex should be locked at this point,
- //so it should be fine to modify xmp-related members of its opaque struct
- s32 _SoundEngine_callbackXmp(void* userdata){
- _SoundEngineOpaque* opq = (_SoundEngineOpaque*)userdata;
- smp_ptr buffer = opq->xmpBuffer; //s16 or smp_s16s
- u32 buffer_len = opq->streamSampleFrames;
- int buffer_stereo = !opq->streamIsMono; //int so i can do << w/o a warning
- s32 buffer_size = buffer_len * sizeof(s16) << buffer_stereo;
- bool checkLoop = opq->xmpCheckLoop;
- memory::set(buffer._data, 0, buffer_size);
- xmp_play_buffer(opq->xmpCtx, buffer._data, buffer_size, checkLoop);
- //apply pan and volume, while interpolating their values
- //from their old state to its new one
- f32 t = 0.0f;
- f32 t_increment = 1.0f/buffer_len;
- smp_f32s volume_old = opq->volumeXmp_old;
- smp_f32s volume_new = opq->volumeXmp_new;
- opq->volumeXmp_old = volume_new; //update old volume to the new one
- if(buffer_stereo){
- //panning is only applied if samples are stereo,
- //so there's no need to declare it outside of this scope
- f32 pan_old = opq->panXmp_old;
- f32 pan_new = opq->panXmp_new;
- opq->panXmp_old = pan_new; //update old pan to the new one
- for(u32 i=0; i<buffer_len; ++i){
- smp_f32s sampleIn = buffer._s16s[i]; //get current sample
- sampleIn *= interpolateF32S(volume_old, volume_new, t); //apply volume
- smp_f32s sampleOut = applyPan(sampleIn, LERP2(pan_old,pan_new, t) ); //apply pan
- buffer._s16s[i] = to_s16s(sampleOut); //update current sample to new value
- t += t_increment; //add to interpolation t value
- }
- } else { //mono
- for(u32 i=0; i<buffer_len; ++i){
- f32 sample = s16_conv( buffer._s16[i] ); //get current sample
- sample *= LERP2(volume_old.l, volume_new.l, t); //apply volume
- buffer._s16[i] = to_s16( sample ); //update current sample to new value
- t += t_increment; //add to interpolation t value
- }
- }
- //handle fade-in and fade-outs
- applyFadeXmp(opq, buffer, buffer_len);
- return 0;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine_music.cpp":
- #include "_kit_shared.hpp"
- #define KIT_INVALID_SOUNDENGINE "invalid sound engine"
- #define KIT_IS_INVALID_SOUNDENGINE (!_valid && !_constructing)
- namespace kit {
- //i'll keep these around, and uncomment one if/when i end up using it
- static const char _kit_xmp_err_format[] = "XMP_ERROR_FORMAT";
- static const char _kit_xmp_err_depack[] = "XMP_ERROR_DEPACK";
- static const char _kit_xmp_err_load[] = "XMP_ERROR_LOAD";
- static const char _kit_xmp_err_system[] = "XMP_ERROR_SYSTEM";
- static const char _kit_xmp_err_internal[] = "XMP_ERROR_INTERNAL";
- static const char _kit_xmp_err_invalid[] = "XMP_ERROR_INVALID";
- //static const char _kit_xmp_err_state[] = "XMP_ERROR_STATE";
- bool SoundEngine::musicIsPlaying(){
- return _opq->xmpPlaying; //no lock needed
- }
- bool SoundEngine::musicIsModuleLoaded(){
- return _opq->xmpModuleLoaded; //no lock needed
- }
- void SoundEngine::musicSetPan(f32 pan){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- lock(true);
- _opq->panXmp_new = convertPan(pan);
- lock(false);
- }
- void SoundEngine::musicSetVolume(f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->volumeXmp_new = volumeNew;
- lock(false);
- }
- void SoundEngine::musicSetPlayback(bool playing){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- //locking is probably not necessary here, due to the way fades work
- _opq->fadeOutXmp = !playing;
- if(playing && !_opq->xmpPlaying){
- int formatFlags = (_opq->streamIsMono) ? XMP_FORMAT_MONO : 0;
- int result = xmp_start_player(_opq->xmpCtx, (int)_opq->streamSampleRate, formatFlags);
- if(result == XMP_ERROR_INTERNAL) throw _kit_xmp_err_internal;
- if(result == XMP_ERROR_INVALID ) throw _kit_xmp_err_invalid;
- if(result == XMP_ERROR_SYSTEM ) throw _kit_xmp_err_system;
- _opq->xmpPlaying = true;
- int interpolation_mode = (_opq->xmpUseNearest) ? XMP_INTERP_NEAREST : XMP_INTERP_LINEAR;
- xmp_set_player(_opq->xmpCtx, XMP_PLAYER_INTERP, interpolation_mode);
- }
- //(xmp_end_player is called inside the callback, not here)
- }
- void SoundEngine::musicSetPlaybackAndWait(bool playing){
- //(musicSetPlayback already does a validity check)
- //if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- bool wasPlaying = _opq->xmpPlaying;
- //mutex is locked inside musicSetPlayback,
- //and there's no need to lock in this function otherwise
- musicSetPlayback(playing);
- if((playing && !wasPlaying) || (!playing && wasPlaying))
- time::sleep( (u32)(_fadeDeltaSeconds*1000) ); //yep, this is all it does (lol)
- }
- void SoundEngine::musicSetCheckLoop(bool enable){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- lock(true);
- _opq->xmpCheckLoop = enable;
- lock(false);
- }
- void SoundEngine::musicSetUseNearest(bool enable){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- lock(true);
- _opq->xmpUseNearest = enable;
- lock(false);
- }
- void SoundEngine::musicSetVolumeForced(f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->volumeXmp_old = volumeNew;
- _opq->volumeXmp_new = volumeNew;
- lock(false);
- }
- void SoundEngine::musicLoadModule(const char* filePath){
- //musicReleaseModule already does a validity check
- //if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(!fileio::fileExists(filePath)) throw "file does not exist";
- musicReleaseModule();
- int result = xmp_load_module(_opq->xmpCtx, filePath);
- if(result == XMP_ERROR_FORMAT) throw _kit_xmp_err_format;
- if(result == XMP_ERROR_DEPACK) throw _kit_xmp_err_depack;
- if(result == XMP_ERROR_LOAD ) throw _kit_xmp_err_load;
- if(result == XMP_ERROR_SYSTEM) throw _kit_xmp_err_system;
- _opq->xmpModuleLoaded = true; //will be set only if load succeeds
- }
- void SoundEngine::musicReleaseModule(){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(_opq->xmpPlaying) xmp_end_player(_opq->xmpCtx);
- if(_opq->xmpModuleLoaded) xmp_release_module(_opq->xmpCtx);
- _opq->xmpModuleLoaded = false;
- }
- void SoundEngine::musicStopForced(){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(_opq->xmpPlaying){
- xmp_end_player(_opq->xmpCtx);
- _opq->xmpPlaying = false;
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine_sfx.cpp":
- #include "_kit_shared.hpp"
- #define KIT_INVALID_SOUNDENGINE "invalid sound engine"
- #define KIT_TRACK_OOB _kit_track_oob
- #define KIT_IS_INVALID_SOUNDENGINE (!_valid && !_constructing)
- #define KIT_IS_TRACK_OOB (track < 0 || track >= _opq->tracks_len)
- namespace kit {
- const char _kit_track_oob[] = "track number is out of bounds";
- bool SoundEngine::sfxIsTrackPlaying(s32 track){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- return _opq->tracks[track].audio != nullptr;
- }
- u32 SoundEngine::sfxGetActiveTracks(){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- u32 activeTracks = 0;
- _SoundEngineTrack* tracks = _opq->tracks;
- s32 tracks_len = _opq->tracks_len;
- lock(true);
- for(s32 t=0; t<tracks_len; ++t)
- if(tracks[t].audio != nullptr) ++activeTracks;
- lock(false);
- return activeTracks;
- }
- void SoundEngine::sfxSetPanAll(f32 pan){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- lock(true);
- _opq->panSfx_new = convertPan(pan);
- lock(false);
- }
- void SoundEngine::sfxSetPan(s32 track, f32 pan){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- lock(true);
- _opq->tracks[track].pan_new = convertPan(pan);
- lock(false);
- }
- void SoundEngine::sfxSetVolumeAll(f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->volumeSfx_new = volumeNew;
- lock(false);
- }
- void SoundEngine::sfxSetVolume(s32 track, f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->tracks[track].volume_new = volumeNew;
- lock(false);
- }
- void SoundEngine::sfxSetVolumeDelta(s32 track, f32 deltaSecondsL, f32 deltaSecondsR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- f64 streamSampleRate = _opq->streamSampleRate;
- smp_f32s volumeDelta((1.0f/deltaSecondsL)/streamSampleRate,
- (1.0f/deltaSecondsR)/streamSampleRate);
- //locking when modifying deltas is unnecessary
- _opq->tracks[track].volumeDelta = volumeDelta;
- }
- void SoundEngine::sfxSetSpeedDelta(s32 track, f64 deltaSeconds){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- f64 speedDelta = (1.0f/deltaSeconds)/_opq->streamSampleRate;
- //locking when modifying deltas is unnecessary
- _opq->tracks[track].speedDelta = speedDelta;
- }
- void SoundEngine::sfxSetVolumeAllForced(f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->volumeSfx_old = volumeNew;
- _opq->volumeSfx_new = volumeNew;
- lock(false);
- }
- void SoundEngine::sfxSetVolumeForced(s32 track, f32 volumeL, f32 volumeR){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- smp_f32s volumeNew(volumeL, volumeR);
- lock(true);
- _opq->tracks[track].volume_old = volumeNew;
- _opq->tracks[track].volume_new = volumeNew;
- lock(false);
- }
- bool SoundEngine::sfxWaitForTracks(size_t timeoutMS){
- u64 timeStamp = time::getTicks(); //intentionally done before validity check
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(timeoutMS == 0) timeoutMS = KIT_U64_MAX; //if 0 is given, wait indefinitely
- u64 timeoutTicks = timeoutMS * (time::getTicksPerSecond()/1000);
- //sfxGetActiveTracks already locks, so there's no need to do it here
- while(sfxGetActiveTracks() > 0){
- time::sleep(10);
- if((time::getTicks()-timeStamp) > timeoutTicks) return false;
- }
- return true;
- }
- bool SoundEngine::sfxWaitForTrack(s32 track, size_t timeoutMS){
- u64 timeStamp = time::getTicks();
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- if(timeoutMS == 0) timeoutMS = KIT_U64_MAX;
- u64 timeoutTicks = timeoutMS * (time::getTicksPerSecond()/1000);
- _SoundEngineTrack& _track = _opq->tracks[track];
- while(_track.audio != nullptr){
- time::sleep(5);
- if((time::getTicks()-timeStamp) > timeoutTicks) return false;
- }
- return true; //will return true only if track finished before timeout
- }
- s32 SoundEngine::sfxPlay(const AudioData* audio,
- f32 volumeL, f32 volumeR,
- f64 speed, f32 pan)
- {
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- //streamTimestamp declared after validity check,
- //just to make sure that stream was actually created
- f64 streamTimestamp = _opq->stream->getTime();
- if(audio == nullptr) throw "audio = nullptr";
- //compiler is complaining about const qualifiers unless i cast audio here
- const AudioDataHeader* audioDataHeader = ((AudioData*)audio)->getData();
- if(audioDataHeader->magic != KIT_MAGIC_KPM) throw "audio is invalid";
- //will return -1 if no available track was found
- s32 queuedTrackNum = -1;
- _SoundEngineTrack* tracks = _opq->tracks;
- s32 tracks_len = _opq->tracks_len;
- lock(true);
- for(s32 t=0; t<tracks_len; ++t){
- _SoundEngineTrack& track = tracks[t];
- if(track.audio == nullptr){
- track.timestamp = streamTimestamp;
- //track.position = <set inside callback>;
- track.speed_old = speed;
- track.speed_new = speed;
- track.speedDelta = 0.0;
- track.pan_old = pan;
- track.pan_new = pan;
- track.volume_old.l = volumeL;
- track.volume_old.r = volumeR;
- track.volume_new.l = volumeL;
- track.volume_new.r = volumeR;
- track.volumeDelta.l = 0.0f;
- track.volumeDelta.r = 0.0f;
- track.volumeMaster.l = audio->volumeL;
- track.volumeMaster.r = audio->volumeR;
- track.loops = audioDataHeader->loopCount;
- track.stopping = false;
- //set last to make sure that all relevant members
- //of the track are set before beginning
- track.audio = audioDataHeader;
- queuedTrackNum = t; break;
- }
- }
- lock(false);
- return queuedTrackNum;
- }
- void SoundEngine::sfxStop(s32 track){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- //'stop' the track by setting a fade-out of _fadeDeltaSeconds,
- //whereupon the track will *actually* stop automatically
- const smp_f32s fadeoutDelta( (1.0f/(-_fadeDeltaSeconds))/_opq->streamSampleRate );
- //locking when modifying deltas is unnecessary
- _opq->tracks[track].volumeDelta = fadeoutDelta;
- }
- void SoundEngine::sfxStopForced(s32 track){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- if(KIT_IS_TRACK_OOB) throw KIT_TRACK_OOB;
- //locking (probably) isn't necessary here, due to the way tracks are managed
- _opq->tracks[track].audio = nullptr; //forcibly mark track as completed
- }
- void SoundEngine::sfxStopAll(){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- const smp_f32s fadeoutDelta( (1.0f/(-_fadeDeltaSeconds))/_opq->streamSampleRate );
- _SoundEngineTrack* tracks = _opq->tracks;
- s32 tracks_len = _opq->tracks_len;
- //locking when modifying deltas is unnecessary
- for(s32 t=0; t<tracks_len; ++t) tracks[t].volumeDelta = fadeoutDelta;
- }
- void SoundEngine::sfxStopAllForced(){
- if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
- _SoundEngineTrack* tracks = _opq->tracks;
- s32 tracks_len = _opq->tracks_len;
- //locking (probably) isn't necessary here, due to the way tracks are managed
- for(s32 t=0; t<tracks_len; ++t) tracks[t].audio = nullptr;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kw32g\src\globals.cpp":
- #include <globals.hpp>
- #include <tile.hpp>
- #include <player.hpp>
- #include <object.hpp>
- #include <save.hpp>
- #include <stdio.h>
- #include <stdlib.h>
- using namespace kit;
- //under normal conditions this should never be called
- //(as in, if i put a type 0 object in a scene, i did something wrong)
- bool obj_dummy(Object* _obj_a, bool render_only){
- _printf("obj_dummy() was called!\n");
- return false;
- }
- char falseStr[] = "false";
- char trueStr[] = "true" ;
- f32 gl_death_prog = DEATH_PROG_MAX;
- Thread* gl_audioManager_thread = nullptr;
- bool gl_audioManager_exit = false;
- bool gl_audioManager_occ_thr = false;
- bool gl_audioManager_occ_sfx = false;
- bool gl_saveRead_called = false;
- u64 gl_tickCounter = 0;
- TimerSimple* gl_frameTimer = nullptr;
- SoundEngine* gl_snd = nullptr;
- Window* gl_win = nullptr;
- BitmapFont* gl_text = nullptr;
- FStr* gl_fstr = nullptr;
- Bitmap* gl_spritesheetPlayer = nullptr;
- Bitmap* gl_spritesheetFont = nullptr; //a copy of gl_text's texture atlas
- Bitmap* gl_spritesheetAbilityIndicators = nullptr;
- //+1 for the array lengths, since the first valid id is 1, not 0
- ControlStates gl_ctrlStates;
- Player gl_player;
- Scene gl_scene;
- SceneDescriptor* gl_scenes[gl_scenes_len+1];
- u16 gl_scene_indices[gl_scenes_len+1];
- Object* gl_objsCache[gl_scenes_len+1];
- Bitmap* gl_backgrounds[gl_backgrounds_len+1];
- Bitmap* gl_tileset_missing = nullptr;
- Bitmap* gl_tilesets[gl_tilesets_len+1];
- Bitmap* gl_objImg[gl_objImg_len+1];
- AudioData* gl_ambience[gl_ambience_len+1];
- SoundEffect* gl_sfx[gl_sfx_len+1];
- const char gl_sfxNames[gl_sfx_len+1][32] = { //file paths, relative to ./dat/sfx/
- "(none)", // 0
- "player_footstep.qoa", // 1
- "player_jumping.qoa", // 2
- "player_landing.qoa", // 3
- "activate_1.qoa", // 4
- "ability_pickup.qoa", // 5
- "ability_removed.qoa", // 6
- "nope_1.qoa", // 7
- "dlelele.qoa", // 8
- "fwshwshwsh.qoa", // 9
- "death.qoa" //10
- };
- //.x is volume, .y is speedRange (which should be casted to f64)
- #define PLV_ PLAYER_LANDING_VOLUME
- const shape::fpoint gl_sfxSettings[gl_sfx_len+1] = {
- { .00f, .00f }, // 0 = none
- { .02f, .10f }, // 1 = player_footstep
- { .03f, .00f }, // 2 = player_jumping
- { PLV_, .20f }, // 3 = player_landing
- { .08f, .00f }, // 4 = activate_1
- { .08f, .00f }, // 5 = ability_pickup
- { .07f, .00f }, // 6 = ability_removed
- { .07f, .00f }, // 7 = nope_1
- { .07f, .00f }, // 8 = dlelele
- { .07f, .00f }, // 9 = fwshwshwsh
- { .13f, .00f }, //10 = death
- };
- #undef PLV_
- const char gl_music[gl_music_len+1][32] = { //file paths, relative to ./dat/music/
- "(no change)", //0
- "sine_half.mod", //1
- "SilverSurfer.xm", //2
- "2ND_PM.S3M", //3
- "tao tao.xm", //4
- };
- const Object_TickCallback gl_objCallbacks[gl_objCallbacks_len+1] = {
- obj_dummy , //0 = no object
- obj_1lever , //1 = lever that controls a binary scene state
- obj_ability , //2 = for enabling abilities
- obj_ability_remover, //3 = for disabling abilities
- obj_generic_sprite , //4 = generic sprite with optional animation
- obj_msgbox , //5 = a messagebox that shows when colliding w/ it (optionally always)
- obj_save_interface , //6 = a way to save, load, or wipe save file data
- obj_teleporter , //7 = teleports the player to a given position and scene
- obj_death_zone , //8 = a static area that kills the player on touch
- obj_death_ball , //9 = a ball of death that also kills the player on touch
- };
- #define TEXT_LINES_DEFINITION
- #include <text_lines.hpp>
- size_t handleInit(){ //returns number of allocations from snd
- gl_frameTimer = new TimerSimple;
- gl_frameTimer->setTimer(0.101);
- srand((u32)time::getTicks());
- size_t allocations_before_snd = memory::getNumAllocations();
- gl_snd = new SoundEngine(SND_TRACK_COUNT);
- gl_snd->streamStart();
- size_t allocations_after_snd = memory::getNumAllocations();
- size_t snd_allocations = allocations_after_snd - allocations_before_snd;
- gl_win = new Window(WINDOW_TITLE, CANVSIZ_X*2, CANVSIZ_Y*2,
- WINFLAG_RESIZABLE | WINFLAG_HIDDEN,
- WINPOS_CENTERED, WINPOS_CENTERED,
- CANVSIZ_X, CANVSIZ_Y, false);
- gl_text = new BitmapFont("dat/img/_font8x8.qoi", gl_win);
- //unnecessary, given that the entire game
- //loads into memory in less than a second
- //gl_textf(0, 0, "loading...");
- //gl_win->present(true);
- //gl_win->setVisibility(true);
- gl_spritesheetPlayer = new Bitmap("dat/img/spritesheet_player.qoi", gl_win);
- gl_spritesheetFont = new Bitmap("dat/img/_font8x8.qoi", gl_win);
- gl_spritesheetAbilityIndicators = new Bitmap("dat/img/ability_indicators.qoi", gl_win);
- //initialize asset pointer arrays
- memset0(gl_scenes); //(these memsets are probably redundant, but just in case)
- memset0(gl_objsCache);
- memset0(gl_backgrounds);
- memset0(gl_tilesets);
- memset0(gl_ambience);
- char* fstr_ptr = gl_fstr->ptr(); //valid until gl_fstr gets destroyed
- //scenes
- for(u32 i=1; i<(gl_scenes_len+1); ++i){
- //(file check is done inside SceneDescriptor's constructor)
- gl_scenes[i] = new SceneDescriptor(i);
- gl_scene_indices[i] = gl_scenes[i]->scene;
- }
- //object caches
- for(u32 i=1; i<(gl_scenes_len+1); ++i){
- //unlike the other asset arrays, the objects in an object cache are zero-indexed
- size_t cache_size = sizeof(Object) * gl_scenes[i]->objs_len;
- if(cache_size) gl_objsCache[i] = (Object*)memory::alloc2( cache_size );
- loadObjects(true, i); //force load all objects in that scene
- }
- //backgrounds
- for(u32 i=1; i<(gl_backgrounds_len+1); ++i){
- gl_fstr->fmt("dat/background/background_%u.qoi", i);
- if(!fileio::fileExists(fstr_ptr))
- throw (const char*)gl_fstr->fmt("\"dat/background/background_%u.qoi\" doesn't exist", i);
- gl_backgrounds[i] = new Bitmap(fstr_ptr, gl_win);
- }
- //tilesets
- for(u32 i=1; i<(gl_tilesets_len+1); ++i){
- gl_fstr->fmt("dat/tileset/tileset_%u.qoi", i);
- if(!fileio::fileExists(fstr_ptr))
- throw (const char*)gl_fstr->fmt("\"dat/tileset/tileset_%u.qoi\" doesn't exist", i);
- gl_tilesets[i] = new Bitmap(fstr_ptr, gl_win);
- }
- //object images
- for(u32 i=1; i<(gl_objImg_len+1); ++i){
- gl_fstr->fmt("dat/obj-img/obj-img_%u.qoi", i);
- if(!fileio::fileExists(fstr_ptr))
- throw (const char*)gl_fstr->fmt("\"dat/obj-img/obj-img_%u.qoi\" doesn't exist", i);
- gl_objImg[i] = new Bitmap(fstr_ptr, gl_win);
- }
- //ambience
- for(u32 i=1; i<(gl_ambience_len+1); ++i){
- gl_fstr->fmt("dat/ambience/ambience_%u.qoa", i);
- if(!fileio::fileExists(fstr_ptr))
- throw (const char*)gl_fstr->fmt("\"dat/ambience/ambience_%u.qoa\" doesn't exist", i);
- gl_ambience[i] = new AudioData(fstr_ptr, gl_snd);
- AudioDataHeader* adata = (AudioDataHeader*)gl_ambience[i]->getData();
- if(!adata) throw "ambience's ._data member was nullptr";
- adata->loopCount = 0xFFFF; //infinite loop
- }
- //sfx
- for(u32 i=1; i<(gl_sfx_len+1); ++i){
- gl_fstr->fmt("dat/sfx/%s", gl_sfxNames[i]);
- if(!fileio::fileExists(fstr_ptr))
- throw (const char*)gl_fstr->fmt("\"dat/sfx/%s\" doesn't exist", gl_sfxNames[i]);
- f32 volume = gl_sfxSettings[i].x;
- f64 speedRange = (f64)gl_sfxSettings[i].y;
- gl_sfx[i] = new SoundEffect(fstr_ptr, volume, speedRange);
- }
- //get length of gl_text_lines
- gl_text_lines_len = 0;
- for(char** p = (char**)gl_text_lines; *p != 0; ++p)
- ++gl_text_lines_len;
- gl_tileset_missing = new Bitmap("dat/tileset/tileset_missing.qoi", gl_win);
- gl_audioManager_thread = new Thread(audioManager);
- gl_frameTimer->wait(2000);
- gl_win->setVisibility(true);
- gl_win->setFocus(true);
- return snd_allocations;
- }
- void handleQuit(){
- if(gl_frameTimer) gl_frameTimer->setTimer(0.05);
- gl_audioManager_exit = true;
- gl_audioManager_thread->waitUntilDone(500);
- delete gl_audioManager_thread;
- if(gl_snd){
- gl_snd->musicStopForced();
- gl_snd->sfxStopAllForced();
- }
- delete gl_text;
- delete gl_win;
- delete gl_spritesheetPlayer;
- delete gl_spritesheetFont;
- delete gl_spritesheetAbilityIndicators;
- //both delete and memory::free should handle nullptrs automagically
- for(u32 i=1; i<(gl_scenes_len +1); ++i){ delete gl_scenes[i];
- /*for(u32 i=1; i<(gl_scenes_len +1); ++i)*/ memory::free(&gl_objsCache[i]); }
- for(u32 i=1; i<(gl_backgrounds_len+1); ++i) delete gl_backgrounds[i];
- for(u32 i=1; i<(gl_tilesets_len +1); ++i) delete gl_tilesets[i];
- for(u32 i=1; i<(gl_objImg_len +1); ++i) delete gl_objImg[i];
- for(u32 i=1; i<(gl_ambience_len +1); ++i) delete gl_ambience[i];
- for(u32 i=1; i<(gl_sfx_len +1); ++i) delete gl_sfx[i];
- delete gl_tileset_missing;
- if(gl_frameTimer) gl_frameTimer->wait(2000);
- delete gl_frameTimer;
- }
- extern int gameMain(int argc, char** argv);
- int main(int argc, char** argv){ try {
- //fstr takes priority in initialization, since it's occasionally used to
- //format error messages, so it's important for it to always be valid
- gl_fstr = new FStr(4096);
- size_t snd_allocs = handleInit();
- saveReadSystem();
- int result = gameMain(argc, argv);
- saveWriteSystem();
- handleQuit();
- delete gl_fstr;
- printf("# OF CONTROLLED ALLOCATIONS = %lli\n",
- memory::getNumAllocations()-snd_allocs-2-1);
- return result;
- } catch(const char* errorText){
- #ifdef _DEBUG
- printf("FATAL EXCEPTION OCCURRED!: \"%s\"\n", errorText);
- #else
- showMessageBox(errorText, "FATAL EXCEPTION OCCURRED! COMPLAIN TO THE DEV! (lol)", MSGBOX_ICN_ERROR);
- #endif /* _DEBUG */
- return -1;
- }}
- void gl_win_drawRectEmpty(shape::rect rect, color::ARGB color, u32 width){
- rect.w += rect.x-1;
- rect.h += rect.y-1;
- shape::point points[5];
- points[0] = shape::point(rect.x, rect.y);
- points[1] = shape::point(rect.w, rect.y);
- points[2] = shape::point(rect.w, rect.h);
- points[3] = shape::point(rect.x, rect.h);
- points[4] = points[0];
- gl_win->drawLines((shape::point*)points, 5, color, width);
- }
- f64 frand(){
- u32 value = (rand()<<15) | rand();
- return (f64)value/(KIT_U32_MAX>>2);
- }
- f32 frandf(){
- u32 value = (rand()<<15) | rand();
- return (f32)value/(KIT_U32_MAX>>2);
- }
- f64 frandRange(f64 start, f64 maxDeviation){
- return start + (frand()*2.0-1.0)*maxDeviation;
- }
- bool rects_overlapping(shape::rect& object_rect,
- shape::rect& obstacle_rect,
- shape::point* delta_p)
- {
- //get bounding boxes of object and obstacle
- shape_quad obj = object_rect;
- shape_quad obs = obstacle_rect;
- bool overlapping = obj.a.x < obs.b.x && obj.b.x > obs.a.x &&
- obj.a.y < obs.b.y && obj.b.y > obs.a.y;
- //delta is initialized so *delta_p can be set regardless of overlap
- shape::point delta(0, 0);
- if(!overlapping || !delta_p) goto _draw_collision_;
- //find minimum translation vector
- //(movement delta needed to resolve collision)
- s32 overlapX1 = obs.b.x - obj.a.x; //obs right edge relative to obj left edge
- s32 overlapX2 = obj.b.x - obs.a.x; //obj right edge relative to obs left edge
- s32 overlapY1 = obs.b.y - obj.a.y; //obs bottom edge relative to obj top edge
- s32 overlapY2 = obj.b.y - obs.a.y; //obj bottom edge relative to obs top edge
- s32 overlapX = (overlapX1 < overlapX2) ? overlapX1 : -overlapX2;
- s32 overlapY = (overlapY1 < overlapY2) ? overlapY1 : -overlapY2;
- if(abs(overlapX) < abs(overlapY)) delta.x = overlapX; //.y will remain 0
- else delta.y = overlapY; //.x will remain 0
- _draw_collision_:
- #if defined(_DEBUG) && defined(SHOW_COLLISIONS)
- gl_win_drawRectEmpty(object_rect, (overlapping) ? 0x00ff00 : 0xff0000);
- gl_win_drawRectEmpty(obstacle_rect, (overlapping) ? 0x00ff00 : 0xff0000);
- #endif
- if(delta_p) *delta_p = delta;
- return overlapping;
- }
- //returns true if subtile has collision
- static inline bool subtile_is_collidable(s32 x, s32 y){
- //this line is probably redundant, since bounds checks should already be done
- //if(x<0 || x>=(TILESIZ_X*2) || y<0 || y>=(TILESIZ_Y*2)) return false;
- //get the associated tile
- s32 index = ARR2D(x>>1, y>>1, TILESIZ_X);
- Tile tile_m = gl_scene.pat_mg[ index ];
- Tile tile_f = gl_scene.pat_fg[ index ];
- if(tile_m.pass|tile_f.pass) return false; //tile has collision completely disabled
- s32 which_bit = (y&1)<<1 | x&1;
- return ((tile_m.collision|tile_f.collision)>>which_bit)&1;
- }
- //returns true only if resulting bounds have volume
- static inline bool get_tile_bounds(shape_quad& bounds){
- //find the boundaries of all tiles that the player is touching
- //(+= 11 so that an east/south subtile boundary is crossed only when
- // a pixel of the player sprite actually overlaps a given tile)
- bounds.b += shape::point(11, 11);
- bounds /= 12; //convert pixels to subtiles
- //
- bounds.a.x = CLAMP(bounds.a.x, 0, TILESIZ_X*2); //skip subtiles that are off-screen
- bounds.a.y = CLAMP(bounds.a.y, 0, TILESIZ_Y*2); //(2 subtiles in a tile lengthwise)
- //
- bounds.b.x = CLAMP(bounds.b.x, 0, TILESIZ_X*2);
- bounds.b.y = CLAMP(bounds.b.y, 0, TILESIZ_Y*2);
- s32 xmin, xmax, ymin, ymax;
- if(abs(bounds.a.x)<abs(bounds.b.x)){ xmin = abs(bounds.a.x), xmax = abs(bounds.b.x); }
- else { xmin = abs(bounds.b.x), xmax = abs(bounds.a.x); }
- if(abs(bounds.a.y)<abs(bounds.b.y)){ ymin = abs(bounds.a.y), ymax = abs(bounds.b.y); }
- else { ymin = abs(bounds.b.y), ymax = abs(bounds.a.y); }
- return (xmax-xmin)>0 && (ymax-ymin)>0;
- }
- #define SO_LOOP_PATTERN 1
- bool subtiles_overlapping(shape::rect& object_rect_ref, shape::point* delta_p){
- shape::rect object_rect = object_rect_ref;
- shape_quad bounds = object_rect;
- shape::point delta(0, 0); //neutral delta by default
- if(!get_tile_bounds(bounds)){ //there are no subtiles to check; exit early
- if(delta_p) *delta_p = delta;
- return false;
- }
- shape::point min = bounds.a;
- shape::point max = bounds.b;
- shape::point sub; //current subtile position
- shape::rect col(0,0, 12,12); //subtile collider
- #if SO_LOOP_PATTERN == 1
- s32 xmid = (min.x+max.x)/2; //x midpoint
- /* bottom-to-top vertically (y = max.y-1; y >= min.y; --y)
- right-to-left on the left half (x = xmid-1; x >= min.x; --x)
- left-to-right on the right half (x = xmid ; x < max.x; ++x) */
- for(sub.y = max.y-1; sub.y >= min.y; --sub.y){ //bottom-to-top vertically
- for(sub.x = xmid-1; sub.x >= min.x; --sub.x){ //right-to-left on the left half
- if(subtile_is_collidable(sub.x, sub.y)){
- col.x = sub.x*12;
- col.y = sub.y*12;
- if(rects_overlapping(object_rect, col, &delta))
- object_rect += delta;
- }
- }
- for(sub.x = xmid; sub.x < max.x; ++sub.x){ //left-to-right on the right half
- if(subtile_is_collidable(sub.x, sub.y)){
- col.x = sub.x*12;
- col.y = sub.y*12;
- if(rects_overlapping(object_rect, col, &delta))
- object_rect += delta;
- }
- }
- }
- #else
- for(sub.y = max.y-1; sub.y >= min.y; --sub.y) //bottom-to-top vertically
- for(sub.x = min.x ; sub.x < max.x; ++sub.x) //left-to-right horizontally
- if(subtile_is_collidable(sub.x, sub.y)){
- col.x = sub.x*12;
- col.y = sub.y*12;
- if(rects_overlapping(object_rect, col, &delta))
- object_rect += delta;
- }
- #endif
- delta.x = object_rect.x - object_rect_ref.x;
- delta.y = object_rect.y - object_rect_ref.y;
- if(delta_p) *delta_p = delta;
- return delta.x!=0 || delta.y!=0;
- }
- void handleEdgeWrap(){
- if(!gl_scene.scene)
- throw "gl_scene.scene == 0 (loadScene(>0) before calling handleEdgeWrap()!)";
- u16 new_scene_id = 0;
- bool call_loadObjects = false;
- if( gl_player.pos.x < 0 ){ //player went past west side
- gl_player.pos.x = CANVSIZ_X;
- new_scene_id = CURRENT_SCENE_PTR->edge_w;
- call_loadObjects = true;
- } else if(gl_player.pos.x > CANVSIZ_X){ //player went past east side
- gl_player.pos.x = 0;
- new_scene_id = CURRENT_SCENE_PTR->edge_e;
- call_loadObjects = true;
- }
- #if DISABLE_NS_EDGES == 0
- else if(gl_player.pos.y < 0 ){ //player went past north side
- gl_player.pos.y = CANVSIZ_Y;
- new_scene_id = CURRENT_SCENE_PTR->edge_n;
- call_loadObjects = true;
- } else if(gl_player.pos.y > CANVSIZ_Y){ //player went past south side
- gl_player.pos.y = 0;
- new_scene_id = CURRENT_SCENE_PTR->edge_s;
- call_loadObjects = true;
- }
- #endif
- if(new_scene_id ) loadScene(new_scene_id);
- if(call_loadObjects) loadObjects();
- }
- #define INDICATOR_SPACING 2
- static inline void drawAbilityIndicators(){
- shape::rect dst(INDICATOR_SPACING,INDICATOR_SPACING, 10,10);
- shape::rect src(0,0, 10,10);
- //shrink
- if(gl_player.has_shrink){
- //src.x = 0;
- gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
- dst.x += 10+INDICATOR_SPACING;
- }
- //double jump
- if(gl_player.has_dbljmp){
- src.x = 10;
- gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
- dst.x += 10+INDICATOR_SPACING;
- }
- //speed
- if(gl_player.has_speed){
- src.x = 20;
- gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
- //dst.x += 10+INDICATOR_SPACING;
- }
- }
- void drawStuff_and_processObjects(){
- bool ro_back = false; //r[ender]o[only] objects that are !in_front
- bool ro_frnt = false; //same thing but only ones with in_front set instead
- //I Can't Believe It's Not Assembly!
- /*_clear_gray :*/ gl_win->clear(0x808080);
- _draw_bg : gl_scene.drawBg();
- /*_draw_mg :*/ gl_scene.drawTiles(false);
- /*_proc_obj_bk:*/ if(processObjects(false,ro_back)){ ro_back=true; goto _draw_bg; }
- /*_draw_player:*/ gl_player.blit();
- /*_draw_fg :*/ gl_scene.drawTiles(true);
- /*_proc_obj_fr:*/ if(processObjects(true ,ro_frnt)){ ro_back=ro_frnt=true; goto _draw_bg; }
- /*_draw_ablity:*/ drawAbilityIndicators();
- }
- //unit should be between 0.0f and 1.0f
- color::ARGB unit_to_ryg(f32 unit){
- unit = CLAMP(unit*2.0f, 0.0f, 2.0f);
- u8 red = 255, green = 255;
- #define _RND(_v) ( (u8)( (_v)+0.5f ) )
- if(unit < 1.0f) green = _RND(255.0f*( unit));
- else red = _RND(255.0f*(2.0f-unit));
- #undef _RND
- return color::ARGB(red, green, 0, 0);
- }
- //assumes 8x8 monospaced with 1 pixel of spacing in both x and y
- shape::point get_text_size(const char* str){
- if(!str) throw "nullptr string was passed to get_text_size()";
- shape::point result(0,9);
- s32 current_width = 0;
- for(; *str != 0; ++str){
- if(*str != '\n'){
- current_width += 9;
- } else {
- result.x = MAX(result.x, current_width);
- result.y += 9;
- current_width = 0;
- }
- }
- result.x = MAX(result.x, current_width);
- if(!result.x) result.y = 0;
- return result;
- }
- //x&y determine the CENTER position of the text, not its top-left corner
- //calculates text_size if either text_size.x or .y is 0
- void drawTextBox(s32 x, s32 y, const char* str, shape::point text_size){
- if(!str) throw "nullptr string was passed to drawTextBox()";
- shape::rect box_rect(x,y, 0,0);
- if(!text_size.x || !text_size.y) text_size = get_text_size(str);
- box_rect.w = text_size.x+2;
- box_rect.h = text_size.y+2;
- box_rect.x -= box_rect.w/2;
- box_rect.y -= box_rect.h/2;
- gl_win->drawRectangles(&box_rect, 1, 0x000000);
- gl_win_drawRectEmpty(box_rect, 0x808080);
- gl_text->print(box_rect.x+2, box_rect.y+2, str);
- }
- bool gl_fullscreen = false;
- static inline void winevent_key_down(u8 vkey){
- switch(vkey){
- case VKEY_ESCAPE: CTRLSTATE_SET(esc_h); break;
- case VKEY_F11 : gl_win->setFullscreen(gl_fullscreen^=1); break;
- #ifdef _DEBUG
- case VKEY_BSLASH: gl_player.confused^=1; break;
- case VKEY_ENTER : gl_player.kill(); break;
- case VKEY_MINUS : saveWrite(); break;
- case VKEY_PLUS : saveRead(); break;
- #endif
- case VKEY_UP : {
- CTRLSTATE_SET(inst.up_p);
- if(PLAYER_CAN_JUMP){
- PLAYER_SET_JMP_FLAGS;
- gl_player.vel.y = -PLAYER_JUMP_STRENGTH;
- gl_player.play_sfx_jumping(!gl_player.dying);
- }
- } break;
- case VKEY_DOWN : {
- CTRLSTATE_SET(inst.down_p);
- } break;
- case VKEY_LEFT : {
- gl_player.going_left = true;
- CTRLSTATE_SET(inst.left_p);
- } break;
- case VKEY_RIGHT: {
- gl_player.going_right = true;
- CTRLSTATE_SET(inst.right_p);
- } break;
- case VKEY_Z : {
- if(gl_player.has_shrink){
- f32 new_scale = (gl_player.scale == 2.0f) ? 1.0f : 2.0f;
- if(!gl_player.setScale(new_scale)) goto _play_nope_1;
- } else {
- _play_nope_1: SFXPTR_PLAY(SFXPTR_NOPE_1);
- }
- } break;
- case VKEY_X : {
- if(gl_player.has_speed) gl_player.enforceMaxVel^=1;
- else SFXPTR_PLAY(SFXPTR_NOPE_1);
- } break;
- }
- }
- static inline void winevent_key_up(u8 vkey){
- switch(vkey){
- case VKEY_ESCAPE: {
- CTRLSTATE_CLR(esc_h);
- } break;
- case VKEY_UP : {
- CTRLSTATE_SET(inst.up_r);
- if(PLAYER_JUMPED && gl_player.vel.y<0)
- gl_player.vel.y *= PLAYER_JUMP_CANCEL;
- } break;
- case VKEY_DOWN : {
- CTRLSTATE_SET(inst.down_r);
- } break;
- case VKEY_LEFT : {
- gl_player.going_left = false;
- CTRLSTATE_SET(inst.left_r);
- } break;
- case VKEY_RIGHT : {
- gl_player.going_right = false;
- CTRLSTATE_SET(inst.right_r);
- } break;
- }
- }
- bool handleEvents(){
- bool run = true;
- WindowEvent e;
- while(pollWindowEvent(&e))
- switch(e.type){
- case WINEVENT_WIN_CLOSE: run = false; break;
- case WINEVENT_KEY_DOWN: if(!e.key.repeat){ winevent_key_down(e.key.vkey); } break;
- case WINEVENT_KEY_UP: winevent_key_up(e.key.vkey); break;
- }
- return run;
- }
- void attemptReset(bool skipRead){
- gl_player.dying = false;
- if(skipRead || !saveRead()){
- //objects should already have been loaded during init
- loadScene(STARTING_SCENE);
- gl_player.pos = STARTING_POSITION;
- gl_player.vel = {0.0f, 0.0f};
- gl_player.resetAbilities();
- gl_player.going_left = false;
- gl_player.going_right = false;
- gl_player.visible = true;
- for(u32 i=1; i<(gl_scenes_len+1); ++i)
- loadObjects(true, i);
- }
- }
- #ifndef LERP
- #define LERP(_v0, _v1, _t) ( (1.0f-(_t)) * (_v0) + (_t) * (_v1) )
- #endif
- //this is an easing function
- static inline f32 ease(f32 unit){
- unit = CLAMP(unit, 0.0f, 1.0f);
- return LERP(unit, 1.0f, unit);
- }
- #define burst_separation 20
- #define hide_rect_width 16
- #define death_prog_inc 0.015f
- void deathAnim(){
- if(gl_death_prog >= DEATH_PROG_MAX) return; //probably unnecessary
- static bool loaded_save;
- static shape::rect player_src;
- static color::ARGB hide_rect_color;
- if(gl_death_prog == 0.0f){
- loaded_save = false;
- //this will only fill player_src with the current
- //player spritesheet rect without actually blitting
- player_src = gl_player.blit(true);
- player_src.y = (8+1)*4; //shift down by 4 8px tiles, with 1px of spacing
- player_src.w = 4; //4x4 to make src rect 1/4 the size of the full sprite
- player_src.h = 4;
- //unnecessary, but a cool effect so i'm keeping it in
- hide_rect_color.r = RND(255.0f*frandf());
- hide_rect_color.g = RND(255.0f*frandf());
- hide_rect_color.b = RND(255.0f*frandf());
- }
- //for drawing rectangles that hide the screen during saveRead
- shape::rect hide[2];
- hide[0].w = hide_rect_width;
- hide[1].w = hide_rect_width;
- if(gl_death_prog < 2.0f){
- f32 prog_unit = CLAMP(gl_death_prog, 0.0f, 1.0f);
- s32 burst_distance = (s32)(ease(prog_unit)*burst_separation);
- shape::rect player_dst = gl_player.getRect();
- shape::rect burst_chunk;
- burst_chunk.w = RND(4.0f*gl_player.scale*(1.0f-prog_unit));
- burst_chunk.h = burst_chunk.w;
- //top-left
- burst_chunk.x = player_dst.x - burst_distance;
- burst_chunk.y = player_dst.y - burst_distance;
- gl_spritesheetPlayer->blitRect(&burst_chunk, &player_src, 0xff00ff);
- player_src.x += 4;
- //top-right
- burst_chunk.x = player_dst.x + burst_distance + 4;
- burst_chunk.y = player_dst.y - burst_distance;
- gl_spritesheetPlayer->blitRect(&burst_chunk, &player_src, 0xff00ff);
- player_src.y += 4;
- //bottom-right
- burst_chunk.x = player_dst.x + burst_distance + 4;
- burst_chunk.y = player_dst.y + burst_distance + 4;
- gl_spritesheetPlayer->blitRect(&burst_chunk, &player_src, 0xff00ff);
- player_src.x -= 4;
- //bottom-left
- burst_chunk.x = player_dst.x - burst_distance;
- burst_chunk.y = player_dst.y + burst_distance + 4;
- gl_spritesheetPlayer->blitRect(&burst_chunk, &player_src, 0xff00ff);
- player_src.y -= 4;
- f32 height_multiplier = MAX(ease(gl_death_prog-1.0f), 0.0f);
- hide[0].h = (s32)(CANVSIZ_Y*height_multiplier);
- hide[1].h = (s32)(CANVSIZ_Y*height_multiplier);
- hide[1].y += CANVSIZ_Y - hide[1].h;
- } else {
- f32 height_multiplier = ease(DEATH_PROG_MAX-gl_death_prog);
- hide[0].h = (s32)(CANVSIZ_Y*height_multiplier);
- hide[1].h = (s32)(CANVSIZ_Y*height_multiplier);
- hide[0].y += CANVSIZ_Y - hide[0].h;
- }
- if(gl_death_prog >= 1.0f){
- hide[1].x += hide_rect_width;
- for(u32 i=0; i<CANVSIZ_X; i+=hide_rect_width*2){
- gl_win->drawRectangles(hide, 2, hide_rect_color);
- hide[0].x += hide_rect_width*2;
- hide[1].x += hide_rect_width*2;
- }
- }
- gl_death_prog += death_prog_inc;
- if(!loaded_save && gl_death_prog >= 2.0f){
- attemptReset();
- loaded_save = true;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement