Advertisement
Kitomas

tile.cpp as of 2024-05-03

May 3rd, 2024
635
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.53 KB | None | 0 0
  1. #include <tile.hpp>
  2. #include <object.hpp>
  3.  
  4. using namespace kit;
  5.  
  6.  
  7.  
  8.  
  9.  
  10. void Scene::drawBg(){
  11.   //don't draw background at all if scene = 0
  12.   if(!scene) return;
  13.   //if background is nullptr, use the 'missing tileset' bitmap instead
  14.    //(since an error would occur during init if the background is invalid,
  15.    // it should be impossible for bmp_bg to be nullptr in the first place)
  16.   if(bmp_bg == nullptr){ gl_tileset_missing->blitRect(nullptr, nullptr); return; }
  17.   shape::point sizeBmp = bmp_bg->getSize();
  18.   if(sizeBmp.x<1 || sizeBmp.y<1) return;
  19.  
  20.  
  21.   if(!repeat_bg){ //stretch entire background to entire canvas
  22.     bmp_bg->blitRect();
  23.  
  24.  
  25.   } else { //otherwise, repeat background bitmap in a tile pattern
  26.     shape::rect dst; //destination rectangle
  27.     dst.w = sizeBmp.x;
  28.     dst.h = sizeBmp.y;
  29.  
  30.     shape::point sizeCanvas = gl_win->getCanvasSize();
  31.  
  32.     //increase x, then y until the entire canvas is drawn to
  33.     for(dst.y = 0;  dst.y < sizeCanvas.y;  dst.y += dst.h)
  34.     for(dst.x = 0;  dst.x < sizeCanvas.x;  dst.x += dst.w)
  35.     {
  36.       bmp_bg->blitRect(&dst, nullptr); //whole bitmap is used when src = nullptr
  37.     }
  38.  
  39.  
  40.   }
  41.  
  42. }
  43.  
  44.  
  45.  
  46.  
  47.  
  48. //note: if slowdown gets to a point where it's noticable,
  49.  //implement a scene pattern cache
  50.  //(as in, bake the 2 layers as bitmaps when loading a new
  51.  // scene, before blitting those bitmaps every draw call)
  52. void Scene::drawTiles(bool drawForeground){
  53.   if(!scene) return; //don't draw any tiles for scene 0
  54.   Tile*              tiles = pat_mg;
  55.   if(drawForeground) tiles = pat_fg;
  56.  
  57.   if(tileset_a > gl_tilesets_len  ||  tileset_b > gl_tilesets_len)
  58.     throw "tileset index is out of bounds";
  59.  
  60.   Bitmap* tileset[2];
  61.   tileset[0] = gl_tilesets[tileset_a];
  62.   tileset[1] = gl_tilesets[tileset_b];
  63.  
  64.   shape::rect src(0, 0, 24, 24); //determines section of tileset to copy from
  65.   shape::rect dst(0, 0, 24, 24); //determines section of canvas to paste to
  66.  
  67.   shape::point sizeCanvas = gl_win->getCanvasSize();
  68.  
  69.  
  70.  
  71.   //for accessing each tile independent of the 2 for loops
  72.   u32 tileindex = -1; //(set to -1 so i can use preincrement while indexing)
  73.  
  74.   //increase x, then y until the entire canvas is drawn to
  75.   for(dst.y = 0;  dst.y < sizeCanvas.y;  dst.y += dst.h)
  76.   for(dst.x = 0;  dst.x < sizeCanvas.x;  dst.x += dst.w)
  77.   {
  78.     Tile tile = tiles[++tileindex];
  79.     if(!tile.id) continue; //tile 0 is always transparent, so it can be skipped
  80.     src.x = ( tile.id    &0b1111) * src.w; //bits 0-3 are the tileset atlas' x
  81.     src.y = ((tile.id>>4)& 0b111) * src.h; //bits 4-6 are the tileset atlas' y
  82.  
  83.  
  84.     Bitmap* _tileset = tileset[tile.tileset]; //(tile.tileset is 1 bit in size)
  85.     if(_tileset != nullptr){
  86.       _tileset->blitRect(&dst, &src, 0xff00ff); //transparency color is magenta
  87.  
  88.     } else { //tileset doesn't exist; draw 'missing tileset' tile
  89.       gl_tileset_missing->blitRect(&dst, nullptr); //transparency is not used
  90.  
  91.     }
  92.  
  93.   }
  94.  
  95. }
  96.  
  97.  
  98.  
  99.  
  100.  
  101. //(also used by both SceneDescriptor's constructor and destructor!)
  102. void SceneDescriptor::unload(){
  103.   if(fileData == nullptr) return;
  104.  
  105.   BinaryData* _fileData = fileData;
  106.   fileData = nullptr;
  107.   delete _fileData;
  108. }
  109.  
  110.  
  111.  
  112.  
  113.  
  114. #define etThrow(_text, _label) { errorText = _text; goto _label; }
  115. #define dfdThrow(_text) etThrow(_text, _DelFD)
  116. SceneDescriptor::SceneDescriptor(u16 scene_id){
  117.   const char* errorText = "(no error)";
  118.   if(0){ //entered into in the event of an exception
  119.     _DelFD: NULLDELETE(fileData);
  120.     throw errorText;
  121.   }
  122.  
  123.  
  124.  
  125.   if(scene_id > gl_scenes_len)
  126.     throw "scene_id > gl_scenes_len";
  127.  
  128.   unload(); //clean up any previous data, if any exists
  129.  
  130.   if(!fileio::fileExists(gl_fstr->fmt("dat/scene/scene_%u.ksd", scene_id)))
  131.     dfdThrow((const char*)gl_fstr->fmt("\"dat/scene/scene_%u.ksd\" doesn't exist", scene_id));
  132.  
  133.   fileData = new BinaryData(gl_fstr->ptr());
  134.   char* _fileData = fileData->getData();
  135.   size_t fileSize = fileData->getSize();
  136.  
  137.  
  138.  
  139.   //handle header data (-sizeof(BinaryData*) used here as to not overwrite fileData!)
  140.   memory::copy(this, _fileData, sizeof(SceneDescriptor)-sizeof(BinaryData*));
  141.   char* data_end = PTR_OFFSET(_fileData, fileSize, char);
  142.  
  143.  
  144.   if(magic != KSD_MAGIC)
  145.     dfdThrow("file is not a scene descriptor");
  146.   if(dataSize != (fileSize-sizeof(SceneDescriptor)))
  147.     dfdThrow("data size is inconsistent with actual file size");
  148.  
  149.  
  150.   //convert file offsets to their actual pointer value (only if offset != 0)
  151.   if(objs  ) objs   = PTR_OFFSET(_fileData, objs, Object); //(these will remain
  152.   if(pat_mg) pat_mg = PTR_OFFSET(_fileData, pat_mg, Tile);  //as nullptr if they
  153.   if(pat_fg) pat_fg = PTR_OFFSET(_fileData, pat_fg, Tile);  //were already)
  154.   if(((char*)objs  ) > data_end) throw "objs goes past file data";
  155.   if(((char*)pat_mg) > data_end) throw "pat_mg goes past file data";
  156.   if(((char*)pat_fg) > data_end) throw "pat_fg goes past file data";
  157.  
  158.  
  159.   if(bmp_bg > gl_backgrounds_len)
  160.     dfdThrow("bmp_bg is out of range");
  161.  
  162.  
  163.   if( (objs == nullptr)  !=  (objs_len == 0) )
  164.     dfdThrow("objs_len is inconsistent with obj file offset");
  165.  
  166.   //set objs' funcUpdate based on its type id
  167.   for(u32 i=0; i<objs_len; ++i){ //loop will not run if objs_len is 0
  168.     if(objs[i].type > gl_objCallbacks_len) throw "invalid object type";
  169.     objs[i].funcUpdate = gl_objCallbacks[objs[i].type];
  170.  
  171.   }
  172.  
  173.  
  174.   if(tileset_a > gl_tilesets_len) dfdThrow("tileset_a out of range");
  175.   if(tileset_b > gl_tilesets_len) dfdThrow("tileset_b out of range");
  176.  
  177.  
  178.   if(edge_n > gl_scenes_len) dfdThrow("edge_n out of range");
  179.   if(edge_s > gl_scenes_len) dfdThrow("edge_s out of range");
  180.   if(edge_w > gl_scenes_len) dfdThrow("edge_w out of range");
  181.   if(edge_e > gl_scenes_len) dfdThrow("edge_e out of range");
  182.   if(scene != scene_id     ) dfdThrow("scene id in file inconsistent with actual id");
  183.  
  184.  
  185.   if(music      != -1  &&  music      > gl_music_len   ) dfdThrow("music out of range");
  186.   if(ambience_a != -1  &&  ambience_a > gl_ambience_len) dfdThrow("ambience_a out of range");
  187.   if(ambience_b != -1  &&  ambience_b > gl_ambience_len) dfdThrow("ambience_b out of range");
  188.  
  189. }
  190.  
  191.  
  192.  
  193.  
  194.  
  195. void loadScene(u16 scene_id, bool loadObjects, bool loadRest){
  196.   if(!scene_id) return; //0 is a special case for most, if not all asset arrays
  197.   if(scene_id > gl_scenes_len) throw "scene_id > gl_scenes_len";
  198.   if(gl_scenes[scene_id] == nullptr) throw "gl_scenes[scene_id] = nullptr";
  199.  
  200.   //(former bug: sceneNew used to be a stack object set to *gl_scenes[scene_id],
  201.    //but doing so causes its destructor to trigger, making .fileData invalid,
  202.    //which breaks things during the program's uninitialization phase.)
  203.   SceneDescriptor* sceneNew = gl_scenes[scene_id];
  204.  
  205.  
  206. //gl_scene.bmp_bg   = gl_backgrounds[sceneNew->bmp_bg]; //handled later
  207.  
  208.   gl_scene.objs_len   = sceneNew->objs_len;
  209.  
  210.   gl_scene.edge_n     = sceneNew->edge_n;
  211.   gl_scene.edge_s     = sceneNew->edge_s;
  212.   gl_scene.edge_w     = sceneNew->edge_w;
  213.   gl_scene.edge_e     = sceneNew->edge_e;
  214.   gl_scene.scene      = sceneNew->scene;
  215.  
  216.   gl_scene.music      = sceneNew->music;
  217.   gl_scene.ambience_a = sceneNew->ambience_a;
  218.   gl_scene.ambience_b = sceneNew->ambience_b;
  219.  
  220.   gl_scene.tileset_a  = sceneNew->tileset_a;
  221.   gl_scene.tileset_b  = sceneNew->tileset_b;
  222. //gl_scene.obj_reset  = 3; //this is handled separately
  223.   gl_scene.repeat_bg  = sceneNew->repeat_bg;
  224.  
  225.  
  226.  
  227.   struct rle_data {
  228.     u16   run;
  229.     Tile tile;
  230.     rle_data() : run(0), tile(0) {}
  231.   };
  232.  
  233.   char*  file_start = sceneNew->fileData->getData();
  234.   size_t file_size  = sceneNew->fileData->getSize();
  235.   char*  data_start = PTR_OFFSET(file_start, sizeof(SceneDescriptor), char);
  236.   char*  data_end   = PTR_OFFSET(file_start, file_size,               char);
  237.  
  238.  
  239.  
  240.   //copy original state of object data to the active scene (if there is any)
  241.   if(loadObjects  &&  gl_scene.objs_len > 0){
  242.     size_t objs_size = sizeof(Object)*gl_scene.objs_len;
  243.     if(PTR_OFFSET(data_start, objs_size, char) > data_end)
  244.       throw "objs went past file data";
  245.  
  246.     if(gl_scene.objs_len > gl_scene.objs_lenmax){ //increase size if necessary
  247.       memory::realloc(&gl_scene.objs, objs_size);
  248.       gl_scene.objs_lenmax = gl_scene.objs_len;
  249.  
  250.     }
  251.  
  252.     memory::copy(gl_scene.objs, sceneNew->objs, objs_size);
  253.  
  254.   }
  255.  
  256.  
  257.  
  258.   //copy bg and tile data to the scene
  259.   if(loadRest){
  260.     if(sceneNew->fileData == nullptr) return;
  261.  
  262.     gl_scene.bmp_bg = nullptr;
  263.     if(sceneNew->bmp_bg <= gl_backgrounds_len)
  264.       gl_scene.bmp_bg = gl_backgrounds[sceneNew->bmp_bg];
  265.  
  266.     rle_data  tile_mg, tile_fg;
  267.     rle_data* rle_mg   = (rle_data*)sceneNew->pat_mg;
  268.     rle_data* rle_fg   = (rle_data*)sceneNew->pat_fg;
  269.     #define   rle_end    ((rle_data*)data_end)
  270.     rle_data* rle_last = PTR_OFFSET(rle_end, -(s64)sizeof(rle_data), rle_data);
  271.     //^^data_last is the location of the last element of the rle
  272.  
  273.  
  274.     if(rle_mg != nullptr){
  275.       for(u32 i=0; i<PATTERN_LEN; ++i){
  276.         if(tile_mg.run == 0){
  277.           if(rle_mg == rle_end) break;
  278.           if(rle_mg > rle_last) throw "rle_mg went past file data";
  279.           tile_mg = *(rle_mg++);
  280.         }
  281.         gl_scene.pat_mg[i] = tile_mg.tile;
  282.         --tile_mg.run;
  283.  
  284.       }
  285.  
  286.     } else {
  287.       memset0(gl_scene.pat_mg);
  288.  
  289.     }
  290.  
  291.  
  292.     if(rle_fg != nullptr){
  293.       for(u32 i=0; i<PATTERN_LEN; ++i){
  294.         if(tile_fg.run == 0){
  295.           if(rle_fg == rle_end) break;
  296.           if(rle_fg > rle_last) throw "rle_fg went past file data";
  297.           tile_fg = *(rle_fg++);
  298.         }
  299.         gl_scene.pat_fg[i] = tile_fg.tile;
  300.         --tile_fg.run;
  301.  
  302.       }
  303.  
  304.     } else {
  305.       memset0(gl_scene.pat_fg);
  306.  
  307.     }
  308.  
  309.   }
  310.  
  311. }
  312.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement