Advertisement
Kitomas

work for 2025-01-31 (3/4)

Jan 31st, 2025
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.74 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"sokoban_and_kit32_2025-01-31\sokoban\src\ctx_main_menu.cpp":
  4. #include <include_all.hpp>
  5.  
  6. #include <cmath>
  7.  
  8.  
  9. using namespace kit;
  10.  
  11.  
  12.  
  13.  
  14.  
  15. enum mouse_zone_names {
  16.   MZONE_PLAY,
  17.   MZONE_EDITOR,
  18.   MZONE_REBIND,
  19.   MZONE_QUIT,
  20.   MZONE_MUSVOL,
  21.   MZONE_SFXVOL,
  22.   MZONE_COUNT,
  23. };
  24.  
  25.  
  26.  
  27.  
  28.  
  29. #define UV_STEP(_amount) ((1.0f/ICON_MENU_LEN)*(_amount))
  30. Texture* icon_menu = nullptr;
  31. Texture* icon_menu_inv = nullptr;
  32.  
  33. static Vertex verts[4];
  34. static s32    verts_indices[6];
  35. static bool   verts_init = false;
  36.  
  37. static inline void init_verts(){
  38.   if(verts_init) return;
  39.   verts_init = true;
  40.  
  41.   clrs::ABGR color = 0xFFFFFFFF;
  42.   verts[0].c = color;
  43.   verts[1].c = color;
  44.   verts[2].c = color;
  45.   verts[3].c = color;
  46.  
  47.   verts[0].v = 0.0f;
  48.   verts[1].v = 0.0f;
  49.   verts[2].v = 1.0f;
  50.   verts[3].v = 1.0f;
  51.  
  52.   verts_indices[0] = 0;
  53.   verts_indices[1] = 1;
  54.   verts_indices[2] = 2;
  55.   verts_indices[3] = 3;
  56.   verts_indices[4] = 1;
  57.   verts_indices[5] = 2;
  58.  
  59. }
  60.  
  61. static inline void _draw_icon(f32 x, f32 y, u32 which,
  62.                               bool inverted)
  63. {
  64.   init_verts();
  65.  
  66.   verts[0].pos = {x   , y   };
  67.   verts[1].pos = {x+32, y   };
  68.   verts[2].pos = {x   , y+32};
  69.   verts[3].pos = {verts[1].x, verts[2].y};
  70.  
  71.   verts[0].u = verts[2].u = UV_STEP(which  );
  72.   verts[1].u = verts[3].u = UV_STEP(which+1);
  73.  
  74.   if(!inverted) rndr->renderGeometry(verts, 4, icon_menu    , verts_indices, 6);
  75.   else          rndr->renderGeometry(verts, 4, icon_menu_inv, verts_indices, 6);
  76.  
  77. }
  78.  
  79. void draw_icon_rgb(f32 x, f32 y, u32 which,
  80.                    clrs::ABGR color, bool inverted)
  81. {
  82.   verts[0].c = color;
  83.   verts[1].c = color;
  84.   verts[2].c = color;
  85.   verts[3].c = color;
  86.  
  87.   _draw_icon(x, y, which, inverted);
  88.  
  89. }
  90.  
  91. void draw_icon_hsv(f32 x, f32 y, u32 which,
  92.                    f32 hue, bool inverted)
  93. {
  94.   verts[0].c = hsv2rgb( fmodf(hue+  0, 360) , 100,100);
  95.   verts[1].c = hsv2rgb( fmodf(hue+ 90, 360) , 100,100);
  96.   verts[2].c = hsv2rgb( fmodf(hue+180, 360) , 100,100);
  97.   verts[3].c = hsv2rgb( fmodf(hue+270, 360) , 100,100);
  98.  
  99.   _draw_icon(x, y, which, inverted);
  100.  
  101. }
  102.  
  103.  
  104.  
  105.  
  106.  
  107. static struct {
  108.   s32  music_pos;
  109.   s32  sfx_pos;
  110.  
  111.   s32  opt;
  112.   u8   opt_color;
  113.  
  114.   bool music_up;
  115.   bool sfx_up;
  116.  
  117.   bool init = false;
  118. } ctx;
  119.  
  120. static inline void new_opt_color(){
  121.   //since text color is black (which is the default text box color),
  122.    //i only want to randomly select colors 1 through 15
  123.   ctx.opt_color = 1+(frandf()*(TEXTCOLORED_LEN-2)+0.5f);
  124. }
  125.  
  126. static inline void reset_ctx(){
  127.   if(ctx.init) return;
  128.  
  129.   music_play((music_index == -1) ? MUSIC_INDEX_musicbox1_intro
  130.                                  : MUSIC_INDEX_musicbox1);
  131.  
  132.   memory::set(&ctx, 0, sizeof(ctx));
  133.  
  134.   ctx.opt = -1;
  135.   new_opt_color();
  136.  
  137.   ctx.init = true;
  138.  
  139.  
  140.   cursor_scroll = false;
  141.   cursor_snow   = true;
  142.  
  143. }
  144.  
  145.  
  146.  
  147.  
  148.  
  149. #define MOUSE_ZONES_LEN countof(mouse_zones, shape::rect)
  150.  
  151. static shape::rect mouse_zones[] = {
  152.   #define UI_TEXT " Play\n Editor\n Rebind\n Quit"
  153.   {263, 262+16*0-2,  16*7+2, 16+2}, //play
  154.   {263, 262+16*1  ,  16*7+2, 16  }, //editor
  155.   {263, 262+16*2  ,  16*7+2, 16  }, //rebind
  156.   {263, 262+16*3  ,  16*7+2, 16  }, //quit
  157.  
  158.   #define BAR_HEIGHT 128
  159.   {LOGI_W-64, LOGI_H-BAR_HEIGHT-32, 32, BAR_HEIGHT+32}, //music volume
  160.   {LOGI_W-32, LOGI_H-BAR_HEIGHT-32, 32, BAR_HEIGHT+32}, //  sfx volume
  161.  
  162. };
  163.  
  164.  
  165.  
  166.  
  167.  
  168. s32 ctx_main_menu_evt(){
  169.   reset_ctx();
  170.  
  171.   Event evt; bool run = true;
  172.  
  173.   #define WAS_MOUSE_DOWN (mouseClick && !mouseDrag)
  174.   #define OPT_CHANGED (ctx.opt != opt_old  &&  ctx.opt != -1)
  175.   bool mouseDrag  = true;
  176.   bool mouseClick = false;
  177.   s32 opt_old       = ctx.opt;
  178.   u32 ctx_which_old = ctx_which;
  179.  
  180.  
  181.   while(pollEvent(&evt) && run)
  182.   switch(evt.type){
  183.     case KEVENT_MOUSE_DOWN: mouseDrag = false; ATTR_FALLTHROUGH;
  184.     case KEVENT_MOUSE_MOVED: {
  185.       mouseClick = evt.mouse.button!=0;
  186.       ctx.opt = -1;
  187.  
  188.       for(u32 i=0; i<MOUSE_ZONES_LEN; ++i){
  189.         shape::point pos = {evt.mouse.x, evt.mouse.y};
  190.         if(point_in_rect(pos, mouse_zones[i])){
  191.           if(opt_old != (s32)i){
  192.             new_opt_color();
  193.           }
  194.           ctx.opt = i; break;
  195.  
  196.         }
  197.  
  198.       }
  199.  
  200.     } goto _def_evt;
  201.  
  202.     default: _def_evt: run = default_event_handler(evt);
  203.   }
  204.  
  205.  
  206.  
  207.   ctx.music_up = false;
  208.   ctx.sfx_up   = false;
  209.  
  210.   if     (ctx.opt<=MZONE_QUIT && OPT_CHANGED   ) SFXPLAY(SFXNAME_BLIP1, 1,1.2);
  211.   else if(ctx.opt!=-1         && WAS_MOUSE_DOWN) SFXPLAY(SFXNAME_CHK1 , 1,1.0);
  212.  
  213.  
  214.  
  215.   switch(ctx.opt){
  216.     case MZONE_PLAY  : if(WAS_MOUSE_DOWN){ ctx_which = CTX_LVL_SELECT; } break;
  217.     case MZONE_EDITOR: if(WAS_MOUSE_DOWN){ ctx_which = CTX_LVL_EDITOR; } break;
  218.     case MZONE_REBIND: if(WAS_MOUSE_DOWN){ ctx_which = CTX_REBINDING;  } break;
  219.     case MZONE_QUIT  : if(WAS_MOUSE_DOWN){ run = false; } break;
  220.  
  221.     case MZONE_MUSVOL: {
  222.       ctx.music_up = true;
  223.       if(mouseClick){
  224.         //should now start at pixel 233, which is 1 pixel into the slider bar
  225.         s32 adjusted = cursor_pos.y-(LOGI_H-BAR_HEIGHT)+1;
  226.         audio->lock();
  227.         settings.music_vol = (f32)adjusted / (BAR_HEIGHT);
  228.         settings.music_vol = CLAMP(1.0f-settings.music_vol, 0.0f, 1.0f);
  229.         audio->unlock();
  230.       }
  231.     } break;
  232.  
  233.     case MZONE_SFXVOL: {
  234.       ctx.sfx_up = true;
  235.       if(mouseClick){
  236.         //should now start at pixel 233, which is 1 pixel into the slider bar
  237.         s32 adjusted = cursor_pos.y-(LOGI_H-BAR_HEIGHT)+1;
  238.         audio->lock();
  239.         settings.sfx_vol = (f32)adjusted / (BAR_HEIGHT);
  240.         settings.sfx_vol = CLAMP(1.0f-settings.sfx_vol, 0.0f, 1.0f);
  241.         sfx->volumeMaster = settings.sfx_vol;
  242.         audio->unlock();
  243.       }
  244.     } break;
  245.  
  246.     default:;
  247.   }
  248.  
  249.  
  250.  
  251.   if(ctx_which_old != ctx_which){
  252.     ctx.init = false;
  253.     return -1;
  254.   }
  255.  
  256.   return run;
  257.  
  258. }
  259.  
  260.  
  261.  
  262.  
  263.  
  264. void ctx_main_menu_draw(){
  265.   if(!ctx.init) return;
  266.   text->scale = {2,2};
  267.  
  268.   //game title
  269.   text->drawBox(KIT_CENTER_TEXT, 32, GAME_NAME);
  270.  
  271.  
  272.  
  273.   //menu buttons
  274.   shape::rect  box   = text->getRect(KIT_CENTER_TEXT, -32-1, UI_TEXT, true);
  275.   shape::point shift = text->drawBoxNoText(box.x, box.y, box.w, box.h);
  276.   shift.x += box.x;
  277.   shift.y += box.y;
  278.  
  279.   //will draw ui text, since it's already in the format buffer from getRect()
  280.   text->draw(shift.x, shift.y);
  281.  
  282.   if(ctx.opt == CLAMP(ctx.opt, MZONE_PLAY, MZONE_QUIT)){
  283.     textColored[ctx.opt_color]->scale = text->scale;
  284.     textColored[ctx.opt_color]->drawChar('\1', shift.x, shift.y + 16*ctx.opt);
  285.   }
  286.  
  287.  
  288.  
  289.   #define BAR_SPEED 8
  290.   if(ctx.music_up) ctx.music_pos = MAX(ctx.music_pos-BAR_SPEED, -BAR_HEIGHT);
  291.   else             ctx.music_pos = MIN(ctx.music_pos+BAR_SPEED, 0          );
  292.  
  293.   if(ctx.sfx_up) ctx.sfx_pos = MAX(ctx.sfx_pos-BAR_SPEED, -BAR_HEIGHT);
  294.   else           ctx.sfx_pos = MIN(ctx.sfx_pos+BAR_SPEED, 0          );
  295.  
  296.  
  297.  
  298.   //music note icon
  299.   draw_icon_rgb(LOGI_W-64, LOGI_H+(f32)ctx.music_pos-33,
  300.                 0, unit_to_ryg(settings.music_vol), false);
  301.  
  302.   //speaker icon
  303.   draw_icon_rgb(LOGI_W-32, LOGI_H+(f32)ctx.sfx_pos-33,
  304.                 1, unit_to_ryg(settings.sfx_vol), false);
  305.  
  306.  
  307.  
  308.   //music volume slider
  309.   shape::rect music_bar = mouse_zones[MZONE_MUSVOL];
  310.   music_bar.y += BAR_HEIGHT+ctx.music_pos+32;
  311.   music_bar.h -= 32;
  312.  
  313.   rndr->setDrawColor(text->txt_bg);
  314.   rndr->fillRects(&music_bar);
  315.   rndr->setDrawColor(text->txt_bd);
  316.   rndr->drawRects(&music_bar);
  317.  
  318.   music_bar += {1, 1 + (s32)((1.0f-settings.music_vol)*(BAR_HEIGHT-3))};
  319.   rndr->setDrawColor(0xFFFFFFFF);
  320.   rndr->drawLine(music_bar.x, music_bar.y, music_bar.x+29, music_bar.y);
  321.  
  322.  
  323.  
  324.   //sfx volume slider
  325.   shape::rect sfx_bar = mouse_zones[MZONE_SFXVOL];
  326.   sfx_bar.y += BAR_HEIGHT+ctx.sfx_pos+32;
  327.   sfx_bar.h -= 32;
  328.  
  329.   rndr->setDrawColor(text->txt_bg);
  330.   rndr->fillRects(&sfx_bar);
  331.   rndr->setDrawColor(text->txt_bd);
  332.   rndr->drawRects(&sfx_bar);
  333.  
  334.   sfx_bar += {1, 1 + (s32)((1.0f-settings.sfx_vol)*(BAR_HEIGHT-3))};
  335.   rndr->setDrawColor(0xFFFFFFFF);
  336.   rndr->drawLine(sfx_bar.x, sfx_bar.y, sfx_bar.x+29, sfx_bar.y);
  337.  
  338.  
  339.  
  340.   #if defined(_DEBUG) && 0
  341.     rndr->setDrawColor(0xFFFF00FF);
  342.     //if(!(frame_num%2))
  343.       rndr->drawRects(mouse_zones, MOUSE_ZONES_LEN);
  344.   #endif /* _DEBUG */
  345.  
  346. }
  347. /******************************************************************************/
  348. /******************************************************************************/
  349. //"sokoban_and_kit32_2025-01-31\sokoban\src\main.cpp":
  350. #include <include_all.hpp>
  351.  
  352. #include <windows.h>
  353.  
  354. #include <unistd.h> //for getcwd()
  355. #include <cstdlib> //for std::srand & std::rand
  356. #include <cmath>
  357.  
  358.  
  359. using namespace kit;
  360.  
  361.  
  362. /******************************************************************************/
  363.  
  364.  
  365. settings_t settings;
  366.  
  367. AudioData* sfxData[SFXDATA_LEN];
  368.  
  369. Window*        wndw = nullptr;
  370. Renderer*      rndr = nullptr;
  371. BFont_Texture* text = nullptr;
  372. BFont_Texture* textColored[16] = {0};
  373.  
  374.  
  375. /****************************** "callbacks.cpp" *******************************/
  376.  
  377.  
  378. s32 cb_audio(void* _dst, const AudioDeviceInfo& info);
  379.  
  380. extern bool  audioIsReady;
  381.  
  382. extern Xmp*        music;
  383. extern Stereo_s16* music_buffer_src; //xmp fills this
  384. extern Stereo_f32* music_buffer_dst; //dst=src, before applying music_fade
  385. extern AudioFade   music_fade;
  386.  
  387.  
  388. /****************************** "utils_core.cpp" ******************************/
  389.  
  390.  
  391. void tile_init();
  392.  
  393. extern Texture* tile_tex;
  394.  
  395.  
  396. /******************************************************************************/
  397.  
  398.  
  399. //just in case you plan on manipulating music_index directly
  400.  //to feed it into music_play or something
  401. static s32 music_index_old = music_index;
  402.  
  403. void music_play(s32 index){
  404.   //since negative indexes are used as a kind of control code,
  405.    //<-1 should be allowed now
  406.   //index = MAX(index, -1);
  407.   if(!audio  ||  index == music_index_old) return;
  408.   audio->lock();
  409.  
  410.   music_fade.fadeIn = false;
  411.   music_fade.fadeOutCalled = false;
  412.   music_index_old = music_index = index;
  413.  
  414.   audio->unlock();
  415.  
  416. }
  417.  
  418.  
  419.  
  420. static u32 sampleRate = 0;
  421.  
  422. void music_setFadeDelta(f32 fadeTimeSeconds){
  423.   if(!sampleRate) return; //just in case
  424.   music_fade.setDelta(sampleRate, fadeTimeSeconds);
  425.  
  426. }
  427.  
  428.  
  429.  
  430. #if RAND_MAX > 32767
  431. #error "RAND_MAX > 32767; frand should be altered to accomodate"
  432. #endif
  433.  
  434. //assumes RAND_MAX is 32767
  435. #define GET_FRAND_VALUE(cast) ( (cast)(std::rand()<<15|std::rand())/0x3FFFFFFF )
  436.  
  437. f64 frand  (){  return GET_FRAND_VALUE(f64);              } // 0.0f -> 1.0f
  438. f64 frand2 (){  return GET_FRAND_VALUE(f64)*2.0f - 1.0f;  } //-1.0f -> 1.0f
  439. f32 frandf (){  return GET_FRAND_VALUE(f32);              } // 0.0f -> 1.0f
  440. f32 frandf2(){  return GET_FRAND_VALUE(f32)*2.0f - 1.0f;  } //-1.0f -> 1.0f
  441.  
  442.  
  443.  
  444. void settings_load(){
  445.   if(fileio::exists(SETTINGS_PATH)){
  446.     size_t      settings_size;
  447.     settings_t* settings_p = (settings_t*)fileio::readAll(SETTINGS_PATH,
  448.                                                           &settings_size);
  449.  
  450.     if(settings_size < sizeof(settings_t)  ||
  451.        settings_p->version != SETTINGS_VERSION)
  452.     {
  453.       memory::free(&settings_p);
  454.       goto _reset_settings;
  455.  
  456.     } else {
  457.       settings = *settings_p;
  458.       memory::free(&settings_p);
  459.  
  460.     }
  461.  
  462.  
  463.   } else { _reset_settings:
  464.     memory::set(&settings, 0, sizeof(settings_t));
  465.     settings.music_vol = 0.75f;
  466.     settings.sfx_vol   = 0.75f;
  467.  
  468.  
  469.   }
  470. }
  471.  
  472.  
  473.  
  474. void settings_save(){
  475.   settings.version = SETTINGS_VERSION;
  476.   settings.sfx_vol = (sfx->volumeMaster.l+sfx->volumeMaster.r)/2;
  477.   fileio::writeAll(SETTINGS_PATH, &settings, sizeof(settings_t));
  478.  
  479. }
  480.  
  481.  
  482.  
  483. #ifdef _DEBUG
  484.   #define kit_logEvent(_type) kit_LogInfo("unhandled event = %s", getEventText(_type))
  485. #else
  486.   #define kit_logEvent(_type) ;//kit_LogInfo("event = 0x%08X", (_type))
  487. #endif
  488.  
  489. #define LOGI_Wh (LOGI_W/2)
  490. #define LOGI_Hh (LOGI_H/2)
  491.  
  492. s32 default_event_handler(Event& evt){
  493.   bool run = true;
  494.  
  495.   switch(evt.type){
  496.     case KEVENT_QUIT: run = false; break;
  497.     case KEVENT_KEY_DOWN: {
  498.       if(evt.key.repeat) break;
  499.       if((evt.key.vkey==VKEY_RETURN && evt.key.kmods&KEYMOD_ALT) ||
  500.          evt.key.vkey == VKEY_F11)
  501.       {
  502.         settings.fullscreen ^= 1;
  503.         //_set_fullscreen:
  504.         wndw->setFullscreen(settings.fullscreen*FULLSCREEN_MODE);
  505.         //makes sure cursor doesn't go out of bounds
  506.         wndw->setGrab(settings.fullscreen);
  507.       }
  508.       /*
  509.       else if(evt.key.vkey == VKEY_ESCAPE &&
  510.               settings.fullscreen)
  511.       {
  512.         settings.fullscreen = false;
  513.         goto _set_fullscreen;
  514.       }
  515.       */
  516.     } break;
  517.     case KEVENT_WIN_MFOCUS_GAINED: showCursor(0); break;
  518.     case KEVENT_WIN_MFOCUS_LOST  : showCursor(1); break;
  519.     case KEVENT_MOUSE_MOVED: {
  520.       cursor_pos  = shape::point(evt.mouse.x, evt.mouse.y);
  521.       cursor_norm = {(f32)(cursor_pos.x-LOGI_Wh)/LOGI_Wh,
  522.                      (f32)(cursor_pos.y-LOGI_Hh)/LOGI_Hh};
  523.     } break;
  524.     case KEVENT_MOUSE_WHEEL: {
  525.       tile_layer = CLAMP(tile_layer+evt.mouse.dy, 0, 999/*or something*/);
  526.     } break;
  527.     default: kit_logEvent(evt.type);
  528.  
  529.   }
  530.  
  531.   return run;
  532.  
  533. }
  534.  
  535.  
  536.  
  537. //unit should be between 0.0f and 1.0f
  538. u32 unit_to_ryg(f32 unit){
  539.   unit = CLAMP(unit*2.0f, 0.0f, 2.0f);
  540.   u8 red = 255,  green = 255;
  541.  
  542.   #define RYG_RND(_v) (  (unsigned char)( (_v)+0.5f )  )
  543.   if(unit < 1.0f) green = RYG_RND(255.0f*(     unit));
  544.   else            red   = RYG_RND(255.0f*(2.0f-unit));
  545.   #undef RYG_RND
  546.  
  547.   return ABGR_U32(red, green, 0, 255);
  548.  
  549. }
  550.  
  551.  
  552.  
  553. u32 hsv2rgb(f32 H, f32 S, f32 V){
  554.   f32 r, g, b;
  555.  
  556.   f32 h = H / 360; //normalize values
  557.   f32 s = S / 100;
  558.   f32 v = V / 100;
  559.  
  560.   //the rest is magic, idk
  561.   s32 i = floor(h*6);
  562.   f32 f = h * 6 - i;
  563.   f32 p = v * (1.0f -            s);
  564.   f32 q = v * (1.0f -       f  * s);
  565.   f32 t = v * (1.0f - (1.0f-f) * s);
  566.  
  567.   switch (i % 6) {
  568.     case 0: r = v, g = t, b = p; break;
  569.     case 1: r = q, g = v, b = p; break;
  570.     case 2: r = p, g = v, b = t; break;
  571.     case 3: r = p, g = q, b = v; break;
  572.     case 4: r = t, g = p, b = v; break;
  573.     case 5: r = v, g = p, b = q; break;
  574.   }
  575.  
  576.   //it should be impossible for r,g,b to be uninitialized
  577.    //due to how the switch is set up, so the warning can be ignored
  578.   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  579.   #pragma GCC diagnostic push
  580.   return ABGR_U32(r*255, g*255, b*255, 255);
  581.   #pragma GCC diagnostic pop
  582.  
  583. }
  584.  
  585. /******************************************************************************/
  586.  
  587.  
  588.  
  589.  
  590.  
  591. #define PREVENT_RUNNING_WHILE_ZIPPED 1
  592.  
  593. int user_main(int argc, char** argv);
  594.  
  595. int main(int argc, char** argv){
  596.   int returnStatus = -1;
  597.   bool extracted = true;
  598. try {
  599.   u64 timeDelta, timeStartAudio, timeStartAll = time::getMS();
  600.  
  601. #if PREVENT_RUNNING_WHILE_ZIPPED == 1
  602.   //this should hopefully prevent people from executing the program
  603.    //before it's unzipped (in most cases, at least)
  604.   #define EXTRACT_MSG "This program must be ran normally, after being unzipped"
  605.   char cwd[256];
  606.   getcwd(cwd, sizeof(cwd));
  607.   cwd[255] = 0; //just in case
  608.   u32 lastChar = strnLen(cwd)-1;
  609.   if(cwd[lastChar]=='/' || cwd[lastChar]=='\\') cwd[lastChar] = 0;
  610.  
  611.   //first check
  612.   //checks if the program's current working directory is
  613.    //"C:\Users\<name>\AppData" (specific to windows)
  614.   #if defined(_WIN32)
  615.   {
  616.     u32 i = 0,  backSlashCount = 0;
  617.     bool foundUsers = false;
  618.  
  619.     if((cwd[0]|32) == 'c') //(x|32 makes the char x lowercase)
  620.     for(; i<256; ++i){ _start:
  621.  
  622.       if(cwd[i] == '\0') break;
  623.       if(cwd[i] == '\\') ++backSlashCount;
  624.  
  625.       if(backSlashCount == 1){
  626.         if(!strnCmp("Users", &cwd[++i], 5)) foundUsers = true;
  627.         goto _start; //++i should only occur once this iteration
  628.  
  629.       }
  630.  
  631.       if(foundUsers  &&  backSlashCount == 3){
  632.         if(!strnCmp("AppData", &cwd[++i], 7)){
  633.           extracted = false; throw EXTRACT_MSG;
  634.         }
  635.         break;
  636.  
  637.       }
  638.  
  639.     }
  640.  
  641.   }
  642.   #endif /* defined(_WIN32) */
  643.  
  644.   //second check
  645.   //all this does is it clips the executable name from the
  646.    //full path (argv[0]) to compare it to the current working directory
  647.   //(this should work even if argv[0] is something else,
  648.    //since you're supposed to run this program normally anyway)
  649.   if(argc > 0){
  650.     char*  path     = argv[0];
  651.     size_t path_len = strnLen(path);
  652.     s32    i        = path_len-1;
  653.     bool   fwdSlash = false;
  654.  
  655.     if(path_len < 256){
  656.       for(; i>=0; --i){
  657.         fwdSlash = path[i]=='/';
  658.         if(fwdSlash  ||  path[i] == '\\'){ path[i] = 0; break; }
  659.       }
  660.  
  661.       if(i >= 0){
  662.         //throw if the paths are different
  663.         if(strnCmp(path, cwd)){ extracted = false; throw EXTRACT_MSG; }
  664.         //put slash back in case user wants to reference argv[0] too
  665.         path[i] = (fwdSlash) ? '/' : '\\';
  666.       }
  667.  
  668.     }
  669.  
  670.   }
  671. #endif /* PREVENT_RUNNING_WHILE_ZIPPED == 1 */
  672.  
  673.   settings_load();
  674.  
  675.   initSubsystems(KINIT_EVERYTHING);
  676.  
  677. /********************************* AUDIO INIT *********************************/
  678.  
  679.   music_fade.fadeVolume = 0.0f;
  680.  
  681.   AudioDeviceInfo audio_info = audiofunc::getDefaultDevInfo();
  682.   audio_info.sampleFormat = SMPFMT_F32;
  683.   audio_info.numChannels  = 2;
  684.   audio_info.zeroBuffer   = true;
  685.   audio_info.callback     = cb_audio;
  686.   audio_info.userdata     = nullptr;
  687.  
  688.   //(libxmp can only take sample rates between 8kHz and 48kHz)
  689.   audio_info.sampleRate = CLAMP(audio_info.sampleRate, 8000, 48000);
  690.   //actually, for some reason setting audio_info's sampleRate to be lower
  691.    //than 15701 causes _audio.pause() to hang indefinitely (for me at least)
  692.   //tbd: figure out why this happens
  693.   audio_info.sampleRate = MAX(audio_info.sampleRate, 15701);
  694.   sampleRate = audio_info.sampleRate;
  695.  
  696.   AudioDevice _audio(nullptr, audio_info, false);  audio = &_audio;
  697.   _audio.play(); //begin fading in audio
  698.   timeStartAudio = time::getMS();
  699.  
  700.   SoundEngine _sfx(SFX_TRACKS, sampleRate);  sfx = &_sfx;
  701.   _sfx.volumeMaster = settings.sfx_vol;
  702.  
  703.   Xmp _music;  music = &_music;
  704.  
  705.   //65536 elements specifically is chosen, so that even if the number
  706.    //of sample frames given to the audio callback changes somehow,
  707.    //there will always be enough space for copying (sample frame count is u16)
  708.   //(src = 262,144 Bytes, dst = 524,288 Bytes)
  709.   music_buffer_src = (Stereo_s16*)memory::alloc2(65536*sizeof(Stereo_s16));
  710.   music_buffer_dst = (Stereo_f32*)memory::alloc2(65536*sizeof(Stereo_f32));
  711.  
  712.   music_fade.userdata_a = (void*)(u64)sampleRate;
  713.   music_setFadeDelta(); //set fade to its default
  714.  
  715.   /*** SFX INIT ***/
  716.  
  717.   AudioData sfxData_blip1("dat/sfx/blip1_v3.ogg", AudioDataLoadOGG);
  718.   AudioData sfxData_chk1("dat/sfx/chk1_v2.ogg", AudioDataLoadOGG);
  719.  
  720.   sfxData_blip1.volume = 0.20f;
  721.   sfxData_chk1.volume  = 0.20f;
  722.  
  723.   sfxData[0] = &sfxData_blip1;
  724.   sfxData[1] = &sfxData_chk1;
  725.  
  726.   //...
  727.  
  728. /********************************* VIDEO INIT *********************************/
  729.  
  730.   audioIsReady = true;
  731.  
  732. { //<- closes at the end of video cleanup
  733.  
  734.   Window _wndw(WIN_TITLE, WIN_W, WIN_H, WIN_FLAGS|WINFLAG_HIDDEN);  wndw=&_wndw;
  735.   Surface icon_win("dat/img/icon_win.png", SurfaceLoadPNG);
  736.   _wndw.setIcon(icon_win);
  737.  
  738.   Renderer _rndr(_wndw);  rndr = &_rndr;
  739.  
  740.   BFont_Texture _text(_rndr, nullptr, nullptr, GRAY(FF), 16384);  text = &_text;
  741.  
  742.   const clrs::ABGR textColored_colors[TEXTCOLORED_LEN] = {
  743.     0xFF000000, //gray0 (  0)
  744.     0xFF555555, //gray1 ( 85)
  745.     0xFFAAAAAA, //gray2 (170)
  746.     0xFFFFFFFF, //gray3 (255)
  747.     0xFF000080, //redLo
  748.     0xFF0000FF, //redHi
  749.     0xFF008000, //greenLo
  750.     0xFF00FF00, //greenHi
  751.     0xFF800000, //blueLo
  752.     0xFFFF0000, //blueHi
  753.     0xFF808000, //cyanLo
  754.     0xFFFFFF00, //cyanHi
  755.     0xFF800080, //magentaLo
  756.     0xFFFF00FF, //magentaHi
  757.     0xFF008080, //yellowLo
  758.     0xFF00FFFF, //yellowHi
  759.   };
  760.  
  761.   for(u32 i=0; i<TEXTCOLORED_LEN; ++i){
  762.     textColored[i] = new BFont_Texture(_rndr, nullptr, nullptr,
  763.                                        textColored_colors[i], 1024);
  764.   }
  765.  
  766.   Texture _tile_tex(*rndr, "dat/img/tiles.png", SurfaceLoadPNG);
  767.   tile_tex = &_tile_tex;
  768.   tile_init();
  769.  
  770.   Surface im_surf0("dat/img/icon_menu.png", SurfaceLoadPNG);
  771.   Surface im_surf(im_surf0, PIXELFMT_ABGR8888);
  772.  
  773.   Texture _icon_menu(*rndr, im_surf);
  774.   icon_menu = &_icon_menu;
  775.  
  776.   shape::point imi_size = im_surf.getSize();
  777.   clrs::ABGR* pixels     = (clrs::ABGR*)im_surf.getPixelData();
  778.   size_t      pixels_len = imi_size.x*imi_size.y;
  779.   for(size_t i=0; i<pixels_len; ++i)
  780.     pixels[i].v = (pixels[i].a<<24) | (0xFFFFFF-(pixels[i].v&0xFFFFFF));
  781.  
  782.   Texture _icon_menu_inv(*rndr, im_surf);
  783.   icon_menu_inv = &_icon_menu_inv;
  784.  
  785.   //...
  786.  
  787. /********************************* USER MAIN **********************************/
  788.  
  789.   wndw->setFullscreen(settings.fullscreen*FULLSCREEN_MODE);
  790.   wndw->setGrab(settings.fullscreen);
  791.  
  792.   timeDelta = time::getMS()-timeStartAll;
  793.   kit_LogInfo("Initialized in %llums", timeDelta);
  794.  
  795.   //audio's actual fade DELAY is 90ms, whereas the fade in after that is 10ms.
  796.    //so 95 should put the audio at about halfway through the fade in
  797.   timeDelta = time::getMS()-timeStartAudio;
  798.   time::sleep((u32)MAX((s64)(95-timeDelta), 1));
  799.  
  800.   //_wndw.setVisibility(true); //this is generally done by user_main
  801.   std::srand((u32)time::getTicks());
  802.   returnStatus = user_main(argc, argv);
  803.   timeStartAll = time::getMS();
  804.   music_setFadeDelta(0.01);
  805.   music_play(-1);
  806.   _wndw.setFullscreen(false);
  807.   _wndw.setVisibility(false);
  808.  
  809.   _audio.pause(); //begin fading out audio
  810.  
  811. /******************************* VIDEO CLEANUP ********************************/
  812.  
  813. {
  814.  
  815.   //...
  816.  
  817. }
  818.  
  819.   for(u32 i=0; i<TEXTCOLORED_LEN; ++i) NULLDELETE(textColored[i],BFont_Texture);
  820.  
  821. } //garbage collect video init stuff
  822.  
  823. /******************************* AUDIO CLEANUP ********************************/
  824.  
  825.   //audio's actual fadeout is 10ms, so waiting ~12ms total should be enough
  826.   while(_audio.isPlaying()) time::sleep(4);
  827.   _audio.lock(); //just in case
  828.  
  829.   memory::free(&music_buffer_src);
  830.   memory::free(&music_buffer_dst);
  831.  
  832. {
  833.  
  834.   //...
  835.  
  836. }
  837.  
  838.   _audio.unlock();
  839.  
  840.   timeDelta = time::getMS()-timeStartAll;
  841.   kit_LogInfo("Uninitialized in %llums", timeDelta);
  842.  
  843. /************************** CATCH EXCEPTION OR EXIT ***************************/
  844.  
  845. } catch(const char* errorText){
  846.     kit_LogError("FATAL EXCEPTION OCCURRED: \"%s\"\n", errorText);
  847.   #ifndef _DEBUG
  848.     MessageBeep(MB_ICONERROR);
  849.     showMsgBox(errorText, "FATAL EXCEPTION OCCURRED!", MSGBOX_ERROR);
  850.   #endif /* _DEBUG */
  851.   //redundant, as quitSubsystems already does this when given KINIT_EVERYTHING
  852.   //freeThreadErrors();
  853.  
  854. } catch(...){
  855.     kit_LogError("FATAL EXCEPTION OCCURRED: \"(unknown type)\"\n");
  856.   #ifndef _DEBUG
  857.     MessageBeep(MB_ICONERROR);
  858.     showMsgBox("(unknown type)", "FATAL EXCEPTION OCCURRED!", MSGBOX_ERROR);
  859.   #endif /* _DEBUG */
  860. }
  861.  
  862.   if(extracted) settings_save();
  863.  
  864.   //can't error, and is also safe to call even if no subsystems are active!
  865.   quitSubsystems(KINIT_EVERYTHING);
  866.  
  867.   //a nonzero value indicates a memory leak!
  868.   if(memory::getNumAllocations())
  869.     kit_LogWarn("# OF ALLOCATIONS = %llu", memory::getNumAllocations());
  870.  
  871.   return returnStatus;
  872.  
  873. }
  874. /******************************************************************************/
  875. /******************************************************************************/
  876. //"sokoban_and_kit32_2025-01-31\sokoban\src\user_main.cpp":
  877. #include <include_all.hpp>
  878.  
  879. #include <unistd.h> //for getcwd()
  880. #include <cmath> //for fabsf
  881.  
  882. //begone, unused parameter warning
  883. #define UM_RETURN(_val) { (void)argc, (void)argv; return (_val); }
  884.  
  885. using namespace kit;
  886.  
  887.  
  888.  
  889.  
  890.  
  891. #define CONTEXTS_LEN countof(contexts, ctx_callbacks)
  892.  
  893. u32 ctx_which = CTX_MAIN_MENU;
  894.  
  895. ctx_callbacks contexts[]{
  896.   {ctx_main_menu_evt , ctx_main_menu_draw },
  897.   {ctx_lvl_select_evt, ctx_lvl_select_draw},
  898.   {ctx_lvl_editor_evt, ctx_lvl_editor_draw},
  899. };
  900.  
  901.  
  902.  
  903.  
  904.  
  905. shape::point  cursor_pos;  //logical coordinates, not window coords
  906. shape::fpoint cursor_norm; //normal coords (-1, 1) (+y is +y, unlike opengl ndc)
  907. bool          cursor_scroll = true;
  908. bool          cursor_snow   = false;
  909.  
  910. u64 frame_num = 0;
  911.  
  912.  
  913.  
  914. #define threshhold        0.80f
  915. #define scroll_multiplier 0.75f
  916. void update_scroll(){
  917.   shape::fpoint scroll_amnt;
  918.  
  919.   if(fabsf(cursor_norm.x) >= threshhold){
  920.     scroll_amnt.x  = closer_to_0(cursor_norm.x,threshhold) / (1-threshhold);
  921.     scroll_amnt.x *= scroll_multiplier;
  922.     tile_camera.x -= scroll_amnt.x;
  923.  
  924.   }
  925.  
  926.   if(fabsf(cursor_norm.y) >= threshhold){
  927.     scroll_amnt.y  = closer_to_0(cursor_norm.y,threshhold) / (1-threshhold);
  928.     scroll_amnt.y *= scroll_multiplier;
  929.     tile_camera.y -= scroll_amnt.y;
  930.  
  931.   }
  932.  
  933. }
  934.  
  935.  
  936.  
  937.  
  938.  
  939. #define SNOWFLAKES_LEN 128
  940.  
  941. typedef shape::point snowflakes_t;
  942.  
  943. static snowflakes_t snowflakes[SNOWFLAKES_LEN];
  944. static bool         snowflakes_dir[SNOWFLAKES_LEN];
  945.  
  946.  
  947.  
  948. #define chance_to_change_direction (1.0f/8)
  949. void update_snowflakes(){
  950.   if(!(frame_num%10)){
  951.     for(u32 i=0; i<countof(snowflakes, snowflakes_t); ++i)
  952.       if(snowflakes[i].y >= LOGI_H){ snowflakes[i] = cursor_pos; break; }
  953.   }
  954.  
  955.   for(u32 i=0; i<countof(snowflakes, snowflakes_t); ++i){
  956.     if(snowflakes[i].y >= LOGI_H) continue;
  957.     if(frandf()<chance_to_change_direction) snowflakes_dir[i] ^= 1;
  958.     snowflakes[i].x += snowflakes_dir[i]*2-1;
  959.     snowflakes[i].y += 1;
  960.  
  961.   }
  962.  
  963. }
  964.  
  965.  
  966.  
  967.  
  968.  
  969. void clear_snowflakes(){
  970.   for(u32 i=0; i<countof(snowflakes, snowflakes_t); ++i) snowflakes[i].y=LOGI_H;
  971.  
  972. }
  973.  
  974.  
  975.  
  976.  
  977.  
  978. int user_main(int argc, char** argv){
  979.   //music_play(0);
  980.  
  981.   wndw->setMinSize(LOGI_W, LOGI_H);
  982.   rndr->setLogicalSize(LOGI_W, LOGI_H);
  983.   wndw->setVisibility(true);
  984.  
  985.   clear_snowflakes();
  986.  
  987.  
  988.  
  989.   while(true){ _start:
  990.     #ifdef _DEBUG
  991.       u64 ticksStart = time::getTicks();
  992.     #endif /* _DEBUG */
  993.     u64 timeStart = time::getMS();
  994.  
  995.     ctx_callbacks callbacks;
  996.     if(ctx_which<CONTEXTS_LEN) callbacks = contexts[ctx_which];
  997.  
  998.     Event e; s32 result = 1;
  999.     if        (callbacks.handle_events   ) result = callbacks.handle_events();
  1000.     else while(pollEvent(&e) && result==1) result = default_event_handler(e);
  1001.  
  1002.     if(result== 0) break;
  1003.     if(result==-1) goto _start; //context switched; load new callback
  1004.  
  1005.     if(cursor_scroll) update_scroll();
  1006.  
  1007.  
  1008.  
  1009.     rndr->setDrawColor(GRAY(40));
  1010.     rndr->clear();
  1011.  
  1012.     if(callbacks.draw_things) callbacks.draw_things();
  1013.  
  1014.     rndr->setDrawColor(0xffffffff);
  1015.     shape::rect cursor_rect = {cursor_pos.x-1, cursor_pos.y-1, 3, 3};
  1016.     rndr->drawRects(&cursor_rect);
  1017.  
  1018.     if(cursor_snow)
  1019.       rndr->drawPoints(snowflakes, countof(snowflakes, snowflakes_t));
  1020.  
  1021.     #ifdef _DEBUG
  1022.       text->scale = {1,1};
  1023.       f64 secondsDelta = (f64)(time::getTicks()-ticksStart)/time::getTicksPerSecond();
  1024.       text->draw(0,-1,"frame %4llu: %3.0fus", 0,  frame_num, secondsDelta*1000000);
  1025.     #endif
  1026.  
  1027.     rndr->present();
  1028.  
  1029.     if(cursor_snow) update_snowflakes();
  1030.  
  1031.     time::sleep(CLAMP(16-(time::getMS()-timeStart), 1, 16));
  1032.     ++frame_num;
  1033.  
  1034.   }
  1035.  
  1036.   UM_RETURN(0);
  1037.  
  1038. }
  1039.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement