Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\main.cpp":
- #include <kit/all.hpp>
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "test_main_utils.hpp"
- using namespace kit;
- //get random 64-bit float value from 0.0 -> 1.0
- f64 drand(){
- u32 value = ((u32)rand())<<15 | rand();
- return (f64)value/(KIT_U32_MAX>>2);
- }
- #define canvasX 256
- #define canvasY 144
- Window* win;
- char buffer[4096];
- size_t numChars = 0;
- shape::point points[] = {
- { 4, 5},
- { 50, 50},
- {150, 50},
- { 25, 2},
- };
- shape::rect rects[] = {
- {1,10, 5,5},
- {3,30, 4,4},
- };
- struct f32_stereo { float l,r; };
- int t=0;
- s32 callback(const void* _inBuffer, void* _outBuffer,
- const AudioStreamInfo* info, void* userdata)
- {
- (void)_inBuffer; //unused
- (void)userdata; //
- f32_stereo* outBuffer = (f32_stereo*)_outBuffer;
- s32 sampleRate = (s32)info->sampleRate;
- u32 numSamples = info->sampleFrames;
- for(u32 i=0; i<numSamples; ++i){
- outBuffer[i].l = sinf(((f32)(t++)/sampleRate)*3.14159f*2*440)*0.5f;
- outBuffer[i].r = outBuffer[i].l;
- }
- return ASTREAM_RTN_CONTINUE;
- }
- s32 threadFunc(void* userdata){
- printf("start of func\n");
- time::sleep(500);
- printf("end of func\n");
- return -2;
- }
- f64 sleepTest(u32 ms){
- u64 ticksStart = time::getTicks();
- time::sleep(ms);
- u64 ticksDelta = time::getTicks()-ticksStart;
- return (f64)ticksDelta/time::getTicksPerSecond();
- }
- u32 profileFrameSleep(){
- f64 closestValue = 0.1, smallestDifference = 1.0;
- for(int i=9; i<17; ++i){
- f64 result = ( sleepTest(i) + sleepTest(i) + sleepTest(i) ) / 3;
- f64 currentDifference = fabs(result-0.01667);
- if(currentDifference < smallestDifference){
- smallestDifference = currentDifference;
- closestValue = result;
- }
- }
- return (u32)(closestValue*1000);
- }
- f32 scale = 1.0f;
- shape::point pos(0,0);
- int main(int argc, char** argv){ try {
- //seed rng
- srand(time::getTicks()&KIT_U32_MAX);
- //create window
- win = new Window("cool snake game", //window title
- 1280, 720, //initial window size
- WINFLAG_RESIZABLE, //window capability flags
- WINPOS_CENTERED, //window x position
- WINPOS_CENTERED, //window y position
- 0, 0, //canvas size
- true); //'can pixels be accessed directly?'
- //win->setVisibility(true);
- //Bitmap bmp(ball, 8,8, win, false);
- Bitmap bmp("mass.qoi", win);
- bmp.setBlitDestination(win);
- win->setCanvasSize(canvasX,canvasY);
- FStr _fstr(2048);
- BitmapFont pico8("_fontPico8.qoi", win);
- BitmapFont text("_font8x8.qoi", win);
- buffer[0] = 0;
- #define pico8f(_x,_y, _fmt,...) pico8.print((_y),(_y), _fstr.fmt(_fmt,__VA_ARGS__), 0)
- #define textf(_x,_y, _fmt,...) text.print((_y),(_y), _fstr.fmt(_fmt,__VA_ARGS__) , 0)
- TimerSimple frameTimer;
- //run loop
- bool run = true, fullscreen = false;
- _before_loop:
- while(run){
- u64 startTicks = time::getTicks();
- frameTimer.setTimer(0.001);
- //process events in event queue
- WindowEvent event;
- while(pollWindowEvent(&event)){
- //printEvent(event);
- switch(event.type){
- case WINEVENT_WIN_CLOSE: run = false; goto _before_loop;
- case WINEVENT_KEY_DOWN:
- {
- switch(event.key.vkey){
- case VKEY_ESCAPE: run = false; goto _before_loop;
- case VKEY_F11 : fullscreen ^= 1; win->setFullscreen(fullscreen); break;
- case VKEY_UP : scale += 0.125f; break;
- case VKEY_DOWN : scale -= 0.125f; break;
- case VKEY_LEFT : pos.y -= 1; break;
- case VKEY_RIGHT : pos.y += 1; break;
- }
- } break;
- case WINEVENT_KEY_CHAR:
- {
- if(event.key.vkey == VKEY_ENTER){
- buffer[(numChars++)&4095] = '\n';
- } else if(event.key.vkey == '\b'){
- buffer[(--numChars)&4095] = 0;
- } else {
- buffer[(numChars++)&4095] = event.key.vkey;
- }
- if(numChars > 4095) numChars = 0;
- } break;
- }
- }
- win->clear(0x007f007f);
- bmp.blit(pos.x,pos.y, scale);
- win->drawRectangles(rects, 2, 0x00007f);
- text.setScale(scale,scale);
- text.print(1,1,buffer);
- //pico8.print(1,1,buffer);
- //pico8f(1,40,"test %u",4);
- win->drawLines(points, 4, 0x0000ff, 5);
- win->drawPoints(points,sizeof(points)/sizeof(shape::point), 0x0000ff, false);
- win->drawPoint({0,0}, 0x0000ff);
- win->present();
- //time::sleep(10);
- frameTimer.wait();
- //printf("%f\n",(f64)(time::getTicks()-startTicks)/10000);
- }
- delete win;
- s32* a = nullptr;
- if(!memory::realloc(&a, sizeof(s32))) return -2;
- *a = 5;
- printf("a = %p, *a = %i\n", a, *a);
- if(!memory::realloc(&a, sizeof(s32)*2)) return -2;
- a[1] = 3;
- printf("a = %p, a[0] = %i, a[1] = %i\n", a, a[0], a[1]);
- memory::free(&a);
- /*
- Thread testThread(threadFunc, nullptr, true);
- AudioStream stream(callback,nullptr,2048);
- stream.start();
- time::sleep(1001);
- stream.stop();
- time::sleep(100);
- */
- printf("%llu,",memory::getNumAllocations());
- MutexSimple* mutex = new MutexSimple;
- printf("%llu,",memory::getNumAllocations());
- delete mutex;
- printf("%llu\n",memory::getNumAllocations());
- return 0;
- } catch(const char* errorText){
- #ifdef _DEBUG
- printf("FATAL EXCEPTION OCCURRED!: \"%s\"\n",errorText);
- #else
- showMessageBox(errorText,"FATAL EXCEPTION OCCURRED!", MSGBOX_ICN_ERROR);
- #endif /* _DEBUG */
- return -1;
- }}
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_AudioStream.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_INVALID_AUDIOSTREAM _kit_invalid_audiostream
- #define KIT_IS_INVALID_AUDIOSTREAM (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_audiostream[] = "invalid audio stream";
- int _AudioStream_PaCallback(const void* inBuffer, void* outBuffer, u32 smpFrames,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags, void* userdata)
- {
- (void)statusFlags; //these are left unused
- AudioStream* stream = (AudioStream*)userdata;
- if(!KIT_IS_CLASS_VALID(stream)) return paAbort;
- _AudioStreamOpaque* opq = (_AudioStreamOpaque*)KIT_GET_CLASS_OPAQUE(stream);
- if(opq == nullptr) return paAbort;
- stream->lock(true);
- //update relevant values in stream info
- AudioStreamInfo* info = &opq->astreamInfo;
- info->timeInput = timeInfo->inputBufferAdcTime;
- info->timeCurrent = timeInfo->currentTime;
- info->timeOutput = timeInfo->outputBufferDacTime;
- if(info->inputDeviceID != -1){
- info->inputBufferSize = smpFrames * info->inputChannels *
- KIT_ASTREAM_FMT_BYTESIZE(info->inputFormat);
- }
- if(info->outputDeviceID != -1){
- info->outputBufferSize = smpFrames * info->outputChannels *
- KIT_ASTREAM_FMT_BYTESIZE(info->inputFormat);
- }
- info->sampleFrames = smpFrames;
- int result = paAbort;
- if(opq->callback != nullptr){
- result = opq->callback(inBuffer, outBuffer, &opq->astreamInfo, opq->userdata);
- }
- stream->lock(false);
- return result;
- }
- void _AudioStream_PaFinishedCallback(void* userdata){
- AudioStream* stream = (AudioStream*)userdata;
- if(!KIT_IS_CLASS_VALID(stream)) return;
- _AudioStreamOpaque* opq = (_AudioStreamOpaque*)KIT_GET_CLASS_OPAQUE(stream);
- if(opq == nullptr) return;
- stream->lock(true);
- if(opq->endCallback != nullptr) opq->endCallback(opq->userdata);
- stream->lock(false);
- }
- void AudioStream::_construct(const AudioStreamParams* params){
- _type = KIT_CLASSTYPE_AUDIOSTREAM;
- if(params == nullptr)
- throw "params = nullptr";
- if(params->inputDeviceID == -1 && params->outputDeviceID == -1)
- throw "no device ID was given";
- if(params->callback == nullptr)
- throw "callback cannot be nullptr";
- _opq = (_AudioStreamOpaque*)memory::alloc(sizeof(_AudioStreamOpaque));
- if(_opq == nullptr) throw "ran out of memory creating _opq";
- memory::set(_opq, 0, sizeof(_AudioStreamOpaque));
- const char* errorText = nullptr;
- if(0){ //entered in the event of an exception
- //(deleting critical section is not necessary, since creation of it will
- //never fail, and it's the last thing to initialize anyway)
- //_DelCritSect: DeleteCriticalSection(&_opq->lock);
- _CloseStream: Pa_CloseStream(_opq->streamPtr);
- _FreeOpaque : memory::free(&_opq);
- throw errorText;
- }
- _opq->callback = params->callback;
- _opq->userdata = params->userdata;
- //input parameters
- PaStreamParameters* inParams = nullptr;
- f64 inDefSmpRate = -1.0;
- if(params->inputDeviceID > -1){
- inParams = &_opq->streamInputParams;
- inParams->device = params->inputDeviceID;
- inParams->channelCount = params->inputChannels;
- inParams->sampleFormat = ConvertToPaSampleFormat(params->inputFormat);
- inParams->suggestedLatency = params->inputSuggestedLatency;
- if(inParams->sampleFormat == paCustomFormat){
- errorText = "invalid input sample format";
- goto _FreeOpaque;
- }
- const PaDeviceInfo* inDevInfo = Pa_GetDeviceInfo(inParams->device);
- if(inDevInfo == nullptr){
- errorText = "invalid input device ID";
- goto _FreeOpaque;
- }
- inDefSmpRate = inDevInfo->defaultSampleRate;
- if(inParams->channelCount < 0)
- inParams->channelCount = MIN(2, inDevInfo->maxInputChannels);
- if(inParams->suggestedLatency < 0.0)
- inParams->suggestedLatency = inDevInfo->defaultHighInputLatency;
- }
- //output parameters
- PaStreamParameters* outParams = nullptr;
- f64 outDefSmpRate = -1.0;
- if(params->outputDeviceID > -1){
- outParams = &_opq->streamOutputParams;
- outParams->device = params->outputDeviceID;
- outParams->channelCount = params->outputChannels;
- outParams->sampleFormat = ConvertToPaSampleFormat(params->outputFormat);
- outParams->suggestedLatency = params->outputSuggestedLatency;
- if(outParams->sampleFormat == paCustomFormat){
- errorText = "invalid output sample format";
- goto _FreeOpaque;
- }
- const PaDeviceInfo* outDevInfo = Pa_GetDeviceInfo(outParams->device);
- if(outDevInfo == nullptr){
- errorText = "invalid output device ID";
- goto _FreeOpaque;
- }
- outDefSmpRate = outDevInfo->defaultSampleRate;
- if(outParams->channelCount < 0)
- outParams->channelCount = MIN(2, outDevInfo->maxOutputChannels);
- if(outParams->suggestedLatency < 0.0)
- outParams->suggestedLatency = outDevInfo->defaultHighOutputLatency;
- }
- //sample rate
- f64 sampleRate = params->sampleRate;
- if(sampleRate < 0.0){
- if(inDefSmpRate != -1.0 && outDefSmpRate != -1.0){
- if(inDefSmpRate != outDefSmpRate) //idk how this would happen, but just in case
- throw "input and output's default sample rates are different";
- sampleRate = inDefSmpRate;
- } else if(inDefSmpRate != -1.0){
- sampleRate = inDefSmpRate;
- } else if(outDefSmpRate != -1.0){
- sampleRate = outDefSmpRate;
- }
- }
- PaError err = Pa_OpenStream(&_opq->streamPtr, inParams, outParams,
- sampleRate, params->sampleFrames, paNoFlag,
- (PaStreamCallback*)_AudioStream_PaCallback, this);
- if(err != paNoError){
- errorText = Pa_GetErrorText(err);
- goto _FreeOpaque;
- }
- err = Pa_SetStreamFinishedCallback(_opq->streamPtr, _AudioStream_PaFinishedCallback);
- if(err != paNoError){
- errorText = Pa_GetErrorText(err);
- goto _CloseStream;
- }
- const PaStreamInfo* streamInfo = Pa_GetStreamInfo(_opq->streamPtr);
- if(streamInfo == nullptr){
- errorText = "failed to get stream info";
- goto _CloseStream;
- }
- AudioStreamInfo* astreamInfo = &_opq->astreamInfo;
- //(time, buffer size, and sample frames are set each callback, but not here)
- astreamInfo->inputDeviceID = params->inputDeviceID;
- astreamInfo->outputDeviceID = params->outputDeviceID;
- astreamInfo->inputChannels = ( inParams != nullptr) ? inParams->channelCount : -1;
- astreamInfo->outputChannels = (outParams != nullptr) ? outParams->channelCount : -1;
- astreamInfo->inputFormat = params->inputFormat;
- astreamInfo->outputFormat = params->outputFormat;
- astreamInfo->sampleRate = streamInfo->sampleRate;
- astreamInfo->inputLatency = streamInfo->inputLatency;
- astreamInfo->outputLatency = streamInfo->outputLatency;
- InitializeCriticalSectionAndSpinCount(&_opq->lock, KIT_LOCK_SPINCOUNT);
- _valid = true;
- _constructing = false;
- }
- AudioStream::AudioStream(AudioStreamCallback callback, void* userdata,
- u32 sampleFrames, s32 channels)
- {
- AudioStreamParams params;
- params.callback = callback;
- params.userdata = userdata;
- params.outputDeviceID = Pa_GetDefaultOutputDevice();
- params.sampleFrames = sampleFrames;
- //all other fields will be set to their defaults
- _construct(¶ms);
- }
- AudioStream::~AudioStream(){
- if(!_valid) return;
- _valid = false;
- if(_opq != nullptr){
- Pa_AbortStream(_opq->streamPtr);
- Pa_CloseStream(_opq->streamPtr);
- DeleteCriticalSection(&_opq->lock);
- memory::free(&_opq);
- }
- }
- bool AudioStream::isActive(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- PaError active = Pa_IsStreamActive(_opq->streamPtr);
- if(active < 0) throw Pa_GetErrorText(active);
- return active;
- }
- f64 AudioStream::getTime(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- f64 time = Pa_GetStreamTime(_opq->streamPtr);
- if(time == 0) throw "failed to get stream's time";
- return time;
- }
- f64 AudioStream::getCPULoad(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- return Pa_GetStreamCpuLoad(_opq->streamPtr);
- }
- AudioStreamInfo AudioStream::getInfo(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- lock(true);
- AudioStreamInfo info = _opq->astreamInfo;
- lock(false);
- return info; //big ol' struct
- }
- void AudioStream::setCallback(AudioStreamCallback newCallback){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- if(newCallback == nullptr) throw "newCallback = nullptr";
- lock(true);
- _opq->callback = newCallback;
- lock(false);
- }
- void AudioStream::setEndCallback(AudioStreamEndCallback newEndCallback){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- lock(true);
- _opq->endCallback = newEndCallback; //can be nullptr
- lock(false);
- }
- void AudioStream::lock(bool locked){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- if(locked) EnterCriticalSection(&_opq->lock);
- else LeaveCriticalSection(&_opq->lock);
- }
- void AudioStream::start(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- PaError err = Pa_StartStream(_opq->streamPtr);
- if(err != paNoError) throw Pa_GetErrorText(err);
- }
- void AudioStream::stop(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- PaError err = Pa_StopStream(_opq->streamPtr);
- if(err != paNoError) throw Pa_GetErrorText(err);
- }
- void AudioStream::abort(){
- if(KIT_IS_INVALID_AUDIOSTREAM) throw KIT_INVALID_AUDIOSTREAM;
- PaError err = Pa_AbortStream(_opq->streamPtr);
- if(err != paNoError) throw Pa_GetErrorText(err);
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_audio_func.cpp":
- #include "_kit_common_shared.hpp"
- namespace kit {
- s32 audio::getDeviceCount(){
- s32 deviceCount = Pa_GetDeviceCount();
- if(deviceCount < 0) throw Pa_GetErrorText(deviceCount);
- return deviceCount;
- }
- s32 audio::getDefInputDevice(){
- s32 defaultInputDevice = Pa_GetDefaultInputDevice();
- if(defaultInputDevice < 0) throw Pa_GetErrorText(defaultInputDevice);
- return defaultInputDevice;
- }
- s32 audio::getDefOutputDevice(){
- s32 defaultOutputDevice = Pa_GetDefaultOutputDevice();
- if(defaultOutputDevice < 0) throw Pa_GetErrorText(defaultOutputDevice);
- return defaultOutputDevice;
- }
- AudioDeviceInfo audio::getDeviceInfo(s32 deviceID){
- const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(deviceID);
- if(deviceInfo == nullptr) throw "Device ID out of range";
- AudioDeviceInfo adeviceInfo;
- adeviceInfo.name = deviceInfo->name;
- adeviceInfo.maxChannels.input = deviceInfo->maxInputChannels;
- adeviceInfo.maxChannels.output = deviceInfo->maxOutputChannels;
- adeviceInfo.defLoLatency.input = deviceInfo->defaultLowInputLatency;
- adeviceInfo.defLoLatency.output = deviceInfo->defaultLowOutputLatency;
- adeviceInfo.defHiLatency.input = deviceInfo->defaultHighInputLatency;
- adeviceInfo.defHiLatency.output = deviceInfo->defaultHighOutputLatency;
- adeviceInfo.defSampleRate = deviceInfo->defaultSampleRate;
- return adeviceInfo;
- }
- bool audio::areParamsSupported(const AudioStreamParams* params,
- const char** reason_p)
- {
- if(params == nullptr) throw "params = nullptr";
- PaStreamParameters inParams, *_inParams = nullptr;
- PaStreamParameters outParams, *_outParams = nullptr;
- f64 inDefSmpRate = -1.0;
- if(params->inputDeviceID > -1){
- _inParams = &inParams;
- inParams.device = params->inputDeviceID;
- inParams.channelCount = params->inputChannels;
- inParams.sampleFormat = ConvertToPaSampleFormat(params->inputFormat);
- inParams.suggestedLatency = params->inputSuggestedLatency;
- const PaDeviceInfo* inDevInfo = Pa_GetDeviceInfo(inParams.device);
- if(inDevInfo == nullptr)
- throw "invalid input device ID";
- inDefSmpRate = inDevInfo->defaultSampleRate;
- if(inParams.channelCount < 0)
- inParams.channelCount = MIN(2, inDevInfo->maxInputChannels);
- if(inParams.suggestedLatency < 0.0)
- inParams.suggestedLatency = inDevInfo->defaultHighInputLatency;
- }
- f64 outDefSmpRate = -1.0;
- if(params->outputDeviceID > -1){
- _outParams = &outParams;
- outParams.device = params->outputDeviceID;
- outParams.channelCount = params->outputChannels;
- outParams.sampleFormat = ConvertToPaSampleFormat(params->outputFormat);
- outParams.suggestedLatency = params->outputSuggestedLatency;
- const PaDeviceInfo* outDevInfo = Pa_GetDeviceInfo(outParams.device);
- if(outDevInfo == nullptr)
- throw "invalid output device ID";
- outDefSmpRate = outDevInfo->defaultSampleRate;
- if(outParams.channelCount < 0)
- outParams.channelCount = MIN(2, outDevInfo->maxOutputChannels);
- if(outParams.suggestedLatency < 0.0)
- outParams.suggestedLatency = outDevInfo->defaultHighOutputLatency;
- }
- f64 sampleRate = params->sampleRate;
- if(sampleRate < 0.0){
- if(inDefSmpRate != -1.0 && outDefSmpRate != -1.0){
- if(inDefSmpRate != outDefSmpRate) //idk how this would happen, but just in case
- throw "input and output's default sample rates are different";
- sampleRate = inDefSmpRate;
- } else if(inDefSmpRate != -1.0){
- sampleRate = inDefSmpRate;
- } else if(outDefSmpRate != -1.0){
- sampleRate = outDefSmpRate;
- }
- }
- PaError err = Pa_IsFormatSupported(_inParams, _outParams, params->sampleRate);
- if(err!=paNoError && reason_p!=nullptr) *reason_p = Pa_GetErrorText(err);
- return err == paNoError;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Bitmap.cpp":
- #include "kit_Bitmap_shared.hpp"
- #define KIT_INVALID_BITMAP _kit_invalid_bitmap
- #define KIT_IS_INVALID_BITMAP (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_bitmap[] = "invalid bitmap";
- void Bitmap::_constructFromMemory(const color::ARGB* pixelData, u32 width, u32 height,
- Window* blit_dst, bool directAccess)
- {
- _type = KIT_CLASSTYPE_BITMAP;
- //validate parameters
- if(!width ) throw "width = 0";
- if(!height) throw "height = 0";
- if(blit_dst == nullptr)
- throw "blit_dst = nullptr"; //(blit_d[e]st[ination])
- if(!KIT_IS_CLASS_TYPE(blit_dst, KIT_CLASSTYPE_WINDOW))
- throw "*blit_dst is not a Window";
- if(!KIT_IS_CLASS_VALID(blit_dst))
- throw "*blit_dst is invalid";
- _WindowOpaque* win_opq = (_WindowOpaque*)KIT_GET_CLASS_OPAQUE(blit_dst);
- //allocate memory for opaque struct (aka the internal bitmap thingy)
- _opq = (_BitmapOpaque*)memory::alloc(sizeof(_BitmapOpaque));
- if(_opq == nullptr) throw "ran out of memory creating _opq";
- memory::set(_opq, 0, sizeof(_BitmapOpaque));
- //fill in that internal bitmap thingy
- if(!PopulateBitmapOpaque(*_opq, pixelData, width, height,
- win_opq, directAccess))
- {
- memory::free(&_opq);
- throw "failed to create internal bitmap";
- }
- //initialize mutex
- InitializeCriticalSectionAndSpinCount(&_opq->lock, KIT_LOCK_SPINCOUNT);
- //set pixels to that of pixelData, if != nullptr
- setPixelData(pixelData, width, height);
- _valid = true;
- _constructing = false;
- }
- //loads from a file
- Bitmap::Bitmap(const char* filePath, Window* blit_dst, bool directAccess){
- BinaryData fileData(filePath); //will throw on failure to read file
- shape::point bmpSize; //filled in with the bitmap's size by _parse<format>
- color::ARGB* pixelData = nullptr; //set by _parse<format> (must be freed after use!)
- switch(fileData.getMagic32()){
- case KIT_MAGIC_QOI: pixelData = _parseQOI(fileData, bmpSize); break;
- default: throw "unknown image format";
- }
- const char* errorText = nullptr;
- try { _constructFromMemory(pixelData, bmpSize.x, bmpSize.y, blit_dst, directAccess);
- } catch(const char* _errorText){ errorText = _errorText; }
- memory::free(&pixelData); //free intermediate pixel array
- if(errorText != nullptr) throw errorText;
- }
- Bitmap::~Bitmap(){
- if(!_valid) return;
- _valid = false;
- if(_opq != nullptr){
- DeleteCriticalSection(&_opq->lock);
- DeleteObject(_opq->handle);
- DeleteDC(_opq->devCtx);
- memory::free(&_opq);
- }
- }
- bool Bitmap::isDirectAccess(){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- return _opq->directAccess;
- }
- color::ARGB* Bitmap::getPixels(){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- if(_opq->directAccess) return _opq->pixels;
- else throw "bitmap does not support direct access";
- }
- shape::point Bitmap::getSize(){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- return _opq->size;
- }
- void Bitmap::getPixelData(color::ARGB* pixelDataOut){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- if(pixelDataOut == nullptr) throw "pixelDataOut = nullptr";
- if(_opq->directAccess){
- memory::copy(pixelDataOut, _opq->pixels,
- sizeof(color::ARGB)*_opq->size.x*_opq->size.y);
- } else {
- GetDIBits(_opq->devCtx, _opq->handle, 0, _opq->size.y, pixelDataOut,
- &_opq->info, DIB_RGB_COLORS);
- }
- }
- void Bitmap::setPixelData(const color::ARGB* pixelData, u32 width, u32 height){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- lock(true);
- //recreate or resize the bitmap if necessary
- if(_opq->size.x!=width || _opq->size.y!=height){
- if(!width ) width = _opq->size.x;
- if(!height) height = _opq->size.y;
- if(!ResizeBitmapOpaque(*_opq, width, height)){
- lock(false);
- throw "failed to resize bitmap";
- }
- }
- //actually set the pixel data (but only if pixelData != nullptr)
- if(pixelData != nullptr){
- if(_opq->directAccess){
- if(_opq->pixels != nullptr)
- memory::copy(_opq->pixels, pixelData, sizeof(color::ARGB)*width*height);
- } else {
- if(_opq->handle != nullptr)
- SetDIBits(_opq->devCtx, _opq->handle, 0, height, pixelData,
- &_opq->info, DIB_RGB_COLORS);
- }
- }
- lock(false);
- }
- void Bitmap::setBlitDestination(Window* blit_dst){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- color::ARGB* pixelData = nullptr;
- //setPixelData also locks, but it's safe to lock >1 on same thread
- lock(true);
- try {
- //store pixel data temporarily
- size_t numPixels = _opq->size.x * _opq->size.y;
- pixelData = (color::ARGB*)memory::alloc(sizeof(color::ARGB) * numPixels);
- if(pixelData == nullptr) throw "failed to allocate pixel data cache";
- getPixelData(pixelData); //fill pixelData with the bitmap's original pixel data
- //switch old window opaque with the new one
- _opq->window = (_WindowOpaque*)KIT_GET_CLASS_OPAQUE(blit_dst);
- //recreate bitmap, before writing its pixel data back
- setPixelData(pixelData, 0, 0);
- memory::free(&pixelData);
- lock(false);
- } catch(const char* errorText){
- //it's actually safe to pass nullptr (&pixelData or pixelData) to free,
- //but i'll keep the if statement here for clarity
- if(pixelData != nullptr) memory::free(&pixelData);
- lock(false);
- throw errorText;
- }
- }
- void Bitmap::lock(bool locked){
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- if(locked) EnterCriticalSection(&_opq->lock);
- else LeaveCriticalSection(&_opq->lock);
- }
- void Bitmap::blitRect(shape::rect* dst, shape::rect* src,
- color::ARGB transparency)
- {
- if(KIT_IS_INVALID_BITMAP) throw KIT_INVALID_BITMAP;
- //if src = nullptr, blit the entire bitmap
- shape::rect _src;
- if(src != nullptr){
- _src = *src;
- } else {
- _src.w = _opq->size.x;
- _src.h = _opq->size.y;
- }
- shape::point canvasSize = _opq->window->canvas.size;
- //if dst = nullptr, stretch the bitmap across the entire canvas
- shape::rect _dst;
- if(dst != nullptr){
- _dst = *dst;
- //also, if dst dimensions < 0, use source dimensions
- if(_dst.w < 0) _dst.w = _src.w;
- if(_dst.h < 0) _dst.h = _src.h;
- } else {
- _dst.w = canvasSize.x;
- _dst.h = canvasSize.y;
- }
- //don't blit if the bitmap would appear off-screen
- if(_dst.x<=-_dst.w || _dst.y<=-_dst.h ||
- _dst.x>=canvasSize.x || _dst.y>=canvasSize.y) return;
- lock(true);
- if(transparency.v == 0x80000000){ //use StretchBlt
- StretchBlt(_opq->window->canvas.devCtx, _dst.x, _dst.y, _dst.w, _dst.h,
- _opq->devCtx, _src.x, _src.y, _src.w, _src.h, SRCCOPY);
- } else { //use TransparentBlt
- transparency.v &= 0x00ffffff; //set high byte of transparent color to 0 just in case
- TransparentBlt(_opq->window->canvas.devCtx, _dst.x, _dst.y, _dst.w, _dst.h,
- _opq->devCtx, _src.x, _src.y, _src.w, _src.h, transparency.v);
- }
- lock(false);
- }
- void Bitmap::blit(s32 x, s32 y, f32 scale,
- color::ARGB transparency)
- {
- shape::rect dst;
- dst.x = x;
- dst.y = y;
- dst.w = (s32)( (f32)_opq->size.x*scale + 0.5f ); //+0.5 for rounding to
- dst.h = (s32)( (f32)_opq->size.y*scale + 0.5f ); //the nearest pixel
- //by making the src parameter nullptr, the entire bitmap is copied
- blitRect(&dst, nullptr, transparency);
- }
- void Bitmap::blitCentered(s32 xCenter, s32 yCenter, f32 scale,
- color::ARGB transparency)
- {
- shape::rect dst;
- dst.w = (s32)( (f32)_opq->size.x*scale + 0.5f ); //+0.5 for rounding to
- dst.h = (s32)( (f32)_opq->size.y*scale + 0.5f ); //the nearest pixel
- dst.x = xCenter - dst.w/2;
- dst.y = yCenter - dst.h/2;
- //by making the src parameter nullptr, the entire bitmap is copied
- blitRect(&dst, nullptr, transparency);
- }
- }; /* namespace kit */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement