Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <tile.hpp>
- #include <object.hpp>
- using namespace kit;
- void Scene::drawBg(){
- //don't draw background at all if scene = 0
- if(!scene) return;
- //if background is nullptr, use the 'missing tileset' bitmap instead
- //(since an error would occur during init if the background is invalid,
- // it should be impossible for bmp_bg to be nullptr in the first place)
- if(bmp_bg == nullptr){ gl_tileset_missing->blitRect(nullptr, nullptr); return; }
- shape::point sizeBmp = bmp_bg->getSize();
- if(sizeBmp.x<1 || sizeBmp.y<1) return;
- if(!repeat_bg){ //stretch entire background to entire canvas
- bmp_bg->blitRect();
- } else { //otherwise, repeat background bitmap in a tile pattern
- shape::rect dst; //destination rectangle
- dst.w = sizeBmp.x;
- dst.h = sizeBmp.y;
- shape::point sizeCanvas = gl_win->getCanvasSize();
- //increase x, then y until the entire canvas is drawn to
- for(dst.y = 0; dst.y < sizeCanvas.y; dst.y += dst.h)
- for(dst.x = 0; dst.x < sizeCanvas.x; dst.x += dst.w)
- {
- bmp_bg->blitRect(&dst, nullptr); //whole bitmap is used when src = nullptr
- }
- }
- }
- //note: if slowdown gets to a point where it's noticable,
- //implement a scene pattern cache
- //(as in, bake the 2 layers as bitmaps when loading a new
- // scene, before blitting those bitmaps every draw call)
- void Scene::drawTiles(bool drawForeground){
- if(!scene) return; //don't draw any tiles for scene 0
- Tile* tiles = pat_mg;
- if(drawForeground) tiles = pat_fg;
- if(tileset_a > gl_tilesets_len || tileset_b > gl_tilesets_len)
- throw "tileset index is out of bounds";
- Bitmap* tileset[2];
- tileset[0] = gl_tilesets[tileset_a];
- tileset[1] = gl_tilesets[tileset_b];
- shape::rect src(0, 0, 24, 24); //determines section of tileset to copy from
- shape::rect dst(0, 0, 24, 24); //determines section of canvas to paste to
- shape::point sizeCanvas = gl_win->getCanvasSize();
- //for accessing each tile independent of the 2 for loops
- u32 tileindex = -1; //(set to -1 so i can use preincrement while indexing)
- //increase x, then y until the entire canvas is drawn to
- for(dst.y = 0; dst.y < sizeCanvas.y; dst.y += dst.h)
- for(dst.x = 0; dst.x < sizeCanvas.x; dst.x += dst.w)
- {
- Tile tile = tiles[++tileindex];
- if(!tile.id) continue; //tile 0 is always transparent, so it can be skipped
- src.x = ( tile.id &0b1111) * src.w; //bits 0-3 are the tileset atlas' x
- src.y = ((tile.id>>4)& 0b111) * src.h; //bits 4-6 are the tileset atlas' y
- Bitmap* _tileset = tileset[tile.tileset]; //(tile.tileset is 1 bit in size)
- if(_tileset != nullptr){
- _tileset->blitRect(&dst, &src, 0xff00ff); //transparency color is magenta
- } else { //tileset doesn't exist; draw 'missing tileset' tile
- gl_tileset_missing->blitRect(&dst, nullptr); //transparency is not used
- }
- }
- }
- //(also used by both SceneDescriptor's constructor and destructor!)
- void SceneDescriptor::unload(){
- if(fileData == nullptr) return;
- BinaryData* _fileData = fileData;
- fileData = nullptr;
- delete _fileData;
- }
- #define etThrow(_text, _label) { errorText = _text; goto _label; }
- #define dfdThrow(_text) etThrow(_text, _DelFD)
- SceneDescriptor::SceneDescriptor(u16 scene_id){
- const char* errorText = "(no error)";
- if(0){ //entered into in the event of an exception
- _DelFD: NULLDELETE(fileData);
- throw errorText;
- }
- if(scene_id > gl_scenes_len)
- throw "scene_id > gl_scenes_len";
- unload(); //clean up any previous data, if any exists
- if(!fileio::fileExists(gl_fstr->fmt("dat/scene/scene_%u.ksd", scene_id)))
- dfdThrow((const char*)gl_fstr->fmt("\"dat/scene/scene_%u.ksd\" doesn't exist", scene_id));
- fileData = new BinaryData(gl_fstr->ptr());
- char* _fileData = fileData->getData();
- size_t fileSize = fileData->getSize();
- //handle header data (-sizeof(BinaryData*) used here as to not overwrite fileData!)
- memory::copy(this, _fileData, sizeof(SceneDescriptor)-sizeof(BinaryData*));
- char* data_end = PTR_OFFSET(_fileData, fileSize, char);
- if(magic != KSD_MAGIC)
- dfdThrow("file is not a scene descriptor");
- if(dataSize != (fileSize-sizeof(SceneDescriptor)))
- dfdThrow("data size is inconsistent with actual file size");
- //convert file offsets to their actual pointer value (only if offset != 0)
- if(objs ) objs = PTR_OFFSET(_fileData, objs, Object); //(these will remain
- if(pat_mg) pat_mg = PTR_OFFSET(_fileData, pat_mg, Tile); //as nullptr if they
- if(pat_fg) pat_fg = PTR_OFFSET(_fileData, pat_fg, Tile); //were already)
- if(((char*)objs ) > data_end) throw "objs goes past file data";
- if(((char*)pat_mg) > data_end) throw "pat_mg goes past file data";
- if(((char*)pat_fg) > data_end) throw "pat_fg goes past file data";
- if(bmp_bg > gl_backgrounds_len)
- dfdThrow("bmp_bg is out of range");
- if( (objs == nullptr) != (objs_len == 0) )
- dfdThrow("objs_len is inconsistent with obj file offset");
- //set objs' funcUpdate based on its type id
- for(u32 i=0; i<objs_len; ++i){ //loop will not run if objs_len is 0
- if(objs[i].type > gl_objCallbacks_len) throw "invalid object type";
- objs[i].funcUpdate = gl_objCallbacks[objs[i].type];
- }
- if(tileset_a > gl_tilesets_len) dfdThrow("tileset_a out of range");
- if(tileset_b > gl_tilesets_len) dfdThrow("tileset_b out of range");
- if(edge_n > gl_scenes_len) dfdThrow("edge_n out of range");
- if(edge_s > gl_scenes_len) dfdThrow("edge_s out of range");
- if(edge_w > gl_scenes_len) dfdThrow("edge_w out of range");
- if(edge_e > gl_scenes_len) dfdThrow("edge_e out of range");
- if(scene != scene_id ) dfdThrow("scene id in file inconsistent with actual id");
- if(music != -1 && music > gl_music_len ) dfdThrow("music out of range");
- if(ambience_a != -1 && ambience_a > gl_ambience_len) dfdThrow("ambience_a out of range");
- if(ambience_b != -1 && ambience_b > gl_ambience_len) dfdThrow("ambience_b out of range");
- }
- void loadScene(u16 scene_id, bool loadObjects, bool loadRest){
- if(!scene_id) return; //0 is a special case for most, if not all asset arrays
- if(scene_id > gl_scenes_len) throw "scene_id > gl_scenes_len";
- if(gl_scenes[scene_id] == nullptr) throw "gl_scenes[scene_id] = nullptr";
- //(former bug: sceneNew used to be a stack object set to *gl_scenes[scene_id],
- //but doing so causes its destructor to trigger, making .fileData invalid,
- //which breaks things during the program's uninitialization phase.)
- SceneDescriptor* sceneNew = gl_scenes[scene_id];
- //gl_scene.bmp_bg = gl_backgrounds[sceneNew->bmp_bg]; //handled later
- gl_scene.objs_len = sceneNew->objs_len;
- gl_scene.edge_n = sceneNew->edge_n;
- gl_scene.edge_s = sceneNew->edge_s;
- gl_scene.edge_w = sceneNew->edge_w;
- gl_scene.edge_e = sceneNew->edge_e;
- gl_scene.scene = sceneNew->scene;
- gl_scene.music = sceneNew->music;
- gl_scene.ambience_a = sceneNew->ambience_a;
- gl_scene.ambience_b = sceneNew->ambience_b;
- gl_scene.tileset_a = sceneNew->tileset_a;
- gl_scene.tileset_b = sceneNew->tileset_b;
- //gl_scene.obj_reset = 3; //this is handled separately
- gl_scene.repeat_bg = sceneNew->repeat_bg;
- struct rle_data {
- u16 run;
- Tile tile;
- rle_data() : run(0), tile(0) {}
- };
- char* file_start = sceneNew->fileData->getData();
- size_t file_size = sceneNew->fileData->getSize();
- char* data_start = PTR_OFFSET(file_start, sizeof(SceneDescriptor), char);
- char* data_end = PTR_OFFSET(file_start, file_size, char);
- //copy original state of object data to the active scene (if there is any)
- if(loadObjects && gl_scene.objs_len > 0){
- size_t objs_size = sizeof(Object)*gl_scene.objs_len;
- if(PTR_OFFSET(data_start, objs_size, char) > data_end)
- throw "objs went past file data";
- if(gl_scene.objs_len > gl_scene.objs_lenmax){ //increase size if necessary
- memory::realloc(&gl_scene.objs, objs_size);
- gl_scene.objs_lenmax = gl_scene.objs_len;
- }
- memory::copy(gl_scene.objs, sceneNew->objs, objs_size);
- }
- //copy bg and tile data to the scene
- if(loadRest){
- if(sceneNew->fileData == nullptr) return;
- gl_scene.bmp_bg = nullptr;
- if(sceneNew->bmp_bg <= gl_backgrounds_len)
- gl_scene.bmp_bg = gl_backgrounds[sceneNew->bmp_bg];
- rle_data tile_mg, tile_fg;
- rle_data* rle_mg = (rle_data*)sceneNew->pat_mg;
- rle_data* rle_fg = (rle_data*)sceneNew->pat_fg;
- #define rle_end ((rle_data*)data_end)
- rle_data* rle_last = PTR_OFFSET(rle_end, -(s64)sizeof(rle_data), rle_data);
- //^^data_last is the location of the last element of the rle
- if(rle_mg != nullptr){
- for(u32 i=0; i<PATTERN_LEN; ++i){
- if(tile_mg.run == 0){
- if(rle_mg == rle_end) break;
- if(rle_mg > rle_last) throw "rle_mg went past file data";
- tile_mg = *(rle_mg++);
- }
- gl_scene.pat_mg[i] = tile_mg.tile;
- --tile_mg.run;
- }
- } else {
- memset0(gl_scene.pat_mg);
- }
- if(rle_fg != nullptr){
- for(u32 i=0; i<PATTERN_LEN; ++i){
- if(tile_fg.run == 0){
- if(rle_fg == rle_end) break;
- if(rle_fg > rle_last) throw "rle_fg went past file data";
- tile_fg = *(rle_fg++);
- }
- gl_scene.pat_fg[i] = tile_fg.tile;
- --tile_fg.run;
- }
- } else {
- memset0(gl_scene.pat_fg);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement