Advertisement
Kitomas

work for 2024-11-21 (5/10)

Nov 22nd, 2024
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.77 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"2024-11-21\src\kit_sdl2\kit_SoundEngine_mixTracks.cpp":
  4. #include "_kit_common.hpp"
  5.  
  6. //lower clip's volume to 0 within 10ms if speed reaches 0
  7. #define speed0VolDeltaMS (10.0f)
  8.  
  9.  
  10. #define MUTEX_PTR ((SDL_mutex*)_lock)
  11.  
  12.  
  13. namespace kit {
  14.  
  15.  
  16.  
  17. /******************************************************************************/
  18.  
  19.  
  20.  
  21. #define HANDLE_LOOP \
  22.   /* loop handling (or end-of-clip handling i guess) */                                 \
  23.   if(trk.position >= loopEnd){ /* audio clip finished loop */                           \
  24.     if(!trk.loops){ trk.stopping = true; break; } /* mark as inactive and break */      \
  25.     if(trk.loops != KIT_U16_MAX) --trk.loops; /* decrement loops (unless infinite) */   \
  26.     while(trk.position >= loopEnd)                                                      \
  27.       trk.position -= loopDifference; /* jump back to the loop's starting point */      \
  28.                                                                                         \
  29.   } else if(trk.position < 0){ /* if clip has yet to start playing */                   \
  30.     if(trk.position < -trk.spd_old){                                                    \
  31.       trk.position += trk.spd_old; /* step forward by current speed */                  \
  32.       continue;                                                                         \
  33.     } else { /* if position >= -speed, the clip should start on this sample */          \
  34.       trk.position = 0.0; /* make sure clip starts at exactly 0 */                      \
  35.     }                                                                                   \
  36.                                                                                         \
  37.   }
  38.  
  39.  
  40.  
  41. #define HANDLE_SPEED_UPDATE \
  42.   /* change old and new speed by speedDelta */                                  \
  43.   f64 currentSpeedDelta = track.spdDelta;                                       \
  44.   trk.spd_old += currentSpeedDelta;                                             \
  45.   trk.spd_new += currentSpeedDelta;                                             \
  46.                                                                                 \
  47.   t += t_inc; /* raise interpolation t value */                                 \
  48.                                                                                 \
  49.   /* start rapid fade out if clip's new speed <= 0 */                           \
  50.   if(LERP2(trk.spd_old, trk.spd_new, t) <= 0.0){                                \
  51.     trk.spd_old = trk.spd_new = 0.0;                                            \
  52.     /* volDelta is sorta volatile, so that might need to be accounted for... */ \
  53.     track.volDelta = speed0VDelta;                                              \
  54.   }
  55.  
  56.  
  57.  
  58. /******************************************************************************/
  59.  
  60.  
  61.  
  62. static inline f32 linearSmpMono(const f32* src, f64 position,
  63.                                 u64 loopEnd = KIT_U64_MAX)
  64. {
  65.   const u64 intPosition = (u64)position;
  66.   const f32 modPosition = (f32)(position-intPosition); //the position's fraction
  67.  
  68.   const f32 smpA = src[ intPosition           ];
  69.   const f32 smpB = src[(intPosition+1)%loopEnd];
  70.  
  71.   return LERP2(smpA, smpB, modPosition);
  72.  
  73. }
  74.  
  75.  
  76.  
  77. static inline Stereo_f32 linearSmpStereo(const Stereo_f32* src, f64 position,
  78.                                          u64 loopEnd = KIT_U64_MAX)
  79. {
  80.   const u64 intPosition = (u64)position;
  81.   const f32 modPosition = (f32)(position-intPosition); //the position's fraction
  82.  
  83.   const Stereo_f32 smpA = src[ intPosition           ];
  84.   const Stereo_f32 smpB = src[(intPosition+1)%loopEnd];
  85.  
  86.   return Stereo_f32(LERP2(smpA.l, smpB.l, modPosition),
  87.                     LERP2(smpA.r, smpB.r, modPosition));
  88.  
  89. }
  90.  
  91.  
  92.  
  93. /******************************************************************************/
  94.  
  95.  
  96.  
  97. static inline bool mixTrack(_SoundEngineTrack& track, u64 refTimestamp,
  98.                             bool sIVIZ, f32 sampleRate, Stereo_f32 volumeMaster,
  99.                             Stereo_f32* dst, size_t dst_len)
  100. {
  101.  
  102.   //the value volumeDelta is set to if the track hits 0x speed
  103.   const Stereo_f32 speed0VDelta = -( (1000.0f/speed0VolDeltaMS) / sampleRate );
  104.  
  105.   //create stack copy of track data
  106.   //(all but a track's deltas are to be referenced with this!)
  107.   _SoundEngineTrack trk = track;
  108.  
  109.   if(trk.audio == nullptr){ //just in case
  110.     SDL_SetError("track's audio = nullptr");
  111.     return false;
  112.   }
  113.  
  114.   //make copies of relevant data from trk.audio
  115.   const bool        stereo    = trk.audio->channels==2;
  116.   const u64         loopStart = trk.audio->loopStart;
  117.   const u64         loopEnd   = trk.audio->loopEnd; //(doubles as src_len)
  118.   const f32*        src_m     = (       f32*)trk.audio->samples;
  119.   const Stereo_f32* src_s     = (Stereo_f32*)trk.audio->samples;
  120.  
  121.   u64 loopDifference = loopEnd - loopStart;
  122.  
  123.   //calculate position based on the difference between
  124.    //the reference and the queued audio clip's timestamps
  125.   if(trk.timestamp > 0){
  126.     f64 difference = (f64)(((s64)refTimestamp)-((s64)trk.timestamp)); //ms
  127.     difference /= 1000;       //milliseconds -> seconds
  128.     difference *= sampleRate; //seconds -> samples
  129.  
  130.     //(starts playing when position reaches 0)
  131.     trk.position = -(difference*trk.spd_old);
  132.     //(alternate calculation; try this if timing feels wrong or something)
  133.     //trk.position = difference*trk.spd_old - dst_len;
  134.  
  135.     track.timestamp = 0; //to ensure that this only occurs once per clip queued
  136.  
  137.   }
  138.  
  139.   //used for interpolating speed and volume settings from old to new
  140.   f32       t     = 0.0f;
  141.   const f32 t_inc = 1.0f/dst_len; //t_inc[rement]
  142.  
  143.  
  144.  
  145.   if(!stereo) //source is mono
  146.   for(size_t i=0; i<dst_len; ++i){
  147.     HANDLE_LOOP;
  148.  
  149.     //get sample
  150.     f32 smp = linearSmpMono(src_m, trk.position, loopEnd);
  151.  
  152.     //apply volumes while interpolating between its old and new state
  153.     smp *= volumeMaster.l * LERP2(trk.vol_old.l, trk.vol_new.l, t);
  154.  
  155.     //mix sample to dst (which is always stereo, so mix smp into both channels)
  156.     dst[i].l += smp;
  157.     dst[i].r += smp;
  158.  
  159.     //update position by speed, while interpolating between speed's old and new state
  160.     trk.position += LERP2(trk.spd_old, trk.spd_new, t);
  161.  
  162.     //change old and new volume by volumeDelta
  163.      //(deltas are referenced directly with track instead of trk)
  164.     const f32 currentVolumeDelta = track.volDelta.l;
  165.     trk.vol_old.l += currentVolumeDelta;
  166.     trk.vol_new.l += currentVolumeDelta;
  167.  
  168.     //make sure both volumes are always between 0.0f and 1.0f
  169.     trk.vol_old.l = CLAMP(trk.vol_old.l, 0.0f, 1.0f);
  170.     trk.vol_new.l = CLAMP(trk.vol_new.l, 0.0f, 1.0f);
  171.  
  172.     HANDLE_SPEED_UPDATE
  173.  
  174.   }
  175.  
  176.  
  177.  
  178.   else //source is stereo
  179.   for(size_t i=0; i<dst_len; ++i){
  180.     HANDLE_LOOP;
  181.  
  182.     //get sample
  183.     Stereo_f32 smp = linearSmpStereo(src_s, trk.position, loopEnd);
  184.  
  185.     //apply volumes while interpolating between its old and new state
  186.     smp.l *= volumeMaster.l * LERP2(trk.vol_old.l, trk.vol_new.l, t);
  187.     smp.r *= volumeMaster.r * LERP2(trk.vol_old.r, trk.vol_new.r, t);
  188.  
  189.     //mix sample to dst
  190.     dst[i].l += smp.l;
  191.     dst[i].r += smp.r;
  192.  
  193.     //update position by speed, while interpolating between speed's old and new state
  194.     trk.position += LERP2(trk.spd_old, trk.spd_new, t);
  195.  
  196.     //change old and new volume by volumeDelta
  197.      //(deltas are referenced directly with track instead of trk)
  198.     const Stereo_f32 currentVolumeDelta = track.volDelta;
  199.     trk.vol_old.l += currentVolumeDelta.l;
  200.     trk.vol_old.r += currentVolumeDelta.r;
  201.     trk.vol_new.l += currentVolumeDelta.l;
  202.     trk.vol_new.r += currentVolumeDelta.r;
  203.  
  204.     //make sure both volumes are always between 0.0f and 1.0f
  205.     trk.vol_old.l = CLAMP(trk.vol_old.l, 0.0f, 1.0f);
  206.     trk.vol_old.r = CLAMP(trk.vol_old.r, 0.0f, 1.0f);
  207.     trk.vol_new.l = CLAMP(trk.vol_new.l, 0.0f, 1.0f);
  208.     trk.vol_new.r = CLAMP(trk.vol_new.r, 0.0f, 1.0f);
  209.  
  210.     HANDLE_SPEED_UPDATE
  211.  
  212.   }
  213.  
  214.  
  215.  
  216.   //set relevant old values to the new ones
  217.    //(deltas don't need to be set)
  218.   track.position = trk.position;
  219.   track.spd_old  = trk.spd_new; //both old *and* new speeds
  220.   track.spd_new  = trk.spd_new;  //must be set to their new values
  221.   track.vol_old  = trk.vol_new; //both old *and* new volumes
  222.   track.vol_new  = trk.vol_new;  //must be set to their new values
  223.   track.loops    = trk.loops;
  224.   track.stopping = trk.stopping;
  225.  
  226.   //if stopIfVolumeIsZero while volume is <=0,
  227.    //mark the track as stopping (if it wasn't already)
  228.   //(sIVIZ is short for stopIfVolumeIsZero)
  229.   if((!stereo  &&  sIVIZ  &&  trk.vol_new.l <= 0) ||
  230.      ( stereo  &&  sIVIZ  &&  trk.vol_new.l <= 0  &&  trk.vol_new.r <= 0))
  231.   {
  232.     track.stopping = true;
  233.   }
  234.  
  235.   //a track is marked as complete if either the clip finishes,
  236.    //or if the volume goes at or below 0 while stopIfVolumeIsZero is true
  237.   if(track.stopping) track.audio = nullptr;
  238.  
  239.   return true;
  240.  
  241. }
  242.  
  243.  
  244.  
  245. /******************************************************************************/
  246.  
  247.  
  248.  
  249. //returns referenceTimestamp, or 0 on error
  250. u64 SoundEngine::mixTracks(Stereo_f32* buffer, size_t buffer_len,
  251.                            u64 referenceTimestamp)
  252. {
  253.   if(MUTEX_PTR == nullptr){
  254.     SDL_SetError("mutex = nullptr");
  255.     return 0;
  256.   }
  257.  
  258.   if(SDL_LockMutex(MUTEX_PTR)<0) return 0;
  259.  
  260.   if(_tracks == nullptr){
  261.     SDL_SetError("_tracks = nullptr");
  262.     referenceTimestamp = 0;
  263.     _unlock_mutex_and_return:
  264.     SDL_UnlockMutex(MUTEX_PTR);
  265.     return referenceTimestamp;
  266.   }
  267.  
  268.   //this will occur if you accidentally use the desired audio device's info
  269.    //while sampleRate is set to 0 (which indicates that the default should
  270.    //be used), instead of the audio device's actual sample rate.
  271.    //this is because the desired info is a const that is not modified,
  272.    //and thus keeping .sampleRate as 0 will set this to 0 as well.
  273.   //TL;DR: use AudioDevice.info.sampleRate after construction instead
  274.    //of using the AudioDeviceInfo you fed to the constructor
  275.   if(sampleRate == 0.0f){
  276.     SDL_SetError("sampleRate = 0.0f");
  277.     return 0;
  278.   }
  279.  
  280.  
  281.  
  282.   _SoundEngineTrack* tracks = _tracks;
  283.   bool                sIVIZ = stopIfVolumeIsZero;
  284.   f32               smpRate = sampleRate;
  285.   Stereo_f32      volMaster = volumeMaster;
  286.  
  287.   for(u16 t=0; t<_tracks_len; ++t){
  288.     if(tracks[t].audio == nullptr) continue;
  289.  
  290.     //modify SoundEngine's master volume by the track's master volume
  291.     Stereo_f32 _volMaster = volMaster;
  292.     _volMaster.l *= tracks[t].volMaster.l;
  293.     _volMaster.r *= tracks[t].volMaster.r;
  294.  
  295.     if(!mixTrack(tracks[t], referenceTimestamp, sIVIZ,
  296.                  smpRate, _volMaster, buffer, buffer_len))
  297.     {
  298.       return 0;
  299.     }
  300.  
  301.   }
  302.  
  303.  
  304.  
  305.   goto _unlock_mutex_and_return;
  306.  
  307. }
  308.  
  309.  
  310.  
  311.  
  312.  
  313. }; /* namespace kit */
  314. /******************************************************************************/
  315. /******************************************************************************/
  316. //"2024-11-21\src\kit_sdl2\kit_Surface.cpp":
  317. #include "_kit_common.hpp"
  318.  
  319. #define SURF_IS_INVALID (!_valid)
  320.  
  321. #define SURF_PTR ((SDL_Surface*)_opq)
  322.  
  323.  
  324. namespace kit {
  325.  
  326.  
  327.  
  328.  
  329.  
  330. Surface::Surface(u32 width, u32 height, u32 pixel_format){
  331.   if(_valid) return;
  332.   _type = KIT_CLASSTYPE_SURFACE;
  333.  
  334.   if(width > KIT_S32_MAX)
  335.     THROW_ERROR("Surface::Surface(new): width > KIT_S32_MAX");
  336.  
  337.   if(height > KIT_S32_MAX)
  338.     THROW_ERROR("Surface::Surface(new): height > KIT_S32_MAX");
  339.  
  340.  
  341.  
  342.   _opq = SDL_CreateRGBSurfaceWithFormat(0, width, height,
  343.                                         SDL_BITSPERPIXEL(pixel_format),
  344.                                         pixel_format);
  345.  
  346.   if(_opq == nullptr)
  347.     THROW_ERRORF("Surface::Surface(new): \"%s\"", SDL_GetError());
  348.  
  349.   ++numAllocations;
  350.  
  351.  
  352.  
  353.   _valid = true;
  354.   _constructing = false;
  355.  
  356. }
  357.  
  358.  
  359.  
  360.  
  361.  
  362. Surface::Surface(const Surface& src, u32 pixel_format){
  363.   if(_valid) return;
  364.   _type = KIT_CLASSTYPE_SURFACE;
  365.  
  366.   if(KIT_GET_CLASS_TYPE(&src) != KIT_CLASSTYPE_SURFACE)
  367.     THROW_ERROR("Surface::Surface(Surface&): src is not a Surface class");
  368.  
  369.  
  370.   SDL_Surface* src_surf = (SDL_Surface*)KIT_GET_CLASS_OPAQUE(&src);
  371.  
  372.   if(src_surf == nullptr)
  373.     THROW_ERROR("Surface::Surface(Surface&): src._opq = nullptr");
  374.  
  375.  
  376.  
  377.   _opq = SDL_ConvertSurfaceFormat(src_surf, pixel_format, 0);
  378.  
  379.   if(_opq == nullptr)
  380.     THROW_ERRORF("Surface::Surface(Surface&): \"%s\"", SDL_GetError());
  381.  
  382.   ++numAllocations;
  383.  
  384.  
  385.  
  386.   _valid = true;
  387.   _constructing = false;
  388.  
  389. }
  390.  
  391.  
  392.  
  393.  
  394.  
  395. Surface::Surface(const Window& src, u32 pixel_format){
  396.   if(_valid) return;
  397.   _type = KIT_CLASSTYPE_SURFACE;
  398.  
  399.   if(KIT_GET_CLASS_TYPE(&src) != KIT_CLASSTYPE_WINDOW)
  400.     THROW_ERROR("Surface::Surface(Window&): src is not a Window class");
  401.  
  402.  
  403.  
  404.   SDL_Window*   src_win    = (SDL_Window*)KIT_GET_CLASS_OPAQUE(&src);
  405.   SDL_Surface** src_surf_p = (SDL_Surface**)&KIT_GET_CLASS_OPAQUE2(&src);
  406.  
  407.   bool src_surf_was_nullptr = *src_surf_p == nullptr;
  408.  
  409.  
  410.  
  411.   *src_surf_p = SDL_GetWindowSurface(src_win);
  412.  
  413.   if(*src_surf_p == nullptr){
  414.     _throw_sdl_error:
  415.     THROW_ERRORF("Surface::Surface(Window&): \"%s\"", SDL_GetError());
  416.   }
  417.  
  418.  
  419.  
  420.   _opq = SDL_ConvertSurfaceFormat(*src_surf_p, pixel_format, 0);
  421.  
  422.  
  423.   if(src_surf_was_nullptr){
  424.     if(SDL_DestroyWindowSurface(src_win) < 0){
  425.       if(_opq != nullptr){
  426.         SDL_FreeSurface(SURF_PTR);
  427.         _opq = nullptr;
  428.  
  429.       }
  430.  
  431.       goto _throw_sdl_error;
  432.  
  433.     }
  434.  
  435.     *src_surf_p = nullptr; //set back
  436.  
  437.   }
  438.  
  439.  
  440.   if(_opq == nullptr) goto _throw_sdl_error;
  441.  
  442.   ++numAllocations;
  443.  
  444.  
  445.  
  446.   _valid = true;
  447.   _constructing = false;
  448.  
  449. }
  450.  
  451.  
  452.  
  453.  
  454.  
  455. //does not increment numAllocations itself
  456. SDL_Surface* _invoke_surface_loader(const char* filePath,
  457.                                     SurfaceLoaderCallback callback,
  458.                                     const char* funcName)
  459. {
  460.   if(!fileio::exists(filePath))
  461.     THROW_ERRORF("%s: \"%s\" doesn't exist", funcName, filePath);
  462.  
  463.   SDL_Surface* surf;
  464.  
  465.  
  466.   if(callback == nullptr){ //load .bmp file
  467.     surf = SDL_LoadBMP(filePath);
  468.  
  469.     if(surf == nullptr) _sdl_err:
  470.       THROW_ERRORF("%s: %s", funcName, SDL_GetError());
  471.  
  472.  
  473.   } else { //load some other file format
  474.     u32 format;
  475.     u31 width, height;
  476.  
  477.     void* pixels_src = callback(filePath, format, width, height);
  478.     if(pixels_src == nullptr)
  479.       THROW_ERRORF("%s: callback() returned nullptr", funcName);
  480.  
  481.     surf = SDL_CreateRGBSurfaceWithFormat(0, width.n, height.n,
  482.                                           SDL_BITSPERPIXEL(format), format);
  483.  
  484.     if(surf == nullptr){
  485.       _free_src_and_sdl_err:
  486.       memory::free(&pixels_src);
  487.       goto _sdl_err;
  488.  
  489.     }
  490.  
  491.  
  492.     if(SDL_LockSurface(surf) < 0)
  493.       goto _free_src_and_sdl_err;
  494.  
  495.  
  496.     void* pixels_dst  = surf->pixels;
  497.     s32   bytesPerRow = surf->pitch;
  498.   //s32   height      = surf->h;
  499.  
  500.     memory::copy(pixels_dst, pixels_src, bytesPerRow*height.n);
  501.  
  502.     SDL_UnlockSurface(surf);
  503.  
  504.  
  505.     memory::free(&pixels_src);
  506.  
  507.  
  508.  
  509.   }
  510.  
  511.  
  512.   return surf;
  513.  
  514. }
  515.  
  516.  
  517.  
  518. void Surface::_construct_file(const char* filePath,
  519.                               SurfaceLoaderCallback callback,
  520.                               const char* funcName)
  521. {
  522.   if(_valid) return;
  523.   _type = KIT_CLASSTYPE_SURFACE;
  524.  
  525.   if(funcName == nullptr)
  526.     funcName = "Surface::Surface(specific file format)";
  527.  
  528.   if(filePath == nullptr)
  529.       THROW_ERRORF("%s: filePath = nullptr", funcName);
  530.  
  531.   _opq = _invoke_surface_loader(filePath, callback, funcName);
  532.   ++numAllocations;
  533.  
  534.   _valid = true;
  535.   _constructing = false;
  536.  
  537. }
  538.  
  539.  
  540.  
  541.  
  542.  
  543. //(the last constructor can be found in "kit_Surface_LoadAllTypes.cpp")
  544.  
  545.  
  546.  
  547.  
  548.  
  549. Surface::~Surface(){
  550.   if(!_valid) return;
  551.   _valid = false;
  552.  
  553.   if(SURF_PTR != nullptr){
  554.     SDL_FreeSurface(SURF_PTR);
  555.     _opq = nullptr;
  556.     --numAllocations;
  557.   }
  558.  
  559. }
  560.  
  561.  
  562.  
  563.  
  564.  
  565. //this is only used for saveImage, as this exists
  566.  //as a byproduct of both SDL_LockSurface and the
  567.  //SurfaceSaverCallback being able to error.
  568. //basically what this does is ensure that
  569.  //SDL_UnlockSurface is called, even if the
  570.  //SurfaceSaverCallback throws an exception
  571. struct _thing_that_locks_surface {
  572.   SDL_Surface* ptr = nullptr;
  573.   bool wasLocked   = false;
  574.  
  575.   _thing_that_locks_surface(SDL_Surface* _ptr){
  576.     if(SDL_LockSurface((ptr = _ptr)) < 0)
  577.       THROW_ERRORF("Surface::saveImage(): \"%s\"", SDL_GetError());
  578.   }
  579.  
  580.   ~_thing_that_locks_surface(){ SDL_UnlockSurface(ptr); }
  581.  
  582. };
  583.  
  584.  
  585. void Surface::saveImage(const char* filePath, SurfaceSaverCallback callback){
  586.   if(SURF_IS_INVALID)
  587.     THROW_ERROR("Surface::saveImage(): invalid Surface");
  588.  
  589.   if(filePath == nullptr)
  590.     THROW_ERROR("Surface::saveImage(): filePath = nullptr");
  591.  
  592.  
  593.  
  594.   if(callback == nullptr){ //save .bmp file
  595.     //afaik, you don't need to lock a surface before calling SDL_SaveBMP_RW,
  596.      //(hopefully i'm not wrong about that!)
  597.     if(SDL_SaveBMP(SURF_PTR, filePath) < 0)
  598.       THROW_ERRORF("Surface::saveImage(): \"%s\"", SDL_GetError());
  599.  
  600.  
  601.   } else { //save some other file format
  602.     _thing_that_locks_surface surface_locker(SURF_PTR); //LMAOOO
  603.  
  604.     callback(filePath, *this);
  605.  
  606.     //(surface should unlock after this code block,
  607.      //or if callback throws an exception)
  608.  
  609.  
  610.   }
  611.  
  612. }
  613.  
  614.  
  615.  
  616.  
  617.  
  618. /******************************************************************************/
  619.  
  620.  
  621.  
  622.  
  623.  
  624. bool Surface::hasRLE(){
  625.   if(SURF_IS_INVALID)
  626.     THROW_ERROR("Surface::hasRLE(): invalid Surface");
  627.  
  628.   return SDL_HasSurfaceRLE(SURF_PTR);
  629.  
  630. }
  631.  
  632.  
  633.  
  634.  
  635.  
  636. bool Surface::hasLockRequirement(){
  637.   if(SURF_IS_INVALID)
  638.     THROW_ERROR("Surface::hasRLE(): invalid Surface");
  639.  
  640.   return SDL_MUSTLOCK(SURF_PTR);
  641.  
  642. }
  643.  
  644.  
  645.  
  646.  
  647.  
  648. u32 Surface::getPixelFmt(){
  649.   if(SURF_IS_INVALID)
  650.     THROW_ERROR("Surface::getPixelFmt(): invalid Surface");
  651.  
  652.   return SURF_PTR->format->format;
  653.  
  654. }
  655.  
  656.  
  657.  
  658.  
  659.  
  660. shape::point Surface::getSize(){
  661.   if(SURF_IS_INVALID)
  662.     THROW_ERROR("Surface::getSize(): invalid Surface");
  663.  
  664.   return shape::point(SURF_PTR->w, SURF_PTR->h);
  665.  
  666. }
  667.  
  668.  
  669.  
  670.  
  671.  
  672. u32 Surface::getBytesPerRow(){
  673.   if(SURF_IS_INVALID)
  674.     THROW_ERROR("Surface::getBytesPerRow(): invalid Surface");
  675.  
  676.   return (u32)SURF_PTR->pitch;
  677.  
  678. }
  679.  
  680.  
  681.  
  682.  
  683.  
  684. void* Surface::getPixelData(){
  685.   if(SURF_IS_INVALID)
  686.     THROW_ERROR("Surface::getPixelData(): invalid Surface");
  687.  
  688.   return SURF_PTR->pixels;
  689.  
  690. }
  691.  
  692.  
  693.  
  694.  
  695.  
  696. void* Surface::getUserdata(){
  697.   if(SURF_IS_INVALID)
  698.     THROW_ERROR("Surface::getUserdata(): invalid Surface");
  699.  
  700.   return SURF_PTR->userdata;
  701.  
  702. }
  703.  
  704.  
  705.  
  706.  
  707.  
  708. u32 Surface::getPaletteLen(){
  709.   if(SURF_IS_INVALID)
  710.     THROW_ERROR("Surface::getPaletteLen(): invalid Surface");
  711.  
  712.   SDL_Palette* palette = SURF_PTR->format->palette;
  713.  
  714.   //idk if this is even possible, but just in case
  715.   if(palette == nullptr) return 0;
  716.  
  717.   if(!SDL_ISPIXELFORMAT_INDEXED(SURF_PTR->format->format)) return 0;
  718.  
  719.   return (u32)palette->ncolors;
  720.  
  721. }
  722.  
  723.  
  724.  
  725.  
  726.  
  727. const colors::ABGR* Surface::getPaletteColors(){
  728.   if(SURF_IS_INVALID)
  729.     THROW_ERROR("Surface::getPaletteColors(): invalid Surface");
  730.  
  731.   SDL_Palette* palette = SURF_PTR->format->palette;
  732.  
  733.   //idk if this is even possible, but just in case
  734.   if(palette == nullptr) return nullptr;
  735.  
  736.   if(!SDL_ISPIXELFORMAT_INDEXED(SURF_PTR->format->format)) return nullptr;
  737.  
  738.   return (const colors::ABGR*)palette->colors;
  739.  
  740. }
  741.  
  742.  
  743.  
  744.  
  745.  
  746. BlendModesEnum Surface::getBlendMode(){
  747.   if(SURF_IS_INVALID)
  748.     THROW_ERROR("Surface::getBlendMode(): invalid Surface");
  749.  
  750.   SDL_BlendMode blendMode;
  751.  
  752.   if(SDL_GetSurfaceBlendMode(SURF_PTR, &blendMode) < 0)
  753.     THROW_ERRORF("Surface::getBlendMode(): \"%s\"", SDL_GetError());
  754.  
  755.   return (BlendModesEnum)blendMode;
  756.  
  757. }
  758.  
  759.  
  760.  
  761.  
  762.  
  763. u8 Surface::getAlphaMod(){
  764.   if(SURF_IS_INVALID)
  765.     THROW_ERROR("Surface::getAlphaMod(): invalid Surface");
  766.  
  767.   u8 alphaMod;
  768.  
  769.   if(SDL_GetSurfaceAlphaMod(SURF_PTR, & alphaMod) < 0)
  770.     THROW_ERRORF("Surface::getAlphaMod(): \"%s\"", SDL_GetError());
  771.  
  772.   return alphaMod;
  773.  
  774. }
  775.  
  776.  
  777.  
  778.  
  779.  
  780. colors::BGR Surface::getColorMod(){
  781.   if(SURF_IS_INVALID)
  782.     THROW_ERROR("Surface::getColorMod(): invalid Surface");
  783.  
  784.   u8 r, g, b;
  785.  
  786.   if(SDL_GetSurfaceColorMod(SURF_PTR, &r, &g, &b) < 0)
  787.     THROW_ERRORF("Surface::getColorMod(): \"%s\"", SDL_GetError());
  788.  
  789.   return colors::BGR888(r, g, b);
  790.  
  791. }
  792.  
  793.  
  794.  
  795.  
  796.  
  797. u32 Surface::getColorKey(){
  798.   if(SURF_IS_INVALID)
  799.     THROW_ERROR("Surface::getColorKey(): invalid Surface");
  800.  
  801.   u32 key;
  802.  
  803.   if(SDL_GetColorKey(SURF_PTR, &key) < 0)
  804.     THROW_ERRORF("Surface::getColorKey(): \"%s\"", SDL_GetError());
  805.  
  806.   return key;
  807.  
  808. }
  809.  
  810.  
  811.  
  812.  
  813.  
  814. /******************************************************************************/
  815.  
  816.  
  817.  
  818.  
  819.  
  820. void Surface::setRLE(bool enable){
  821.   if(SURF_IS_INVALID)
  822.     THROW_ERROR("Surface::setRLE(): invalid Surface");
  823.  
  824.   if(SDL_SetSurfaceRLE(SURF_PTR, enable) < 0)
  825.     THROW_ERRORF("Surface::setRLE(): \"%s\"", SDL_GetError());
  826.  
  827. }
  828.  
  829.  
  830.  
  831.  
  832.  
  833. void Surface::setUserdata(void* userdata){
  834.   if(SURF_IS_INVALID)
  835.     THROW_ERROR("Surface::setUserdata(): invalid Surface");
  836.  
  837.   SURF_PTR->userdata = userdata;
  838.  
  839. }
  840.  
  841.  
  842.  
  843.  
  844.  
  845. void Surface::setPaletteColors(const colors::ABGR* newColors,
  846.                                u32 numColors, u32 firstColor)
  847. {
  848.   if(SURF_IS_INVALID)
  849.     THROW_ERROR("Surface::setPaletteColors(): invalid Surface");
  850.  
  851.   if(newColors == nullptr)
  852.     THROW_ERROR("Surface::setPaletteColors(): newColors = nullptr");
  853.  
  854.   if(numColors > KIT_S32_MAX)
  855.     THROW_ERROR("Surface::setPaletteColors(): numColors > KIT_S32_MAX");
  856.  
  857.   if(firstColor > KIT_S32_MAX)
  858.     THROW_ERROR("Surface::setPaletteColors(): firstColor > KIT_S32_MAX");
  859.  
  860.  
  861.   SDL_Palette* palette = SURF_PTR->format->palette;
  862.  
  863.   if(!SDL_ISPIXELFORMAT_INDEXED(SURF_PTR->format->format)  ||
  864.      palette == nullptr  ||  !palette->ncolors)
  865.   {
  866.     THROW_ERROR("Surface::setPaletteColors(): Surface doesn't use a palette");
  867.   }
  868.  
  869.  
  870.   if(SDL_SetPaletteColors(palette, (SDL_Color*)newColors, firstColor, numColors) < 0)
  871.     THROW_ERRORF("Surface::setPaletteColors(): \"%s\"", SDL_GetError());
  872.  
  873. }
  874.  
  875.  
  876.  
  877.  
  878.  
  879. void Surface::setBlendMode(BlendModesEnum blendMode){
  880.   if(SURF_IS_INVALID)
  881.     THROW_ERROR("Surface::setBlendMode(): invalid Surface");
  882.  
  883.   if(SDL_SetSurfaceBlendMode(SURF_PTR, (SDL_BlendMode)blendMode) < 0)
  884.     THROW_ERRORF("Surface::setBlendMode(): \"%s\"", SDL_GetError());
  885.  
  886. }
  887.  
  888.  
  889.  
  890.  
  891.  
  892. void Surface::setAlphaMod(u8 alphaMod){
  893.   if(SURF_IS_INVALID)
  894.     THROW_ERROR("Surface::setAlphaMod(): invalid Surface");
  895.  
  896.   if(SDL_SetSurfaceAlphaMod(SURF_PTR, alphaMod) < 0)
  897.     THROW_ERRORF("Surface::setAlphaMod(): \"%s\"", SDL_GetError());
  898.  
  899. }
  900.  
  901.  
  902.  
  903.  
  904.  
  905. void Surface::setColorMod(colors::BGR colorMod){
  906.   if(SURF_IS_INVALID)
  907.     THROW_ERROR("Surface::setColorMod(): invalid Surface");
  908.  
  909.   if(SDL_SetSurfaceColorMod(SURF_PTR, colorMod.r, colorMod.g, colorMod.b) < 0)
  910.     THROW_ERRORF("Surface::setColorMod(): \"%s\"", SDL_GetError());
  911.  
  912. }
  913.  
  914.  
  915.  
  916.  
  917.  
  918. void Surface::setColorKey(bool enable, u32 key){
  919.   if(SURF_IS_INVALID)
  920.     THROW_ERROR("Surface::setColorKey(): invalid Surface");
  921.  
  922.   if(SDL_SetColorKey(SURF_PTR, enable, key) < 0)
  923.     THROW_ERRORF("Surface::setColorKey(): \"%s\"", SDL_GetError());
  924.  
  925. }
  926.  
  927.  
  928.  
  929.  
  930.  
  931. /******************************************************************************/
  932.  
  933.  
  934.  
  935.  
  936.  
  937. u32 Surface::mapRGB(colors::BGR inputColor){
  938.   if(SURF_IS_INVALID)
  939.     THROW_ERROR("Surface::mapRGB(): invalid Surface");
  940.  
  941.   return SDL_MapRGB(SURF_PTR->format, inputColor.r, inputColor.g, inputColor.b);
  942.  
  943. }
  944.  
  945.  
  946.  
  947.  
  948.  
  949. u32 Surface::mapRGBA(colors::ABGR inputColor){
  950.   if(SURF_IS_INVALID)
  951.     THROW_ERROR("Surface::mapRGBA(): invalid Surface");
  952.  
  953.   return SDL_MapRGBA(SURF_PTR->format, inputColor.r, inputColor.g,
  954.                                        inputColor.b, inputColor.a);
  955.  
  956. }
  957.  
  958.  
  959.  
  960.  
  961.  
  962. void Surface::lock(bool locked){
  963.   if(SURF_IS_INVALID)
  964.     THROW_ERROR("Surface::lock(): invalid Surface");
  965.  
  966.  
  967.   if(locked){
  968.     if(SDL_LockSurface(SURF_PTR) < 0)
  969.       THROW_ERRORF("Surface::lock(): \"%s\"", SDL_GetError());
  970.  
  971.   } else {
  972.     SDL_UnlockSurface(SURF_PTR);
  973.  
  974.   }
  975.  
  976. }
  977.  
  978.  
  979.  
  980.  
  981.  
  982. }; /* namespace kit */
  983. /******************************************************************************/
  984. /******************************************************************************/
  985. //"2024-11-21\src\kit_sdl2\kit_Surface_blit.cpp":
  986. #include "_kit_common.hpp"
  987.  
  988. //i won't be checking for this here
  989.  //(nor will i be doing most checks that i'd normally do)
  990. //#define SURF_IS_INVALID (!_valid)
  991.  
  992. #define SURF_PTR ((SDL_Surface*)_opq)
  993.  
  994. #define BLIT_SURF   SDL_BlitSurface
  995. #define BLIT_SCALED SDL_BlitScaled
  996.  
  997.  
  998. namespace kit {
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004. void Surface::fillRects(colors::ABGR color, const shape::rect* rects,
  1005.                                             size_t rects_len)
  1006. {
  1007.   if(rects_len > KIT_S32_MAX)
  1008.     THROW_ERROR("Surface::fillRects(): rects_len > KIT_S32_MAX");
  1009.  
  1010.  
  1011.   u32 mapped_color = SDL_MapRGBA(SURF_PTR->format, color.r, color.g,
  1012.                                                    color.b, color.a);
  1013.  
  1014.  
  1015.   int err;
  1016.  
  1017.   if(rects == nullptr || !rects_len){
  1018.     err = SDL_FillRect(SURF_PTR, (SDL_Rect*)rects, mapped_color);
  1019.  
  1020.   } else {
  1021.     err = SDL_FillRects(SURF_PTR, (SDL_Rect*)rects, (int)rects_len, mapped_color);
  1022.  
  1023.   }
  1024.  
  1025.  
  1026.   if(err < 0)
  1027.     THROW_ERRORF("Surface::fillRects(): \"%s\"", SDL_GetError());
  1028.  
  1029. }
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035. /******************************************************************************/
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041. void Surface::blit(Surface& dst_surf, const shape::rect* dst,
  1042.                                       const shape::rect* src)
  1043. {
  1044.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE(&dst_surf);
  1045.  
  1046.   //(.w & .h of dst should be ignored by SDL_UpperBlit,
  1047.    //so setting them is unnecessary)
  1048.   SDL_Rect  dstrect_sdl;
  1049.   SDL_Rect* dstrect_sdl_p;
  1050.  
  1051.   if(dst != nullptr){
  1052.     dstrect_sdl.x = dst->x;
  1053.     dstrect_sdl.y = dst->y;
  1054.     dstrect_sdl_p = &dstrect_sdl;
  1055.  
  1056.   } else {
  1057.     dstrect_sdl.x = 0;
  1058.     dstrect_sdl.y = 0;
  1059.     dstrect_sdl_p = nullptr;
  1060.  
  1061.   }
  1062.  
  1063.   if(BLIT_SURF(SURF_PTR, (SDL_Rect*)src, dst_sdl, dstrect_sdl_p) < 0)
  1064.     THROW_ERRORF("Surface::blit(Surface&): \"%s\"", SDL_GetError());
  1065.  
  1066. }
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072. void Surface::blit(Window& dst_surf, const shape::rect* dst,
  1073.                                      const shape::rect* src)
  1074. {
  1075.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE2(&dst_surf);
  1076.  
  1077.   if(dst_sdl == nullptr)
  1078.     THROW_ERROR("Surface::blit(Window&): Window doesn't have a surface");
  1079.  
  1080.   //(.w & .h of dst should be ignored by SDL_UpperBlit,
  1081.    //so setting them is unnecessary)
  1082.   SDL_Rect  dstrect_sdl;
  1083.   SDL_Rect* dstrect_sdl_p;
  1084.  
  1085.   if(dst != nullptr){
  1086.     dstrect_sdl.x = dst->x;
  1087.     dstrect_sdl.y = dst->y;
  1088.     dstrect_sdl_p = &dstrect_sdl;
  1089.  
  1090.   } else {
  1091.     dstrect_sdl.x = 0;
  1092.     dstrect_sdl.y = 0;
  1093.     dstrect_sdl_p = nullptr;
  1094.  
  1095.   }
  1096.  
  1097.   if(BLIT_SURF(SURF_PTR, (SDL_Rect*)src, dst_sdl, dstrect_sdl_p) < 0)
  1098.     THROW_ERRORF("Surface::blit(Window&): \"%s\"", SDL_GetError());
  1099.  
  1100. }
  1101.  
  1102.  
  1103.  
  1104.  
  1105.  
  1106. /******************************************************************************/
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112. void Surface::blitScaled(Surface& dst_surf, const shape::rect* dst,
  1113.                                             const shape::rect* src)
  1114. {
  1115.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE(&dst_surf);
  1116.  
  1117.   SDL_Rect  dstrect_sdl;
  1118.   SDL_Rect* dstrect_sdl_p;
  1119.  
  1120.   if(dst != nullptr){
  1121.     dstrect_sdl   = *(SDL_Rect*)dst;
  1122.     dstrect_sdl_p = &dstrect_sdl;
  1123.  
  1124.   } else {
  1125.     dstrect_sdl_p = nullptr;
  1126.  
  1127.   }
  1128.  
  1129.   if(BLIT_SCALED(SURF_PTR, (SDL_Rect*)src, dst_sdl, dstrect_sdl_p) < 0)
  1130.     THROW_ERRORF("Surface::blitScaled(Surface&): \"%s\"", SDL_GetError());
  1131.  
  1132. }
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138. void Surface::blitScaled(Window& dst_surf, const shape::rect* dst,
  1139.                                            const shape::rect* src)
  1140. {
  1141.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE2(&dst_surf);
  1142.  
  1143.   if(dst_sdl == nullptr)
  1144.     THROW_ERROR("Surface::blitScaled(Window&): Window doesn't have a surface");
  1145.  
  1146.   SDL_Rect  dstrect_sdl;
  1147.   SDL_Rect* dstrect_sdl_p;
  1148.  
  1149.   if(dst != nullptr){
  1150.     dstrect_sdl   = *(SDL_Rect*)dst;
  1151.     dstrect_sdl_p = &dstrect_sdl;
  1152.  
  1153.   } else {
  1154.     dstrect_sdl_p = nullptr;
  1155.  
  1156.   }
  1157.  
  1158.   if(BLIT_SCALED(SURF_PTR, (SDL_Rect*)src, dst_sdl, dstrect_sdl_p) < 0)
  1159.     THROW_ERRORF("Surface::blitScaled(Window&): \"%s\"", SDL_GetError());
  1160.  
  1161. }
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167. /******************************************************************************/
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173. void Surface::blitAt(Surface& dst_surf,  s32 x, s32 y, f32 scale){
  1174.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE(&dst_surf);
  1175.  
  1176.  
  1177.   SDL_Rect dstrect_sdl;
  1178.   dstrect_sdl.x = x;
  1179.   dstrect_sdl.y = y;
  1180.   dstrect_sdl.w = dst_sdl->w;
  1181.   dstrect_sdl.h = dst_sdl->h;
  1182.  
  1183.  
  1184.   int err;
  1185.  
  1186.   if(scale == 1.0f){ //fast blit
  1187.     dstrect_sdl.x -= dstrect_sdl.w/2;
  1188.     dstrect_sdl.y -= dstrect_sdl.h/2;
  1189.     err = BLIT_SURF(SURF_PTR, nullptr, dst_sdl, &dstrect_sdl);
  1190.  
  1191.   } else { //scaled blit
  1192.     dstrect_sdl.w *= scale;
  1193.     dstrect_sdl.h *= scale;
  1194.     dstrect_sdl.x -= dstrect_sdl.w/2;
  1195.     dstrect_sdl.y -= dstrect_sdl.h/2;
  1196.     err = BLIT_SCALED(SURF_PTR, nullptr, dst_sdl, &dstrect_sdl);
  1197.  
  1198.   }
  1199.  
  1200.  
  1201.   if(err) THROW_ERRORF("Surface::blitAt(Surface&): \"%s\"", SDL_GetError());
  1202.  
  1203. }
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209. void Surface::blitAt(Window& dst_surf,  s32 x, s32 y, f32 scale){
  1210.   SDL_Surface* dst_sdl = (SDL_Surface*)KIT_GET_CLASS_OPAQUE2(&dst_surf);
  1211.  
  1212.   if(dst_sdl == nullptr)
  1213.     THROW_ERROR("Surface::blitAt(Window&): Window doesn't have a surface");
  1214.  
  1215.  
  1216.   SDL_Rect dstrect_sdl;
  1217.   dstrect_sdl.x = x;
  1218.   dstrect_sdl.y = y;
  1219.   dstrect_sdl.w = dst_sdl->w;
  1220.   dstrect_sdl.h = dst_sdl->h;
  1221.  
  1222.  
  1223.   int err;
  1224.  
  1225.   if(scale == 1.0f){ //fast blit
  1226.     dstrect_sdl.x -= dstrect_sdl.w/2;
  1227.     dstrect_sdl.y -= dstrect_sdl.h/2;
  1228.     err = BLIT_SURF(SURF_PTR, nullptr, dst_sdl, &dstrect_sdl);
  1229.  
  1230.   } else { //scaled blit
  1231.     dstrect_sdl.w *= scale;
  1232.     dstrect_sdl.h *= scale;
  1233.     dstrect_sdl.x -= dstrect_sdl.w/2;
  1234.     dstrect_sdl.y -= dstrect_sdl.h/2;
  1235.     err = BLIT_SCALED(SURF_PTR, nullptr, dst_sdl, &dstrect_sdl);
  1236.  
  1237.   }
  1238.  
  1239.  
  1240.   if(err) THROW_ERRORF("Surface::blitAt(Window&): \"%s\"", SDL_GetError());
  1241.  
  1242. }
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248. }; /* namespace kit */
  1249.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement