Advertisement
Kitomas

work for 2024-09-27

Sep 27th, 2024
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 74.79 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"sdl2rnd\src\file.cpp":
  4. #include <stdio.h>
  5.  
  6. #include <scene.hpp>
  7. //#include <file.hpp>
  8. //#include <memory.hpp>
  9.  
  10.  
  11. namespace file {
  12.  
  13.  
  14.  
  15.  
  16. bool exists(const char* filePath){
  17.   if(filePath == nullptr) throw "filePath = nullptr";
  18.  
  19.   FILE* file = fopen(filePath, "rb");
  20.   if(file != nullptr){
  21.     fclose(file);
  22.     return true;
  23.  
  24.   } else {
  25.     return false;
  26.  
  27.   }
  28. }
  29.  
  30.  
  31.  
  32.  
  33. s32 getSize(const char* filePath){
  34.   if(!exists(filePath)) throw fstr("file \"%s\" does not exist", filePath);
  35.  
  36.   FILE* file = fopen(filePath, "rb");
  37.   if(file == nullptr) throw "failed to open file";
  38.  
  39.   fseek(file, 0L, SEEK_END);
  40.   s32 fileSize = ftell(file);
  41.  
  42.   fclose(file);
  43.  
  44.   return fileSize;
  45. }
  46.  
  47.  
  48.  
  49.  
  50. }; /* namespace file */
  51.  
  52.  
  53.  
  54.  
  55.  
  56. BinaryData::BinaryData(const char* filePath){
  57.   s64 _fileSize = file::getSize(filePath); //also checks to see if file exists
  58.   size_t fileSize = (size_t)_fileSize;
  59.  
  60.   if(_fileSize <  0          ) throw "file size < 0";
  61.   if(_fileSize == 0          ) throw "file size = 0";
  62.   if(_fileSize >  INT_S32_MAX) throw "file size > INT_MAX";
  63.  
  64.  
  65.   *(char**)&data = (char*)memory::alloc(fileSize);
  66.   if(data == nullptr) throw "failed to allocate memory for data";
  67.  
  68.  
  69.   FILE* file = fopen(filePath, "rb");
  70.   if(file == nullptr) throw "failed to open file";
  71.   size_t bytesRead = fread(data, sizeof(char), fileSize, file);
  72.  
  73.   const char* err_msg = nullptr;
  74.  
  75.   if(bytesRead != fileSize){
  76.     if(       feof(file)) err_msg = "unexpected EOF";
  77.     else if(ferror(file)) err_msg = "failed to read file";
  78.     else                  err_msg = "bytes read != file size";
  79.  
  80.     char* _data = (char*)data;
  81.     memory::free(&_data);
  82.  
  83.   }
  84.  
  85.   fclose(file);
  86.   *(size_t*)&data_len = fileSize;
  87.   if(err_msg != nullptr) throw err_msg;
  88.  
  89. }
  90.  
  91.  
  92.  
  93.  
  94. BinaryData::~BinaryData(){
  95.   char* _data = (char*)data;
  96.   memory::free(&_data);
  97.  
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104. void BinaryData::loadFromMemory(const void* data, size_t dataSize){
  105.   if(!dataSize) throw "dataSize = 0";
  106.  
  107.   char* _data = (char*)data;
  108.   char* _data_new = (char*)memory::realloc(&_data, dataSize);
  109.   if(_data_new == nullptr) throw "failed to allocate memory for data";
  110.  
  111.   if(_data != nullptr) memcpy(_data_new, _data, MIN(dataSize, data_len));
  112.  
  113.   *(char**)data = _data_new;
  114.  
  115. }
  116. /******************************************************************************/
  117. /******************************************************************************/
  118. //"sdl2rnd\src\main.cpp":
  119. #define SDL_MAIN_HANDLED
  120. #include <scene.hpp>
  121.  
  122. int sceneMain(int argc, char** argv);
  123.  
  124.  
  125.  
  126.  
  127.  
  128. int main(int argc, char** argv){
  129.   int returnStatus = -1;
  130.  
  131. try {
  132.  
  133.   //i will uncomment this when my dumb ass gets around to putting in SIMD functionality
  134.   //if(!SDL_HasAVX()) throw "this program requires AVX, which this CPU doesn't support";
  135.  
  136.   if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)<0) throw SDL_GetError();
  137.  
  138.  
  139.  
  140.   //should be redundant, but just in case
  141.   SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
  142.  
  143.  
  144.  
  145.   if(file::exists("geotex.bmp")){
  146.     geometrySrf = SDL_LoadBMP("geotex.bmp");
  147.     if(!geometrySrf) throw SDL_GetError();
  148.   }
  149.   // /*
  150.   else throw "\"geotex.bmp\" does not exist!";
  151.   // */
  152.  
  153.   canvas = new Canvas(WIN_W,WIN_H, CNV_W,CNV_H,
  154.                       WIN_TITLE " " TRAP_PROMPT);
  155.  
  156.   //SDL_ShowWindow(canvas->getWin()); //done inside sceneMain
  157.  
  158.   if(geometrySrf){
  159.     geometryTex = SDL_CreateTextureFromSurface(canvas->getRnd(), geometrySrf);
  160.     if(!geometryTex) throw SDL_GetError();
  161.   }
  162.  
  163.   text_p = new Text("font8x8.bmp");
  164.  
  165.  
  166.   returnStatus = sceneMain(argc, argv);
  167.  
  168.  
  169.   SAFE_DELETE(text_p);
  170.   if(geometryTex) SDL_DestroyTexture(geometryTex);
  171.   delete canvas;
  172.   if(geometrySrf) SDL_FreeSurface(geometrySrf);
  173.  
  174.   scene_ori.freeAll();
  175.   scene_wka.freeAll();
  176.   scene_wkb.freeAll();
  177.  
  178.  
  179.  
  180. } catch(const char* errorText){
  181. #ifdef _DEBUG
  182.   Log("Error = \"%s\"", errorText);
  183. #else
  184.   SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "THE GAME CRASHED!", errorText, nullptr);
  185. #endif
  186. }
  187.  
  188.  
  189.   Log("# OF ALLOCATIONS = %lu", (unsigned)memory::getNumAllocations());
  190.  
  191.   SDL_Quit();
  192.  
  193.   return returnStatus;
  194. }
  195. /******************************************************************************/
  196. /******************************************************************************/
  197. //"sdl2rnd\src\memory.cpp":
  198. #include <stdlib.h>
  199.  
  200. #include <memory.hpp>
  201.  
  202. #ifdef    free
  203. #undef    free
  204. #endif /* free */
  205.  
  206. #ifdef    realloc
  207. #undef    realloc
  208. #endif /* realloc */
  209.  
  210. //turns something into a void**
  211.  //(this makes some code here easier for me to read)
  212. #define VPP(_ptr_p) ((void**)(_ptr_p))
  213.  
  214.  
  215.  
  216.  
  217. static size_t numAllocations = 0;
  218.  
  219.  
  220.  
  221.  
  222. void* memory::alloc(size_t size){
  223.   void* newHeapMemory = malloc(size);
  224.   if(newHeapMemory != nullptr) ++numAllocations;
  225.   return newHeapMemory;
  226.  
  227. }
  228.  
  229.  
  230. void memory::_free_real(void* ptr_p){
  231.   if(VPP(ptr_p) != nullptr  &&  *VPP(ptr_p) != nullptr){
  232.     --numAllocations;
  233.     free(*VPP(ptr_p));
  234.     *VPP(ptr_p) = nullptr;
  235.   }
  236. }
  237.  
  238.  
  239. void* memory::_realloc_real(void* ptr_p, size_t newSize){
  240.   void* ptr_new = nullptr;
  241.  
  242.   if(VPP(ptr_p) != nullptr){
  243.     ptr_new = realloc(*VPP(ptr_p), newSize);
  244.  
  245.     if(ptr_new != nullptr){
  246.       if(*VPP(ptr_p) == nullptr) ++numAllocations;
  247.       *VPP(ptr_p) = ptr_new;
  248.  
  249.     }
  250.   }
  251.  
  252.   return ptr_new;
  253.  
  254. }
  255.  
  256.  
  257.  
  258. size_t memory::getNumAllocations(){
  259.   return numAllocations;
  260.  
  261. }
  262.  
  263.  
  264.  
  265.  
  266. void* memory::allocSIMD(size_t size){
  267.   void* newHeapMemory = SDL_SIMDAlloc(size);
  268.   if(newHeapMemory != nullptr) ++numAllocations;
  269.   return newHeapMemory;
  270.  
  271. }
  272.  
  273.  
  274. void memory::freeSIMD(void* ptr_p){
  275.   if(VPP(ptr_p) != nullptr  &&  *VPP(ptr_p) != nullptr){
  276.     --numAllocations;
  277.     SDL_SIMDFree(*VPP(ptr_p));
  278.     *VPP(ptr_p) = nullptr;
  279.   }
  280. }
  281.  
  282.  
  283. void* memory::reallocSIMD(void* ptr_p, size_t newSize){
  284.   void* ptr_new = nullptr;
  285.  
  286.   if(VPP(ptr_p) != nullptr){
  287.     ptr_new = SDL_SIMDRealloc(*VPP(ptr_p), newSize);
  288.  
  289.     if(ptr_new != nullptr){
  290.       if(*VPP(ptr_p) == nullptr) ++numAllocations;
  291.       *VPP(ptr_p) = ptr_new;
  292.  
  293.     }
  294.   }
  295.  
  296.   return ptr_new;
  297.  
  298. }
  299.  
  300.  
  301.  
  302. size_t memory::getSIMDAlignment(){
  303.   return SDL_SIMDGetAlignment();
  304. }
  305.  
  306.  
  307.  
  308.  
  309.  
  310. #define DONT_USE_AVX
  311.  
  312.  
  313.  
  314.  
  315. void* memory::set(void* _dst, char v, size_t size){
  316. #ifdef DONT_USE_AVX
  317.   return memset(_dst, (int)v, size);
  318. #else
  319.   //tbd
  320.   if(!size) return _dst;
  321.  
  322.   size_t offset_fnt = size
  323.   size_t offset_bck = size
  324.  
  325.   //skip if there's nothing left to set
  326.   if(size >= 32){
  327.     __m256i write_block = _mm256_set1_epi8(v);
  328.  
  329.   }
  330.  
  331.  
  332.   return _dst;
  333.  
  334. #endif
  335. }
  336.  
  337.  
  338.  
  339.  
  340. void* memory::copy(void* dst, const void* src, size_t size){
  341. #ifdef DONT_USE_AVX
  342.   return memcpy(dst, src, size);
  343. #else
  344. #endif
  345. }
  346. /******************************************************************************/
  347. /******************************************************************************/
  348. //"sdl2rnd\src\sceneMain.cpp":
  349. #include <scene.hpp>
  350.  
  351.  
  352. //1 ship, 1 'skybox', 1 gear icon, 1 door, <bullet_count> bullets,
  353.  //4 asteroids, 16 mini-asteroids, and 64 micro-asteroids
  354. #define bullet_count 4
  355. #define asteroid_count (4 + 4*4 + 4*4*4)
  356. MeshSimple* meshes[1 + 1 + 1 + 1 + bullet_count + asteroid_count];
  357. #define     meshes_len (sizeof(meshes)/sizeof(MeshSimple*))
  358.  
  359. #define bullet_offset 4
  360. #define asteroid_offset (bullet_offset+bullet_count)
  361.  
  362. #define _mesh_ship (meshes[0])
  363. #define _mesh_skybox (meshes[1])
  364. #define _mesh_gear (meshes[2])
  365. #define _mesh_door (meshes[3])
  366. #define _mesh_bullet(which) (meshes[bullet_offset+(which)])
  367. #define _mesh_asteroid(which) (meshes[asteroid_offset+(which)])
  368.  
  369. #define mesh_ship (*_mesh_ship)
  370. #define mesh_skybox (*_mesh_skybox)
  371. #define mesh_gear (*_mesh_gear)
  372. #define mesh_door (*_mesh_door)
  373. #define mesh_bullet(which) (*_mesh_bullet(which))
  374. #define mesh_asteroid(which) (*_mesh_asteroid(which))
  375.  
  376. #define asteroid_normal(which) mesh_asteroid(      which )
  377. #define asteroid_mini(which)   mesh_asteroid(4+   (which))
  378. #define asteroid_micro(which)  mesh_asteroid(4+16+(which))
  379. #define asteroid_menu asteroid_micro
  380.  
  381. #define state_normal(which) state.asteroids[      which ]
  382. #define state_mini(which)   state.asteroids[4+   (which)]
  383. #define state_micro(which)  state.asteroids[4+16+(which)]
  384.  
  385. #define bullet_size 0.25f
  386.  
  387. #define nrml_siz 1.00f
  388. #define mini_siz 0.75f
  389. #define mcro_siz 0.50f
  390. #define menu_siz mcro_siz
  391.  
  392. //application of values are as follows:
  393.  //camera's current position = old*mod + new*(1.0f-mod)
  394.  //old = camera's current position
  395. #define camera_mod 0.85f
  396. #define camera_lpf(_member) \
  397.   camera_old._member*camera_mod + camera_new._member*(1.0f-camera_mod)
  398. Location camera_old;
  399. Location camera_cur; //subject to different rules to that of scene_camera
  400. Location camera_new;
  401.  
  402. #define bullet_speed 0.60f
  403. #define ship_speed_x 0.15f
  404. #define ship_speed_y 0.15f
  405. #define ship_speed_z 0.15f
  406.  
  407. #define ship_camera_distance    1.3f
  408. #define ship_camera_y_offset    0.25f
  409. #define ship_camera_down_tilt   0.02f
  410. #define ship_decay_multiplier_a 0.88f
  411. #define ship_decay_multiplier_b 0.5f
  412.  
  413.  
  414.  
  415.  
  416.  
  417. #define CFG_FILENAME "./config.bin"
  418. #define CFG_VERSION 5
  419.  
  420. struct _cfg_s {
  421.   int version = CFG_VERSION;
  422.  
  423.   float high_score = 0.0f;
  424.  
  425.   #define BIND_COUNT 6
  426.   SDL_Scancode bind_right   = SDL_SCANCODE_D;
  427.   SDL_Scancode bind_left    = SDL_SCANCODE_A;
  428.   SDL_Scancode bind_forward = SDL_SCANCODE_W;
  429.   SDL_Scancode bind_back    = SDL_SCANCODE_S;
  430.   SDL_Scancode bind_up      = SDL_SCANCODE_LSHIFT;
  431.   SDL_Scancode bind_down    = SDL_SCANCODE_LCTRL;
  432.  
  433.   int win_w = WIN_W,  win_h = WIN_H;
  434.  
  435.   float lastrand = 0.9f; //used to modify srand when starting a game
  436.  
  437.   //maximum number of normal asteroids that can exist at once
  438.   //(takes into account mini and micro asteroids,
  439.    //assuming one or more normal ones have split)
  440.   int num_asteroids = 4;
  441.  
  442.   float sensitivity = 1.0f; //mouse look sensitivity
  443.  
  444.   bool invert_y = false; //inverts vertical mouse input
  445.  
  446.   bool maximized = false;
  447.   bool fullscreen = false;
  448.  
  449. };
  450.  
  451. _cfg_s cfg;
  452.  
  453. //WEIRD POINTER STUFF LMAOOO
  454. SDL_Scancode* bind_array = (SDL_Scancode*)(&cfg.high_score+1);
  455. SDL_Scancode  bind_array_defaults[BIND_COUNT];
  456.  
  457. const char* bind_names[] = {
  458.   "right",
  459.   "left",
  460.   "forward",
  461.   "back",
  462.   "up",
  463.   "down",
  464. };
  465.  
  466.  
  467.  
  468. #define MENU_REBINDING -3
  469. #define MENU_DEAD      -2
  470. #define MENU_PLAYING   -1
  471. #define MENU_QUIT       0
  472. #define MENU_PLAY       1
  473. #define MENU_ASTEROIDS  2
  474. #define MENU_REBIND     3
  475.  
  476. #define MENU_MAX        MENU_REBIND
  477.  
  478. struct bulletElement {
  479.   Vec3    vel = {0,0,0};
  480.   bool active = false;
  481. };
  482.  
  483. enum asteroidTypeEnum { ATYPE_NORMAL = 0, ATYPE_MINI, ATYPE_MICRO, };
  484.  
  485. struct asteroidElement {
  486.   asteroidElement* children = nullptr;
  487.   Vec3                  vel = {0,0,0};
  488.   char            parent_id = -1;
  489.   char      children_active = -1;
  490.   char                 type = -1; //asteroidTypeEnum
  491.   bool               active = false;
  492. };
  493.  
  494. struct _state_s {
  495.   bulletElement bullets[bullet_count];
  496.   int active_bullets = 0;
  497.  
  498.   asteroidElement asteroids[asteroid_count];
  499.   int active_asteroids = 0;
  500.  
  501.   int menu = MENU_PLAY;
  502.  
  503.   int which_rebind = 0;
  504.  
  505.   bool pressed_right   = false;
  506.   bool pressed_left    = false;
  507.   bool pressed_forward = false;
  508.   bool pressed_back    = false;
  509.   bool pressed_up      = false;
  510.   bool pressed_down    = false;
  511.  
  512.   bool quit = false;
  513.  
  514. };
  515.  
  516. _state_s state;
  517.  
  518. bool* pressed_array = (bool*)(&state.which_rebind+1);
  519.  
  520.  
  521.  
  522.  
  523.  
  524. #define skybox_bounds ((CLIP_FAR/32) - 1.0f)
  525. static inline bool keepInBounds(Location& loc){
  526.   bool wrappedAround = false;
  527.   if(fabsf(loc.x)>skybox_bounds){ loc.x = (1-2*(loc.x>=0))*skybox_bounds; wrappedAround = true; }
  528.   if(fabsf(loc.y)>skybox_bounds){ loc.y = (1-2*(loc.y>=0))*skybox_bounds; wrappedAround = true; }
  529.   if(fabsf(loc.z)>skybox_bounds){ loc.z = (1-2*(loc.z>=0))*skybox_bounds; wrappedAround = true; }
  530.   return wrappedAround;
  531. }
  532.  
  533.  
  534.  
  535. template<class T> inline T umod(T a, int b){
  536.   a %= b;
  537.   if(a < 0) a += b;
  538.   return a;
  539. }
  540.  
  541.  
  542.  
  543. #define SQR(thing) ((thing)*(thing))
  544.  
  545. static inline float locHypot(const Location& loc){
  546.   return sqrtf(SQR(loc.x)+SQR(loc.y)+SQR(loc.z));
  547. }
  548.  
  549. static inline float locDistance(const Location& l_a, const Location& l_b){
  550.   return sqrtf(SQR(l_b.x-l_a.x)+SQR(l_b.y-l_a.y)+SQR(l_b.z-l_a.z));
  551. }
  552.  
  553.  
  554.  
  555. //assumes RAND_MAX is 32767
  556. static inline float randf(){
  557.   return (float)(rand()<<15|rand())/0x3fffffff;
  558. }
  559.  
  560. static inline float randf2(){
  561.   return randf()*2.0f - 1.0f;
  562. }
  563.  
  564.  
  565.  
  566.  
  567.  
  568. bool cursorIsTrapped = false;
  569. void trapCursor(bool enable){
  570.   if(enable == cursorIsTrapped) return;
  571.   SDL_SetWindowTitle(canvas->getWin(), fstr(WIN_TITLE " %s", (enable) ? UNTRAP_PROMPT : TRAP_PROMPT));
  572.   if(SDL_SetRelativeMouseMode((enable) ? SDL_TRUE : SDL_FALSE)<0) throw SDL_GetError();
  573.   cursorIsTrapped = enable;
  574. }
  575.  
  576.  
  577. void setFullscreen(bool enable){
  578.   SDL_SetWindowFullscreen(canvas->getWin(), (enable) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
  579.   cfg.fullscreen = enable;
  580. }
  581.  
  582.  
  583.  
  584.  
  585.  
  586. void mouseMoved(s32 dx, s32 dy);
  587. void mouseButton(u8 button, bool clicked);
  588. void keyPress(SDL_Keysym key, bool pressed, u16 modifiers);
  589.  
  590. //returns false if state.quit gets flipped
  591. bool handleEvents(){
  592.   SDL_Event evt;
  593.   while(SDL_PollEvent(&evt))
  594.   switch(evt.type){
  595.     case SDL_QUIT: state.quit = true; SDL_ShowCursor(true); return false;
  596.     case SDL_WINDOWEVENT: {
  597.       switch(evt.window.event){
  598.         case SDL_WINDOWEVENT_FOCUS_LOST: trapCursor(false); break;
  599.         case SDL_WINDOWEVENT_RESIZED: cfg.win_w = evt.window.data1, cfg.win_h = evt.window.data2; break;
  600.         case SDL_WINDOWEVENT_RESTORED: cfg.maximized = false; break;
  601.         case SDL_WINDOWEVENT_MAXIMIZED: cfg.maximized = true; break;
  602.         default: ;//Log("%X", evt.window.event);
  603.       }
  604.     } break;
  605.     case SDL_KEYDOWN: {
  606.       if(evt.key.repeat) break;
  607.       if(evt.key.keysym.sym == SDLK_ESCAPE){ trapCursor(false); break; }
  608.       if(evt.key.keysym.sym == SDLK_F11){ setFullscreen(!cfg.fullscreen); break; }
  609.     } SDL_FALLTHROUGH;
  610.     case SDL_KEYUP: {
  611.       keyPress(evt.key.keysym,
  612.                (evt.key.state == SDL_PRESSED) ? true : false,
  613.                evt.key.keysym.mod);
  614.     } break;
  615.     case SDL_MOUSEBUTTONDOWN:{
  616.       if(cursorIsTrapped)
  617.         mouseButton(evt.button.button, evt.button.state == SDL_PRESSED);
  618.       if(evt.button.button == SDL_BUTTON_LEFT)
  619.         trapCursor(true);
  620.     } break;
  621.     case SDL_MOUSEMOTION: {
  622.       if(cfg.invert_y) evt.motion.yrel = -evt.motion.yrel;
  623.       if(cursorIsTrapped) mouseMoved(evt.motion.xrel, evt.motion.yrel);
  624.     } break;
  625.  
  626.     default: ;//Log("%X", evt.type);
  627.   }
  628.  
  629.   return !state.quit;
  630.  
  631. }
  632.  
  633.  
  634.  
  635.  
  636.  
  637. Vec3 rotatePRY(float pitch, float roll, float yaw,
  638.                float   x_0, float  y_0, float z_0)
  639. {
  640.   const float cosPitch = cosf(pitch);
  641.   const float sinPitch = sinf(pitch);
  642.   const float cosRoll  = cosf(roll );
  643.   const float sinRoll  = sinf(roll );
  644.   const float cosYaw   = cosf(yaw  );
  645.   const float sinYaw   = sinf(yaw  );
  646.  
  647.   float y_1 = cosPitch*y_0 - sinPitch*z_0;
  648.   float z_1 = sinPitch*y_0 + cosPitch*z_0;
  649.  
  650.   float x_2 = cosRoll*x_0 - sinRoll*y_1;
  651.   float y_2 = sinRoll*x_0 + cosRoll*y_1;
  652.  
  653.   float x_3 =  cosYaw*x_2 + sinYaw*z_1;
  654.   float z_2 = -sinYaw*x_2 + cosYaw*z_1;
  655.  
  656.   return Vec3(x_3, y_2, z_2);
  657.  
  658. }
  659.  
  660. //motion is relative to camera's current direction
  661. static inline void moveCamera(float x_0, float y_0, float z_0){
  662.   Vec3 motion = rotatePRY(-camera_cur.pitch,
  663.                           -camera_cur.roll,
  664.                           -camera_cur.yaw,
  665.                           x_0, y_0, z_0);
  666.  
  667.   camera_cur.x += motion.x;
  668.   camera_cur.y += motion.y;
  669.   camera_cur.z += motion.z;
  670.  
  671. }
  672.  
  673. bool fireBullet(){
  674.   if(state.active_bullets >= bullet_count) return false; //max bullets reached
  675.  
  676.   int which = -1;
  677.   for(int i=0; i<bullet_count; ++i){
  678.     if(!state.bullets[i].active){ which = i; break; }
  679.   }
  680.   if(which == -1)
  681.     throw "could not find empty spot in bullet queue, despite active bullets being < maximum"; //return false;
  682.  
  683.  
  684.   Vec3 direction = rotatePRY(-camera_cur.pitch,
  685.                              -camera_cur.roll,
  686.                              -camera_cur.yaw,
  687.                              0.0f, 0.0f, 1.0f);
  688.  
  689.  
  690.   mesh_bullet(which).p.x     = -camera_cur.x + direction.x;
  691.   mesh_bullet(which).p.y     = -camera_cur.y + direction.y;
  692.   mesh_bullet(which).p.z     = -camera_cur.z + direction.z;
  693.   mesh_bullet(which).p.pitch = -camera_cur.pitch;
  694.   mesh_bullet(which).p.roll  = -camera_cur.roll;
  695.   mesh_bullet(which).p.yaw   = -camera_cur.yaw;
  696.  
  697.  
  698.   state.bullets[which].vel  = direction;
  699.   state.bullets[which].vel *= bullet_speed;
  700.  
  701. //lol
  702. #pragma GCC diagnostic push
  703. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  704.   state.bullets[which].active = true;
  705. #pragma GCC diagnostic pop
  706.  
  707.  
  708.   ++state.active_bullets;
  709.  
  710.   return true;
  711.  
  712. }
  713.  
  714.  
  715.  
  716.  
  717.  
  718. #define max_asteroid_speed 0.1
  719. void asteroidCreate(int which){
  720.   Location newloc = mesh_asteroid(which).p;
  721.  
  722.   do {
  723.     newloc.x = randf()*skybox_bounds*2 - skybox_bounds;
  724.     newloc.y = randf()*skybox_bounds*2 - skybox_bounds;
  725.     newloc.z = randf()*skybox_bounds*2 - skybox_bounds;
  726.   } while( locDistance(newloc, camera_cur) < (skybox_bounds/3) );
  727.  
  728.  
  729.   float max_type_speed = max_asteroid_speed*(1+state.asteroids[which].type);
  730.   mesh_asteroid(which).p = newloc;
  731.   state.asteroids[which].vel.x  = randf2() * max_type_speed;
  732.   state.asteroids[which].vel.y  = randf2() * max_type_speed;
  733.   state.asteroids[which].vel.z  = randf2() * max_type_speed;
  734.   state.asteroids[which].active = true;
  735.  
  736. }
  737.  
  738.  
  739.  
  740. void asteroidSplit(int which){
  741. /*
  742.   asteroidElement* ast = state.asteroids[which];
  743.  
  744.   while(ast->children){
  745.  
  746.   }
  747. */
  748.  
  749.   /*
  750.   if(ast->type == ATYPE_MICRO){
  751.     ast->
  752.  
  753.   } else if(ast->type == ATYPE_MINI){
  754.  
  755.  
  756.   } else {
  757.  
  758.  
  759.   }*/
  760.  
  761. }
  762.  
  763.  
  764.  
  765.  
  766.  
  767. //
  768.  
  769.  
  770.  
  771.  
  772.  
  773. #define mdelta_divisor_a 200
  774. #define mdelta_divisor_b 200
  775. #define mdelta_divisor_c 1000
  776.  
  777. void mouseMoved(s32 dx, s32 dy){
  778.   if(state.menu != MENU_PLAYING) return;
  779.  
  780.   #define rotmod(value) fmodf(value, _2pi)
  781.   #define rotclamp(value) CLAMP(value, -_pi, _pi)
  782.   #define rotclamph(value) CLAMP(value, -(_pi/2), (_pi/2))
  783.  
  784.   camera_cur.yaw   = rotmod(   camera_cur.yaw  -((float)dx/mdelta_divisor_a)*cfg.sensitivity);
  785.   camera_cur.pitch = rotclamph(camera_cur.pitch+((float)dy/mdelta_divisor_a)*cfg.sensitivity);
  786.  
  787.   mesh_ship.p.roll  = rotclamph(mesh_ship.p.roll -((float)dx/mdelta_divisor_b)*cfg.sensitivity);
  788.   mesh_ship.p.pitch = rotclamph(mesh_ship.p.pitch-((float)dy/mdelta_divisor_b)*cfg.sensitivity);
  789.  
  790. }
  791.  
  792.  
  793.  
  794.  
  795.  
  796. void mouseButton(u8 button, bool clicked){
  797.   if(state.menu != MENU_PLAYING) return;
  798.  
  799.   if(button == SDL_BUTTON_LEFT  &&  clicked) fireBullet();
  800.  
  801. }
  802.  
  803.  
  804.  
  805.  
  806.  
  807. static inline bool bindingIsValid(SDL_Scancode scancode, unsigned index){
  808.   if(index > INT_S32_MAX) //just in case
  809.     throw "bindingIsValid(): index > 2147483647";
  810.  
  811.   //bindings shouldn't share the same scancode,
  812.    //so check current bindings until right before current index (not BIND_COUNT)
  813.   for(unsigned i=0; i<index; ++i) //loop shouldn't start at all if index is 0
  814.     if(bind_array[i] == scancode) return false;
  815.  
  816.   return true;
  817.  
  818. }
  819.  
  820.  
  821. void keyPress(SDL_Keysym key, bool pressed, u16 modifiers){
  822.   //Log("0x%02X, %i, 0x%04X", key.scancode, pressed, modifiers);
  823.  
  824.   if(state.menu == MENU_PLAYING){
  825.     for(unsigned i=0; i<BIND_COUNT; ++i){
  826.       if(key.scancode == bind_array[i])
  827.         pressed_array[i] = pressed;
  828.     }
  829.  
  830.     if(pressed){
  831.       if(key.sym == SDLK_SPACE    ) fireBullet();
  832.       if(key.sym == SDLK_BACKSPACE) state.menu = MENU_PLAY;
  833.     }
  834.  
  835.  
  836.   } else if(state.menu == MENU_REBINDING){
  837.     if(!pressed) return;
  838.     if(key.sym == SDLK_RETURN  ||  key.sym == SDLK_SPACE) return;
  839.     if( key.sym == SDLK_UP    ||  key.sym == SDLK_DOWN  ||
  840.         key.sym == SDLK_LEFT  ||  key.sym == SDLK_RIGHT )
  841.     {
  842.       return;
  843.     }
  844.  
  845.     if(key.sym == SDLK_BACKSPACE){
  846.       for(int i=0; i<BIND_COUNT; ++i) bind_array[i] = bind_array_defaults[i];
  847.       state.menu = MENU_REBIND;
  848.       return;
  849.     }
  850.  
  851.     if(bindingIsValid(key.scancode, state.which_rebind)){
  852.       bind_array[state.which_rebind] = key.scancode;
  853.       ++state.which_rebind;
  854.     }
  855.  
  856.     if(state.which_rebind >= BIND_COUNT) state.menu = MENU_REBIND;
  857.  
  858.  
  859.   } else if(state.menu >= 0){
  860.     if(!pressed) return;
  861.  
  862.     if(key.sym == SDLK_RETURN  ||  key.sym == SDLK_SPACE){
  863.       switch(state.menu){
  864.         case MENU_QUIT     : state.quit = true; break;
  865.         case MENU_PLAY     : state.menu = MENU_PLAYING; break;
  866.         case MENU_ASTEROIDS: cfg.num_asteroids = cfg.num_asteroids%4+1; break;
  867.         case MENU_REBIND   : state.menu = MENU_REBINDING; state.which_rebind = 0; break;
  868.         default:;
  869.       }
  870.  
  871.     } else if(key.scancode == cfg.bind_left  ||  key.scancode == SDL_SCANCODE_LEFT){
  872.       state.menu = umod(state.menu-1, MENU_MAX+1);
  873.  
  874.     } else if(key.scancode == cfg.bind_right  ||  key.scancode == SDL_SCANCODE_RIGHT){
  875.       state.menu = umod(state.menu+1, MENU_MAX+1);
  876.  
  877.     } else switch(state.menu){
  878. #ifdef _DEBUG
  879.       case MENU_QUIT: {
  880.         if(key.scancode == SDL_SCANCODE_RSHIFT) mesh_ship.p.yaw = 0.0f;
  881.       } break;
  882. #endif
  883.       case MENU_ASTEROIDS: {
  884.         if(key.scancode == cfg.bind_back  ||  key.scancode == SDL_SCANCODE_DOWN)
  885.           cfg.num_asteroids = MAX(cfg.num_asteroids-1, 1);
  886.         else if(key.scancode == cfg.bind_forward  ||  key.scancode == SDL_SCANCODE_UP)
  887.           cfg.num_asteroids = MIN(cfg.num_asteroids+1, 4);
  888.       } break;
  889.       default:;
  890.  
  891.     }
  892.  
  893.  
  894.   } else {
  895.  
  896.  
  897.   }
  898.  
  899. }
  900.  
  901.  
  902.  
  903.  
  904.  
  905. int sceneMain(int argc, char** argv){
  906.  
  907. /************************************ INIT ************************************/
  908.  
  909.   _mesh_ship   = new MeshSimple("ship.obj");
  910.   _mesh_skybox = new MeshSimple("skybox.obj");
  911.   _mesh_gear   = new MeshSimple("gear.obj");
  912.   _mesh_door   = new MeshSimple("door.obj");
  913.   for(unsigned i=0; i<bullet_count; ++i)
  914.     _mesh_bullet(i) = new MeshSimple("bullet.obj");
  915.   for(unsigned i=0; i<asteroid_count; ++i)
  916.     _mesh_asteroid(i) = new MeshSimple("asteroid.obj");
  917.  
  918.   for(int i=0; i<BIND_COUNT; ++i)
  919.     bind_array_defaults[i] = bind_array[i];
  920.  
  921.   cfg.version = CFG_VERSION;
  922.  
  923.   if(file::exists(CFG_FILENAME)){
  924.     BinaryData _cfg_file(CFG_FILENAME);
  925.     _cfg_s* cfg_file = (_cfg_s*)_cfg_file.data;
  926.  
  927.     //always make sure high score carries over, since i won't be changing its
  928.      //placement between changes to the overall structure of _cfg_s
  929.     cfg.high_score = cfg_file->high_score;
  930.  
  931.     if( _cfg_file.data_len == sizeof(cfg)  &&
  932.          cfg_file->version == cfg.version  )
  933.     {
  934.       cfg = *cfg_file;
  935.     }
  936.  
  937.   }
  938.  
  939.   sceneRebuild(meshes, meshes_len);
  940.  
  941.   for(unsigned i=0; i<bullet_count; ++i) mesh_bullet(i).p.scale = bullet_size;
  942.  
  943.   for(unsigned i=0; i< 4; ++i) mesh_asteroid(     i).p.scale = nrml_siz; //normal
  944.   for(unsigned i=0; i<16; ++i) mesh_asteroid(   4+i).p.scale = mini_siz; //mini
  945.   for(unsigned i=0; i<64; ++i) mesh_asteroid(16+4+i).p.scale = mcro_siz; //micro
  946.  
  947.   state.menu = -1;
  948.  
  949.   if(cfg.maximized) SDL_MaximizeWindow(canvas->getWin());
  950.   else SDL_SetWindowSize(canvas->getWin(), cfg.win_w, cfg.win_h);
  951.   setFullscreen(cfg.fullscreen);
  952.  
  953.   SDL_ShowWindow(canvas->getWin());
  954.   canvas->clear();
  955.   canvas->present(0);
  956.  
  957.  
  958.   Uint64 startTime;
  959.   SDL_RWops* cfg_file;
  960.  
  961.   float viewport_fov = 75; //degrees of vertical field of view
  962.   float viewport_mod = tan(viewport_fov/(360.0f/_pi));
  963.   SDL_Rect crosshair = {CNV_W/2-1, CNV_H/2-1, 2, 2};
  964.  
  965.  
  966.   for(int n=0; n<4; ++n){
  967.     state_normal(n).children        = &state_mini(n*4);
  968.     state_normal(n).vel             = Vec3(0.0f, 0.0f, 0.0f);
  969.     state_normal(n).parent_id       = -1;
  970.     state_normal(n).children_active = 0;
  971.     state_normal(n).type            = ATYPE_NORMAL;
  972.     state_normal(n).active          = false;
  973.   }
  974.  
  975.   for(int m=0; m<16; ++m){
  976.     state_mini(m).children        = &state_micro(m*4);
  977.     state_mini(m).vel             = Vec3(0.0f, 0.0f, 0.0f);
  978.     state_mini(m).parent_id       = m>>2;
  979.     state_mini(m).children_active = 0;
  980.     state_mini(m).type            = ATYPE_MINI;
  981.     state_mini(m).active          = false;
  982.   }
  983.  
  984.   for(int u=0; u<64; ++u){
  985.     state_micro(u).children        = nullptr;
  986.     state_micro(u).vel             = Vec3(0.0f, 0.0f, 0.0f);
  987.     state_micro(u).parent_id       = 4 + (u>>2);
  988.     state_micro(u).children_active = -1;
  989.     state_micro(u).type            = ATYPE_MICRO;
  990.     state_micro(u).active          = false;
  991.   }
  992.  
  993.  
  994.  
  995.  
  996.  
  997. /**********************************/ _MENU: /**********************************/
  998.  
  999.   #define menu_mesh_spacing 3.0f
  1000.  
  1001.   memory::set(&scene_camera, 0, sizeof(scene_camera));
  1002.   scene_camera.scale = 1.0f/16;
  1003.   scene_camera.pitch = 0.3f;
  1004.   scene_camera.y     = 0.25f;
  1005.   scene_camera.z     = -0.25f;
  1006.  
  1007.   memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
  1008.   mesh_ship.p.scale =  1.0f;
  1009.   mesh_ship.p.x     = menu_mesh_spacing*MENU_PLAY;
  1010.   mesh_ship.p.z     =  1.0f;
  1011.  
  1012.   memory::set(&mesh_skybox.p, 0, sizeof(mesh_skybox.p));
  1013.  
  1014.   memory::set(&mesh_gear.p, 0, sizeof(mesh_gear.p));
  1015.   mesh_gear.p.scale = 1.0f;
  1016.   mesh_gear.p.x     = menu_mesh_spacing*MENU_REBIND;
  1017.   mesh_gear.p.z     = 1.0f;
  1018.  
  1019.   memory::set(&mesh_door.p, 0, sizeof(mesh_door.p));
  1020.   mesh_door.p.scale = 1.0f;
  1021.   mesh_door.p.x     = menu_mesh_spacing*MENU_QUIT;
  1022.   mesh_door.p.z     = 1.0f;
  1023.  
  1024.   for(unsigned i=0; i<bullet_count; ++i){
  1025.     mesh_bullet(i).p.y = CLIP_FAR*2;
  1026.     state.bullets[i].active = false;
  1027.   }
  1028.  
  1029.   state.active_bullets = 0;
  1030.  
  1031.   for(unsigned i=0; i<asteroid_count; ++i){
  1032.     mesh_asteroid(i).p.x = menu_mesh_spacing*MENU_ASTEROIDS;
  1033.     mesh_asteroid(i).p.y = CLIP_FAR*2;
  1034.     mesh_asteroid(i).p.z = 1.0f;
  1035.   }
  1036.  
  1037.   asteroid_menu(0).p.x += -menu_siz/2; //bottom-left
  1038.   asteroid_menu(0).p.y  = -menu_siz/2;  //
  1039.  
  1040.   asteroid_menu(1).p.x +=  menu_siz/2; //bottom-right
  1041.   asteroid_menu(1).p.y  = -menu_siz/2;  //
  1042.  
  1043.   asteroid_menu(2).p.x += -menu_siz/2; //top-left
  1044.   asteroid_menu(2).p.y  =  menu_siz/2;  //
  1045.  
  1046.   asteroid_menu(3).p.x +=  menu_siz/2; //top-right
  1047.   asteroid_menu(3).p.y  =  menu_siz/2;  //
  1048.  
  1049.  
  1050.  
  1051.   if(state.menu < 0) state.menu = MENU_PLAY;
  1052.  
  1053.   camera_old.x   = menu_mesh_spacing * state.menu;
  1054.   camera_new.x   = camera_old.x;
  1055.   scene_camera.x = camera_old.x;
  1056.  
  1057.   while(!state.quit && state.menu != MENU_PLAYING){
  1058.     startTime = SDL_GetTicks64();
  1059.     if(!handleEvents()) break;
  1060.  
  1061.  
  1062.     if(state.menu >= 0){
  1063.       mesh_ship.p.yaw += _2pi/60/8;
  1064.       mesh_gear.p.yaw  = mesh_ship.p.yaw;
  1065.       mesh_door.p.yaw  = mesh_ship.p.yaw;
  1066.       for(unsigned i=0; i<4; ++i)
  1067.         asteroid_menu(i).p.yaw = mesh_ship.p.yaw;
  1068.  
  1069.       camera_new.x   = menu_mesh_spacing * state.menu;
  1070.       scene_camera.x = camera_lpf(x);
  1071.       camera_old.x   = scene_camera.x;
  1072.  
  1073.       asteroid_menu(0).p.z = (cfg.num_asteroids >= 1) ? 1.0f : -100.0f;
  1074.       asteroid_menu(1).p.z = (cfg.num_asteroids >= 2) ? 1.0f : -100.0f;
  1075.       asteroid_menu(2).p.z = (cfg.num_asteroids >= 3) ? 1.0f : -100.0f;
  1076.       asteroid_menu(3).p.z = (cfg.num_asteroids >= 4) ? 1.0f : -100.0f;
  1077.  
  1078.       //putting this in this code block technically causes a graphical glitch
  1079.        //where the framebuffer elements related to geometry gradually fade
  1080.        //out when rebinding controls, but i'll include it until something
  1081.        //inexplicably breaks, just because the effect looks so cool
  1082.       scene_wka.setAll(scene_ori);
  1083.       for(unsigned i=0; i<meshes_len; ++i)
  1084.         if(meshes[i]) sceneApplyTransform(meshes[i]);
  1085.       sceneApplyTransform(nullptr);
  1086.       //(to fix this, simply move the previous 4 lines out of this code block)
  1087.  
  1088.     }
  1089.  
  1090.  
  1091.     canvas->clear();
  1092.     sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
  1093.  
  1094.     #define text_margin (16/(CNV_DIV))
  1095.     text_box(CENTER_TEXT, text_margin, 0, WIN_TITLE);
  1096.  
  1097.     switch(state.menu){
  1098.       case MENU_QUIT     : {
  1099.         //text_box(CENTER_TEXT, CENTER_TEXT, 0, "(there's supposed to be a\nspinning door here, but i\nhaven't modeled that yet)");
  1100.         text_box(CENTER_TEXT, -text_margin-1, 0,
  1101.                  "           \n-     QUIT GAME     >\n");
  1102.       } break;
  1103.       case MENU_PLAY     : {
  1104.         text_box(CENTER_TEXT, -text_margin-1, 0,
  1105.                  "           \n<    START GAME     >\n");
  1106.       } break;
  1107.       case MENU_ASTEROIDS: {
  1108.         textf_box(CENTER_TEXT, -text_margin-1,
  1109.                   "                  ^\n< # OF ASTEROIDS: %i >\n                  V", cfg.num_asteroids);
  1110.       } break;
  1111.       case MENU_REBIND   : {
  1112.         text_box(CENTER_TEXT, -text_margin-1, 0,
  1113.                  "                 \n<  REBIND CONTROLS  -\n");
  1114.       } break;
  1115.       case MENU_REBINDING: {
  1116.         textf_box(CENTER_TEXT, CENTER_TEXT,
  1117.                   "Press a key for \"%s\"\n(backspace will reset all bindings to their defaults!)", bind_names[state.which_rebind]);
  1118.       } break;
  1119.       default:;
  1120.     }
  1121.  
  1122.     canvas->present((unsigned)(MAX(1, (16-(int)(SDL_GetTicks64()-startTime)) )));
  1123.  
  1124.  
  1125.   }
  1126.  
  1127.   if(state.quit) goto _QUIT;
  1128.  
  1129.  
  1130.  
  1131.   while(!cursorIsTrapped){
  1132.     if(!handleEvents()) break;
  1133.     text_box(CENTER_TEXT, CENTER_TEXT, 0, "(click in the window to start)");
  1134.     canvas->present(16);
  1135.   }
  1136.  
  1137.   srand((unsigned)( SDL_GetTicks64() + (unsigned)(cfg.lastrand*10000) ));
  1138.   cfg.lastrand = randf();
  1139.  
  1140.   if(!state.quit) goto _GAME;
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146. /**********************************/ _QUIT: /**********************************/
  1147.  
  1148.   cfg_file = SDL_RWFromFile(CFG_FILENAME, "wb");
  1149.   if(!cfg_file) throw SDL_GetError();
  1150.   if(SDL_RWwrite(cfg_file, &cfg, 1, sizeof(cfg))<sizeof(cfg)) throw SDL_GetError();
  1151.   if(SDL_RWclose(cfg_file)<0) throw SDL_GetError();
  1152.  
  1153.   for(unsigned i=0; i<meshes_len; ++i)
  1154.     SAFE_DELETE(meshes[i]);
  1155.  
  1156.   return 0;
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162. /**********************************/ _GAME: /**********************************/
  1163.  
  1164.   mesh_skybox.p.scale  = skybox_bounds*2;
  1165.   mesh_gear.p.scale    = 0.0f;
  1166.   mesh_door.p.scale    = 0.0f;
  1167.   asteroid_menu(0).p.y = CLIP_FAR*2;
  1168.   asteroid_menu(1).p.y = CLIP_FAR*2;
  1169.   asteroid_menu(2).p.y = CLIP_FAR*2;
  1170.   asteroid_menu(3).p.y = CLIP_FAR*2;
  1171.  
  1172.   memory::set(&camera_old, 0, sizeof(camera_old));
  1173.   memory::set(&camera_cur, 0, sizeof(camera_cur));
  1174.   memory::set(&camera_new, 0, sizeof(camera_new));
  1175.   memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
  1176.   mesh_ship.p.scale = 1.0f;
  1177.  
  1178.   scene_camera.yaw   = 0.0f;
  1179.   scene_camera.pitch = ship_camera_down_tilt;
  1180.   scene_camera.roll  = 0.0f;
  1181.   scene_camera.x     = 0.0f;
  1182.   scene_camera.y     = ship_camera_y_offset;
  1183.   scene_camera.z     = -ship_camera_distance;
  1184.  
  1185.   unsigned ship_offset = mesh_ship.verts_len;
  1186.   unsigned num_normal  = cfg.num_asteroids   ;
  1187.   unsigned num_mini    = cfg.num_asteroids* 4;
  1188.   unsigned num_micro   = cfg.num_asteroids*16;
  1189.  
  1190.   state.active_asteroids = 0;
  1191.   for(int i=0; i<asteroid_count; ++i) state.asteroids[i].active = false;
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.   _out_of_game_loop: //jumped to for the purpose of forcefully breaking the loop
  1198.   while(!state.quit  &&  state.menu == MENU_PLAYING){
  1199.     startTime = SDL_GetTicks64();
  1200.     if(!handleEvents()) break;
  1201.  
  1202.  
  1203.  
  1204.     for(unsigned i=0; i<bullet_count; ++i){
  1205.       if(state.bullets[i].active){
  1206.         mesh_bullet(i).p.x += state.bullets[i].vel.x;
  1207.         mesh_bullet(i).p.y += state.bullets[i].vel.y;
  1208.         mesh_bullet(i).p.z += state.bullets[i].vel.z;
  1209.  
  1210.         if(keepInBounds(mesh_bullet(i).p)){
  1211.           mesh_bullet(i).p.y      = CLIP_FAR*2;
  1212.           state.bullets[i].active = false;
  1213.           --state.active_bullets;
  1214.         }
  1215.  
  1216.       }
  1217.  
  1218.     }
  1219.  
  1220.  
  1221.  
  1222.     Vec3 moveVector(0.0f, 0.0f, 0.0f);
  1223.     if(state.pressed_right  ) moveVector.x += ship_speed_x;
  1224.     if(state.pressed_left   ) moveVector.x -= ship_speed_x;
  1225.     if(state.pressed_forward) moveVector.z += ship_speed_z;
  1226.     if(state.pressed_back   ) moveVector.z -= ship_speed_z;
  1227.     if(state.pressed_up     ) moveVector.y += ship_speed_y;
  1228.     if(state.pressed_down   ) moveVector.y -= ship_speed_y;
  1229.  
  1230.     moveCamera(-moveVector.x, -moveVector.y, -moveVector.z);
  1231.     keepInBounds(camera_cur);
  1232.  
  1233.  
  1234.  
  1235.     for(int b=-1; b<bullet_count; ++b){
  1236.       if(b >= 0  &&  !state.bullets[b].active) continue;
  1237.       Location loc = (b>=0) ? mesh_bullet(b).p : camera_cur;
  1238.       float l_dist = (b>=0) ? bullet_size/2 : 0.5f;
  1239.  
  1240.  
  1241.       for(unsigned n=0; n<num_normal; ++n){
  1242.         if(!state_normal(n).active) continue;
  1243.         asteroid_normal(n).p.x += state_normal(n).vel.x;
  1244.         asteroid_normal(n).p.y += state_normal(n).vel.y;
  1245.         asteroid_normal(n).p.z += state_normal(n).vel.z;
  1246.         if(locDistance(loc,asteroid_normal(n).p)<(l_dist+nrml_siz)){
  1247.           if(b>=0){
  1248.             asteroidSplit(n);
  1249.             mesh_bullet(b).p.y      = CLIP_FAR*2;
  1250.             state.bullets[b].active = false;
  1251.             --state.active_bullets;
  1252.           } else {
  1253.             state.menu = MENU_DEAD;
  1254.             goto _out_of_game_loop;
  1255.           }
  1256.         }
  1257.  
  1258.       }
  1259.  
  1260.  
  1261.       for(unsigned m=0; m<num_mini; ++m){
  1262.         if(!state_mini(m).active) continue;
  1263.         asteroid_mini(m).p.x += state_mini(m).vel.x;
  1264.         asteroid_mini(m).p.y += state_mini(m).vel.y;
  1265.         asteroid_mini(m).p.z += state_mini(m).vel.z;
  1266.         if(locDistance(loc,asteroid_mini(m).p)<(l_dist+mini_siz)){
  1267.           if(b>=0){
  1268.             asteroidSplit(4+m);
  1269.             mesh_bullet(b).p.y      = CLIP_FAR*2;
  1270.             state.bullets[b].active = false;
  1271.             --state.active_bullets;
  1272.           } else {
  1273.             state.menu = MENU_DEAD;
  1274.             goto _out_of_game_loop;
  1275.           }
  1276.         }
  1277.  
  1278.       }
  1279.  
  1280.  
  1281.       for(unsigned u=0; u<num_micro; ++u){
  1282.         if(!state_micro(u).active) continue;
  1283.         asteroid_micro(u).p.x += state_micro(u).vel.x;
  1284.         asteroid_micro(u).p.y += state_micro(u).vel.y;
  1285.         asteroid_micro(u).p.z += state_micro(u).vel.z;
  1286.         if(locDistance(loc,asteroid_micro(u).p)<(l_dist+mcro_siz)){
  1287.           if(b>=0){
  1288.             asteroidSplit(4+16+u);
  1289.             mesh_bullet(b).p.y      = CLIP_FAR*2;
  1290.             state.bullets[b].active = false;
  1291.             --state.active_bullets;
  1292.           } else {
  1293.             state.menu = MENU_DEAD;
  1294.             goto _out_of_game_loop;
  1295.           }
  1296.         }
  1297.  
  1298.       }
  1299.  
  1300.     }
  1301.  
  1302.  
  1303.  
  1304.     mesh_ship.p.roll  *= ship_decay_multiplier_a;
  1305.     mesh_ship.p.pitch *= ship_decay_multiplier_a;
  1306.  
  1307.     scene_wka.setAll(scene_ori);
  1308.  
  1309.     for(unsigned i=1; i<meshes_len; ++i)
  1310.       if(meshes[i]) sceneApplyTransform(meshes[i]);
  1311.  
  1312.     //rotate all but the ship's verts
  1313.     translateWka(camera_cur, ship_offset, LOOP_END_MAX);
  1314.     rotateWka(camera_cur, ship_offset, LOOP_END_MAX);
  1315.  
  1316.     meshTransform(mesh_ship);
  1317.  
  1318.     sceneApplyTransform(nullptr);
  1319.  
  1320.  
  1321.  
  1322.     canvas->clear();
  1323.     sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
  1324.     canvas->renderFillRect(&crosshair, 0xffffffff);
  1325.  
  1326.     #define brr_width 20
  1327.     #define brr_height 40
  1328.     #define brr_height_b (int)( (1.0f-((float)(state.active_bullets)/bullet_count))*brr_height )
  1329.     SDL_Rect bullets_remaining_rect = {CNV_W-brr_width, CNV_H-brr_height,
  1330.                                              brr_width,       brr_height};
  1331.     canvas->renderFillRectBordered(bullets_remaining_rect);
  1332.     bullets_remaining_rect.w -= 2;
  1333.     bullets_remaining_rect.h  = MAX(brr_height_b-2, 0);
  1334.     bullets_remaining_rect.x += 1;
  1335.     bullets_remaining_rect.y  = CNV_H-bullets_remaining_rect.h-1;
  1336.     canvas->renderFillRect(&bullets_remaining_rect, 0x00ff00);
  1337.     textf(4-brr_width/2, 3-brr_height/2, "%u", bullet_count-state.active_bullets);
  1338.  
  1339.     //textf_box(0,0,"(backspace returns\nto the main menu)");
  1340. #ifdef _DEBUG
  1341.     //bullet queue
  1342.     int b=0; for(int i=0; i<bullet_count; ++i) b += state.bullets[i].active;
  1343.     textf_box(0,10, "actually active bullets = %u", b);
  1344. #endif
  1345.  
  1346.     canvas->present((unsigned)(MAX(1, (16-(int)(SDL_GetTicks64()-startTime)) )));
  1347.  
  1348.   }
  1349.  
  1350.  
  1351.  
  1352.  
  1353.  
  1354.   //while(!state.quit  &&  state.menu == MENU_DEAD){ }
  1355.  
  1356.   //if(state.quit) goto _QUIT;
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.   if(state.quit) goto _QUIT;
  1363.   else           goto _MENU;
  1364.  
  1365. }
  1366. /******************************************************************************/
  1367. /******************************************************************************/
  1368. //"sdl2rnd\src\scene_stuff.cpp":
  1369. #include <scene.hpp>
  1370.  
  1371. Canvas*           canvas = nullptr;
  1372. SDL_Surface* geometrySrf = nullptr;
  1373. SDL_Texture* geometryTex = nullptr;
  1374.  
  1375. GeometryBuffer scene_ori; //original state
  1376. GeometryBuffer scene_wka; //work buffer a
  1377. GeometryBuffer scene_wkb; //work buffer b
  1378.  
  1379. Location       scene_camera; //camera's position, rotation, and scale
  1380.  
  1381.  
  1382.  
  1383.  
  1384.  
  1385. //does not clean up already allocated stuff on throwing here bc i'm lazy
  1386. Canvas::Canvas(int winW, int winH, int cnvW, int cnvH, const char* title){
  1387.   win = SDL_CreateWindow((title) ? title : "",
  1388.                          SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,
  1389.                          winW, winH, SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE);
  1390.   if(!win){ _throw_sdlerr: throw SDL_GetError(); }
  1391.  
  1392.   SDL_SetWindowMinimumSize(win, cnvW, cnvH);
  1393.  
  1394.  
  1395.  
  1396.   rnd = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED |
  1397.                                     SDL_RENDERER_TARGETTEXTURE /*|
  1398.                                     SDL_RENDERER_PRESENTVSYNC*/);
  1399.   if(!rnd) goto _throw_sdlerr;
  1400.  
  1401.  
  1402.  
  1403.   cnv = SDL_CreateTexture(rnd, SDL_PIXELFORMAT_ABGR8888,
  1404.                           SDL_TEXTUREACCESS_TARGET, cnvW, cnvH);
  1405.   if(!cnv) goto _throw_sdlerr;
  1406.  
  1407.  
  1408.  
  1409.   //SDL_ShowWindow(win); //done inside sceneMain
  1410.  
  1411. }
  1412.  
  1413.  
  1414.  
  1415. Canvas::~Canvas(){
  1416.   if(cnv){ SDL_DestroyTexture (cnv); cnv = nullptr; }
  1417.   if(rnd){ SDL_DestroyRenderer(rnd); rnd = nullptr; }
  1418.   if(win){ SDL_DestroyWindow  (win); win = nullptr; }
  1419.  
  1420. }
  1421.  
  1422.  
  1423.  
  1424.  
  1425.  
  1426. //only triangle faces are allowed! also, any material data is ignored!
  1427. MeshSimple::MeshSimple(const char* fileName){
  1428.   if(!file::exists(fileName)) throw fstr("obj file \"%s\" does not exist", fileName);
  1429.  
  1430.   //note: vertex data counts include the padding at index 0,
  1431.    //so a single triangle would actually have a count of 4
  1432.   //furthermore, the positions array has a length of count*3,
  1433.    //so the first vertex would actually start at index 3
  1434.    //(this goes for texcoords and normals too, though
  1435.    // texcoords has a length of count*2 instead of count*3)
  1436.    //(THIS ALSO GOES FOR INDICES)
  1437.   fastObjMesh* msh = fast_obj_read(fileName);
  1438.   if(!msh) throw "failed to read obj file";
  1439.  
  1440.  
  1441.   first_index = -1; //placeholder
  1442.  
  1443.   p.yaw   = 0.0f;
  1444.   p.pitch = 0.0f;
  1445.   p.roll  = 0.0f;
  1446.   p.scale = 1.0f;
  1447.   p.x=p.y=p.z = 0.0f;
  1448.  
  1449.   verts_len = msh->face_count * 3;
  1450.   verts     = (Vertex*)memory::allocSIMD(verts_len * sizeof(Vertex));
  1451.   memory::set(verts, 255, verts_len * sizeof(Vertex));
  1452.  
  1453.  
  1454.   int       faces_len = msh->face_count;
  1455.   Triangle* faces     = (Triangle*)verts;
  1456.  
  1457.   const fastObjIndex* indices   = msh->indices;
  1458.   const Vec3*         positions = (Vec3*)msh->positions;
  1459.   const Vec2*         texcoords = (Vec2*)msh->texcoords;
  1460.   const Vec3*         normals   = (Vec3*)msh->normals;
  1461.  
  1462.   for(int i=0; i<faces_len; ++i){
  1463.     if(msh->face_vertices[i] != 3)
  1464.       throw "obj cannot have non-triangle faces";
  1465.  
  1466.     fastObjIndex index_a = indices[i*3 + 0];
  1467.     fastObjIndex index_b = indices[i*3 + 1];
  1468.     fastObjIndex index_c = indices[i*3 + 2];
  1469.  
  1470.  
  1471.     faces[i].a.p = positions[index_a.p];
  1472.     faces[i].b.p = positions[index_b.p];
  1473.     faces[i].c.p = positions[index_c.p];
  1474.  
  1475.     faces[i].a.t = texcoords[index_a.t];
  1476.     faces[i].b.t = texcoords[index_b.t];
  1477.     faces[i].c.t = texcoords[index_c.t];
  1478.  
  1479.     faces[i].a.n = normals[index_a.n];
  1480.     faces[i].b.n = normals[index_b.n];
  1481.     faces[i].c.n = normals[index_c.n];
  1482.  
  1483.   }
  1484.  
  1485.  
  1486.   fast_obj_destroy(msh);
  1487.  
  1488. }
  1489.  
  1490.  
  1491.  
  1492. MeshSimple::~MeshSimple(){
  1493.   SAFE_FREE_SIMD(verts);
  1494.  
  1495. }
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501. void sceneRebuild(MeshSimple** meshes, int meshes_len){
  1502.   if(!meshes) throw "meshes = nullptr";
  1503.   unsigned vert_count_total = 0;
  1504.  
  1505.   for(int m=0; m<meshes_len; ++m){
  1506.     if(!meshes[m]) continue;
  1507.     meshes[m]->first_index = vert_count_total;
  1508.     vert_count_total += meshes[m]->verts_len;
  1509.   }
  1510.  
  1511.   scene_ori.reallocAll(vert_count_total);
  1512.   scene_wka.reallocAll(vert_count_total);
  1513.   scene_wkb.reallocAll(vert_count_total);
  1514.  
  1515.   scene_camera.yaw   = 0.0f;
  1516.   scene_camera.pitch = 0.0f;
  1517.   scene_camera.roll  = 0.0f;
  1518.   scene_camera.scale = 1.0f;
  1519.   scene_camera.x     = 0.0f;
  1520.   scene_camera.y     = 0.0f;
  1521.   scene_camera.z     = 0.0f;
  1522.  
  1523.  
  1524.  
  1525.   int vo = 0;
  1526.  
  1527.   for(int m=0; m<meshes_len; ++m){
  1528.     MeshSimple* mesh      = meshes[m];
  1529.     if(!mesh) continue;
  1530.     Vertex*     verts     = mesh->verts;
  1531.     unsigned    verts_len = mesh->verts_len;
  1532.  
  1533.  
  1534.     for(unsigned v=0; v<verts_len; ++v){
  1535.       Vertex vert = verts[v];
  1536.       scene_ori.p[vo].x     = vert.px;
  1537.       scene_ori.p[vo].y     = vert.py;
  1538.       scene_ori.colors[vo]  = vert.color;
  1539.       scene_ori.t[vo].x     = vert.t.x;
  1540.       //the uv coords seem to be flipped on the y axis for some reason
  1541.       scene_ori.t[vo].y     = 1.0f-vert.t.y;
  1542.       scene_ori.p_z[vo]     = vert.pz;
  1543.       scene_ori.n[vo]       = vert.n;
  1544.       scene_ori.indices[vo] = vo;
  1545.  
  1546.       //make uv coords wrap around if outside range of 0.0f -> 1.0f
  1547. #if UV_COORD_WRAPAROUND == 1
  1548.       scene_ori.t[vo].x = fmodf(scene_ori.t[vo].x, 1.0f);
  1549.       scene_ori.t[vo].y = fmodf(scene_ori.t[vo].y, 1.0f);
  1550.       if(scene_ori.t[vo].x < 0.0f) scene_ori.t[vo].x += 1.0f;
  1551.       if(scene_ori.t[vo].y < 0.0f) scene_ori.t[vo].y += 1.0f;
  1552. #endif
  1553.  
  1554.       ++vo;
  1555.  
  1556.     }
  1557.  
  1558.   }
  1559.  
  1560. }
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566. void rotateWka(Location p, unsigned loop_start, unsigned loop_end){
  1567.   loop_end   = MIN(loop_end, scene_wka.num_vertices);
  1568.   loop_start = MIN(loop_start, loop_end);
  1569.  
  1570.   const float cosYaw   = cosf(p.yaw  );
  1571.   const float sinYaw   = sinf(p.yaw  );
  1572.   const float cosPitch = cosf(p.pitch);
  1573.   const float sinPitch = sinf(p.pitch);
  1574.   const float cosRoll  = cosf(p.roll );
  1575.   const float sinRoll  = sinf(p.roll );
  1576.  
  1577.   for(unsigned i=loop_start; i<loop_end; ++i){
  1578.     //vertex positions
  1579.     float x0 = scene_wka.p[i].x;
  1580.     float y0 = scene_wka.p[i].y;
  1581.     float z0 = scene_wka.p_z[i];
  1582.     float x1 =  cosYaw  *x0 + sinYaw  *z0;
  1583.     float z1 = -sinYaw  *x0 + cosYaw  *z0;
  1584.     float y1 =  cosPitch*y0 - sinPitch*z1;
  1585.     scene_wka.p_z[i] = sinPitch*y0 + cosPitch*z1;
  1586.     scene_wka.p[i].x = cosRoll *x1 - sinRoll *y1;
  1587.     scene_wka.p[i].y = sinRoll *x1 + cosRoll *y1;
  1588.     //vertex normals (currently unused)
  1589.     /* tbd: uncomment these once they start being used
  1590.     x0 = scene_wka.n[i].x;
  1591.     y0 = scene_wka.n[i].y;
  1592.     z0 = scene_wka.n[i].z;
  1593.     x1 =  cosYaw  *x0 + sinYaw  *z0;
  1594.     z1 = -sinYaw  *x0 + cosYaw  *z0;
  1595.     y1 =  cosPitch*y0 - sinPitch*z1;
  1596.     scene_wka.n[i].x = sinPitch*y0 + cosPitch*z1;
  1597.     scene_wka.n[i].y = cosRoll *x1 - sinRoll *y1;
  1598.     scene_wka.n[i].z = sinRoll *x1 + cosRoll *y1;
  1599.     */
  1600.   }
  1601.  
  1602. }
  1603.  
  1604.  
  1605. void scaleWka(Location p, unsigned loop_start, unsigned loop_end){
  1606.   loop_end   = MIN(loop_end, scene_wka.num_vertices);
  1607.   loop_start = MIN(loop_start, loop_end);
  1608.  
  1609.   if(p.scale != 0.0f){
  1610.     for(unsigned i=loop_start; i<loop_end; ++i){
  1611.       scene_wka.p[i].x *= p.scale;
  1612.       scene_wka.p[i].y *= p.scale;
  1613.       scene_wka.p_z[i] *= p.scale;
  1614.     }
  1615.  
  1616.  
  1617.   } else {
  1618.     memory::set(&scene_wka.p[loop_start], 0,
  1619.                 (loop_end-loop_start)*sizeof(scene_wka.p[loop_start]));
  1620.  
  1621.     memory::set(&scene_wka.p_z[loop_start], 0,
  1622.                 (loop_end-loop_start)*sizeof(scene_wka.p_z[loop_start]));
  1623.  
  1624.  
  1625.   }
  1626.  
  1627. }
  1628.  
  1629.  
  1630. void translateWka(Location p, unsigned loop_start, unsigned loop_end){
  1631.   loop_end   = MIN(loop_end, scene_wka.num_vertices);
  1632.   loop_start = MIN(loop_start, loop_end);
  1633.  
  1634.   for(unsigned i=loop_start; i<loop_end; ++i){
  1635.     scene_wka.p[i].x += p.x;
  1636.     scene_wka.p[i].y += p.y;
  1637.     scene_wka.p_z[i] += p.z;
  1638.   }
  1639.  
  1640. }
  1641.  
  1642.  
  1643. //operates on scene_wka, while assuming that
  1644.  //the contents of scene_ori were just copied
  1645. //if mesh == nullptr, translate camera (AKA the entirety of wka)
  1646. void sceneApplyTransform(MeshSimple* mesh){
  1647.   if(mesh != nullptr){
  1648.     const Location p          = mesh->p;
  1649.     const unsigned loop_start = mesh->first_index;
  1650.     const unsigned loop_end   = loop_start + mesh->verts_len;
  1651.  
  1652.     const bool shouldRotate    = p.yaw || p.pitch || p.roll;
  1653.     const bool shouldScale     = p.scale != 1.0f;
  1654.     const bool shouldTranslate = p.x || p.y || p.z;
  1655.  
  1656.     //if mesh is to be transformed, order is: rotate,  scale, translate
  1657.     if(shouldRotate   ) rotateWka   (p, loop_start, loop_end);
  1658.     if(shouldScale    ) scaleWka    (p, loop_start, loop_end);
  1659.     if(shouldTranslate) translateWka(p, loop_start, loop_end);
  1660.  
  1661.  
  1662.   } else {
  1663.     Location _p = scene_camera;
  1664.     _p.yaw   = -_p.yaw;
  1665.     _p.pitch = -_p.pitch;
  1666.     _p.roll  = -_p.roll;
  1667.     if(_p.scale != 0.0f) _p.scale = 1.0f/_p.scale;
  1668.     _p.x = -_p.x;
  1669.     _p.y = -_p.y;
  1670.     _p.z = -_p.z;
  1671.  
  1672.     const Location p          = _p;
  1673.     const unsigned loop_start = 0;
  1674.     const unsigned loop_end   = scene_wka.num_vertices;
  1675.  
  1676.     const bool shouldRotate    = p.yaw || p.pitch || p.roll;
  1677.     const bool shouldScale     = p.scale != 1.0f;
  1678.     const bool shouldTranslate = p.x || p.y || p.z;
  1679.  
  1680.     //if camera is to be transformed, order is: translate, rotate, scale
  1681.     if(shouldTranslate) translateWka(p, loop_start, loop_end);
  1682.     if(shouldRotate   ) rotateWka   (p, loop_start, loop_end);
  1683.     if(shouldScale    ) scaleWka    (p, loop_start, loop_end);
  1684.  
  1685.   }
  1686.  
  1687.  
  1688. }
  1689.  
  1690.  
  1691.  
  1692.  
  1693.  
  1694. #define CBF_ADD_VERT {                                                  \
  1695.   scene_wkb.p      [scene_wkb.num_vertices] = scene_wka.p[i];           \
  1696.   scene_wkb.colors [scene_wkb.num_vertices] = scene_wka.colors[i];      \
  1697.   scene_wkb.t      [scene_wkb.num_vertices] = scene_wka.t[i];           \
  1698.   /*redundant; indices are set at sceneClipPlanesAndLumFade*/           \
  1699. /*scene_wkb.indices[scene_wkb.num_vertices] = scene_wkb.num_vertices;*/ \
  1700.   scene_wkb.p_z    [scene_wkb.num_vertices] = scene_wka.p_z[i];         \
  1701.   scene_wkb.n      [scene_wkb.num_vertices] = scene_wka.n[i];           \
  1702.   scene_wkb.mids   [scene_wkb.num_vertices] = midpoint;                 \
  1703.   ++scene_wkb.num_vertices;                                             }
  1704.  
  1705. //reminder, dot product is: "(a.x * b.x) + (a.y * b.y) + (a.z * b.z)"
  1706. static inline bool isBackFace(Vec3 midpoint, Vec3 surface_normal){
  1707.   return ( (-midpoint.x*surface_normal.x) +
  1708.            (-midpoint.y*surface_normal.y) +
  1709.            (-midpoint.z*surface_normal.z) ) < 0.0f;
  1710.  
  1711. }
  1712.  
  1713.  
  1714. //wkb = backface_cull(wka)
  1715. void sceneCullBackFaces(){
  1716.   scene_wkb.num_vertices = 0;
  1717.  
  1718.  
  1719.   for(unsigned i=0; i<scene_wka.num_vertices;){
  1720.     unsigned _i = i;
  1721.     Vec3 a(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1722.     Vec3 b(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1723.     Vec3 c(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1724.  
  1725.     Vec3 u(b.x-a.x, b.y-a.y, b.z-a.z);
  1726.     Vec3 v(c.x-a.x, c.y-a.y, c.z-a.z);
  1727.  
  1728.  
  1729.     Vec3 midpoint;
  1730.     midpoint.x = (a.x + b.x + c.x) * 0.333333333f;
  1731.     midpoint.y = (a.y + b.y + c.y) * 0.333333333f;
  1732.     midpoint.z = (a.z + b.z + c.z) * 0.333333333f;
  1733.  
  1734.     Vec3 surface_normal;
  1735.     surface_normal.x = u.y*v.z - u.z*v.y;
  1736.     surface_normal.y = u.z*v.x - u.x*v.z;
  1737.     surface_normal.z = u.x*v.y - u.y*v.x;
  1738.  
  1739.  
  1740.     if(!isBackFace(midpoint, surface_normal)){
  1741.       CBF_ADD_VERT;  ++i;
  1742.       CBF_ADD_VERT;  ++i;
  1743.       CBF_ADD_VERT;  ++i;
  1744.  
  1745.     } else {
  1746.       i += 3;
  1747.  
  1748.     }
  1749.  
  1750.   }
  1751.  
  1752. }
  1753.  
  1754.  
  1755.  
  1756.  
  1757.  
  1758. #define CPLF_ADD_VERT(z_) {                                             \
  1759.   luminosity = 1.0f - ((z_-CLIP_NEAR)/(CLIP_FAR-CLIP_NEAR));            \
  1760.   color = (scene_wkb.colors[i].v&255) * luminosity;                     \
  1761.   color |= color<< 8;                                                   \
  1762.   color |= color<<16;                                                   \
  1763.                                                                         \
  1764.   scene_wka.p      [scene_wka.num_vertices]   = scene_wkb.p[i];         \
  1765.   scene_wka.colors [scene_wka.num_vertices].v = color;                  \
  1766.   scene_wka.t      [scene_wka.num_vertices]   = scene_wkb.t[i];         \
  1767.   scene_wka.indices[scene_wka.num_vertices]   = scene_wka.num_vertices; \
  1768.   scene_wka.p_z    [scene_wka.num_vertices]   = scene_wkb.p_z[i];       \
  1769.   scene_wka.n      [scene_wka.num_vertices]   = scene_wkb.n[i];         \
  1770.   scene_wka.mids   [scene_wka.num_vertices]   = scene_wkb.mids[i];      \
  1771.   ++scene_wka.num_vertices;                                             }
  1772.  
  1773. //wka = plane_clip(wkb)
  1774. //wka = apply_luminosity_fade(wka)
  1775. void sceneClipPlanesAndLumFade(){
  1776. #if PRECISE_CLIPPING == 0
  1777.   scene_wka.num_vertices = 0;
  1778.  
  1779.   for(unsigned i=0; i<scene_wkb.num_vertices;){
  1780.     unsigned _i = i;
  1781.     float za = scene_wkb.p_z[_i];  ++_i;
  1782.     float zb = scene_wkb.p_z[_i];  ++_i;
  1783.     float zc = scene_wkb.p_z[_i];  ++_i;
  1784. #ifndef CLIP_NEAR
  1785.   #define CLIP_NEAR 1.0f
  1786.   #define CLIP_NEAR_WAS_UNDEF
  1787. #endif
  1788.     //if triangle is out of bounds z-wise, don't append it to wka
  1789.     if(za < CLIP_NEAR || za >= CLIP_FAR ||
  1790.        zb < CLIP_NEAR || zb >= CLIP_FAR ||
  1791.        zc < CLIP_NEAR || zc >= CLIP_FAR )
  1792.     {
  1793.       i += 3;
  1794.  
  1795.     } else {
  1796.       float luminosity; unsigned color;
  1797.       CPLF_ADD_VERT(za);  ++i;
  1798.       CPLF_ADD_VERT(zb);  ++i;
  1799.       CPLF_ADD_VERT(zc);  ++i;
  1800.  
  1801.     }
  1802. #ifdef CLIP_NEAR_WAS_UNDEF
  1803.   #undef CLIP_NEAR
  1804.   #undef CLIP_NEAR_WAS_UNDEF
  1805. #endif
  1806.   }
  1807. #else
  1808.   scene_wka.setAll(scene_wkb);
  1809.  
  1810.  
  1811. #endif
  1812. }
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818. #define SP_ADD_VERT(_p) {                                               \
  1819.   scene_wkb.p      [scene_wkb.num_vertices].x = _p.x;                   \
  1820.   scene_wkb.p      [scene_wkb.num_vertices].y = _p.y;                   \
  1821.   scene_wkb.colors [scene_wkb.num_vertices]   = scene_wka.colors[i];    \
  1822.   scene_wkb.t      [scene_wkb.num_vertices]   = scene_wka.t[i];         \
  1823.   scene_wkb.indices[scene_wkb.num_vertices]   = scene_wkb.num_vertices; \
  1824.   scene_wkb.p_z    [scene_wkb.num_vertices]   = _p.z;                   \
  1825.   scene_wkb.n      [scene_wkb.num_vertices]   = scene_wka.n[i];         \
  1826.   scene_wkb.mids   [scene_wkb.num_vertices]   = scene_wka.mids[i];      \
  1827.   ++scene_wkb.num_vertices;                                             }
  1828.  
  1829. #define SIMPLE_PROJECTION 0
  1830. //wkb = project(wka) (also culls triangles that are off-screen)
  1831. void sceneProject(float viewportMultiplierX, float viewportMultiplierY){
  1832. #if SIMPLE_PROJECTION == 1
  1833.   scene_wkb.setAll(scene_wka);
  1834.   // /=z
  1835.   for(unsigned i=0; i<scene_wkb.num_vertices; ++i){
  1836.     scene_wkb.p[i].x /= scene_wkb.p_z[i];
  1837.     scene_wkb.p[i].y /= scene_wkb.p_z[i];
  1838.   }
  1839.  
  1840.   // move to screenspace
  1841.   for(unsigned i=0; i<scene_wkb.num_vertices; ++i){
  1842.     scene_wkb.p[i].x *=  CNV_W/2;  scene_wkb.p[i].x += CNV_W/2;
  1843.     scene_wkb.p[i].y *= -CNV_H/2;  scene_wkb.p[i].y += CNV_H/2;
  1844.   }
  1845.  
  1846.  
  1847.  
  1848. #else
  1849.   scene_wkb.num_vertices = 0;
  1850.  
  1851.   //for dividing via multiplying by the inverse of the divisor
  1852.   float v_x_inv = 1.0f/viewportMultiplierX;
  1853.   float v_y_inv = 1.0f/viewportMultiplierY;
  1854.  
  1855.  
  1856.   for(unsigned i=0; i<scene_wka.num_vertices;){
  1857.     unsigned _i = i;
  1858.     Vec3 a(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1859.     Vec3 b(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1860.     Vec3 c(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]);  ++_i;
  1861.  
  1862.  
  1863.     // (P*d)/z = P'
  1864.      // *= d (near plane)
  1865. #ifdef CLIP_NEAR //if undefined, CLIP_NEAR is assumed to equal 1.0f
  1866.     a.x *= CLIP_NEAR,  a.y *= CLIP_NEAR;
  1867.     b.x *= CLIP_NEAR,  b.y *= CLIP_NEAR;
  1868.     c.x *= CLIP_NEAR,  c.y *= CLIP_NEAR;
  1869. #endif
  1870.      // /= z
  1871.     a.x /= a.z,  a.y /= a.z;
  1872.     b.x /= b.z,  b.y /= b.z;
  1873.     c.x /= c.z,  c.y /= c.z;
  1874.  
  1875.     // (P'*C)/V
  1876.      // *C
  1877.     a.x *= CNV_W/2,  a.y *= -CNV_H/2; //(-canvas_height, otherwise things will
  1878.     b.x *= CNV_W/2,  b.y *= -CNV_H/2;  //appear upside-down!)
  1879.     c.x *= CNV_W/2,  c.y *= -CNV_H/2;
  1880.      // /V
  1881.     a.x *= v_x_inv,  a.y *= v_y_inv; //remember, this is actually a division
  1882.     b.x *= v_x_inv,  b.y *= v_y_inv;
  1883.     c.x *= v_x_inv,  c.y *= v_y_inv;
  1884.  
  1885.     //push right and down into screen space
  1886.     a.x += CNV_W/2,  a.y += CNV_H/2;
  1887.     b.x += CNV_W/2,  b.y += CNV_H/2;
  1888.     c.x += CNV_W/2,  c.y += CNV_H/2;
  1889.  
  1890.  
  1891.     //copy triangle to wkb, unless all 3 points are off-screen
  1892.     if( (a.x < 0 || a.x >= CNV_W  ||  a.y < 0 || a.y >= CNV_H) &&
  1893.         (b.x < 0 || b.x >= CNV_W  ||  b.y < 0 || b.y >= CNV_H) &&
  1894.         (c.x < 0 || c.x >= CNV_W  ||  c.y < 0 || c.y >= CNV_H) )
  1895.     {
  1896.       i += 3;
  1897.  
  1898.     } else {
  1899.       SP_ADD_VERT(a);  ++i;
  1900.       SP_ADD_VERT(b);  ++i;
  1901.       SP_ADD_VERT(c);  ++i;
  1902.  
  1903.     }
  1904.  
  1905.  
  1906.   }
  1907.  
  1908.  
  1909.  
  1910. #endif
  1911. }
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917. void sceneZSort(){
  1918.   //compiler complains if i try to capture scene_wkb directly
  1919.   GeometryBuffer wkb_copy = scene_wkb;
  1920.  
  1921.   std::sort(wkb_copy.indices_v, wkb_copy.indices_v+wkb_copy.num_vertices/3,
  1922.   [&wkb_copy](Vec3Int a, Vec3Int b){
  1923.     return wkb_copy.mids[b.x].z<wkb_copy.mids[a.x].z;
  1924.   });
  1925. }
  1926.  
  1927.  
  1928.  
  1929.  
  1930. void scenePS1Geometry(GeometryBuffer& buffer){
  1931. #if PS1_SNAP > 0
  1932.   unsigned num_vertices = buffer.num_vertices;
  1933.   Vec2* xy = buffer.p;
  1934.   float* z = buffer.p_z;
  1935.  
  1936.   for(unsigned i=0; i<num_vertices; ++i){
  1937.     #define _PS1_SNAP (PS1_SNAP PS1_SNAP_MOD)
  1938.     #define VERT_SNAP(value) ( (float)((s64)((value)*_PS1_SNAP)) / _PS1_SNAP )
  1939.     xy[i].x = VERT_SNAP(xy[i].x);
  1940.     xy[i].y = VERT_SNAP(xy[i].y);
  1941.     z[i]    = VERT_SNAP(z[i]   );
  1942.   }
  1943. #endif
  1944. }
  1945. /******************************************************************************/
  1946. /******************************************************************************/
  1947. //"sdl2rnd\src\Text.cpp":
  1948. #include <scene.hpp>
  1949.  
  1950. char _fstr_failure[] = "(FSTR FAILED)";
  1951. char _fstr[2][FSTR_LEN];
  1952. int  _fstr_which = 0;
  1953.  
  1954. Text* text_p = nullptr;
  1955.  
  1956.  
  1957.  
  1958.  
  1959.  
  1960. //assumes that font image uses accepted dimensions and formatting,
  1961.  //and that black is used as the transparent color
  1962. Text::Text(const char* bmpPath){
  1963.   if(!file::exists(bmpPath)) throw fstr("font bitmap \"%s\" doesn't exist", bmpPath);
  1964.  
  1965.   SDL_Surface* _input = SDL_LoadBMP(bmpPath);
  1966.   if(!_input) throw SDL_GetError();
  1967.  
  1968.   SDL_Surface* input = SDL_ConvertSurfaceFormat(_input, SDL_PIXELFORMAT_ABGR8888, 0);
  1969.   SDL_FreeSurface(_input); //shouldn't overwrite sdl error
  1970.   if(!input) throw SDL_GetError();
  1971.  
  1972.  
  1973.   SDL_SetColorKey(input, SDL_TRUE, 0xff000000);
  1974.  
  1975.   w = (input->w/16)-1;
  1976.   h = (input->h/16)-1;
  1977.  
  1978.  
  1979.   if(!canvas) throw "canvas object doesn't exist";
  1980.   atlas = SDL_CreateTextureFromSurface(canvas->getRnd(), input);
  1981.   SDL_FreeSurface(input);
  1982.   if(!atlas) throw SDL_GetError();
  1983.  
  1984. }
  1985.  
  1986.  
  1987.  
  1988.  
  1989.  
  1990. SDL_Point Text::getTextSize(const char* text, float scale){
  1991.   if(!text) throw "string given to Text was nullptr";
  1992.   SDL_Point scaled_dimensions = { MAX((int)(w*scale),1), MAX((int)(h*scale),1) };
  1993.   SDL_Point size = { 0, scaled_dimensions.y*(*text!=0) };
  1994.  
  1995.   char chr;
  1996.   int max_width = 0;
  1997.  
  1998.  
  1999.   while( (chr=*(text++)) )
  2000.   if(chr == '\n'){
  2001.     if(max_width < size.x) max_width = size.x;
  2002.     size.x  = 0;
  2003.     size.y += scaled_dimensions.y;
  2004.  
  2005.   } else {
  2006.     size.x += scaled_dimensions.x;
  2007.  
  2008.   }
  2009.  
  2010.  
  2011.   if(size.x < max_width) size.x = max_width;
  2012.  
  2013.   return size;
  2014.  
  2015. }
  2016.  
  2017.  
  2018.  
  2019.  
  2020.  
  2021. void Text::draw(int x, int y, const char* _text, unsigned maxLen, float scale){
  2022.   if(!_text) throw "string given to Text was nullptr";
  2023.   bool cnvWasTarget = canvas->isCnvTarget();
  2024.   SDL_Renderer* rnd = canvas->getRnd();
  2025.   SDL_Texture*  cnv = canvas->getCnv();
  2026.  
  2027.   if(!cnvWasTarget && SDL_SetRenderTarget(rnd,cnv)<0)
  2028.     throw SDL_GetError();
  2029.  
  2030.  
  2031.  
  2032.   //if high bit of maxLen is set, ignore automatic origin rules
  2033.   if(!(maxLen&0x80000000)){
  2034.     SDL_Point textSize;
  2035.     bool getTextSize_called = false;
  2036.  
  2037.     if(x < 0){
  2038.       textSize = getTextSize(_text, scale);
  2039.       getTextSize_called = true;
  2040.  
  2041.       if(x == CENTER_TEXT) x = CNV_W/2 - textSize.x/2;
  2042.       else                 x = CNV_W   - textSize.x + x + 1;
  2043.  
  2044.     }
  2045.  
  2046.     if(y < 0){
  2047.       if(!getTextSize_called)
  2048.         textSize = getTextSize(_text, scale);
  2049.  
  2050.       if(y == CENTER_TEXT) y = CNV_H/2 - textSize.y/2;
  2051.       else                 y = CNV_H   - textSize.y + y + 1;
  2052.  
  2053.     }
  2054.  
  2055.   } else {
  2056.     maxLen &= 0x7fffffff;
  2057.  
  2058.   }
  2059.  
  2060.  
  2061.  
  2062.   SDL_Rect src = {0,0, w,h};
  2063.   SDL_Rect dst = {x,y, MAX((int)(w*scale), 1),
  2064.                        MAX((int)(h*scale), 1)};
  2065.  
  2066.   int src_stride_w = src.w + 1;
  2067.   int src_stride_h = src.h + 1;
  2068.  
  2069.   const unsigned char* text = (unsigned char*)_text;
  2070.   unsigned char chr;
  2071.  
  2072.  
  2073.  
  2074.   if(!maxLen) --maxLen;
  2075.  
  2076.   while( (chr=*(text++)) && (maxLen--) )
  2077.   if(chr == '\n'){
  2078.     dst.x  = x;
  2079.     dst.y += dst.h;
  2080.  
  2081.   } else {
  2082.     src.x = ( chr    &15)*src_stride_w + 1;
  2083.     src.y = ((chr>>4)&15)*src_stride_h + 1;
  2084.     if(SDL_RenderCopy(rnd, atlas, &src, &dst)<0) throw SDL_GetError();
  2085.     dst.x += dst.w;
  2086.  
  2087.   }
  2088.  
  2089.  
  2090.  
  2091.   if(!cnvWasTarget && SDL_SetRenderTarget(rnd,nullptr)<0)
  2092.     throw SDL_GetError();
  2093.  
  2094. }
  2095.  
  2096.  
  2097.  
  2098.  
  2099.  
  2100. void Text::drawBox(int x, int y, const char* text, unsigned maxLen, float scale){
  2101.   SDL_Point textSize = getTextSize(text, scale);
  2102.   SDL_Rect dst = {x,y, textSize.x+3,textSize.y+3};
  2103.  
  2104.  
  2105.   if(dst.x == CENTER_TEXT) dst.x = CNV_W/2 - dst.w/2;
  2106.   else if(dst.x < 0)       dst.x = CNV_W - dst.w + dst.x + 1;
  2107.  
  2108.   if(dst.y == CENTER_TEXT) dst.y = CNV_H/2 - dst.h/2;
  2109.   else if(dst.y < 0)       dst.y = CNV_H - dst.h + dst.y + 1;
  2110.  
  2111.  
  2112.   #define B_C 0xc0
  2113.   #define BORDER_COLOR ABGR(B_C,B_C,B_C,255)
  2114.   canvas->renderFillRectBordered(dst, BORDER_COLOR, 0xff000000);
  2115.   draw(dst.x+2,dst.y+2, text, 0x80000000|maxLen, scale);
  2116.  
  2117. }
  2118. /******************************************************************************/
  2119. /******************************************************************************/
  2120. //"sdl2rnd\include\common.hpp":
  2121. #ifndef _UTILS_COMMON_HPP
  2122. #define _UTILS_COMMON_HPP
  2123.  
  2124. #include <SDL2/SDL.h>
  2125.  
  2126. //#include <immintrin.h>
  2127.  
  2128. #include <algorithm> //for std::sort
  2129.  
  2130. #define INT_S32_MAX (0x7fffffff)
  2131. #define INT_U64_MSb (0x8000000000000000)
  2132. #define _pi (3.1415926535897932384626433f) //overkill for single-precision lol
  2133. #define _2pi (_pi*2)
  2134. #define _pi2 (_pi/2)
  2135. #define _pi4 (_pi/4)
  2136. #define _pi8 (_pi/8)
  2137.  
  2138. #define MIN(_a, _b) ( ((_a)<(_b)) ? (_a) : (_b) )
  2139. #define MAX(_a, _b) ( ((_a)>(_b)) ? (_a) : (_b) )
  2140. #define MIN3(_a, _b, _c) MIN(MIN(_a, _b), _c)
  2141. #define MAX3(_a, _b, _c) MAX(MAX(_a, _b), _c)
  2142. #define CLAMP(_n, _mn, _mx) MIN(MAX(_n, _mn),_mx)
  2143.  
  2144. #define SAFE_FREE(ptr) if(ptr){ memory::free(&ptr); ptr = nullptr; }
  2145. #define SAFE_FREE_SIMD(ptr) if(ptr){ memory::freeSIMD(&ptr); ptr = nullptr; }
  2146. #define SAFE_DELETE(ptr) if(ptr){ delete ptr; ptr = nullptr; }
  2147.  
  2148.  
  2149. #ifdef _DEBUG
  2150. #define Log(...) SDL_Log(__VA_ARGS__)
  2151. #else
  2152. #define Log(...)
  2153. #endif /* _DEBUG */
  2154.  
  2155. #define loghere Log("\"%s\": %3i",__FILE__,__LINE__);
  2156.  
  2157.  
  2158. typedef Uint8  u8;
  2159. typedef Uint16 u16;
  2160. typedef Uint32 u32;
  2161. typedef Uint64 u64;
  2162.  
  2163. typedef Sint8  s8;
  2164. typedef Sint16 s16;
  2165. typedef Sint32 s32;
  2166. typedef Sint64 s64;
  2167.  
  2168. typedef  float f32;
  2169. typedef double f64;
  2170.  
  2171.  
  2172. namespace shape {
  2173.   typedef SDL_Point  point;
  2174.   typedef SDL_FPoint pointf;
  2175.   typedef SDL_Rect   rect;
  2176.   typedef SDL_FRect  rectf;
  2177. };
  2178.  
  2179.  
  2180.  
  2181. #endif /* _UTILS_COMMON_HPP */
  2182. /******************************************************************************/
  2183. /******************************************************************************/
  2184. //"sdl2rnd\include\file.hpp":
  2185. #ifndef _UTILS_FILE_HPP
  2186. #define _UTILS_FILE_HPP
  2187.  
  2188.  
  2189. #include "common.hpp"
  2190.  
  2191.  
  2192. namespace file {
  2193.  
  2194.  
  2195.  
  2196. bool exists(const char* filePath);
  2197.  
  2198.  
  2199. s32 getSize(const char* filePath);
  2200.  
  2201.  
  2202.  
  2203. };
  2204.  
  2205.  
  2206.  
  2207.  
  2208. struct BinaryData { //16B
  2209.   union {
  2210.     void* const  ptr;
  2211.     char* const data = nullptr;
  2212.   };
  2213.   const size_t data_len = 0;
  2214.  
  2215.   BinaryData(const char* filePath);
  2216.   BinaryData(const void* data, size_t dataSize){ loadFromMemory(data, dataSize); }
  2217.  
  2218.   ~BinaryData();
  2219.  
  2220.   //will (re)allocate dataSize bytes for _data, before copying data to _data
  2221.    //(if data is nullptr, this behaves as if you were realloc'ing _data)
  2222.    //(also, the actual num of bytes copied is equal to MIN(dataSize, data_len))
  2223.   void loadFromMemory(const void* data, size_t dataSize);
  2224. };
  2225.  
  2226.  
  2227.  
  2228. #endif /* _UTILS_FILEDATA_HPP */
  2229. /******************************************************************************/
  2230. /******************************************************************************/
  2231. //"sdl2rnd\include\memory.hpp":
  2232. #ifndef _UTILS_MEMORY_HPP
  2233. #define _UTILS_MEMORY_HPP
  2234.  
  2235.  
  2236. #include "common.hpp"
  2237.  
  2238.  
  2239. namespace memory {
  2240.  
  2241.  
  2242.  
  2243.  
  2244. void* alloc(size_t size);
  2245.  
  2246. //this version of free is especially useful, because it's safe to pass nullptr to!
  2247.  //this rule goes for both ptr_p and *ptr_p
  2248. #ifndef   free
  2249. #define   free _free_real
  2250. #endif /* free */
  2251. void _free_real(void* ptr_p);
  2252. //^^i would call this just free, but that seems to cause conflicts
  2253.  //if calling free from memory::free, resulting in recursion >:(
  2254.  
  2255. #ifndef   realloc
  2256. #define   realloc _realloc_real
  2257. #endif /* realloc */
  2258. void* _realloc_real(void* ptr_p, size_t newSize);
  2259.  
  2260. //^^(for both free and realloc, a void** declared in function as void*,
  2261.  //  so you don't need to explicitly cast it to void**)
  2262.  
  2263.  
  2264. size_t getNumAllocations();
  2265.  
  2266.  
  2267.  
  2268.  
  2269. void* allocSIMD(size_t size);
  2270.  
  2271. void freeSIMD(void* ptr_p);
  2272.  
  2273. void* reallocSIMD(void* ptr_p, size_t newSize);
  2274.  
  2275.  
  2276. size_t getSIMDAlignment();
  2277.  
  2278.  
  2279.  
  2280.  
  2281. struct wrapper {
  2282.   void* ptr = nullptr;
  2283.  
  2284. inline wrapper(size_t size){ if(!(ptr=alloc(size))) throw "Failed to allocate memory"; }
  2285. inline ~wrapper(){ _free_real(&ptr); }
  2286.  
  2287. inline void* reallocate(size_t newSize){ return _realloc_real(&ptr, newSize); }
  2288.  
  2289. };
  2290.  
  2291.  
  2292. struct wrapperSIMD {
  2293.   void* ptr = nullptr;
  2294.  
  2295. inline wrapperSIMD(size_t size){ if(!(ptr=allocSIMD(size))) throw "Failed to allocate SIMD memory"; }
  2296. inline ~wrapperSIMD(){ freeSIMD(&ptr); }
  2297.  
  2298. inline void* reallocate(size_t newSize){ return reallocSIMD(&ptr, newSize); }
  2299.  
  2300. };
  2301.  
  2302.  
  2303.  
  2304.  
  2305.  
  2306. void* set(void* dst, char v, size_t size);
  2307.  
  2308. void* copy(void* dst, const void* src, size_t size);
  2309.  
  2310.  
  2311.  
  2312.  
  2313.  
  2314. }; /* namespace memory */
  2315.  
  2316. #endif /* _UTILS_MEMORY_HPP */
  2317. /******************************************************************************/
  2318. /******************************************************************************/
  2319. //"sdl2rnd\include\scene.hpp":
  2320. #ifndef _SCENE_HPP
  2321. #define _SCENE_HPP
  2322.  
  2323. #include <common.hpp>
  2324. #include <file.hpp>
  2325. #include <memory.hpp>
  2326. #include <Text.hpp>
  2327.  
  2328. #include <fast_obj.hpp>
  2329.  
  2330. /*
  2331. //fov (in degrees) to viewport dimensions, assuming near plane = 1
  2332. //( v=tan(f/(360/pi)), f=atan(v*(360/pi)) )
  2333. #define fx_360_pi (360.0/pi)
  2334. #define FOV_TO_VIEWPORT(_fov ) (tan((_fov)/fx_360_pi))
  2335. #define VIEWPORT_TO_FOV(_view) (atan(_view)*fx_360_pi)
  2336. */
  2337.  
  2338. #define WIN_W 512*2
  2339. #define WIN_H 288*2
  2340. #define CNV_DIV 2
  2341.  
  2342. #ifdef _DEBUG
  2343. #define WIN_TITLE "Not Asteroids (DEBUG BUILD)"
  2344. #else
  2345. #define WIN_TITLE "Not Asteroids"
  2346. #endif
  2347.  
  2348. #define TRAP_PROMPT "(press f11 to enable fullscreen)"
  2349. #define UNTRAP_PROMPT "(press f11 to enable fullscreen; esc to free mouse)"
  2350.  
  2351. #define CNV_W ((WIN_W)/(CNV_DIV))
  2352. #define CNV_H ((WIN_H)/(CNV_DIV))
  2353.  
  2354. //#define CLIP_NEAR 0.8f //if undefined, near plane is assumed to be 1.0f
  2355. #define CLIP_FAR 768.0f//512.0f
  2356.  
  2357. //will simplify vertex positions to 1/PS1_SNAP'th
  2358.  //(if 0, feature is disabled)
  2359. #define PS1_SNAP 8
  2360. #define PS1_SNAP_MOD
  2361.  
  2362. #define cosf cosf
  2363. #define sinf sinf
  2364.  
  2365. //will make any texture coordinates wrap around to fit within the 0.0-1.0 range
  2366. //(will turn 1.3 to 0.3, -0.3 to 0.7, and so on)
  2367. #define UV_COORD_WRAPAROUND 1 //0&1 to disable and enable respectively
  2368.  
  2369. //if 1, proper clip plane handling will be enabled, instead of triangles simply
  2370.  //disappearing the moment a triangle passes through a clip plane boundary
  2371. #define PRECISE_CLIPPING 0 //(currently not implemented; keep this equal to 0)
  2372.  
  2373.  
  2374.  
  2375.  
  2376.  
  2377. struct Vec2    {
  2378.   float x, y;
  2379.   inline Vec2(float _x, float _y) : x(_x), y(_y) {}
  2380.   inline Vec2() : x(0), y(0) {}
  2381. };
  2382. struct Vec3    {
  2383.   float x, y, z;
  2384.   inline Vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
  2385.   inline Vec3() : x(0), y(0), z(0) {}
  2386.   inline Vec3& operator*=(const float& m){ x*=m, y*=m, z*=m;  return *this; }
  2387. } __attribute__((packed));
  2388. struct Vec3Int { int   x, y, z; } __attribute__((packed));
  2389. struct Vec4    { float x, y, z, w; };
  2390.  
  2391. union ABGR {
  2392.   unsigned v;
  2393.   struct {
  2394.     unsigned char r;
  2395.     unsigned char g;
  2396.     unsigned char b;
  2397.     unsigned char a;
  2398.   };
  2399.   inline ABGR() : v(0) {}
  2400.   inline ABGR(unsigned _v) : v(_v) {}
  2401.   inline ABGR(char _r, char _g, char _b, char _a) : r(_r), g(_g), b(_b), a(_a) {}
  2402. };
  2403.  
  2404. struct Vertex { //40B; 3D vertex
  2405.   union {
  2406.     Vec3 p;
  2407.     struct { float px, py, pz; } __attribute__((packed));
  2408.   };
  2409.  
  2410.   ABGR color;
  2411.  
  2412.   union {
  2413.     Vec2 t;
  2414.     struct { float tx, ty; }; };
  2415.  
  2416.   union {
  2417.     Vec3 n;
  2418.     struct { float nx, ny, nz; } __attribute__((packed));
  2419.   };
  2420.  
  2421.   unsigned _padding32;
  2422.  
  2423. };
  2424.  
  2425. struct Triangle { Vertex a, b, c; };
  2426.  
  2427. struct Location {
  2428.   //(transformations are applied in order of how they appear here)
  2429.   float yaw, pitch, roll;
  2430.   float scale;
  2431.   float x, y, z;
  2432. } __attribute__((packed));
  2433.  
  2434.  
  2435.  
  2436. class Canvas;
  2437.  
  2438. struct GeometryBuffer { //fed into SDL_RenderGeometryRaw
  2439.   Vec2*      p = nullptr; //vertex positions
  2440.   ABGR* colors = nullptr;
  2441.   Vec2*      t = nullptr; //uv coords
  2442.  
  2443.   union {
  2444.     Vec3Int* indices_v;
  2445.     int*     indices = nullptr;
  2446.   };
  2447.  
  2448.   //(z axis is separated, since SDL_RenderGeometryRaw doesn't use it)
  2449.   float* p_z = nullptr;
  2450.   Vec3*    n = nullptr; //normals
  2451.   Vec3* mids = nullptr; //face midpoints
  2452.  
  2453.   size_t num_vertices = 0;
  2454.  
  2455.  
  2456.   void reallocAll(size_t n_v){
  2457.     if(0){ _oom_error: throw "failed to reallocate memory for GeometryBuffer"; }
  2458.     if(!memory::reallocSIMD(&p,       n_v * sizeof(p[0]      ))) goto _oom_error;
  2459.     if(!memory::reallocSIMD(&colors,  n_v * sizeof(colors[0] ))) goto _oom_error;
  2460.     if(!memory::reallocSIMD(&t,       n_v * sizeof(t[0]      ))) goto _oom_error;
  2461.     if(!memory::reallocSIMD(&indices, n_v * sizeof(indices[0]))) goto _oom_error;
  2462.     if(!memory::reallocSIMD(&p_z,     n_v * sizeof(p_z[0]    ))) goto _oom_error;
  2463.     if(!memory::reallocSIMD(&n,       n_v * sizeof(n[0]      ))) goto _oom_error;
  2464.     if(!memory::reallocSIMD(&mids,    n_v * sizeof(mids[0]   ))) goto _oom_error;
  2465.     num_vertices = n_v;
  2466.  
  2467.   }
  2468.  
  2469.   void freeAll(){
  2470.     SAFE_FREE_SIMD(p      );
  2471.     SAFE_FREE_SIMD(colors );
  2472.     SAFE_FREE_SIMD(t      );
  2473.     SAFE_FREE_SIMD(indices);
  2474.     SAFE_FREE_SIMD(p_z    );
  2475.     SAFE_FREE_SIMD(n      );
  2476.     SAFE_FREE_SIMD(mids   );
  2477.     num_vertices = 0;
  2478.  
  2479.   }
  2480.  
  2481.   //assumes both this and src have the same or larger allocated sizes,
  2482.    //otherwise this will probably break catastrophically
  2483.   void setAll(GeometryBuffer& src){
  2484.     memory::copy(p,       src.p,       src.num_vertices * sizeof(p[0]      ));
  2485.     memory::copy(colors,  src.colors,  src.num_vertices * sizeof(colors[0] ));
  2486.     memory::copy(t,       src.t,       src.num_vertices * sizeof(t[0]      ));
  2487.     memory::copy(indices, src.indices, src.num_vertices * sizeof(indices[0]));
  2488.     memory::copy(p_z,     src.p_z,     src.num_vertices * sizeof(p_z[0]    ));
  2489.     memory::copy(n,       src.n,       src.num_vertices * sizeof(n[0]      ));
  2490.     memory::copy(mids,    src.mids,    src.num_vertices * sizeof(mids[0]   ));
  2491.     num_vertices = src.num_vertices;
  2492.   }
  2493.  
  2494. };
  2495.  
  2496.  
  2497.  
  2498.  
  2499.  
  2500. extern Canvas* canvas;
  2501. extern SDL_Surface* geometrySrf;
  2502. extern SDL_Texture* geometryTex;
  2503.  
  2504. //pipeline goes as follows:
  2505. //
  2506. //wka = ori (deep copy)
  2507. //transform meshes in wka (in order of operation):
  2508. //  rotate
  2509. //  scale
  2510. //  translate
  2511. //wka = camera_rotate(wka):
  2512. //  translate
  2513. //  rotate
  2514. //  scale
  2515. //
  2516. //wkb = backface_cull(wka)
  2517. //
  2518. //wka = plane_clip(wkb)
  2519. //wka = apply_luminosity_fade(wka)
  2520. //
  2521. //wkb = project(wka) (also culls triangles that are off-screen)
  2522. //wkb = z_sort(wkb) (make sure to reset indices before doing this!)
  2523. //render(wkb)
  2524.  
  2525. extern GeometryBuffer scene_ori; //original state
  2526. extern GeometryBuffer scene_wka; //work buffer a
  2527. extern GeometryBuffer scene_wkb; //work buffer b
  2528.  
  2529. //camera's position, rotation, and scale
  2530.  //(unlike meshes, the camera's scale is the inverse of the scene scale result,
  2531.  // meaning that the scene's scale is 1.0f/scene_camera.scale. For example,
  2532.  // a scene_camera.scale of 0.25f will grow the scene by 4x)
  2533. extern Location    scene_camera;
  2534.  
  2535.  
  2536.  
  2537.  
  2538.  
  2539. class Canvas {
  2540.   SDL_Window*   win = nullptr;
  2541.   SDL_Renderer* rnd = nullptr;
  2542.   SDL_Texture*  cnv = nullptr;
  2543.   bool  cnvIsTarget = false;
  2544.  
  2545.  
  2546. public:
  2547.  
  2548.  
  2549.   Canvas(int winW, int winH, int cnvW, int cnvH, const char* title = nullptr);
  2550.   ~Canvas();
  2551.  
  2552.  
  2553.   inline SDL_Window*   getWin(){ return win; };
  2554.   inline SDL_Renderer* getRnd(){ return rnd; };
  2555.   inline SDL_Texture*  getCnv(){ return cnv; };
  2556.   inline bool          isCnvTarget(){ return cnvIsTarget; }
  2557.  
  2558.  
  2559.   inline void clear(ABGR c = 0xff000000){
  2560.     if(!cnvIsTarget){
  2561.       if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
  2562.       cnvIsTarget = true;
  2563.     }
  2564.     SDL_SetRenderDrawColor(rnd, c.r, c.g, c.b, c.a);
  2565.     SDL_RenderClear(rnd);
  2566.   }
  2567.  
  2568.  
  2569.   inline void renderGeometry(const GeometryBuffer& buffer){
  2570.     if(!buffer.num_vertices) return;
  2571.     if(!cnvIsTarget){
  2572.       if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
  2573.       cnvIsTarget = true;
  2574.     }
  2575.     if(SDL_RenderGeometryRaw(rnd,                       geometryTex,
  2576.                              (float*)buffer.p,          sizeof(buffer.p[0]),
  2577.                              (SDL_Color*)buffer.colors, sizeof(buffer.colors[0]),
  2578.                              (float*)buffer.t,          sizeof(buffer.t[0]),
  2579.                              buffer.num_vertices,
  2580.                              buffer.indices,            buffer.num_vertices,
  2581.                              sizeof(buffer.indices[0])) < 0)
  2582.     {
  2583.       throw SDL_GetError();
  2584.     }
  2585.   }
  2586.  
  2587.  
  2588.   inline void renderFillRect(const SDL_Rect* dst, ABGR c){
  2589.     if(!cnvIsTarget){
  2590.       if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
  2591.       cnvIsTarget = true;
  2592.     }
  2593.     if(SDL_SetRenderDrawColor(rnd, c.r, c.g, c.b, c.a)<0) throw SDL_GetError();
  2594.     if(SDL_RenderFillRect(rnd, dst)<0) throw SDL_GetError();
  2595.   }
  2596.  
  2597.  
  2598.   inline void renderFillRectBordered(SDL_Rect dst, ABGR c_bdr = 0xffffffff,
  2599.                                                    ABGR c_bkg = 0xff000000)
  2600.   {
  2601.     if(!cnvIsTarget){
  2602.       if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
  2603.       cnvIsTarget = true;
  2604.     }
  2605.     if(SDL_SetRenderDrawColor(rnd, c_bkg.r, c_bkg.g, c_bkg.b, c_bkg.a)<0) throw SDL_GetError();
  2606.     if(SDL_RenderFillRect(rnd, &dst)<0) throw SDL_GetError();
  2607.     if(SDL_SetRenderDrawColor(rnd, c_bdr.r, c_bdr.g, c_bdr.b, c_bdr.a)<0) throw SDL_GetError();
  2608.     if(SDL_RenderDrawRect(rnd, &dst)<0) throw SDL_GetError();
  2609.   }
  2610.  
  2611.  
  2612.   inline void renderCopy(SDL_Texture& texture, const SDL_Rect* src, SDL_Rect* dst){
  2613.     if(!cnvIsTarget){
  2614.       if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
  2615.       cnvIsTarget = true;
  2616.     }
  2617.     if(SDL_RenderCopy(rnd, &texture, src, dst)<0) throw SDL_GetError();
  2618.   }
  2619.  
  2620.  
  2621.   inline void present(unsigned delayMS = 16){
  2622.     if(cnvIsTarget){
  2623.       if(SDL_SetRenderTarget(rnd, nullptr)<0) throw SDL_GetError();
  2624.       cnvIsTarget = false;
  2625.     }
  2626.     SDL_RenderCopy(rnd, cnv, nullptr, nullptr);
  2627.     SDL_RenderPresent(rnd);
  2628.     if(delayMS > 0) SDL_Delay(delayMS);
  2629.   }
  2630.  
  2631. };
  2632.  
  2633.  
  2634.  
  2635.  
  2636.  
  2637. struct MeshSimple {
  2638.   //every 3 verts makes a triangle (no quads nor n-gons)
  2639.   Vertex*  verts;
  2640.   unsigned verts_len; // = faces_len * 3
  2641.   Location p;
  2642.  
  2643.   //index of the mesh's place within scene vertices
  2644.   unsigned first_index;
  2645.  
  2646.   unsigned _padding32;
  2647.  
  2648.  
  2649.   MeshSimple(const char* fileName);
  2650.   ~MeshSimple();
  2651.  
  2652.  
  2653. #if defined(_DEBUG) && 1
  2654.   inline Vertex& vert(size_t i){
  2655.     if(i >= verts_len) throw "vert index out of bounds";
  2656.     return verts[i];
  2657.   }
  2658. #else
  2659.   inline Vertex& vert(size_t i){ return verts[i]; }
  2660. #endif /* defined(_DEBUG) */
  2661.  
  2662. };
  2663.  
  2664.  
  2665.  
  2666.  
  2667.  
  2668. void sceneRebuild(MeshSimple** meshes, int meshes_len);
  2669.  
  2670. #define LOOP_END_MAX 0xffffffff
  2671.  
  2672. //operates on scene_wka, while assuming that
  2673.  //the contents of scene_ori were just copied
  2674. //if mesh == nullptr, rotate entirety of wka
  2675. void rotateWka(Location p, unsigned loop_start, unsigned loop_end);
  2676. void scaleWka(Location p, unsigned loop_start, unsigned loop_end);
  2677. void translateWka(Location p, unsigned loop_start, unsigned loop_end);
  2678. void sceneApplyTransform(MeshSimple* mesh);
  2679.  
  2680. static inline void meshRotate(MeshSimple& mesh){
  2681.   rotateWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
  2682.  
  2683. static inline void meshScale(MeshSimple& mesh){
  2684.   scaleWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
  2685.  
  2686. static inline void meshTranslate(MeshSimple& mesh){
  2687.   translateWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
  2688.  
  2689. static inline void meshTransform(MeshSimple& mesh){
  2690.   sceneApplyTransform(&mesh); }
  2691.  
  2692. static inline void cameraTransform(){
  2693.   sceneApplyTransform(nullptr); }
  2694.  
  2695.  
  2696. //wkb = backface_cull(wka)
  2697. void sceneCullBackFaces();
  2698.  
  2699.  
  2700. //wka = plane_clip(wkb)
  2701. //wka = apply_luminosity_fade(wka)
  2702. void sceneClipPlanesAndLumFade();
  2703.  
  2704.  
  2705. //wkb = project(wka) (also culls triangles that are off-screen)
  2706. void sceneProject(float viewportMultiplierX, float viewportMultiplierY);
  2707.  
  2708.  
  2709. //wkb = z_sort(wkb) (make sure to reset indices before doing this!)
  2710. void sceneZSort();
  2711.  
  2712.  
  2713. //create a vertex snap effect on wkb (optional)
  2714. void scenePS1Geometry(GeometryBuffer& buffer);
  2715.  
  2716.  
  2717.  
  2718.  
  2719.  
  2720. //maybe next time i could do an xor to determine which
  2721.  //work buffer is used each operation...
  2722. static inline void sceneRender(float viewportMultiplierX = ((float)CNV_W)/((float)CNV_H),
  2723.                                float viewportMultiplierY = 1.0f)
  2724. {
  2725.   sceneCullBackFaces();
  2726.   sceneClipPlanesAndLumFade();
  2727. #if PS1_SNAP > 0
  2728.   scenePS1Geometry(scene_wka); //(optional)
  2729. #endif
  2730.   sceneProject(viewportMultiplierX, viewportMultiplierY);
  2731.   //Log("number of active triangles = %4u", (unsigned)(scene_wkb.num_vertices/3));
  2732.   sceneZSort();
  2733.   canvas->renderGeometry(scene_wkb);
  2734. }
  2735.  
  2736.  
  2737.  
  2738.  
  2739.  
  2740. #endif /* _SCENE_HPP */
  2741. /******************************************************************************/
  2742. /******************************************************************************/
  2743. //"sdl2rnd\include\Text.hpp":
  2744. #ifndef _TEXT_HPP
  2745. #define _TEXT_HPP
  2746.  
  2747. #include <SDL2/SDL.h>
  2748.  
  2749.  
  2750.  
  2751.  
  2752.  
  2753. class Text {
  2754.   SDL_Texture* atlas = nullptr;
  2755.   int w, h; //width of each glyph
  2756.  
  2757.  
  2758. public:
  2759.  
  2760.   Text(const char* bmpPath);
  2761.   inline ~Text(){ if(atlas){ SDL_DestroyTexture(atlas); atlas = nullptr; } }
  2762.  
  2763.   //returns the bounding box, in pixels
  2764.   SDL_Point getTextSize(const char* text, float scale = 1.0f);
  2765.  
  2766.   //set x and/or y to this to center the text on-screen on that axis
  2767.   #define CENTER_TEXT (-2147483647) //aka 0x80000001
  2768.   void draw(int x, int y, const char* text, unsigned maxLen = 0, float scale = 1.0f);
  2769.   //(x & y can also be other values <0, which will make the text start drawing at
  2770.    //CNV_W-text_width+x+1 & CNV_H-text_height+y+1 respectively)
  2771.   //(also, the high bit of maxLen must not be set, as that is used as a flag internally)
  2772.  
  2773.   //same rules apply, but the x & y are adjusted
  2774.    //to match a 2-pixel border around the text
  2775.   void drawBox(int x, int y, const char* text, unsigned maxLen = 0, float scale = 1.0f);
  2776.  
  2777.  
  2778. };
  2779.  
  2780.  
  2781.  
  2782.  
  2783.  
  2784. #define FSTR_LEN 4096
  2785. extern char _fstr_failure[]; // = "(FSTR FAILED)"
  2786. extern char _fstr[2][FSTR_LEN];
  2787. extern int  _fstr_which;
  2788. //(could potentially cast result to const char* if necessary)
  2789. #define fstr(...) ( \
  2790.   (snprintf(_fstr[(_fstr_which^=1)],FSTR_LEN,__VA_ARGS__)>=0) \
  2791.     ? _fstr[_fstr_which] : _fstr_failure \
  2792. )
  2793.  
  2794.  
  2795.  
  2796.  
  2797.  
  2798. extern Text* text_p;
  2799. #define text(_x, _y, _maxLen, _text)     text_p->draw   (_x, _y, _text, _maxLen, 1.0f)
  2800. #define text_box(_x, _y, _maxLen, _text) text_p->drawBox(_x, _y, _text, _maxLen, 1.0f)
  2801. #define textf(_x, _y, ...)               text_p->draw   (_x, _y, fstr(__VA_ARGS__), 0, 1.0f)
  2802. #define textf_box(_x, _y, ...)           text_p->drawBox(_x, _y, fstr(__VA_ARGS__), 0, 1.0f)
  2803.  
  2804.  
  2805.  
  2806.  
  2807.  
  2808. #endif /* _TEXT_HPP */
  2809.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement