Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_memory.cpp":
- #include "_kit_common_shared.hpp"
- //turns something into a void**
- //(this makes some code here easier for me to read)
- #define VPP(_ptr_p) ((void**)(_ptr_p))
- namespace kit {
- static size_t numAllocations = 0;
- void* memory::alloc(size_t size){
- void* newHeapMemory = CoTaskMemAlloc(size);
- if(newHeapMemory != nullptr) ++numAllocations;
- return newHeapMemory;
- }
- void memory::free(void* ptr_p){
- if(VPP(ptr_p) != nullptr && *VPP(ptr_p) != nullptr){
- --numAllocations;
- CoTaskMemFree(*VPP(ptr_p));
- *VPP(ptr_p) = nullptr;
- }
- }
- void* memory::realloc(void* ptr_p, size_t newSize){
- void* ptr_new = nullptr;
- if(VPP(ptr_p) != nullptr){
- ptr_new = CoTaskMemRealloc(*VPP(ptr_p), newSize);
- if(ptr_new != nullptr){
- if(*VPP(ptr_p) == nullptr) ++numAllocations;
- *VPP(ptr_p) = ptr_new;
- }
- }
- return ptr_new;
- }
- void* memory::alloc2(size_t size){
- void* newHeapMemory = CoTaskMemAlloc(size);
- if(newHeapMemory == nullptr) throw "failed to allocate memory";
- ++numAllocations;
- return newHeapMemory;
- }
- void memory::free2(void* ptr_p){
- if( VPP(ptr_p) == nullptr) throw "ptr_p == nullptr";
- if(*VPP(ptr_p) == nullptr) throw "*ptr_p == nullptr";
- --numAllocations;
- CoTaskMemFree(*VPP(ptr_p));
- *VPP(ptr_p) = nullptr;
- }
- void* memory::realloc2(void* ptr_p, size_t newSize){
- void* ptr_new = nullptr;
- if(VPP(ptr_p) != nullptr){
- ptr_new = CoTaskMemRealloc(*VPP(ptr_p), newSize);
- if(ptr_new != nullptr){
- if(*VPP(ptr_p) == nullptr) ++numAllocations;
- *VPP(ptr_p) = ptr_new;
- }
- } else {
- throw "ptr_p = nullptr";
- }
- if(ptr_new == nullptr) throw "failed to reallocate memory";
- return ptr_new;
- }
- size_t memory::getNumAllocations(){
- return numAllocations;
- }
- //currently just a wrapper, but now i can make my own implementation
- //whenever i want, without replacing every call to memset with it
- void* memory::set(void* ptr, s32 value, size_t size){
- if(ptr == nullptr) return nullptr; //now it's safe to pass nullptr :D
- return memset(ptr, value, size);
- }
- void* memory::set2(void* ptr, s32 value, size_t size){
- if(ptr == nullptr) throw "ptr = nullptr";
- return memset(ptr, value, size);
- }
- void* memory::copy(void* destination, const void* source, size_t size){
- return memcpy(destination, source, size);
- }
- void* memory::copy2(void* destination, const void* source, size_t size){
- if(destination == nullptr) throw "destination = nullptr";
- if(source == nullptr) throw "source = nullptr";
- return memcpy(destination, source, size);
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Mutex.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_MUTEX_NULLPTR _kit_mutex_nullptr
- using namespace kit;
- static const char _kit_mutex_nullptr[] = "internal mutex = nullptr";
- MutexSimple::MutexSimple(u32 spinCount){
- _type = KIT_CLASSTYPE_MUTEXSIMPLE;
- //(no cast needed when allocating, since _mutex_p is already void*)
- _mutex_p = memory::alloc(sizeof(CRITICAL_SECTION));
- if(_mutex_p == nullptr) throw "ran out of memory creating internal mutex";
- memory::set(_mutex_p, 0, sizeof(CRITICAL_SECTION));
- if(spinCount == -1){
- InitializeCriticalSection((CRITICAL_SECTION*)_mutex_p);
- //to my knowledge, there is no GetCriticalSectionSpinCount,
- //so i need to probe for it with a "Set" before setting it back
- //(also, i tried to grab the SpinCount member of the critical section
- // directly, but that seemed to result in undefined behavior for some reason!!!)
- _spinCount = SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, 0);
- SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, _spinCount);
- } else {
- InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)_mutex_p, spinCount);
- _spinCount = spinCount;
- }
- _valid = true;
- _constructing = false;
- }
- MutexSimple::~MutexSimple(){
- if(!_valid) return;
- _valid = false;
- DeleteCriticalSection((CRITICAL_SECTION*)_mutex_p);
- memory::free(&_mutex_p);
- }
- void MutexSimple::setSpinCount(u32 spinCount){
- if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
- SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, spinCount);
- _spinCount = spinCount;
- }
- void MutexSimple::lock(bool locked){
- if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
- if(locked) EnterCriticalSection((CRITICAL_SECTION*)_mutex_p);
- else LeaveCriticalSection((CRITICAL_SECTION*)_mutex_p);
- }
- bool MutexSimple::tryLock(){
- if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
- return TryEnterCriticalSection((CRITICAL_SECTION*)_mutex_p);
- }
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Thread.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_INVALID_THREAD _kit_invalid_thread
- #define KIT_IS_INVALID_THREAD (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_thread[] = "invalid thread";
- DWORD WINAPI _ThreadFunctionWrapper(LPVOID userdata){
- _ThreadOpaque* _opq = (_ThreadOpaque*)userdata;
- _ThreadOpaque opq = *_opq; //make stack copy of opaque
- s32 returnValue = opq.threadFunc(opq.threadUserdata);
- if(!opq.threadDetached){
- _opq->threadReturn = returnValue;
- _opq->threadDone = true;
- }
- return 0;
- }
- Thread::Thread(ThreadFunction func, void* userdata,
- bool detached, size_t stackSize)
- {
- _type = KIT_CLASSTYPE_THREAD;
- if(func == nullptr) throw "func = nullptr";
- _opq = (_ThreadOpaque*)memory::alloc(sizeof(_ThreadOpaque));
- if(_opq == nullptr) throw "ran out of memory creating _opq";
- memory::set(_opq, 0, sizeof(_ThreadOpaque));
- _opq->threadFunc = func;
- _opq->threadUserdata = userdata;
- _opq->threadDetached = detached;
- _opq->threadDone = false; //redundant, but included for clarity
- _opq->threadHandle = CreateThread(nullptr, stackSize, _ThreadFunctionWrapper,
- _opq, 0, &_opq->threadID);
- if(_opq->threadHandle == nullptr){
- memory::free(&_opq);
- throw "failed to create thread";
- }
- _valid = true;
- _constructing = false;
- }
- Thread::~Thread(){
- if(!_valid) return;
- _valid = false;
- if(_opq != nullptr){
- if(!_opq->threadDetached) waitUntilDone(KIT_S32_MIN+1);
- memory::free(&_opq);
- }
- }
- bool Thread::isDone(){
- if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
- return _opq->threadDone;
- }
- u32 Thread::getID(){
- if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
- return _opq->threadID;
- }
- void Thread::setPriority(s32 priority, bool backgroundMode){
- if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
- if(priority < -3 || priority > 2) throw "priority is invalid";
- bool somethingChanged = false;
- if(priority != THREAD_NO_CHANGE) somethingChanged = true;
- else priority = _priority;
- if(backgroundMode != _backgroundMode) somethingChanged = true;
- if(somethingChanged){
- s32 priorityFlags = priority;
- if(backgroundMode != _backgroundMode){
- if(backgroundMode) priorityFlags |= THREAD_MODE_BACKGROUND_BEGIN;
- else priorityFlags |= THREAD_MODE_BACKGROUND_END;
- }
- if(!SetThreadPriority(_opq->threadHandle, priorityFlags))
- throw "failed to set thread priority";
- }
- _priority = priority;
- _backgroundMode = backgroundMode;
- }
- s32 Thread::waitUntilDone(u32 timeoutMilliseconds){
- //this prevents the program from aborting when called inside
- //Thread's destructor, as normally an exception will be thrown
- //if _valid and _constructing are both false
- if(timeoutMilliseconds != (KIT_S32_MIN+1)){
- if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
- }
- if(_opq->threadDetached) throw "cannot wait on a detached thread";
- u32 result = WaitForSingleObject(_opq->threadHandle, timeoutMilliseconds);
- switch(result){
- case WAIT_ABANDONED: throw "wait was abandoned";
- case WAIT_TIMEOUT : throw "wait timed out";
- case WAIT_FAILED :
- default : throw "wait invocation failed";
- case WAIT_OBJECT_0 :; //success
- }
- return _opq->threadReturn;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_time.cpp":
- #include "_kit_common_shared.hpp"
- namespace kit {
- u64 time::getTicks(){
- LARGE_INTEGER ticks;
- QueryPerformanceCounter(&ticks);
- return ticks.QuadPart;
- }
- u64 time::getTicksPerSecond(){
- return w32::ticksPerSecond.QuadPart;
- }
- f64 time::getUptime(){
- return (f64)time::getTicks()/w32::ticksPerSecond.QuadPart;
- }
- void time::ticksleep(u64 ticks){
- if(ticks == 0){ Sleep(0); return; }
- //if you attempt to ticksleep longer than this, you're doing something wrong lol
- if(ticks > KIT_S64_MAX) throw "cannot wait for more than 2^63 ticks";
- HANDLE timerHandle = CreateWaitableTimerW(nullptr, true, nullptr);
- if(timerHandle == nullptr) throw "failed to create timer object";
- LARGE_INTEGER relTime; //relative time (in 100ns intervals)
- relTime.QuadPart = -(s64)( ((f64)ticks/w32::ticksPerSecond.QuadPart) * 10000000 );
- if(!SetWaitableTimer(timerHandle, &relTime, 0, nullptr, nullptr, false)){
- CloseHandle(timerHandle);
- throw "failed to set timer object";
- }
- WaitForSingleObject(timerHandle, INFINITE);
- CloseHandle(timerHandle);
- }
- void time::sleep(u32 milliseconds){
- if(milliseconds != 0){
- //i thought this would be more precise than Sleep, but it seems to be
- //about the same. whatever, i'll figure out a better solution later
- time::ticksleep(milliseconds*(w32::ticksPerSecond.QuadPart/1000));
- } else {
- Sleep(0); //Sleep 0 should at least do scheduley scheduler things
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Timer.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_INVALID_TIMER _kit_invalid_timer
- #define KIT_IS_INVALID_TIMER (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_timer[] = "invalid timer";
- TimerSimple::TimerSimple(bool manualReset)
- {
- _type = KIT_CLASSTYPE_TIMER;
- _timer_ptr = CreateWaitableTimerW(nullptr, manualReset, nullptr);
- if(_timer_ptr == nullptr) throw "failed to create timer object";
- _valid = true;
- _constructing = false;
- }
- TimerSimple::~TimerSimple(){
- if(!_valid) return;
- _valid = false;
- if(_timer_ptr != nullptr) CloseHandle(_timer_ptr);
- }
- void TimerSimple::setTimer(f64 durationSeconds){
- if(KIT_IS_INVALID_TIMER) throw KIT_INVALID_TIMER;
- if(durationSeconds < 0) throw "durationSeconds < 0";
- LARGE_INTEGER dueTime;
- dueTime.QuadPart = -(LONGLONG)(durationSeconds*10000000);
- if(!SetWaitableTimer(_timer_ptr, &dueTime, 0, nullptr, nullptr, false))
- throw "failed to set timer object";
- }
- void TimerSimple::wait(u32 timeoutMilliseconds){
- if(KIT_IS_INVALID_TIMER) throw KIT_INVALID_TIMER;
- if(!timeoutMilliseconds) timeoutMilliseconds = INFINITE;
- DWORD result = WaitForSingleObject(_timer_ptr, timeoutMilliseconds);
- if(result != WAIT_OBJECT_0){
- //tbd: handle failure
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Window.cpp":
- #include "kit_Window_shared.hpp"
- #include "kit_Bitmap_shared.hpp" //uses some of its inlines
- #define KIT_IS_INVALID_WINDOW ( (!_valid && !_constructing) || _opq->winClosed )
- #define KIT_INVALID_WINDOW _kit_invalid_window
- namespace kit {
- static const char _kit_invalid_window[] = "invalid window";
- namespace w32 {
- u32 winCount = 0; //number of existing kit::Window instances
- const char winClassName[] = "kit::Window Class";
- WNDCLASSEXA winClass;
- ATOM winClassAtom;
- };
- Window::Window(const char* windowTitle,
- s32 windowWidth, s32 windowHeight,
- u32 windowFlags,
- s32 windowX, s32 windowY,
- s32 canvasWidth, s32 canvasHeight,
- bool directAccess)
- {
- _type = KIT_CLASSTYPE_WINDOW;
- _opq = (_WindowOpaque*)memory::alloc(sizeof(_WindowOpaque));
- if(_opq == nullptr) throw "ran out of memory creating _opq";
- memory::set(_opq, 0, sizeof(_WindowOpaque));
- char* errorText = "no error";
- if(0){ //this code block is only entered via goto in the event of an exception
- //(destroying the canvas is unnecessary, as it's the last thing to be made anyway)
- //_DestroyCanvas : DeleteObject(_opq->canvas.handle);
- // DeleteDC(_opq->canvas.devCtx);
- _DestroyWindow : DestroyWindow(_opq->winHandle);
- _UnregisterClass: if(w32::winCount == 0) UnregisterClassA(w32::winClassName, w32::hThisInst);
- _DelCritSection : DeleteCriticalSection(&_opq->lock);
- /*_FreePixels :*/if(!directAccess) memory::free(&_opq->canvas.pixels);
- /*_FreeOpaque :*/memory::free(&_opq);
- throw (const char*)errorText;
- }
- //window title
- if(windowTitle != nullptr){
- if( strncpy_s(_title, 256, windowTitle, 255) )
- throw "windowTitle failed to copy";
- _title[255] = 0; //just in case
- } else {
- _title[0] = 0;
- }
- u32 screenWidth = GetSystemMetrics(SM_CXSCREEN);
- u32 screenHeight = GetSystemMetrics(SM_CYSCREEN);
- //window size
- if(windowWidth <1) windowWidth = screenWidth;
- if(windowHeight<1) windowHeight = screenHeight;
- if(directAccess){
- _opq->canvas.pixels = nullptr;
- } else {
- //used for some drawing operations
- _opq->canvas.pixels = (color::ARGB*) memory::alloc2(sizeof(color::ARGB) *
- screenWidth*screenHeight);
- memory::set(_opq->canvas.pixels, 0, sizeof(color::ARGB) *
- screenWidth*screenHeight);
- }
- //initialize mutex
- InitializeCriticalSectionAndSpinCount(&_opq->lock, KIT_LOCK_SPINCOUNT);
- //create and register window class (only if no other windows are present)
- if(w32::winCount == 0){
- w32::winClass.cbSize = sizeof(WNDCLASSEX);
- w32::winClass.style = CS_DBLCLKS; //allow double clicks
- w32::winClass.lpfnWndProc = w32::WindowProc;
- w32::winClass.cbClsExtra = 0;
- w32::winClass.cbWndExtra = 0;
- w32::winClass.hInstance = w32::hThisInst;
- w32::winClass.hIcon = nullptr;
- w32::winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
- w32::winClass.hbrBackground = nullptr;
- w32::winClass.lpszMenuName = nullptr;
- w32::winClass.lpszClassName = w32::winClassName;
- w32::winClass.hIconSm = nullptr; //(the window's small icon)
- w32::winClassAtom = RegisterClassExA(&w32::winClass);
- if(!w32::winClassAtom){
- errorText = "RegisterClassA() failed";
- goto _DelCritSection;
- }
- }
- _opq->winStretchMode = KIT_INITIAL_STRETCH_MODE;
- HandlePreCreationWindowFlags(_opq, windowFlags);
- //create window
- shape::point winSize = CalculateWindowSize(windowWidth, windowHeight,
- _opq->winFlags, _opq->winFlagsEx);
- _opq->winHandle = CreateWindowExA(_opq->winFlagsEx, w32::winClassName, _title,
- _opq->winFlags, windowX, windowY, winSize.x, winSize.y,
- nullptr, nullptr, w32::hThisInst, (LPVOID)this);
- if(_opq->winHandle == nullptr){
- errorText = "CreateWindowA() failed";
- goto _UnregisterClass;
- }
- //create canvas
- if(canvasWidth>windowWidth || canvasHeight>windowHeight){
- errorText = "canvas size is larger than the window";
- goto _DestroyWindow;
- }
- if(canvasWidth <1) canvasWidth = windowWidth;
- if(canvasHeight<1) canvasHeight = windowHeight;
- _opq->canvasStretch = (canvasWidth<windowWidth || canvasHeight<windowHeight);
- if(!PopulateBitmapOpaque(_opq->canvas, nullptr, canvasWidth, canvasHeight,
- _opq, directAccess))
- {
- errorText = "failed to create canvas";
- goto _DestroyWindow;
- }
- _opq->winRect.x = (windowX != WINPOS_UNCHANGED) ? windowX : WINPOS_UNDEFINED;
- _opq->winRect.y = (windowY != WINPOS_UNCHANGED) ? windowY : WINPOS_UNDEFINED;
- _opq->winRect.w = winSize.x;
- _opq->winRect.h = winSize.y;
- setWindowRect(&_opq->winRect);
- //until i can figure out why setting WS_POPUP *before* window creation
- //crashes the program, this solution seems to work
- u32 currentStyle = GetWindowLongA(_opq->winHandle, GWL_STYLE);
- if(windowFlags & WINFLAG_BORDERLESS){
- currentStyle &= ~WS_CAPTION;
- currentStyle |= WS_POPUP;
- SetWindowLongA(_opq->winHandle, GWL_STYLE, currentStyle);
- }
- //if( windowFlags & WINFLAG_MINIMIZED ) setMinimized(true); //tbd: fix this
- if( windowFlags & WINFLAG_MAXIMIZED ) setMaximized(true);
- if( windowFlags & WINFLAG_FULLSCREEN) setFullscreen(true);
- if(!(windowFlags & WINFLAG_HIDDEN) ) setVisibility(true);
- if( windowFlags & WINFLAG_FOCUS ) setFocus(true);
- _opq->winClosed = false;
- _opq->winIndex = w32::winCount++; //set window index, before adding to total count
- _valid = true;
- _constructing = false;
- }
- Window::~Window(){
- if(!_valid) return;
- _valid = false;
- --w32::winCount; //remove window from total count
- if(_opq != nullptr){
- DeleteObject(_opq->canvas.handle);
- DeleteDC(_opq->canvas.devCtx);
- DestroyWindow(_opq->winHandle);
- if(w32::winCount == 0) UnregisterClassA(w32::winClassName, w32::hThisInst);
- DeleteCriticalSection(&_opq->lock);
- if(!_opq->canvas.directAccess) memory::free(&_opq->canvas.pixels);
- memory::free(&_opq);
- }
- }
- bool Window::isClosed(){
- //(can't use KIT_IS_INVALID_WINDOW here)
- if(!_valid && !_constructing) throw KIT_INVALID_WINDOW;
- return _opq->winClosed; //set by w32::WindowProc, rather than destructor
- }
- //queries the actual state of the window, rather than winRect,
- //because setWindowRect(nullptr) does not actually modify winRect
- shape::rect Window::getWindowRect(){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- RECT winRectTmp;
- GetWindowRect(_opq->winHandle, &winRectTmp); //get window's bounding box
- return ConvertToKitRect(winRectTmp);
- }
- shape::point Window::getCanvasSize(){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- return _opq->canvas.size;
- }
- color::ARGB* Window::getPixels(){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(_opq->canvas.directAccess) return _opq->canvas.pixels;
- else throw "window's canvas does not support direct access";
- }
- //if newRect == nullptr, the window will stretch to fit the whole screen
- void Window::setWindowRect(const shape::rect* newRect){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- s32 screenWidth = GetSystemMetrics(SM_CXSCREEN);
- s32 screenHeight = GetSystemMetrics(SM_CYSCREEN);
- if(newRect != nullptr){
- shape::rect winRectCurrent = getWindowRect();
- shape::point centerPos;
- centerPos.x = screenWidth /2 - winRectCurrent.w/2;
- centerPos.y = screenHeight/2 - winRectCurrent.h/2;
- shape::rect _newRect = *newRect; //make a copy of newRect
- if( _newRect.x == WINPOS_UNDEFINED) _newRect.x = CW_USEDEFAULT;
- else if(_newRect.x == WINPOS_CENTERED ) _newRect.x = centerPos.x;
- else if(_newRect.x == WINPOS_UNCHANGED) _newRect.x = winRectCurrent.x;
- if( _newRect.y == WINPOS_UNDEFINED) _newRect.y = CW_USEDEFAULT;
- else if(_newRect.y == WINPOS_CENTERED ) _newRect.y = centerPos.y;
- else if(_newRect.y == WINPOS_UNCHANGED) _newRect.y = winRectCurrent.y;
- if(_newRect.w==WINPOS_UNCHANGED || _newRect.w<1) _newRect.w = winRectCurrent.w;
- if(_newRect.h==WINPOS_UNCHANGED || _newRect.h<1) _newRect.h = winRectCurrent.h;
- SetWindowPos(_opq->winHandle, nullptr, _newRect.x,_newRect.y,
- _newRect.w, _newRect.h, SWP_NOZORDER);
- _opq->winRect = getWindowRect(); //update the window's rect to reflect changes
- } else { //internally, this option is solely used by setFullscreen
- //winRect automatically gets overwritten for every WM_MOVE and WM_SIZE message,
- //so record its previous value so it can be set back after the SetWindowPos
- shape::rect winRectPrevious = _opq->winRect;
- //this will (should) fill the entire screen, assuming there's no
- //window decoration in the way of doing so
- SetWindowPos(_opq->winHandle, nullptr, 0,0,
- screenWidth, screenHeight, SWP_NOZORDER);
- //winRect is set back to its original state,
- //so that its rect pre-fullscreen is preserved
- _opq->winRect = winRectPrevious;
- }
- }
- void Window::setCanvasSize(s32 width, s32 height){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- lock(true); //just in case
- if(width <1) width = _opq->winRect.w;
- if(height<1) height = _opq->winRect.h;
- _opq->canvasStretch = (width<_opq->winRect.w || height<_opq->winRect.h);
- if(!ResizeBitmapOpaque(_opq->canvas, width, height))
- throw "failed to resize canvas";
- //it's safe to lock a CRITICAL_SECTION multiple times on a single thread,
- //so long as it's unlocked an equal number of times
- lock(false);
- }
- void Window::setMinimized(bool minimize){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- ShowWindow(_opq->winHandle, (minimize) ? SW_MINIMIZE : SW_NORMAL);
- _opq->winMaximized = false;
- _opq->winMinimized = minimize;
- }
- void Window::setMaximized(bool maximize){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- ShowWindow(_opq->winHandle, (maximize) ? SW_MAXIMIZE : SW_NORMAL);
- _opq->winMinimized = false;
- _opq->winMaximized = maximize;
- }
- void Window::setFullscreen(bool fullscreen){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(fullscreen){ //modify values accordingly
- //style flags
- SetWindowLongA(_opq->winHandle, GWL_STYLE,
- _opq->winFlags & ~(WS_CAPTION | WS_THICKFRAME));
- //extended style flags
- SetWindowLongA(_opq->winHandle, GWL_EXSTYLE,
- _opq->winFlagsEx & ~(WS_EX_DLGMODALFRAME |
- WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
- //stretch window to match screen's width and height
- setWindowRect(nullptr);
- } else { //restore values to what they were before
- //restore style flags
- SetWindowLongA(_opq->winHandle, GWL_STYLE, _opq->winFlags);
- //restore extended style flags
- SetWindowLongA(_opq->winHandle, GWL_EXSTYLE, _opq->winFlagsEx);
- //restore window position and size
- setWindowRect(&_opq->winRect);
- }
- //idk for sure why this fixes the issue of the window breaking when
- //fullscreen is toggled, but if it works in the constructor and here too,
- //then i have no problem with doing it this way :)
- //(maybe showing it again invokes some update thingy)
- setVisibility(_opq->winShown);
- _opq->winFullscreen = fullscreen;
- }
- void Window::setVisibility(bool show){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- ShowWindow(_opq->winHandle, (show) ? SW_SHOW : SW_HIDE);
- _opq->winShown = show;
- //*maybe* set _opq->winFlags (probably not needed, though)
- }
- void Window::setFocus(bool enable){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- SetFocus((enable) ? _opq->winHandle : nullptr);
- _opq->winFocus = enable;
- }
- //this determines how the canvas stretches to the window, which is why
- //winStretchMode is modified here (since window is the canvas's blit destination)
- void Window::setCanvasInterpolationMode(bool halftone){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- //(no call to SetStretchBltMode, as that's done inside WindowProc)
- _opq->winStretchMode = (halftone) ? HALFTONE : COLORONCOLOR;
- }
- //like setCanvasInterpolationMode, canvas's stretch mode is altered,
- //since the canvas is ultimately the bitmap's blit destination
- void Window::setBitmapInterpolationMode(bool halftone){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- u32 mode = (halftone) ? HALFTONE : COLORONCOLOR;
- SetStretchBltMode(_opq->canvas.devCtx, mode);
- _opq->canvas.stretchMode = mode;
- }
- void Window::lock(bool locked){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(locked) EnterCriticalSection(&_opq->lock);
- else LeaveCriticalSection(&_opq->lock);
- }
- void Window::present(bool updateImmediately){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- InvalidateRect(_opq->winHandle, nullptr, false);
- if(updateImmediately) UpdateWindow(_opq->winHandle);
- }
- void Window::clear(color::ARGB color){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- HBRUSH brushHandle = CreateSolidBrush(color.v);
- HBRUSH brushHandleOld = (HBRUSH)SelectObject(_opq->canvas.devCtx, brushHandle);
- RECT rectF;
- rectF.left = 0;
- rectF.top = 0;
- rectF.right = _opq->canvas.size.x;
- rectF.bottom = _opq->canvas.size.y;
- FillRect(_opq->canvas.devCtx, &rectF, brushHandle);
- SelectObject(_opq->canvas.devCtx, brushHandleOld);
- DeleteObject(brushHandle);
- }
- #define ARGB_to_ABGR(_c) RGB(color.r, color.g, color.b)
- void Window::drawPoint(shape::point point, color::ARGB color){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- SetPixel(_opq->canvas.devCtx, point.x, point.y, ARGB_to_ABGR(color));
- }
- void Window::drawPoints(shape::point* points, size_t points_len,
- color::ARGB color, bool useSetPixel)
- {
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(points == nullptr) throw "points = nullptr";
- HDC canvasDC = _opq->canvas.devCtx;
- if(useSetPixel){
- COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
- for(size_t i=0; i<points_len; ++i)
- SetPixel(canvasDC, points[i].x, points[i].y, _color);
- } else {
- lock(true);
- shape::point size = _opq->canvas.size;
- color::ARGB* pixels = _opq->canvas.pixels;
- //if canvas is not direct access, its pixel data needs to be copied to
- //canvas.pixels (which is valid whether or not directAccess is true)
- if(!_opq->canvas.directAccess){
- GetDIBits(canvasDC, _opq->canvas.handle, 0, size.y,
- pixels, &_opq->canvas.info, DIB_RGB_COLORS);
- }
- //bitmap coordinates are weird, in that they go bottom-up, not top-down
- //like most other image formats. this means the y coordinate needs to
- //be inverted, which looks like: "output_y = size.y-1-input_y".
- shape::point sizeMinus1 = size;
- --sizeMinus1.x, --sizeMinus1.y;
- for(size_t i=0; i<points_len; ++i){
- shape::point p = points[i];
- if(p.x<0 || p.y<0 || p.x>sizeMinus1.x || p.y>sizeMinus1.y) continue;
- pixels[ p.x + (sizeMinus1.y-p.y)*size.x ] = color;
- }
- if(!_opq->canvas.directAccess){
- //copy the modified pixel data back to the canvas
- SetDIBits(canvasDC, _opq->canvas.handle, 0, size.y,
- pixels, &_opq->canvas.info, DIB_RGB_COLORS);
- }
- lock(false);
- }
- }
- void Window::drawLines(shape::point* lineEnds, size_t lineEnds_len,
- color::ARGB color, u32 width)
- {
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(lineEnds == nullptr) throw "lineEnds = nullptr";
- if(width == 0) throw "width = 0";
- if(lineEnds_len > 0){
- HDC canvasDC = _opq->canvas.devCtx;
- COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
- HPEN penHandle = CreatePen(PS_SOLID, width&KIT_S32_MAX, _color);
- HPEN penHandleOld = (HPEN)SelectObject(canvasDC, penHandle);
- MoveToEx(canvasDC, lineEnds[0].x, lineEnds[0].y, nullptr);
- for(size_t i=1; i<lineEnds_len; ++i)
- LineTo(canvasDC, lineEnds[i].x, lineEnds[i].y);
- SelectObject(canvasDC, penHandleOld);
- DeleteObject(penHandle);
- }
- }
- void Window::drawLineSegments(shape::line* lines, size_t lines_len,
- color::ARGB color, u32 width)
- {
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(lines == nullptr) throw "lines = nullptr";
- if(width == 0) throw "width = 0";
- if(lines_len > 0){
- HDC canvasDC = _opq->canvas.devCtx;
- COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
- HPEN penHandle = CreatePen(PS_SOLID, width&KIT_S32_MAX, _color);
- HPEN penHandleOld = (HPEN)SelectObject(canvasDC, penHandle);
- for(size_t i=0; i<lines_len; ++i){
- shape::line l = lines[i];
- MoveToEx(canvasDC, l.x0, l.y0, nullptr);
- LineTo(canvasDC, l.x1, l.y1);
- }
- SelectObject(canvasDC, penHandleOld);
- DeleteObject(penHandle);
- }
- }
- void Window::drawRectangles(shape::rect* rects, size_t rects_len, color::ARGB color){
- if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
- if(rects == nullptr) throw "rects = nullptr";
- if(rects_len > 0){
- HDC canvasDC = _opq->canvas.devCtx;
- COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
- HBRUSH brushHandle = CreateSolidBrush(_color);
- HBRUSH brushHandleOld = (HBRUSH)SelectObject(canvasDC, brushHandle);
- for(size_t i=0; i<rects_len; ++i){
- RECT rectF = ((RECT*)rects)[i];
- //RECT effectively uses 2 points to define a rectangle, whereas
- //shape::rect uses 1 point, plus a width and height.
- //that means the 2nd point must be converted, like this:
- rectF.right += rectF.left; //b.x += a.x
- rectF.bottom += rectF.top; //b.y += a.y
- FillRect(canvasDC, &rectF, brushHandle);
- }
- SelectObject(canvasDC, brushHandleOld);
- DeleteObject(brushHandle);
- }
- }
- }; /* namespace kit */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement