Advertisement
Kitomas

work for 2025-03-28 (1/2)

Mar 28th, 2025
364
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 35.62 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"gdi_winmm_2025-03-28\src\user_audio.cpp":
  4. #include <public_stuff.hpp>
  5.  
  6.  
  7.  
  8. /*
  9. #define volume 0.05f
  10. #define u8_smp(_smp) (  (s16)( ((_smp)-128)<<8 )  ) //u8 to s16 sample
  11. void audio_callback(s16* smp, u32 len){
  12.   static s64 t = 0;
  13.  
  14.   for(u32 i=0; i<len; ++i){
  15.     //bytebeat shamelessly stolen from dollchan (go check out their bytebeat editor, seriously)
  16.     smp[i] = u8_smp( (((t/10|0)^(t/10|0)-1280)%11*t/2&127)+(((t/640|0)^(t/640|0)-2)%13*t/2&127) );
  17.     smp[i] *= volume;
  18.     ++t;
  19.  
  20.   }
  21.  
  22. }
  23. */
  24.  
  25.  
  26.  
  27. #include <math.h>
  28.  
  29. // This plays a 440Hz sine wave
  30.  
  31. void user_audio(StereoF32* stream, u32 len, u32 sampleRate, f64 timeStamp)
  32. {
  33.   static f64        t = 0;
  34.   static f64 modulate = 0.0f;
  35.  
  36.  
  37.   for(u32 i=0; i<len; ++i){
  38.     f32 cycle = ((f32)t/sampleRate) * M_2PIf;
  39.  
  40.     f64 increment  =  1.0 + (f64)sinF(modulate)*0.3;
  41.     t += increment;
  42.     modulate = fmod(modulate+0.0001, M_2PIf);
  43.  
  44.     f32 smp = sinF(cycle*440);
  45.  
  46.     smp *= 0.10f / increment;
  47.     stream[i].l = smp;
  48.     stream[i].r = smp;
  49.  
  50.   }
  51.  
  52.  
  53.   t = fmod(t, sampleRate);
  54.  
  55.  
  56.  
  57.  
  58. /*
  59.   // The static keyword here just makes the variable persistent, in that
  60.   // its state is preserved between each call to user_audio
  61.   static u64 t = 0; // u[nsigned] 64-bit integer
  62.  
  63.  
  64.   for(u32 i=0; i<len; ++i){ //For every sample to be filled in the audio buffer
  65.  
  66.     // t is incremented every sample, and is divided by the sample rate to
  67.     // basically make a percentage of how far it is through a second.
  68.     // This is then multiplied by 2pi, which effectively makes it oscillate
  69.     // once every second if you fed cycle into sin directly
  70.     f32 cycle = ((f32)(t++)/sampleRate) * M_2PIf;
  71.  
  72.     // cycle is multiplied by 440 so that it oscillates 440 times a second
  73.     // instead of just once.
  74.     // (Also, sinF is just sin but it uses 32-bit f[loats] instead of 64-bit,
  75.     //  and unlike the actual sinf, this is a custom implementation)
  76.     f32 smp = sinF(cycle*440); // This ofc returns a number from -1.0 to 1.0
  77.  
  78.     // 20% volume
  79.     smp *= 0.20f;
  80.  
  81.     // Since the audio stream is stereo, the sample is applied to
  82.     // both 'ears' so-to-speak.
  83.     stream[i].l = smp;
  84.     stream[i].r = smp;
  85.  
  86.   }
  87.  
  88.  
  89.   // Unnecessary, since a u64 is so big, but this makes it so that
  90.   // even if it was a smaller integer size, it will never overflow.
  91.   // (The % operator does a division, but gets the remainder instead)
  92.   t %= sampleRate;
  93. */
  94.  
  95. }
  96. /******************************************************************************/
  97. /******************************************************************************/
  98. //"gdi_winmm_2025-03-28\src\user_main.cpp":
  99. #include <math.h>
  100.  
  101. #include <public_stuff.hpp>
  102.  
  103.  
  104.  
  105. // Creates an ARGB color in the form of a u32, not Color24
  106. #ifndef   ABGR_U32
  107. #define   ABGR_U32(_r,_g,_b,_a)      (\
  108.   ((u32)(_a)<<24) | ((u32)(_b)<<16)  |\
  109.   ((u32)(_g)<< 8) | ((u32)(_r)    )  )
  110. #endif /* ABGR_U32 */
  111.  
  112. u32 hsv2rgb(f32 h, f32 s, f32 v){
  113.   f32 r, g, b;
  114.  
  115.   // Normalize values
  116.   h /= 360;
  117.   s /= 100;
  118.   v /= 100;
  119.  
  120.   // The rest is magic, idk
  121.   s32 i = floor(h*6);
  122.   f32 f = h * 6 - i;
  123.   f32 p = v * (1.0f -            s);
  124.   f32 q = v * (1.0f -       f  * s);
  125.   f32 t = v * (1.0f - (1.0f-f) * s);
  126.  
  127.   switch (i % 6) {
  128.     case 0: r = v, g = t, b = p; break;
  129.     case 1: r = q, g = v, b = p; break;
  130.     case 2: r = p, g = v, b = t; break;
  131.     case 3: r = p, g = q, b = v; break;
  132.     case 4: r = t, g = p, b = v; break;
  133.     case 5: r = v, g = p, b = q; break;
  134.   }
  135.  
  136.   // It should be impossible for r,g,b to be uninitialized
  137.   // due to how the switch is set up, so the warning can be ignored.
  138.   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  139.   #pragma GCC diagnostic push
  140.   return ABGR_U32(r*255, g*255, b*255, 255);
  141.   #pragma GCC diagnostic pop
  142.  
  143. }
  144.  
  145.  
  146.  
  147.  
  148.  
  149. static inline u8 sinF_unit_u8(f32 x){ return (0.5f + sinF(x)*0.5f) * 255; }
  150.  
  151.  
  152.  
  153. int user_main(int argc, char** argv){
  154.   for(u32 i=0; i<256; ++i)
  155.     pixels_palette[i].v = hsv2rgb(((f32)i/256)*360.0f, 100.0f, 100.0f);
  156.   //  pixels_palette[i].v = ABGR_U32(i, i, i, 255);
  157.  
  158.   update_palette();
  159.  
  160.  
  161.  
  162.   u64 f = 0; // Frame counter
  163.  
  164.   while(!win_closed){
  165.     Event evt;
  166.     while(pollEvent(&evt));
  167.     if(win_closed) break;
  168.  
  169.  
  170.     for(int y=0; y<CANVAS_H; ++y)
  171.     for(int x=0; x<CANVAS_W; ++x)
  172.     {
  173.       f32 ux  =  (f32)x / (CANVAS_W-1);
  174.       f32 uy  =  (f32)y / (CANVAS_H-1);
  175.       f32 uf  =  (f32)f / 60;
  176.  
  177.       f32 xmod = cosF( (uy+uf/3) * M_2PIf );
  178.  
  179.  
  180.       u8 value = sinF_unit_u8( (xmod*ux + uy + uf) * M_2PIf );
  181.       PixelCoords which_pixel = {(u8)x, (u8)y};
  182.  
  183.       pixels[ which_pixel.v ].v = value;
  184.  
  185.     }
  186.  
  187.  
  188.     canvas_present(); // Draws the canvas to the window
  189.  
  190.     timeSleep(16); // Waits for about 16ms to approximate 60fps (1000/16 = 62.5)
  191.     ++f; // Increment frames
  192.  
  193.   }
  194.  
  195.  
  196.  
  197.   return 0;
  198.  
  199. }
  200. /******************************************************************************/
  201. /******************************************************************************/
  202. //"gdi_winmm_2025-03-28\src\win32\audio.cpp":
  203. #include <win32/audio.hpp>
  204.  
  205. #include <public_stuff.hpp>
  206.  
  207.  
  208.  
  209.  
  210.  
  211. void user_audio(StereoF32* stream, u32 len, u32 sampleRate, f64 timeStamp);
  212.  
  213.  
  214.  
  215.  
  216.  
  217. #define _chunk_count 3
  218. #define fade_delta_len 0.010f //for 10ms
  219.  
  220. static StereoF32 samples_in[4096];
  221. static StereoS16 _chunk_data[_chunk_count][4096];
  222. static WAVEHDR   _chunk_header[_chunk_count];
  223. static int       _chunk_which;
  224.  
  225. static HWAVEOUT wave_out;
  226.  
  227. static bool fade_in     = true;
  228. static f32  fade_volume = 0.0f;
  229.  
  230. u32 audio_samples = 0;
  231. u32 sample_rate   = 0;
  232.  
  233.  
  234.  
  235.  
  236.  
  237. static inline void call_user_audio(int which){
  238.   // Zero out user buffer, before invoking user function
  239.   memSet(samples_in, 0, audio_samples*sizeof(StereoF32));
  240.   user_audio(samples_in, audio_samples, sample_rate, timeGetSeconds());
  241.  
  242.   // Convert stereo f32 (-1.0f to 1.0f) to stereo s16 (-32768 to 32767)
  243.   StereoS16* samples_out = _chunk_data[which];
  244.  
  245.   // 'By how much does the fade volume change every frame?'
  246.   const f32 fade_delta = 1.0f / (fade_delta_len*sample_rate);
  247.  
  248.  
  249.  
  250.   if(fade_in && fade_volume>=1.0f){ // Fully faded in
  251.     for(u32 i=0; i<audio_samples; ++i){
  252.       samples_out[i].l  =  (s16)( CLAMP(samples_in[i].l, -1.0f, 1.0f) * 32767 );
  253.       samples_out[i].r  =  (s16)( CLAMP(samples_in[i].r, -1.0f, 1.0f) * 32767 );
  254.  
  255.     }
  256.  
  257.   } else if(fade_in){ // Currently fading in
  258.     for(u32 i=0; i<audio_samples; ++i){
  259.       f32 smp_l  =  (s16)( CLAMP(samples_in[i].l, -1.0f, 1.0f) * 32767 );
  260.       f32 smp_r  =  (s16)( CLAMP(samples_in[i].r, -1.0f, 1.0f) * 32767 );
  261.  
  262.       smp_l *= fade_volume;
  263.       smp_r *= fade_volume;
  264.       fade_volume = MIN(fade_volume+fade_delta, 1.0f);
  265.  
  266.       samples_out[i].l = smp_l;
  267.       samples_out[i].r = smp_r;
  268.  
  269.     }
  270.  
  271.   } else { // if(!fade_in)
  272.     for(u32 i=0; i<audio_samples; ++i){
  273.       f32 smp_l  =  (s16)( CLAMP(samples_in[i].l, -1.0f, 1.0f) * 32767 );
  274.       f32 smp_r  =  (s16)( CLAMP(samples_in[i].r, -1.0f, 1.0f) * 32767 );
  275.  
  276.       smp_l *= fade_volume;
  277.       smp_r *= fade_volume;
  278.       fade_volume = MAX(fade_volume-fade_delta, 0.0f);
  279.  
  280.       samples_out[i].l = smp_l;
  281.       samples_out[i].r = smp_r;
  282.  
  283.     }
  284.  
  285.   }
  286.  
  287. }
  288.  
  289.  
  290.  
  291.  
  292.  
  293. void CALLBACK WaveOutProc(HWAVEOUT hwo, UINT msg, DWORD_PTR inst,
  294.                           DWORD_PTR param1, DWORD_PTR param2)
  295. {
  296.   if(msg == WOM_DONE){
  297.     call_user_audio(_chunk_which);
  298.  
  299.     waveOutWrite(hwo, &_chunk_header[_chunk_which], sizeof(WAVEHDR));
  300.  
  301.     _chunk_which += 1;
  302.     _chunk_which %= _chunk_count;
  303.  
  304.   }
  305.  
  306. }
  307.  
  308.  
  309.  
  310.  
  311.  
  312. int WaveOutInit(){
  313.   MMRESULT err;
  314.   WAVEOUTCAPS devcaps;
  315.  
  316.   if((err = waveOutGetDevCapsA(WAVE_MAPPER, &devcaps, sizeof(WAVEOUTCAPS))))
  317.     return -1;
  318.  
  319.   if(devcaps.dwFormats & WAVE_FORMAT_4S16) // 44100Hz, Stereo, s16
  320.   {
  321.     audio_samples =  2048;
  322.     sample_rate   = 44100;
  323.   }
  324.   else if(devcaps.dwFormats & WAVE_FORMAT_96S16) // 96000Hz, Stereo, s16
  325.   {
  326.     audio_samples =  4096;
  327.     sample_rate   = 96000;
  328.   }
  329.   else if(devcaps.dwFormats & WAVE_FORMAT_2S16) // 22050Hz, Stereo, s16
  330.   {
  331.     audio_samples =  1024;
  332.     sample_rate   = 22050;
  333.   }
  334.   else if(devcaps.dwFormats & WAVE_FORMAT_1S16) // 11025Hz, Stereo, s16
  335.   {
  336.     audio_samples =   512;
  337.     sample_rate   = 11025;
  338.   }
  339.   else // No valid 16-bit stereo sample rate is supported!
  340.   {
  341.     return -2;
  342.   }
  343.  
  344.  
  345.  
  346.   _chunk_which = 0;
  347.  
  348.  
  349.  
  350.   WAVEFORMATEX fmt;
  351.   fmt.wFormatTag     = WAVE_FORMAT_PCM;
  352.   fmt.nChannels      =  2;
  353.   fmt.nSamplesPerSec = sample_rate;
  354.   fmt.wBitsPerSample = 16;
  355.   fmt.cbSize         =  0;
  356.  
  357.   fmt.nBlockAlign     = fmt.nChannels      * fmt.wBitsPerSample / 8;
  358.   fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
  359.  
  360.  
  361.  
  362.   if(waveOutOpen(&wave_out, WAVE_MAPPER, &fmt,
  363.                  (DWORD_PTR)WaveOutProc, 0, CALLBACK_FUNCTION))
  364.   {
  365.     return -3;
  366.   }
  367.  
  368.   #define WO_VOLUME(_left, _right) ( ((_right)<<16) | (_left) )
  369.  
  370.   err = waveOutSetVolume(wave_out, WO_VOLUME(0xffff, 0xffff));
  371.  
  372.   // Even if the function isn't supported, hopefully it'll just default to 100%
  373.   if(err && err != MMSYSERR_NOTSUPPORTED) return -4;
  374.  
  375.  
  376.  
  377.   // Set header info and prime the audio buffers
  378.   for(u32 i=0; i<_chunk_count; ++i){
  379.     _chunk_header[i].lpData          = (CHAR*)_chunk_data[i];
  380.     _chunk_header[i].dwBufferLength  = audio_samples*sizeof(s16)*fmt.nChannels;
  381.     _chunk_header[i].dwBytesRecorded = 0;
  382.     _chunk_header[i].dwUser          = 0;
  383.     _chunk_header[i].dwFlags         = 0;
  384.     _chunk_header[i].dwLoops         = 0;
  385.     _chunk_header[i].lpNext          = nullptr;
  386.     _chunk_header[i].reserved        = 0;
  387.  
  388.     if(waveOutPrepareHeader(wave_out, &_chunk_header[i], sizeof(WAVEHDR)))
  389.       return -5;
  390.  
  391.     memSet(_chunk_data[i], 0, _chunk_header[i].dwBufferLength);
  392.     if(waveOutWrite(wave_out, &_chunk_header[i], sizeof(WAVEHDR)))
  393.       return -6;
  394.  
  395.   }
  396.  
  397.  
  398.  
  399.   return 0;
  400.  
  401. }
  402.  
  403.  
  404.  
  405.  
  406.  
  407. void WaveOutQuit(){
  408.   // Fade audio out smoothly before pausing
  409.   fade_in = false;
  410.   while(fade_volume > 0.0f) Sleep(10);
  411.  
  412.   // Also make sure all buffers have played
  413.   #define chunk_time ((f64)(_chunk_count*audio_samples)/sample_rate)
  414.   Sleep((DWORD)(chunk_time*1000));
  415.  
  416.   waveOutPause(wave_out);
  417.  
  418. }
  419. /******************************************************************************/
  420. /******************************************************************************/
  421. //"gdi_winmm_2025-03-28\src\win32\functions.cpp":
  422. #include <win32/audio.hpp>
  423. #include <win32/video.hpp>
  424. #include <win32/misc.hpp>
  425.  
  426.  
  427.  
  428.  
  429.  
  430. _Ole32_func_t _Ole32_func;
  431.  
  432. char _Ole32_names[] = // prefix = "CoTaskMem"
  433.   "Alloc\0"
  434.   "Realloc\0"
  435.   "Free\0"
  436.   "\0";
  437.  
  438.  
  439.  
  440.  
  441.  
  442. _Winmm_func_t _Winmm_func;
  443.  
  444. char _Winmm_names[] = // prefix = "waveOut"
  445. //"GetNumDevs\0"
  446.   "GetDevCapsA\0"
  447. //"GetVolume\0"
  448.   "SetVolume\0"
  449. //"GetErrorTextA\0"
  450.   "Open\0"
  451. //"Close\0"
  452.   "PrepareHeader\0"
  453. //"UnprepareHeader\0"
  454.   "Write\0"
  455.   "Pause\0"
  456. //"Restart\0"
  457. //"Reset\0"
  458. //"BreakLoop\0"
  459. //"GetPosition\0"
  460. //"GetPitch\0"
  461. //"SetPitch\0"
  462. //"GetPlaybackRate\0"
  463. //"SetPlaybackRate\0"
  464. //"GetID\0"
  465. //"Message\0"
  466.   "\0";
  467.  
  468.  
  469.  
  470.  
  471.  
  472. _User32_func_t _User32_func;
  473.  
  474. char _User32_names_a[] = // prefix = ""
  475.   "RegisterClassA\0"
  476.   "CreateWindowExA\0"
  477.   "DefWindowProcA\0"
  478.   "InvalidateRect\0"
  479.   "UpdateWindow\0"
  480.   "BeginPaint\0"
  481.   "EndPaint\0"
  482.   "PeekMessageA\0"
  483.   "DispatchMessageA\0"
  484.   "DestroyWindow\0"
  485. //"ReleaseDC\0"
  486. //"GetDC\0"
  487.   "PostQuitMessage\0"
  488.   "MessageBoxA\0"
  489.   "TranslateMessage\0"
  490.   "GetWindowLongA\0"
  491.   "AdjustWindowRectEx\0"
  492.   "LoadCursorA\0"
  493.   "MapVirtualKeyA\0"
  494. //"GetCursorPos\0"
  495.   "ScreenToClient\0"
  496.   "\0";
  497.  
  498.  
  499.  
  500.  
  501.  
  502. _Gdi32_func_t _Gdi32_func;
  503.  
  504. char _Gdi32_names_a[] = // prefix = ""
  505.   "CreateCompatibleDC\0"
  506.   "CreateDIBSection\0"
  507.   "SelectObject\0"
  508.   "DeleteObject\0"
  509. //"BitBlt\0"
  510.   "DeleteDC\0"
  511.   "StretchBlt\0"
  512.   "CreateCompatibleBitmap\0"
  513.   "SetStretchBltMode\0"
  514.   "SetDIBColorTable\0"
  515.   "\0";
  516. /******************************************************************************/
  517. /******************************************************************************/
  518. //"gdi_winmm_2025-03-28\src\win32\input.cpp":
  519. #include <win32/input.hpp>
  520. #include <win32/misc.hpp>
  521.  
  522. #include <public_stuff.hpp>
  523.  
  524.  
  525.  
  526. CRITICAL_SECTION events_lock;
  527. Event            events_queue[65536];
  528. u16              events_next = 0;
  529. u16              events_end  = 0;
  530.  
  531. Event_Key_Mod key_mods;
  532. bool          key_states[256] = {0};
  533.  
  534. Point2d mouse_position = {0};
  535. bool    mouse_was_moved_before = false;
  536.  
  537.  
  538.  
  539.  
  540.  
  541. extern HWND win;
  542.  
  543. int InputInit(){
  544.   // This function has no failure condition
  545.   InitializeCriticalSectionAndSpinCount(&events_lock,
  546.                                         CRITICAL_SECTION_SPINCOUNT);
  547.  
  548.   // Get initial position of mouse
  549.   // (Actually this isn't necessary due to the way deltas are calculated)
  550.   //if(!GetCursorPos((POINT*)&mouse_position)) return -1;
  551.   //if(!ScreenToClient(win, (POINT*)&mouse_position)) return -2;
  552.  
  553.   return 0;
  554.  
  555. }
  556.  
  557.  
  558.  
  559. void InputQuit(){}
  560.  
  561.  
  562.  
  563.  
  564.  
  565. // Returns false if queue is full
  566. bool AddToEventQueue(Event& event){
  567.   EnterCriticalSection(&events_lock);
  568.  
  569.   bool success = false;
  570.  
  571.   if((events_end+1) != events_next){
  572.     events_queue[events_end++] = event;
  573.     success = true;
  574.  
  575.   }
  576.  
  577.   LeaveCriticalSection(&events_lock);
  578.  
  579.   return success;
  580.  
  581. }
  582.  
  583.  
  584.  
  585. // Returns a EVENT_NULL event if queue is empty
  586. Event RemoveFromEventQueue(){
  587.   EnterCriticalSection(&events_lock);
  588.  
  589.   Event event;
  590.   event.type = EVENT_NULL;
  591.  
  592.   if(events_next != events_end)
  593.     event = events_queue[events_next++];
  594.  
  595.   LeaveCriticalSection(&events_lock);
  596.  
  597.   return event;
  598.  
  599. }
  600.  
  601.  
  602.  
  603.  
  604.  
  605. // Calling this exclusively in the main thread is recommended
  606. bool pollEvent(Event* event_p){
  607.   // Take one event off the current event queue and set it to *event_p
  608.   EnterCriticalSection(&events_lock);
  609.  
  610.   Event event = RemoveFromEventQueue();
  611.  
  612.   LeaveCriticalSection(&events_lock);
  613.  
  614.  
  615.  
  616.   // If previous event queue is now empty, process any pending window messages,
  617.   // while adding any events generated by WindowProc to the event queue
  618.   if(events_next == events_end){
  619.     MSG message;
  620.  
  621.     while(PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)){
  622.       TranslateMessage(&message);
  623.       DispatchMessageA(&message);
  624.  
  625.     }
  626.  
  627.   }
  628.  
  629.  
  630.  
  631.   if(event_p != nullptr) *event_p = event;
  632.  
  633.   return event.type != EVENT_NULL;
  634.  
  635. }
  636.  
  637.  
  638. /******************************************************************************/
  639. /******************************************************************************/
  640. //"gdi_winmm_2025-03-28\src\win32\main.cpp":
  641. #include <win32/audio.hpp>
  642. #include <win32/video.hpp>
  643. #include <win32/input.hpp>
  644. #include <win32/misc.hpp>
  645.  
  646. #include <public_stuff.hpp>
  647.  
  648.  
  649.  
  650.  
  651.  
  652. static HMODULE _Ole32_dll;
  653. static HMODULE _Winmm_dll;
  654. static HMODULE _User32_dll;
  655. static HMODULE _Gdi32_dll;
  656.  
  657.  
  658.  
  659.  
  660.  
  661. int user_main(int argc, char** argv);
  662.  
  663.  
  664.  
  665.  
  666.  
  667. // Doing "*((FARPROC*)&_name)" to work around not
  668. // being able to directly cast an lvalue.
  669. // (This is only really useful for isolated function pointers.)
  670. #define LOAD_FUNC(_pre, _post, _name, _dll) \
  671.   *((FARPROC*)&_name) = loadFunction(_pre, _post, _dll)
  672.  
  673.  
  674.  
  675. char _functionNameBuffer[256];
  676.  
  677. FARPROC loadFunction(const char* prefix, const char* postfix, HMODULE dll){
  678.   strnCpy(_functionNameBuffer, prefix, 256);
  679.   strCat(_functionNameBuffer, postfix);
  680.  
  681.   _functionNameBuffer[255] = 0; // Just in case
  682.  
  683.   return GetProcAddress(dll, _functionNameBuffer);
  684.  
  685. }
  686.  
  687.  
  688.  
  689. // Postfixes string should look like: "nameA\0nameB\0nameC\0\0"
  690. bool loadFunctions(const char* prefix, const char* postfixes, HMODULE dll,
  691.                    FARPROC* funcs, int from)
  692. {
  693.   while(*postfixes != '\0'){
  694.     if(!( funcs[from++] = loadFunction(prefix, postfixes, dll) ))
  695.       return false;
  696.  
  697.     // +1 to get past null-terminator
  698.     postfixes += strnLen(postfixes, 256)+1;
  699.  
  700.   }
  701.  
  702.   return true;
  703.  
  704. }
  705.  
  706.  
  707.  
  708.  
  709.  
  710. //
  711.  
  712.  
  713.  
  714.  
  715.  
  716. #define MAIN_ASSERT(_success, _code) \
  717.   if(!(_success)){ returnCode = (_code); goto _main_return; }
  718.  
  719. int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
  720.                    LPSTR     lpszArg,   int       nCmdShow)
  721. {
  722.   int err, returnCode = 0;
  723.  
  724.   // g++ doesn't seem to allow gotos that might maybe possibly step
  725.   // over declarations, so the exit is near the top as a workaround
  726.   if(0){ _main_return:
  727.     // Seemingly due to WinMM being janky and old, in some environments the
  728.     // program hangs indefinitely unless I explicitly exit the process like
  729.     // this for some reason!
  730.     ExitProcess((UINT)returnCode);
  731.     return returnCode;
  732.   }
  733.  
  734.   #ifdef _DEBUG
  735.     f64 timeStart = timeGetSeconds();
  736.   #endif /* _DEBUG */
  737.  
  738.  
  739.  
  740.  
  741.  
  742.   _Ole32_dll = LoadLibrary("Ole32.dll");
  743.   MAIN_ASSERT(_Ole32_dll, -1);
  744.  
  745.   _Winmm_dll = LoadLibrary("Winmm.dll");
  746.   MAIN_ASSERT(_Winmm_dll, -2);
  747.  
  748.   _User32_dll = LoadLibrary("User32.dll");
  749.   MAIN_ASSERT(_User32_dll, -3);
  750.  
  751.   _Gdi32_dll = LoadLibrary("Gdi32.dll");
  752.   MAIN_ASSERT(_Gdi32_dll, -4);
  753.  
  754.  
  755.  
  756.  
  757.  
  758.   MAIN_ASSERT(loadFunctions("CoTaskMem", _Ole32_names, _Ole32_dll,
  759.                             _Ole32_func.ptrs, 0), -10);
  760.  
  761.  
  762.  
  763.   MAIN_ASSERT(loadFunctions("waveOut", _Winmm_names, _Winmm_dll,
  764.                             _Winmm_func.ptrs, 0), -11);
  765.  
  766.  
  767.  
  768.   #define LOAD_USER32_FUNC(_prefix, _namegroup, _from, _errcode)               \
  769.     MAIN_ASSERT(loadFunctions(_prefix, _User32_names_##_namegroup, _User32_dll,\
  770.                               _User32_func.ptrs, (_from)), (_errcode))
  771.  
  772.   LOAD_USER32_FUNC("", a, 0, -12);
  773.  
  774.  
  775.  
  776.   #define LOAD_GDI32_FUNC(_prefix, _namegroup, _from, _errcode)              \
  777.     MAIN_ASSERT(loadFunctions(_prefix, _Gdi32_names_##_namegroup, _Gdi32_dll,\
  778.                               _Gdi32_func.ptrs, (_from)), (_errcode))
  779.  
  780.   LOAD_GDI32_FUNC("", a, 0, -13);
  781.  
  782.  
  783.  
  784.  
  785.  
  786.   err = WaveOutInit(); // Also starts audio automatically
  787.   MAIN_ASSERT(err == 0, err-100);
  788.  
  789.   err = WindowInit(hThisInst);
  790.   MAIN_ASSERT(err == 0, err-200);
  791.  
  792.   err = InputInit();
  793.   MAIN_ASSERT(err == 0, err-300);
  794.  
  795.  
  796.  
  797.   _printf("Initialized in: %.4f seconds!\n", timeGetSeconds()-timeStart);
  798.  
  799.   returnCode = user_main(0, nullptr); // TBD: provide main's arguments
  800.  
  801.  
  802.  
  803.   InputQuit();
  804.  
  805.   WindowQuit();
  806.  
  807.   WaveOutQuit();
  808.  
  809.  
  810.  
  811.  
  812.  
  813.   // Make sure no unused parameter warnings occur for these
  814.   (void)hThisInst;
  815.   (void)hPrevInst;
  816.   (void)lpszArg;
  817.   (void)nCmdShow;
  818.  
  819.   goto _main_return;
  820.  
  821. }
  822. /******************************************************************************/
  823. /******************************************************************************/
  824. //"gdi_winmm_2025-03-28\src\win32\misc.cpp":
  825. #include <windows.h>
  826.  
  827. #include <public_stuff.hpp>
  828.  
  829.  
  830.  
  831.  
  832.  
  833. extern HWND win;
  834.  
  835. u32 showMessageBox(const char* text, const char* title,
  836.                    u32 type, u32 defaultButton)
  837. {
  838.   if(!text ) text  = "";
  839.   if(!title) title = "";
  840.  
  841.   defaultButton = (defaultButton&3)<<8; //0x000 -> 0x300
  842.  
  843.   return MessageBoxA(win, text, title, type|defaultButton);
  844.  
  845. }
  846.  
  847.  
  848.  
  849.  
  850.  
  851. u64 timeGetPerfCounter(){
  852.   u64 result;
  853.   QueryPerformanceCounter((LARGE_INTEGER*)&result);
  854.   return result;
  855.  
  856. }
  857.  
  858.  
  859.  
  860. static u64 perfFreq = 0;
  861.  
  862. u64 timeGetPerfFreq(){
  863.   if(!perfFreq)
  864.     QueryPerformanceFrequency((LARGE_INTEGER*)&perfFreq);
  865.  
  866.   return perfFreq;
  867.  
  868. }
  869.  
  870.  
  871.  
  872. f64 timeGetSeconds(){
  873.   return (f64)timeGetPerfCounter()/timeGetPerfFreq();
  874.  
  875. }
  876.  
  877.  
  878.  
  879. void timeSleep(u32 milliseconds){
  880.   Sleep((DWORD)milliseconds);
  881.  
  882. }
  883. /******************************************************************************/
  884. /******************************************************************************/
  885. //"gdi_winmm_2025-03-28\src\win32\std.cpp":
  886. #include <public_stuff.hpp>
  887.  
  888.  
  889.  
  890.  
  891.  
  892. void* memSet(void* dst, int val, size_t len){
  893.   u8* _dst = (u8*)dst;
  894.   u8 value = (u8 )val;
  895.  
  896.   while((len--) > 0)
  897.     *_dst++ = value;
  898.  
  899.   return dst;
  900.  
  901. }
  902.  
  903.  
  904.  
  905.  
  906.  
  907. //  (len_max does not include null-terminator!)
  908. //  (If !len_max, call is analogous to str(not n)len)
  909. size_t strnLen(const char* str, size_t len_max){
  910.   size_t len = 0;
  911.  
  912.   if(!len_max){
  913.     for(; str[len]; ++len);
  914.  
  915.   } else {
  916.     for(; str[len] && len<len_max; ++len);
  917.  
  918.   }
  919.  
  920.   return len;
  921.  
  922. }
  923.  
  924.  
  925.  
  926. char* strnCpy(char* str_dst, const char* str_src, size_t len_max){
  927.   char* _str_dst = str_dst; // Copy original state of str_dst
  928.  
  929.   if(!len_max){
  930.     while((*str_dst++ = *str_src++));
  931.  
  932.   } else {
  933.     size_t i = 0;
  934.     while(i++ != len_max && (*str_dst++ = *str_src++));
  935.  
  936.   }
  937.  
  938.  
  939.   *str_dst = 0; // Null-terminator
  940.  
  941.   return _str_dst;
  942.  
  943. }
  944.  
  945.  
  946.  
  947. char* strCat(char* dst, const char* src){
  948.   char* dst_start = dst;
  949.  
  950.   while(*dst) ++dst;
  951.   while((*dst++ = *src++));
  952.  
  953.   return dst_start;
  954.  
  955. }
  956.  
  957.  
  958.  
  959. // (len_max does not include null-terminator!)
  960. // (If !len_max, call is analogous to str(not n)cmp)
  961. s32 strnCmp(const char* str_a, const char* str_b, size_t len_max){
  962.   if(!len_max){
  963.     while(*str_a && (*str_a == *str_b))
  964.       ++str_a, ++str_b;
  965.  
  966.   } else {
  967.     --len_max;
  968.     while(*str_a && (*str_a == *str_b) && len_max)
  969.       ++str_a, ++str_b, --len_max;
  970.  
  971.   }
  972.  
  973.   return (*(const u8*)str_a) - (*(const u8*)str_b);
  974.  
  975. }
  976.  
  977.  
  978.  
  979.  
  980.  
  981. #define sinf_bhaskara_fmod(_x, _y) (   (_x) - (  (s64)((_x)/(_y)) * (_y)  )   )
  982.  
  983. // Custom sinf implementation; a little under 2% error iirc
  984. // (You could switch floats with doubles here, though the approximation's
  985. // lack of precision prevents that switch from being all that useful.)
  986. f32 sinF(f32 x){
  987.   // Keep x within the domain of >=0  ->  <pi,
  988.   // while preserving relevant info
  989.   bool negative = x<0.0f;
  990.   if(x < 0.0f) x = -x; //x = fabsf(x);
  991.   x = sinf_bhaskara_fmod(x, M_2PIf); //x %= 2pi
  992.   // 'If original value of x%(2pi) is between _ -> _, returned value will be _':
  993.    //>-2pi -> <=-pi,  >=0
  994.    //> -pi -> <=  0,  <=0
  995.    //>=  0 -> <  pi,  >=0
  996.    //>= pi -> < 2pi,  <=0
  997.   negative ^= x>=M_PIf;
  998.   if(x >= M_PIf) x -= M_PIf; //x %= pi
  999.  
  1000.   // Uses Bhaskara I's sine approximation formula
  1001.   f32 result = 16.0f*x * (M_PIf-x);
  1002.   result /= 5.0f*M_PIf*M_PIf - result*0.25f;
  1003.   return (negative) ? -result : result;
  1004.  
  1005. }
  1006. /******************************************************************************/
  1007. /******************************************************************************/
  1008. //"gdi_winmm_2025-03-28\src\win32\video.cpp":
  1009. #include "_WindowProc.hpp"
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015. // Header + 256 colors (AKA 8-bpp)
  1016. static u8         _canvas_info[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256];
  1017. static BITMAPINFO* canvas_info = (BITMAPINFO*)_canvas_info; // Lol
  1018. static HBITMAP     canvas;
  1019. static HDC         canvas_dc;
  1020.  
  1021. Color8*  pixels         = nullptr;
  1022. Color24* pixels_palette = (Color24*)canvas_info->bmiColors;
  1023.  
  1024.  
  1025.  
  1026. static const char win_class_name[] = "Normal Resizable Window";
  1027. static WNDCLASS   win_class = {0};
  1028. HWND              win;
  1029. bool              win_closed = false;
  1030. Point2d           win_size = {CANVAS_W*WINDOW_RESMUL, CANVAS_H*WINDOW_RESMUL};
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036. // Canvas is 256x144 at 8-bpp
  1037. static inline bool InitCanvas(){
  1038.   canvas_info->bmiHeader.biSize = sizeof(canvas_info->bmiHeader);
  1039.  
  1040.   canvas_info->bmiHeader.biWidth  = CANVAS_W;
  1041.   canvas_info->bmiHeader.biHeight = CANVAS_H;
  1042.  
  1043.   canvas_info->bmiHeader.biPlanes      = 1;
  1044.   canvas_info->bmiHeader.biBitCount    = 8; // 8-bpp
  1045.   canvas_info->bmiHeader.biCompression = BI_RGB;
  1046.   canvas_info->bmiHeader.biSizeImage   = 0; // Valid for uncompressed bitmaps
  1047.  
  1048.   canvas_info->bmiHeader.biXPelsPerMeter = 3780; // Approximately 96dpi
  1049.   canvas_info->bmiHeader.biYPelsPerMeter = 3780;
  1050.  
  1051.   canvas_info->bmiHeader.biClrUsed      = 0; // Maximum # of colors used (256)
  1052.   canvas_info->bmiHeader.biClrImportant = 0; // All colors are important
  1053.  
  1054.  
  1055.  
  1056.   // Generate 256-color palette
  1057.   for(int i=0; i<256; ++i){
  1058.     Color8 color = i; // Sets the ".v" member to i
  1059.  
  1060.     #define conv_rg(_c) ((u8)( (255.0f*((f32)(_c)/7)) + 0.5f ))
  1061.     #define conv_b(_c) ((_c)*85)
  1062.     pixels_palette[i].r = conv_rg(color.r);
  1063.     pixels_palette[i].g = conv_rg(color.g);
  1064.     pixels_palette[i].b = conv_b(color.b);
  1065.     pixels_palette[i]._ = 0;
  1066.  
  1067.   }
  1068.  
  1069.  
  1070.  
  1071.   canvas_dc = CreateCompatibleDC(nullptr);
  1072.   if(!canvas_dc) return false;
  1073.  
  1074.  
  1075.  
  1076.   canvas = CreateDIBSection(nullptr, canvas_info, DIB_RGB_COLORS,
  1077.                             (void**)&pixels, nullptr, 0);
  1078.   if(!canvas) return false;
  1079.  
  1080.  
  1081.  
  1082.   HGDIOBJ result = SelectObject(canvas_dc, canvas);
  1083.  
  1084.   return result != nullptr  &&  result != HGDI_ERROR;
  1085.  
  1086. }
  1087.  
  1088.  
  1089.  
  1090.  
  1091.  
  1092. LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); // Forward declaration
  1093.  
  1094. int WindowInit(HINSTANCE hThisInst){
  1095.   if(!InitCanvas()) return -1;
  1096.  
  1097.   win_class.style         = CS_DBLCLKS; // Allow double clicks
  1098.   win_class.lpfnWndProc   = WindowProc;
  1099.   win_class.hInstance     = hThisInst;
  1100.   win_class.hCursor       = LoadCursorA(nullptr, IDC_ARROW);
  1101.   win_class.lpszClassName = win_class_name;
  1102.   RegisterClassA(&win_class);
  1103.  
  1104.   win = CreateWindowExA(WS_EX_LEFT, win_class_name, WINDOW_NAME,
  1105.                         WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  1106.                         CW_USEDEFAULT, CW_USEDEFAULT, // X, Y
  1107.                         win_size.x, win_size.y, // W, H
  1108.                         nullptr, nullptr, hThisInst, nullptr);
  1109.  
  1110.   if(!win) return -2;
  1111.  
  1112.   return 0;
  1113.  
  1114. }
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120. void WindowQuit(){} // TBD (actually it may not be necessary at all, but w/e)
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126. void canvas_present(bool immediate){
  1127.   // Marks the canvas to be redrawn.
  1128.   // If this is not called, Win32 will assume no redraw
  1129.   // is being requested at all!
  1130.   InvalidateRect(win, nullptr, FALSE);
  1131.  
  1132.   // Win32 technically will redraw it automatically when it needs to (assuming
  1133.   // InvalidateRect was called), but doing this will send a paint message
  1134.   // immediately.
  1135.   //
  1136.   // This is useful if you end up updating the canvas slightly
  1137.   // after it would've updated normally, potentially making it
  1138.   // look like a frame was skipped
  1139.   if(immediate) UpdateWindow(win);
  1140.  
  1141. }
  1142.  
  1143.  
  1144.  
  1145. void close_window(){
  1146.   if(win_closed) return;
  1147.  
  1148.   DeleteObject(canvas);
  1149.   DeleteDC(canvas_dc);
  1150.   DestroyWindow(win);
  1151.   //UnregisterClassA
  1152.   //DeleteCriticalSection
  1153.  
  1154.   win_closed = true;
  1155.  
  1156. }
  1157.  
  1158.  
  1159.  
  1160. #ifndef   INT_MAX
  1161. #define   INT_MAX 2147483647
  1162. #endif /* INT_MAX */
  1163.  
  1164. bool update_palette(const Color24* new_palette,
  1165.                     u32 first_color, u32 num_colors)
  1166. {
  1167.   // Return early if any of the parameters are out of range
  1168.   if(new_palette == nullptr) return false;
  1169.   if(first_color >  INT_MAX) return false;
  1170.   if(num_colors  >  INT_MAX) return false;
  1171.  
  1172.  
  1173.   first_color = MIN(first_color, 255);
  1174.   num_colors  = MIN(num_colors , 256);
  1175.  
  1176.   if((first_color+num_colors) > 256)
  1177.     num_colors = 256-first_color;
  1178.  
  1179.  
  1180.   bool success = SetDIBColorTable(canvas_dc, first_color, num_colors,
  1181.                                   (const RGBQUAD*)new_palette) != 0;
  1182.  
  1183.   return success;
  1184.  
  1185. }
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191. extern CRITICAL_SECTION events_lock;
  1192. extern Event            events_queue[65536];
  1193. extern u16              events_next;
  1194. extern u16              events_end;
  1195.  
  1196. extern Event_Key_Mod key_mods;
  1197. extern bool          key_states[256];
  1198.  
  1199. extern Point2d mouse_position;
  1200. extern bool    mouse_was_moved_before;
  1201.  
  1202.  
  1203.  
  1204. LRESULT CALLBACK WindowProc(HWND winHandle, UINT message,
  1205.                             WPARAM wParam, LPARAM lParam)
  1206. {
  1207.   LRESULT returnResult = 0;
  1208.  
  1209.   Event evt; // Will be populated by any call to HANDLE_EVENT_<?>()...
  1210.   memSet(&evt, 0, sizeof(Event)); //(this is done BEFORE setting anything)
  1211.   evt.type = EVENT_COMMON; //...otherwise it will stay common
  1212.  
  1213.   bool switchBool  = false; // Multipurpose
  1214.   bool switchBool2 = true;  // ^^(switchBool2 intentionally initialized to true)
  1215.   u32  switchFlags = 0;     // ^^
  1216.  
  1217.  
  1218.  
  1219.   switch(message){
  1220.     case WM_DESTROY:
  1221.       PostQuitMessage(0);
  1222.     case WM_QUIT:
  1223.     {
  1224.       evt.type = EVENT_QUIT;
  1225.       win_closed = true;
  1226.     } break;
  1227.  
  1228.  
  1229.  
  1230.     case WM_GETMINMAXINFO: // For enforcing a minimum window size
  1231.     {
  1232.       u32 winStyleCurrent   = GetWindowLongA(winHandle, GWL_STYLE  );
  1233.       u32 winStyleExCurrent = GetWindowLongA(winHandle, GWL_EXSTYLE);
  1234.  
  1235.       Point2d winSizeAdjusted = CalculateWindowSize(CANVAS_W, CANVAS_H,
  1236.                                                     winStyleCurrent,
  1237.                                                     winStyleExCurrent);
  1238.  
  1239.       // Set the MINMAXINFO struct provided by lParam
  1240.       MINMAXINFO* mmi = (MINMAXINFO*)lParam;
  1241.       mmi->ptMinTrackSize.x = winSizeAdjusted.x;
  1242.       mmi->ptMinTrackSize.y = winSizeAdjusted.y;
  1243.  
  1244.     } break;
  1245.  
  1246.  
  1247.  
  1248.     case WM_SIZE: // Also redraw canvas if window is being resized
  1249.       win_size.x = LOWORD(lParam);
  1250.       win_size.y = HIWORD(lParam);
  1251.     case WM_PAINT:
  1252.     {
  1253.       // Prepare window for painting
  1254.       PAINTSTRUCT paint;
  1255.       HDC winDevCtx = BeginPaint(winHandle, &paint); // Window device context
  1256.       Rect2d rectW = ConvertToKitRect(paint.rcPaint); // Window's rect
  1257.  
  1258.       // Copy canvas bitmap to window
  1259.       SetStretchBltMode(winDevCtx, COLORONCOLOR); // Nearest-neighbor
  1260.       StretchBlt(winDevCtx, rectW.x,rectW.y,  rectW.w,  rectW.h,
  1261.                  canvas_dc,       0,      0, CANVAS_W, CANVAS_H, SRCCOPY);
  1262.  
  1263.       if(message == WM_SIZE)
  1264.         canvas_present(true);
  1265.  
  1266.     } break;
  1267.  
  1268.  
  1269.  
  1270.     case WM_KILLFOCUS:
  1271.     {
  1272.       // If a key is released outside the client area, its key up message
  1273.       // is never sent, so here the key states are reset when unfocusing...
  1274.       // ...but first, send a key up event for every currently pressed key
  1275.  
  1276.       // Call QPC only once, since the events technically happen simultaneously
  1277.       QueryPerformanceCounter((LARGE_INTEGER*)&evt.key.timestamp);
  1278.  
  1279.       KEY_Params params = 0;
  1280.       params.currUnpressed = 1;
  1281.  
  1282.       for(u32 chr=0; chr<256; ++chr){
  1283.         // Send a KEY_UP only if the state was previously true
  1284.         if(key_states[chr] == true){
  1285.           params.scanCode = MapVirtualKeyA(chr, MAPVK_VK_TO_VSC);
  1286.           HANDLE_KEY_CHARUPDOWN(evt, false, chr, params, 0);
  1287.           if(!AddToEventQueue(evt)){ _printf("EVENT QUEUE IS FULL!!!\n"); }
  1288.         }
  1289.       }
  1290.  
  1291.       memSet(key_states, 0, sizeof(bool)*256); //NOW the states can be reset
  1292.  
  1293.       // Reset all key modifiers (except for toggles) too
  1294.       key_mods.all &= 0xff00; // Non-toggles are stored in low byte
  1295.  
  1296.     } break;
  1297.  
  1298.  
  1299.  
  1300.     //EVENT_KEY_CHAR, EVENT_KEY_UP, EVENT_KEY_DOWN
  1301.     case WM_CHAR:
  1302.     case WM_SYSKEYUP:
  1303.     case WM_SYSKEYDOWN:
  1304.     case WM_KEYUP:
  1305.     case WM_KEYDOWN:
  1306.     case WM_SYSCHAR:
  1307.     {
  1308.       // Marshal relevant stuff to pass to event handler
  1309.       bool    charEvent = message==WM_CHAR;
  1310.       u8 virtualKeyCode = (u8) wParam;
  1311.       KEY_Params params = (u32)lParam;
  1312.  
  1313.       // Set repeat flag
  1314.       params.repeatCount = (!params.currUnpressed)    == true &&
  1315.                            key_states[virtualKeyCode] == true;
  1316.  
  1317.       if(!charEvent){
  1318.         bool keydown = message==WM_KEYDOWN;
  1319.         bool pressed = !params.currUnpressed;
  1320.         key_states[virtualKeyCode] = pressed;
  1321.  
  1322.         // Update any relevant key modifiers
  1323.         switch(virtualKeyCode){
  1324.           case VKEY_SHIFT    : { key_mods.lshift = key_mods.rshift = pressed; } break;
  1325.           case VKEY_CONTROL  : { key_mods.lctrl  = key_mods.rctrl  = pressed; } break;
  1326.           case VKEY_ALT      : { key_mods.lalt   = key_mods.ralt   = pressed; } break;
  1327.           case VKEY_LWIN     : { key_mods.lgui   = pressed; } break;
  1328.           case VKEY_RWIN     : { key_mods.rgui   = pressed; } break;
  1329.           case VKEY_NUMLOCK  : if(keydown){ key_mods.numlock^=1; } break;
  1330.           case VKEY_CAPSLOCK : if(keydown){ key_mods.capslock^=1; } break;
  1331.           case VKEY_SCROLLOCK: if(keydown){ key_mods.scrollock^=1; } break;
  1332.           default:;
  1333.         }
  1334.  
  1335.       }
  1336.  
  1337.       HANDLE_KEY_CHARUPDOWN(evt, charEvent, virtualKeyCode,
  1338.                                     params,   key_mods.all);
  1339.  
  1340.     } break;
  1341.  
  1342.  
  1343.  
  1344.     //EVENT_MOUSE_MOVED
  1345.     case WM_MOUSEMOVE:
  1346.     {
  1347.       // Get button states
  1348.       MOUSE_ButtonStates buttonStates;
  1349.       buttonStates.left   = (wParam&MK_LBUTTON ) != 0;
  1350.       buttonStates.middle = (wParam&MK_MBUTTON ) != 0;
  1351.       buttonStates.right  = (wParam&MK_RBUTTON ) != 0;
  1352.       buttonStates.x1     = (wParam&MK_XBUTTON1) != 0;
  1353.       buttonStates.x2     = (wParam&MK_XBUTTON2) != 0;
  1354.  
  1355.       // Get new mouse position
  1356.       Point2d mousePositionNew;
  1357.       mousePositionNew.x = GET_X_LPARAM(lParam);
  1358.       mousePositionNew.y = GET_Y_LPARAM(lParam);
  1359.  
  1360.       // If this is the first instance of WINEVENT_MOUSE_MOVE,
  1361.       // there is no previous mouse position, so the delta should be 0 then
  1362.       if(!mouse_was_moved_before){
  1363.         mouse_position = mousePositionNew;
  1364.         mouse_was_moved_before = true;
  1365.       }
  1366.  
  1367.       HANDLE_MOUSE_MOVED(evt, buttonStates.value,
  1368.                          mouse_position, mousePositionNew);
  1369.  
  1370.       mouse_position = mousePositionNew; // Set current position to new one
  1371.  
  1372.     } break;
  1373.  
  1374.  
  1375.  
  1376.     case WM_MOUSELEAVE:
  1377.     {
  1378.       // Indicates that the mouse will have yet to be moved inside client area
  1379.       mouse_was_moved_before = false;
  1380.     } break;
  1381.  
  1382.  
  1383.  
  1384.     //EVENT_MOUSE_HWHEEL, EVENT_MOUSE_VWHEEL
  1385.     case WM_MOUSEHWHEEL:
  1386.     case WM_MOUSEWHEEL:
  1387.     {
  1388.       bool verticalScroll = message==WM_MOUSEWHEEL;
  1389.  
  1390.       s16 scrollAmount = (s16)HIWORD(wParam);
  1391.  
  1392.       MOUSE_ButtonStates buttonStates;
  1393.       buttonStates.left   = (wParam&MK_LBUTTON ) != 0;
  1394.       buttonStates.middle = (wParam&MK_MBUTTON ) != 0;
  1395.       buttonStates.right  = (wParam&MK_RBUTTON ) != 0;
  1396.       buttonStates.x1     = (wParam&MK_XBUTTON1) != 0;
  1397.       buttonStates.x2     = (wParam&MK_XBUTTON2) != 0;
  1398.  
  1399.       Point2d scrollMousePosition;
  1400.       scrollMousePosition.x = GET_X_LPARAM(lParam);
  1401.       scrollMousePosition.y = GET_Y_LPARAM(lParam);
  1402.  
  1403.       // The coordinates are relative to the screen, not the window (for some reason)
  1404.       ScreenToClient(winHandle, (POINT*)&scrollMousePosition);
  1405.  
  1406.       HANDLE_MOUSE_HVWHEEL(evt, verticalScroll, scrollAmount,
  1407.                            buttonStates.value, scrollMousePosition);
  1408.  
  1409.     } break;
  1410.  
  1411.  
  1412.  
  1413.     //EVENT_MOUSE_UP, EVENT_MOUSE_DOWN
  1414.      //switchBool  = evt.mouse.dblClick
  1415.      //switchBool2 = evt.mouse.pressed
  1416.      //switchFlags = evt.mouse.button
  1417.     case WM_LBUTTONDBLCLK: switchBool  = true;  goto _notLButtonUp;
  1418.     case WM_LBUTTONUP    : switchBool2 = false; _notLButtonUp:
  1419.     case WM_LBUTTONDOWN  : switchFlags |= MBUTTON_LEFT; goto _handleMouseClick;
  1420.  
  1421.     case WM_MBUTTONDBLCLK: switchBool  = true;  goto _notMButtonUp;
  1422.     case WM_MBUTTONUP    : switchBool2 = false; _notMButtonUp:
  1423.     case WM_MBUTTONDOWN  : switchFlags |= MBUTTON_MIDDLE; goto _handleMouseClick;
  1424.  
  1425.     case WM_RBUTTONDBLCLK: switchBool  = true;  goto _notRButtonUp;
  1426.     case WM_RBUTTONUP    : switchBool2 = false; _notRButtonUp:
  1427.     case WM_RBUTTONDOWN  : switchFlags |= MBUTTON_RIGHT; goto _handleMouseClick;
  1428.  
  1429.     case WM_XBUTTONDBLCLK: switchBool  = true;  goto _notXButtonUp;
  1430.     case WM_XBUTTONUP    : switchBool2 = false; _notXButtonUp:
  1431.     case WM_XBUTTONDOWN  : if(wParam & MK_XBUTTON1) switchFlags |= MBUTTON_X1;
  1432.                            else                     switchFlags |= MBUTTON_X2;
  1433.     {
  1434.       _handleMouseClick:
  1435.  
  1436.       Point2d clickPosition;
  1437.       clickPosition.x = GET_X_LPARAM(lParam);
  1438.       clickPosition.y = GET_Y_LPARAM(lParam);
  1439.  
  1440.       u8   buttonStates = (u8)switchFlags;
  1441.       bool pressed      = switchBool2;
  1442.       bool doubleClick  = switchBool;
  1443.  
  1444.       HANDLE_MOUSE_UPDOWN(evt, clickPosition,
  1445.                           buttonStates, pressed, doubleClick);
  1446.  
  1447.     } break;
  1448.  
  1449.  
  1450.  
  1451.     default: returnResult = DefWindowProcA(winHandle, message, wParam, lParam);
  1452.  
  1453.   }
  1454.  
  1455.  
  1456.  
  1457.   if(evt.type != EVENT_COMMON  &&  evt.common.timestamp == 0)
  1458.   {
  1459.     // Idk how expensive QPC is, so I'll only call it if the event is valid
  1460.     QueryPerformanceCounter((LARGE_INTEGER*)&evt.common.timestamp);
  1461.  
  1462.     // I pray AddToEventQueue never fails ever
  1463.     if(!AddToEventQueue(evt)){ _printf("EVENT QUEUE IS FULL!!!\n"); }
  1464.  
  1465.   }
  1466.  
  1467.  
  1468.  
  1469.   return returnResult;
  1470.  
  1471. }
  1472.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement