Advertisement
Kitomas

2024-07-19 (2/13)

Jul 19th, 2024
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 30.29 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"kit_w32\src\kit_win32\kit_memory.cpp":
  4. #include "_kit_common_shared.hpp"
  5.  
  6. //turns something into a void**
  7.  //(this makes some code here easier for me to read)
  8. #define VPP(_ptr_p) ((void**)(_ptr_p))
  9.  
  10.  
  11. namespace kit {
  12.  
  13.  
  14. static size_t numAllocations = 0;
  15.  
  16.  
  17.  
  18.  
  19. void* memory::alloc(size_t size){
  20.   void* newHeapMemory = CoTaskMemAlloc(size);
  21.   if(newHeapMemory != nullptr) ++numAllocations;
  22.   return newHeapMemory;
  23. }
  24.  
  25.  
  26. void memory::free(void* ptr_p){
  27.   if(VPP(ptr_p) != nullptr  &&  *VPP(ptr_p) != nullptr){
  28.     --numAllocations;
  29.     CoTaskMemFree(*VPP(ptr_p));
  30.     *VPP(ptr_p) = nullptr;
  31.   }
  32. }
  33.  
  34.  
  35. void* memory::realloc(void* ptr_p, size_t newSize){
  36.   void* ptr_new = nullptr;
  37.  
  38.   if(VPP(ptr_p) != nullptr){
  39.     ptr_new = CoTaskMemRealloc(*VPP(ptr_p), newSize);
  40.  
  41.     if(ptr_new != nullptr){
  42.       if(*VPP(ptr_p) == nullptr) ++numAllocations;
  43.       *VPP(ptr_p) = ptr_new;
  44.  
  45.     }
  46.   }
  47.  
  48.   return ptr_new;
  49. }
  50.  
  51.  
  52.  
  53. void* memory::alloc2(size_t size){
  54.   void* newHeapMemory = CoTaskMemAlloc(size);
  55.   if(newHeapMemory == nullptr) throw "failed to allocate memory";
  56.   ++numAllocations;
  57.   return newHeapMemory;
  58. }
  59.  
  60.  
  61. void memory::free2(void* ptr_p){
  62.   if( VPP(ptr_p) == nullptr) throw  "ptr_p == nullptr";
  63.   if(*VPP(ptr_p) == nullptr) throw "*ptr_p == nullptr";
  64.   --numAllocations;
  65.   CoTaskMemFree(*VPP(ptr_p));
  66.   *VPP(ptr_p) = nullptr;
  67. }
  68.  
  69.  
  70. void* memory::realloc2(void* ptr_p, size_t newSize){
  71.   void* ptr_new = nullptr;
  72.  
  73.   if(VPP(ptr_p) != nullptr){
  74.     ptr_new = CoTaskMemRealloc(*VPP(ptr_p), newSize);
  75.  
  76.     if(ptr_new != nullptr){
  77.       if(*VPP(ptr_p) == nullptr) ++numAllocations;
  78.       *VPP(ptr_p) = ptr_new;
  79.  
  80.     }
  81.   } else {
  82.     throw "ptr_p = nullptr";
  83.   }
  84.  
  85.   if(ptr_new == nullptr) throw "failed to reallocate memory";
  86.  
  87.   return ptr_new;
  88. }
  89.  
  90.  
  91.  
  92. size_t memory::getNumAllocations(){
  93.   return numAllocations;
  94. }
  95.  
  96.  
  97.  
  98.  
  99. //currently just a wrapper, but now i can make my own implementation
  100.  //whenever i want, without replacing every call to memset with it
  101. void* memory::set(void* ptr, s32 value, size_t size){
  102.   if(ptr == nullptr) return nullptr; //now it's safe to pass nullptr :D
  103.   return memset(ptr, value, size);
  104. }
  105.  
  106.  
  107. void* memory::set2(void* ptr, s32 value, size_t size){
  108.   if(ptr == nullptr) throw "ptr = nullptr";
  109.   return memset(ptr, value, size);
  110. }
  111.  
  112.  
  113.  
  114.  
  115. void* memory::copy(void* destination, const void* source, size_t size){
  116.   return memcpy(destination, source, size);
  117. }
  118.  
  119.  
  120. void* memory::copy2(void* destination, const void* source, size_t size){
  121.   if(destination == nullptr) throw "destination = nullptr";
  122.   if(source      == nullptr) throw "source = nullptr";
  123.   return memcpy(destination, source, size);
  124. }
  125.  
  126.  
  127.  
  128.  
  129. }; /* namespace kit */
  130. /******************************************************************************/
  131. /******************************************************************************/
  132. //"kit_w32\src\kit_win32\kit_Mutex.cpp":
  133. #include "_kit_common_shared.hpp"
  134.  
  135. #define KIT_MUTEX_NULLPTR _kit_mutex_nullptr
  136.  
  137.  
  138. using namespace kit;
  139.  
  140. static const char _kit_mutex_nullptr[] = "internal mutex = nullptr";
  141.  
  142.  
  143.  
  144.  
  145. MutexSimple::MutexSimple(u32 spinCount){
  146.   _type = KIT_CLASSTYPE_MUTEXSIMPLE;
  147.  
  148.   //(no cast needed when allocating, since _mutex_p is already void*)
  149.   _mutex_p = memory::alloc(sizeof(CRITICAL_SECTION));
  150.   if(_mutex_p == nullptr) throw "ran out of memory creating internal mutex";
  151.   memory::set(_mutex_p, 0, sizeof(CRITICAL_SECTION));
  152.  
  153.   if(spinCount == -1){
  154.     InitializeCriticalSection((CRITICAL_SECTION*)_mutex_p);
  155.     //to my knowledge, there is no GetCriticalSectionSpinCount,
  156.      //so i need to probe for it with a "Set" before setting it back
  157.      //(also, i tried to grab the SpinCount member of the critical section
  158.      // directly, but that seemed to result in undefined behavior for some reason!!!)
  159.     _spinCount = SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, 0);
  160.     SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, _spinCount);
  161.  
  162.   } else {
  163.     InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)_mutex_p, spinCount);
  164.     _spinCount = spinCount;
  165.  
  166.   }
  167.  
  168.   _valid = true;
  169.   _constructing = false;
  170. }
  171.  
  172.  
  173.  
  174. MutexSimple::~MutexSimple(){
  175.   if(!_valid) return;
  176.   _valid = false;
  177.   DeleteCriticalSection((CRITICAL_SECTION*)_mutex_p);
  178.   memory::free(&_mutex_p);
  179. }
  180.  
  181.  
  182.  
  183.  
  184. void MutexSimple::setSpinCount(u32 spinCount){
  185.   if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
  186.   SetCriticalSectionSpinCount((CRITICAL_SECTION*)_mutex_p, spinCount);
  187.   _spinCount = spinCount;
  188. }
  189.  
  190.  
  191.  
  192.  
  193. void MutexSimple::lock(bool locked){
  194.   if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
  195.   if(locked) EnterCriticalSection((CRITICAL_SECTION*)_mutex_p);
  196.   else       LeaveCriticalSection((CRITICAL_SECTION*)_mutex_p);
  197. }
  198.  
  199.  
  200.  
  201. bool MutexSimple::tryLock(){
  202.   if(_mutex_p == nullptr) throw KIT_MUTEX_NULLPTR;
  203.   return TryEnterCriticalSection((CRITICAL_SECTION*)_mutex_p);
  204. }
  205. /******************************************************************************/
  206. /******************************************************************************/
  207. //"kit_w32\src\kit_win32\kit_Thread.cpp":
  208. #include "_kit_common_shared.hpp"
  209.  
  210. #define KIT_INVALID_THREAD _kit_invalid_thread
  211.  
  212. #define KIT_IS_INVALID_THREAD (!_valid && !_constructing)
  213.  
  214.  
  215. namespace kit {
  216.  
  217. static const char _kit_invalid_thread[] = "invalid thread";
  218.  
  219.  
  220.  
  221.  
  222. DWORD WINAPI _ThreadFunctionWrapper(LPVOID userdata){
  223.   _ThreadOpaque* _opq = (_ThreadOpaque*)userdata;
  224.   _ThreadOpaque opq = *_opq; //make stack copy of opaque
  225.  
  226.   s32 returnValue = opq.threadFunc(opq.threadUserdata);
  227.  
  228.   if(!opq.threadDetached){
  229.     _opq->threadReturn = returnValue;
  230.     _opq->threadDone   = true;
  231.   }
  232.  
  233.   return 0;
  234. }
  235.  
  236.  
  237.  
  238.  
  239. Thread::Thread(ThreadFunction func, void* userdata,
  240.                bool detached, size_t stackSize)
  241. {
  242.   _type = KIT_CLASSTYPE_THREAD;
  243.  
  244.   if(func == nullptr) throw "func = nullptr";
  245.  
  246.  
  247.   _opq = (_ThreadOpaque*)memory::alloc(sizeof(_ThreadOpaque));
  248.   if(_opq == nullptr) throw "ran out of memory creating _opq";
  249.   memory::set(_opq, 0, sizeof(_ThreadOpaque));
  250.  
  251.   _opq->threadFunc     = func;
  252.   _opq->threadUserdata = userdata;
  253.   _opq->threadDetached = detached;
  254.   _opq->threadDone     = false; //redundant, but included for clarity
  255.  
  256.  
  257.   _opq->threadHandle = CreateThread(nullptr, stackSize, _ThreadFunctionWrapper,
  258.                                     _opq, 0, &_opq->threadID);
  259.  
  260.   if(_opq->threadHandle == nullptr){
  261.     memory::free(&_opq);
  262.     throw "failed to create thread";
  263.   }
  264.  
  265.  
  266.   _valid = true;
  267.   _constructing = false;
  268. }
  269.  
  270.  
  271.  
  272. Thread::~Thread(){
  273.   if(!_valid) return;
  274.   _valid = false;
  275.  
  276.   if(_opq != nullptr){
  277.     if(!_opq->threadDetached) waitUntilDone(KIT_S32_MIN+1);
  278.     memory::free(&_opq);
  279.   }
  280. }
  281.  
  282.  
  283.  
  284.  
  285. bool Thread::isDone(){
  286.   if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
  287.   return _opq->threadDone;
  288. }
  289.  
  290.  
  291.  
  292. u32 Thread::getID(){
  293.   if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
  294.   return _opq->threadID;
  295. }
  296.  
  297.  
  298.  
  299.  
  300. void Thread::setPriority(s32 priority, bool backgroundMode){
  301.   if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
  302.   if(priority < -3  ||  priority > 2) throw "priority is invalid";
  303.  
  304.  
  305.   bool somethingChanged = false;
  306.  
  307.   if(priority != THREAD_NO_CHANGE) somethingChanged = true;
  308.   else                             priority = _priority;
  309.  
  310.   if(backgroundMode != _backgroundMode) somethingChanged = true;
  311.  
  312.  
  313.   if(somethingChanged){
  314.     s32 priorityFlags = priority;
  315.  
  316.     if(backgroundMode != _backgroundMode){
  317.       if(backgroundMode) priorityFlags |= THREAD_MODE_BACKGROUND_BEGIN;
  318.       else               priorityFlags |= THREAD_MODE_BACKGROUND_END;
  319.     }
  320.  
  321.     if(!SetThreadPriority(_opq->threadHandle, priorityFlags))
  322.       throw "failed to set thread priority";
  323.   }
  324.  
  325.  
  326.   _priority       = priority;
  327.   _backgroundMode = backgroundMode;
  328. }
  329.  
  330.  
  331.  
  332.  
  333. s32 Thread::waitUntilDone(u32 timeoutMilliseconds){
  334.   //this prevents the program from aborting when called inside
  335.    //Thread's destructor, as normally an exception will be thrown
  336.    //if _valid and _constructing are both false
  337.   if(timeoutMilliseconds != (KIT_S32_MIN+1)){
  338.     if(KIT_IS_INVALID_THREAD) throw KIT_INVALID_THREAD;
  339.   }
  340.   if(_opq->threadDetached) throw "cannot wait on a detached thread";
  341.  
  342.  
  343.   u32 result = WaitForSingleObject(_opq->threadHandle, timeoutMilliseconds);
  344.  
  345.   switch(result){
  346.     case WAIT_ABANDONED: throw "wait was abandoned";
  347.     case WAIT_TIMEOUT  : throw "wait timed out";
  348.     case WAIT_FAILED   :
  349.     default            : throw "wait invocation failed";
  350.     case WAIT_OBJECT_0 :; //success
  351.   }
  352.  
  353.  
  354.   return _opq->threadReturn;
  355. }
  356.  
  357.  
  358.  
  359.  
  360. }; /* namespace kit */
  361. /******************************************************************************/
  362. /******************************************************************************/
  363. //"kit_w32\src\kit_win32\kit_time.cpp":
  364. #include "_kit_common_shared.hpp"
  365.  
  366.  
  367. namespace kit {
  368.  
  369.  
  370.  
  371.  
  372. u64 time::getTicks(){
  373.   LARGE_INTEGER ticks;
  374.   QueryPerformanceCounter(&ticks);
  375.   return ticks.QuadPart;
  376. }
  377.  
  378.  
  379.  
  380. u64 time::getTicksPerSecond(){
  381.   return w32::ticksPerSecond.QuadPart;
  382. }
  383.  
  384.  
  385.  
  386. f64 time::getUptime(){
  387.   return (f64)time::getTicks()/w32::ticksPerSecond.QuadPart;
  388. }
  389.  
  390.  
  391.  
  392.  
  393. void time::ticksleep(u64 ticks){
  394.   if(ticks == 0){ Sleep(0); return; }
  395.  
  396.   //if you attempt to ticksleep longer than this, you're doing something wrong lol
  397.   if(ticks > KIT_S64_MAX) throw "cannot wait for more than 2^63 ticks";
  398.  
  399.   HANDLE timerHandle = CreateWaitableTimerW(nullptr, true, nullptr);
  400.   if(timerHandle == nullptr) throw "failed to create timer object";
  401.  
  402.  
  403.   LARGE_INTEGER relTime; //relative time (in 100ns intervals)
  404.   relTime.QuadPart = -(s64)( ((f64)ticks/w32::ticksPerSecond.QuadPart) * 10000000 );
  405.  
  406.   if(!SetWaitableTimer(timerHandle, &relTime, 0, nullptr, nullptr, false)){
  407.     CloseHandle(timerHandle);
  408.     throw "failed to set timer object";
  409.   }
  410.  
  411.  
  412.   WaitForSingleObject(timerHandle, INFINITE);
  413.  
  414.   CloseHandle(timerHandle);
  415. }
  416.  
  417.  
  418.  
  419. void time::sleep(u32 milliseconds){
  420.   if(milliseconds != 0){
  421.     //i thought this would be more precise than Sleep, but it seems to be
  422.      //about the same. whatever, i'll figure out a better solution later
  423.     time::ticksleep(milliseconds*(w32::ticksPerSecond.QuadPart/1000));
  424.   } else {
  425.     Sleep(0); //Sleep 0 should at least do scheduley scheduler things
  426.   }
  427. }
  428.  
  429.  
  430.  
  431.  
  432. }; /* namespace kit */
  433. /******************************************************************************/
  434. /******************************************************************************/
  435. //"kit_w32\src\kit_win32\kit_Timer.cpp":
  436. #include "_kit_common_shared.hpp"
  437.  
  438. #define KIT_INVALID_TIMER _kit_invalid_timer
  439.  
  440. #define KIT_IS_INVALID_TIMER (!_valid && !_constructing)
  441.  
  442.  
  443. namespace kit {
  444.  
  445. static const char _kit_invalid_timer[] = "invalid timer";
  446.  
  447.  
  448.  
  449.  
  450. TimerSimple::TimerSimple(bool manualReset)
  451. {
  452.   _type = KIT_CLASSTYPE_TIMER;
  453.  
  454.   _timer_ptr = CreateWaitableTimerW(nullptr, manualReset, nullptr);
  455.   if(_timer_ptr == nullptr) throw "failed to create timer object";
  456.  
  457.   _valid = true;
  458.   _constructing = false;
  459. }
  460.  
  461.  
  462.  
  463.  
  464. TimerSimple::~TimerSimple(){
  465.   if(!_valid) return;
  466.   _valid = false;
  467.  
  468.   if(_timer_ptr != nullptr) CloseHandle(_timer_ptr);
  469. }
  470.  
  471.  
  472.  
  473.  
  474. void TimerSimple::setTimer(f64 durationSeconds){
  475.   if(KIT_IS_INVALID_TIMER) throw KIT_INVALID_TIMER;
  476.   if(durationSeconds < 0) throw "durationSeconds < 0";
  477.  
  478.   LARGE_INTEGER dueTime;
  479.   dueTime.QuadPart = -(LONGLONG)(durationSeconds*10000000);
  480.   if(!SetWaitableTimer(_timer_ptr, &dueTime, 0, nullptr, nullptr, false))
  481.     throw "failed to set timer object";
  482. }
  483.  
  484.  
  485.  
  486.  
  487. void TimerSimple::wait(u32 timeoutMilliseconds){
  488.   if(KIT_IS_INVALID_TIMER) throw KIT_INVALID_TIMER;
  489.   if(!timeoutMilliseconds) timeoutMilliseconds = INFINITE;
  490.  
  491.   DWORD result = WaitForSingleObject(_timer_ptr, timeoutMilliseconds);
  492.   if(result != WAIT_OBJECT_0){
  493.     //tbd: handle failure
  494.   }
  495. }
  496.  
  497.  
  498.  
  499.  
  500. }; /* namespace kit */
  501. /******************************************************************************/
  502. /******************************************************************************/
  503. //"kit_w32\src\kit_win32\kit_Window.cpp":
  504. #include "kit_Window_shared.hpp"
  505. #include "kit_Bitmap_shared.hpp" //uses some of its inlines
  506.  
  507. #define KIT_IS_INVALID_WINDOW ( (!_valid && !_constructing) || _opq->winClosed )
  508. #define KIT_INVALID_WINDOW _kit_invalid_window
  509.  
  510.  
  511. namespace kit {
  512.  
  513. static const char _kit_invalid_window[] = "invalid window";
  514.  
  515. namespace w32 {
  516.   u32         winCount = 0; //number of existing kit::Window instances
  517.   const char  winClassName[] = "kit::Window Class";
  518.   WNDCLASSEXA winClass;
  519.   ATOM        winClassAtom;
  520. };
  521.  
  522.  
  523.  
  524.  
  525. Window::Window(const char* windowTitle,
  526.                s32 windowWidth, s32 windowHeight,
  527.                u32 windowFlags,
  528.                s32 windowX,     s32 windowY,
  529.                s32 canvasWidth, s32 canvasHeight,
  530.                bool directAccess)
  531. {
  532.   _type = KIT_CLASSTYPE_WINDOW;
  533.  
  534.   _opq = (_WindowOpaque*)memory::alloc(sizeof(_WindowOpaque));
  535.   if(_opq == nullptr) throw "ran out of memory creating _opq";
  536.   memory::set(_opq, 0, sizeof(_WindowOpaque));
  537.  
  538.   char* errorText = "no error";
  539.   if(0){ //this code block is only entered via goto in the event of an exception
  540.     //(destroying the canvas is unnecessary, as it's the last thing to be made anyway)
  541.     //_DestroyCanvas  : DeleteObject(_opq->canvas.handle);
  542.     //                  DeleteDC(_opq->canvas.devCtx);
  543.     _DestroyWindow  : DestroyWindow(_opq->winHandle);
  544.     _UnregisterClass: if(w32::winCount == 0) UnregisterClassA(w32::winClassName, w32::hThisInst);
  545.     _DelCritSection : DeleteCriticalSection(&_opq->lock);
  546.   /*_FreePixels    :*/if(!directAccess) memory::free(&_opq->canvas.pixels);
  547.   /*_FreeOpaque    :*/memory::free(&_opq);
  548.     throw (const char*)errorText;
  549.   }
  550.  
  551.  
  552.   //window title
  553.   if(windowTitle != nullptr){
  554.     if( strncpy_s(_title, 256, windowTitle, 255) )
  555.       throw "windowTitle failed to copy";
  556.     _title[255] = 0; //just in case
  557.   } else {
  558.     _title[0] = 0;
  559.   }
  560.  
  561.  
  562.   u32 screenWidth  = GetSystemMetrics(SM_CXSCREEN);
  563.   u32 screenHeight = GetSystemMetrics(SM_CYSCREEN);
  564.  
  565.  
  566.   //window size
  567.   if(windowWidth <1) windowWidth  = screenWidth;
  568.   if(windowHeight<1) windowHeight = screenHeight;
  569.  
  570.  
  571.   if(directAccess){
  572.     _opq->canvas.pixels = nullptr;
  573.   } else {
  574.     //used for some drawing operations
  575.     _opq->canvas.pixels = (color::ARGB*) memory::alloc2(sizeof(color::ARGB) *
  576.                                                         screenWidth*screenHeight);
  577.     memory::set(_opq->canvas.pixels, 0, sizeof(color::ARGB) *
  578.                                         screenWidth*screenHeight);
  579.   }
  580.  
  581.  
  582.   //initialize mutex
  583.   InitializeCriticalSectionAndSpinCount(&_opq->lock, KIT_LOCK_SPINCOUNT);
  584.  
  585.  
  586.   //create and register window class (only if no other windows are present)
  587.   if(w32::winCount == 0){
  588.     w32::winClass.cbSize        = sizeof(WNDCLASSEX);
  589.     w32::winClass.style         = CS_DBLCLKS; //allow double clicks
  590.     w32::winClass.lpfnWndProc   = w32::WindowProc;
  591.     w32::winClass.cbClsExtra    = 0;
  592.     w32::winClass.cbWndExtra    = 0;
  593.     w32::winClass.hInstance     = w32::hThisInst;
  594.     w32::winClass.hIcon         = nullptr;
  595.     w32::winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  596.     w32::winClass.hbrBackground = nullptr;
  597.     w32::winClass.lpszMenuName  = nullptr;
  598.     w32::winClass.lpszClassName = w32::winClassName;
  599.     w32::winClass.hIconSm       = nullptr; //(the window's small icon)
  600.     w32::winClassAtom = RegisterClassExA(&w32::winClass);
  601.     if(!w32::winClassAtom){
  602.       errorText = "RegisterClassA() failed";
  603.       goto _DelCritSection;
  604.     }
  605.   }
  606.  
  607.  
  608.   _opq->winStretchMode = KIT_INITIAL_STRETCH_MODE;
  609.  
  610.   HandlePreCreationWindowFlags(_opq, windowFlags);
  611.  
  612.  
  613.   //create window
  614.   shape::point winSize = CalculateWindowSize(windowWidth, windowHeight,
  615.                                              _opq->winFlags, _opq->winFlagsEx);
  616.  
  617.   _opq->winHandle = CreateWindowExA(_opq->winFlagsEx, w32::winClassName, _title,
  618.                                     _opq->winFlags, windowX, windowY, winSize.x, winSize.y,
  619.                                     nullptr, nullptr, w32::hThisInst, (LPVOID)this);
  620.  
  621.   if(_opq->winHandle == nullptr){
  622.     errorText = "CreateWindowA() failed";
  623.     goto _UnregisterClass;
  624.   }
  625.  
  626.  
  627.   //create canvas
  628.   if(canvasWidth>windowWidth || canvasHeight>windowHeight){
  629.     errorText = "canvas size is larger than the window";
  630.     goto _DestroyWindow;
  631.   }
  632.  
  633.   if(canvasWidth <1) canvasWidth  = windowWidth;
  634.   if(canvasHeight<1) canvasHeight = windowHeight;
  635.  
  636.   _opq->canvasStretch = (canvasWidth<windowWidth || canvasHeight<windowHeight);
  637.  
  638.   if(!PopulateBitmapOpaque(_opq->canvas, nullptr, canvasWidth, canvasHeight,
  639.                            _opq, directAccess))
  640.   {
  641.     errorText = "failed to create canvas";
  642.     goto _DestroyWindow;
  643.   }
  644.  
  645.  
  646.   _opq->winRect.x = (windowX != WINPOS_UNCHANGED) ? windowX : WINPOS_UNDEFINED;
  647.   _opq->winRect.y = (windowY != WINPOS_UNCHANGED) ? windowY : WINPOS_UNDEFINED;
  648.   _opq->winRect.w = winSize.x;
  649.   _opq->winRect.h = winSize.y;
  650.   setWindowRect(&_opq->winRect);
  651.  
  652.  
  653.   //until i can figure out why setting WS_POPUP *before* window creation
  654.    //crashes the program, this solution seems to work
  655.   u32 currentStyle = GetWindowLongA(_opq->winHandle, GWL_STYLE);
  656.   if(windowFlags & WINFLAG_BORDERLESS){
  657.     currentStyle &= ~WS_CAPTION;
  658.     currentStyle |= WS_POPUP;
  659.     SetWindowLongA(_opq->winHandle, GWL_STYLE, currentStyle);
  660.   }
  661.  
  662. //if(  windowFlags & WINFLAG_MINIMIZED ) setMinimized(true); //tbd: fix this
  663.   if(  windowFlags & WINFLAG_MAXIMIZED ) setMaximized(true);
  664.   if(  windowFlags & WINFLAG_FULLSCREEN) setFullscreen(true);
  665.   if(!(windowFlags & WINFLAG_HIDDEN)   ) setVisibility(true);
  666.   if(  windowFlags & WINFLAG_FOCUS     ) setFocus(true);
  667.  
  668.  
  669.   _opq->winClosed = false;
  670.   _opq->winIndex = w32::winCount++; //set window index, before adding to total count
  671.   _valid = true;
  672.   _constructing = false;
  673. }
  674.  
  675.  
  676.  
  677. Window::~Window(){
  678.   if(!_valid) return;
  679.   _valid = false;
  680.   --w32::winCount; //remove window from total count
  681.  
  682.   if(_opq != nullptr){
  683.     DeleteObject(_opq->canvas.handle);
  684.     DeleteDC(_opq->canvas.devCtx);
  685.     DestroyWindow(_opq->winHandle);
  686.     if(w32::winCount == 0) UnregisterClassA(w32::winClassName, w32::hThisInst);
  687.     DeleteCriticalSection(&_opq->lock);
  688.     if(!_opq->canvas.directAccess) memory::free(&_opq->canvas.pixels);
  689.     memory::free(&_opq);
  690.   }
  691. }
  692.  
  693.  
  694.  
  695.  
  696. bool Window::isClosed(){
  697.   //(can't use KIT_IS_INVALID_WINDOW here)
  698.   if(!_valid && !_constructing) throw KIT_INVALID_WINDOW;
  699.   return _opq->winClosed; //set by w32::WindowProc, rather than destructor
  700. }
  701.  
  702.  
  703.  
  704. //queries the actual state of the window, rather than winRect,
  705.  //because setWindowRect(nullptr) does not actually modify winRect
  706. shape::rect Window::getWindowRect(){
  707.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  708.   RECT winRectTmp;
  709.   GetWindowRect(_opq->winHandle, &winRectTmp); //get window's bounding box
  710.   return ConvertToKitRect(winRectTmp);
  711. }
  712.  
  713.  
  714.  
  715. shape::point Window::getCanvasSize(){
  716.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  717.   return _opq->canvas.size;
  718. }
  719.  
  720.  
  721.  
  722. color::ARGB* Window::getPixels(){
  723.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  724.   if(_opq->canvas.directAccess) return _opq->canvas.pixels;
  725.   else throw "window's canvas does not support direct access";
  726. }
  727.  
  728.  
  729.  
  730.  
  731. //if newRect == nullptr, the window will stretch to fit the whole screen
  732. void Window::setWindowRect(const shape::rect* newRect){
  733.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  734.  
  735.  
  736.   s32 screenWidth  = GetSystemMetrics(SM_CXSCREEN);
  737.   s32 screenHeight = GetSystemMetrics(SM_CYSCREEN);
  738.  
  739.  
  740.   if(newRect != nullptr){
  741.     shape::rect winRectCurrent = getWindowRect();
  742.  
  743.     shape::point centerPos;
  744.     centerPos.x = screenWidth /2 - winRectCurrent.w/2;
  745.     centerPos.y = screenHeight/2 - winRectCurrent.h/2;
  746.  
  747.  
  748.     shape::rect _newRect = *newRect; //make a copy of newRect
  749.  
  750.     if(     _newRect.x == WINPOS_UNDEFINED) _newRect.x = CW_USEDEFAULT;
  751.     else if(_newRect.x == WINPOS_CENTERED ) _newRect.x = centerPos.x;
  752.     else if(_newRect.x == WINPOS_UNCHANGED) _newRect.x = winRectCurrent.x;
  753.  
  754.     if(     _newRect.y == WINPOS_UNDEFINED) _newRect.y = CW_USEDEFAULT;
  755.     else if(_newRect.y == WINPOS_CENTERED ) _newRect.y = centerPos.y;
  756.     else if(_newRect.y == WINPOS_UNCHANGED) _newRect.y = winRectCurrent.y;
  757.  
  758.     if(_newRect.w==WINPOS_UNCHANGED || _newRect.w<1) _newRect.w = winRectCurrent.w;
  759.     if(_newRect.h==WINPOS_UNCHANGED || _newRect.h<1) _newRect.h = winRectCurrent.h;
  760.  
  761.  
  762.     SetWindowPos(_opq->winHandle, nullptr, _newRect.x,_newRect.y,
  763.                  _newRect.w, _newRect.h, SWP_NOZORDER);
  764.  
  765.     _opq->winRect = getWindowRect(); //update the window's rect to reflect changes
  766.  
  767.  
  768.   } else { //internally, this option is solely used by setFullscreen
  769.  
  770.     //winRect automatically gets overwritten for every WM_MOVE and WM_SIZE message,
  771.      //so record its previous value so it can be set back after the SetWindowPos
  772.     shape::rect winRectPrevious = _opq->winRect;
  773.  
  774.     //this will (should) fill the entire screen, assuming there's no
  775.      //window decoration in the way of doing so
  776.     SetWindowPos(_opq->winHandle, nullptr, 0,0,
  777.                  screenWidth, screenHeight, SWP_NOZORDER);
  778.  
  779.     //winRect is set back to its original state,
  780.      //so that its rect pre-fullscreen is preserved
  781.     _opq->winRect = winRectPrevious;
  782.  
  783.  
  784.   }
  785. }
  786.  
  787.  
  788.  
  789. void Window::setCanvasSize(s32 width, s32 height){
  790.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  791.  
  792.   lock(true); //just in case
  793.  
  794.  
  795.   if(width <1) width  = _opq->winRect.w;
  796.   if(height<1) height = _opq->winRect.h;
  797.  
  798.   _opq->canvasStretch = (width<_opq->winRect.w || height<_opq->winRect.h);
  799.  
  800.   if(!ResizeBitmapOpaque(_opq->canvas, width, height))
  801.     throw "failed to resize canvas";
  802.  
  803.  
  804.   //it's safe to lock a CRITICAL_SECTION multiple times on a single thread,
  805.    //so long as it's unlocked an equal number of times
  806.   lock(false);
  807. }
  808.  
  809.  
  810.  
  811. void Window::setMinimized(bool minimize){
  812.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  813.   ShowWindow(_opq->winHandle, (minimize) ? SW_MINIMIZE : SW_NORMAL);
  814.   _opq->winMaximized = false;
  815.   _opq->winMinimized = minimize;
  816. }
  817.  
  818.  
  819.  
  820. void Window::setMaximized(bool maximize){
  821.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  822.   ShowWindow(_opq->winHandle, (maximize) ? SW_MAXIMIZE : SW_NORMAL);
  823.   _opq->winMinimized = false;
  824.   _opq->winMaximized = maximize;
  825. }
  826.  
  827.  
  828.  
  829. void Window::setFullscreen(bool fullscreen){
  830.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  831.  
  832.  
  833.   if(fullscreen){ //modify values accordingly
  834.     //style flags
  835.     SetWindowLongA(_opq->winHandle, GWL_STYLE,
  836.                    _opq->winFlags & ~(WS_CAPTION | WS_THICKFRAME));
  837.  
  838.     //extended style flags
  839.     SetWindowLongA(_opq->winHandle, GWL_EXSTYLE,
  840.                    _opq->winFlagsEx & ~(WS_EX_DLGMODALFRAME |
  841.                    WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
  842.  
  843.     //stretch window to match screen's width and height
  844.     setWindowRect(nullptr);
  845.  
  846.  
  847.   } else { //restore values to what they were before
  848.     //restore style flags
  849.     SetWindowLongA(_opq->winHandle, GWL_STYLE, _opq->winFlags);
  850.  
  851.     //restore extended style flags
  852.     SetWindowLongA(_opq->winHandle, GWL_EXSTYLE, _opq->winFlagsEx);
  853.  
  854.     //restore window position and size
  855.     setWindowRect(&_opq->winRect);
  856.  
  857.  
  858.   }
  859.  
  860.   //idk for sure why this fixes the issue of the window breaking when
  861.    //fullscreen is toggled, but if it works in the constructor and here too,
  862.    //then i have no problem with doing it this way :)
  863.    //(maybe showing it again invokes some update thingy)
  864.   setVisibility(_opq->winShown);
  865.  
  866.   _opq->winFullscreen = fullscreen;
  867. }
  868.  
  869.  
  870.  
  871. void Window::setVisibility(bool show){
  872.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  873.   ShowWindow(_opq->winHandle, (show) ? SW_SHOW : SW_HIDE);
  874.   _opq->winShown = show;
  875.   //*maybe* set _opq->winFlags (probably not needed, though)
  876. }
  877.  
  878.  
  879.  
  880. void Window::setFocus(bool enable){
  881.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  882.   SetFocus((enable) ? _opq->winHandle : nullptr);
  883.   _opq->winFocus = enable;
  884. }
  885.  
  886.  
  887.  
  888. //this determines how the canvas stretches to the window, which is why
  889.  //winStretchMode is modified here (since window is the canvas's blit destination)
  890. void Window::setCanvasInterpolationMode(bool halftone){
  891.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  892.   //(no call to SetStretchBltMode, as that's done inside WindowProc)
  893.   _opq->winStretchMode = (halftone) ? HALFTONE : COLORONCOLOR;
  894. }
  895.  
  896.  
  897.  
  898. //like setCanvasInterpolationMode, canvas's stretch mode is altered,
  899.  //since the canvas is ultimately the bitmap's blit destination
  900. void Window::setBitmapInterpolationMode(bool halftone){
  901.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  902.   u32 mode = (halftone) ? HALFTONE : COLORONCOLOR;
  903.   SetStretchBltMode(_opq->canvas.devCtx, mode);
  904.   _opq->canvas.stretchMode = mode;
  905. }
  906.  
  907.  
  908.  
  909.  
  910. void Window::lock(bool locked){
  911.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  912.   if(locked) EnterCriticalSection(&_opq->lock);
  913.   else       LeaveCriticalSection(&_opq->lock);
  914. }
  915.  
  916.  
  917.  
  918.  
  919. void Window::present(bool updateImmediately){
  920.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  921.   InvalidateRect(_opq->winHandle, nullptr, false);
  922.   if(updateImmediately) UpdateWindow(_opq->winHandle);
  923. }
  924.  
  925.  
  926.  
  927. void Window::clear(color::ARGB color){
  928.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  929.   HBRUSH brushHandle    = CreateSolidBrush(color.v);
  930.   HBRUSH brushHandleOld = (HBRUSH)SelectObject(_opq->canvas.devCtx, brushHandle);
  931.  
  932.   RECT rectF;
  933.   rectF.left   = 0;
  934.   rectF.top    = 0;
  935.   rectF.right  = _opq->canvas.size.x;
  936.   rectF.bottom = _opq->canvas.size.y;
  937.  
  938.   FillRect(_opq->canvas.devCtx, &rectF, brushHandle);
  939.  
  940.   SelectObject(_opq->canvas.devCtx, brushHandleOld);
  941.   DeleteObject(brushHandle);
  942. }
  943.  
  944.  
  945.  
  946. #define ARGB_to_ABGR(_c) RGB(color.r, color.g, color.b)
  947.  
  948. void Window::drawPoint(shape::point point, color::ARGB color){
  949.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  950.   SetPixel(_opq->canvas.devCtx, point.x, point.y, ARGB_to_ABGR(color));
  951. }
  952.  
  953.  
  954.  
  955. void Window::drawPoints(shape::point* points, size_t points_len,
  956.                         color::ARGB color, bool useSetPixel)
  957. {
  958.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  959.   if(points == nullptr) throw "points = nullptr";
  960.  
  961.   HDC canvasDC = _opq->canvas.devCtx;
  962.  
  963.   if(useSetPixel){
  964.     COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
  965.  
  966.     for(size_t i=0; i<points_len; ++i)
  967.       SetPixel(canvasDC, points[i].x, points[i].y, _color);
  968.  
  969.  
  970.   } else {
  971.     lock(true);
  972.  
  973.     shape::point size   = _opq->canvas.size;
  974.     color::ARGB* pixels = _opq->canvas.pixels;
  975.  
  976.     //if canvas is not direct access, its pixel data needs to be copied to
  977.      //canvas.pixels (which is valid whether or not directAccess is true)
  978.     if(!_opq->canvas.directAccess){
  979.       GetDIBits(canvasDC, _opq->canvas.handle, 0, size.y,
  980.                 pixels, &_opq->canvas.info, DIB_RGB_COLORS);
  981.     }
  982.  
  983.  
  984.     //bitmap coordinates are weird, in that they go bottom-up, not top-down
  985.      //like most other image formats. this means the y coordinate needs to
  986.      //be inverted, which looks like: "output_y = size.y-1-input_y".
  987.     shape::point sizeMinus1 = size;
  988.     --sizeMinus1.x, --sizeMinus1.y;
  989.  
  990.     for(size_t i=0; i<points_len; ++i){
  991.       shape::point p = points[i];
  992.       if(p.x<0 || p.y<0  ||  p.x>sizeMinus1.x || p.y>sizeMinus1.y) continue;
  993.       pixels[ p.x + (sizeMinus1.y-p.y)*size.x ] = color;
  994.     }
  995.  
  996.  
  997.     if(!_opq->canvas.directAccess){
  998.       //copy the modified pixel data back to the canvas
  999.       SetDIBits(canvasDC, _opq->canvas.handle, 0, size.y,
  1000.                 pixels, &_opq->canvas.info, DIB_RGB_COLORS);
  1001.     }
  1002.  
  1003.     lock(false);
  1004.  
  1005.  
  1006.   }
  1007. }
  1008.  
  1009.  
  1010.  
  1011.  
  1012. void Window::drawLines(shape::point* lineEnds, size_t lineEnds_len,
  1013.                        color::ARGB color, u32 width)
  1014. {
  1015.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  1016.   if(lineEnds == nullptr) throw "lineEnds = nullptr";
  1017.   if(width == 0) throw "width = 0";
  1018.  
  1019.  
  1020.   if(lineEnds_len > 0){
  1021.     HDC canvasDC = _opq->canvas.devCtx;
  1022.  
  1023.     COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
  1024.  
  1025.     HPEN penHandle    = CreatePen(PS_SOLID, width&KIT_S32_MAX, _color);
  1026.     HPEN penHandleOld = (HPEN)SelectObject(canvasDC, penHandle);
  1027.  
  1028.  
  1029.     MoveToEx(canvasDC, lineEnds[0].x, lineEnds[0].y, nullptr);
  1030.     for(size_t i=1; i<lineEnds_len; ++i)
  1031.       LineTo(canvasDC, lineEnds[i].x, lineEnds[i].y);
  1032.  
  1033.  
  1034.     SelectObject(canvasDC, penHandleOld);
  1035.     DeleteObject(penHandle);
  1036.  
  1037.   }
  1038. }
  1039.  
  1040.  
  1041.  
  1042. void Window::drawLineSegments(shape::line* lines, size_t lines_len,
  1043.                               color::ARGB color, u32 width)
  1044. {
  1045.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  1046.   if(lines == nullptr) throw "lines = nullptr";
  1047.   if(width == 0) throw "width = 0";
  1048.  
  1049.  
  1050.   if(lines_len > 0){
  1051.     HDC canvasDC = _opq->canvas.devCtx;
  1052.  
  1053.     COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
  1054.  
  1055.     HPEN penHandle    = CreatePen(PS_SOLID, width&KIT_S32_MAX, _color);
  1056.     HPEN penHandleOld = (HPEN)SelectObject(canvasDC, penHandle);
  1057.  
  1058.  
  1059.     for(size_t i=0; i<lines_len; ++i){
  1060.       shape::line l = lines[i];
  1061.       MoveToEx(canvasDC, l.x0, l.y0, nullptr);
  1062.       LineTo(canvasDC, l.x1, l.y1);
  1063.     }
  1064.  
  1065.  
  1066.     SelectObject(canvasDC, penHandleOld);
  1067.     DeleteObject(penHandle);
  1068.  
  1069.   }
  1070. }
  1071.  
  1072.  
  1073.  
  1074.  
  1075. void Window::drawRectangles(shape::rect* rects, size_t rects_len, color::ARGB color){
  1076.   if(KIT_IS_INVALID_WINDOW) throw KIT_INVALID_WINDOW;
  1077.   if(rects == nullptr) throw "rects = nullptr";
  1078.  
  1079.  
  1080.   if(rects_len > 0){
  1081.     HDC canvasDC = _opq->canvas.devCtx;
  1082.  
  1083.     COLORREF _color = ARGB_to_ABGR(color); //color used is abgr, not argb
  1084.  
  1085.     HBRUSH brushHandle    = CreateSolidBrush(_color);
  1086.     HBRUSH brushHandleOld = (HBRUSH)SelectObject(canvasDC, brushHandle);
  1087.  
  1088.  
  1089.     for(size_t i=0; i<rects_len; ++i){
  1090.       RECT rectF = ((RECT*)rects)[i];
  1091.       //RECT effectively uses 2 points to define a rectangle, whereas
  1092.        //shape::rect uses 1 point, plus a width and height.
  1093.        //that means the 2nd point must be converted, like this:
  1094.       rectF.right  += rectF.left; //b.x += a.x
  1095.       rectF.bottom += rectF.top;  //b.y += a.y
  1096.  
  1097.       FillRect(canvasDC, &rectF, brushHandle);
  1098.     }
  1099.  
  1100.  
  1101.     SelectObject(canvasDC, brushHandleOld);
  1102.     DeleteObject(brushHandle);
  1103.  
  1104.   }
  1105. }
  1106.  
  1107.  
  1108.  
  1109.  
  1110. }; /* namespace kit */
  1111.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement