#======================================================================= # This module is a little fix that works around PC hardware limitations. # Since Essentials isn't working with software rendering anymore, it now # has to deal with the limits of the GPU. For the most part this is no # big deal, but people do have some really big tilesets. # # The fix is simple enough: If your tileset is too big, a new # bitmap will be constructed with all the excess pixels sent to the # image's right side. This basically means that you now have a limit # far higher than you should ever actually need. # # Hardware limit -> max tileset length: # 1024px -> 4096px # 2048px -> 16384px (enough to get the normal limit) # 4096px -> 65536px (enough to load pretty much any tileset) # 8192px -> 262144px # 16384px -> 1048576px (what most people have at this point) # ~Roza/Zoroark #======================================================================= class TilemapRenderer module TilesetWrapper TILESET_WIDTH = SOURCE_TILE_WIDTH * TILESET_TILES_PER_ROW # Looks useless, but covers weird numbers given to mkxp.json or a funky driver MAX_TEX_SIZE = (Bitmap.max_size / 1024) * 1024 MAX_TEX_SIZE_BOOSTED = MAX_TEX_SIZE**2 / TILESET_WIDTH module_function def wrapTileset(originalbmp) width = originalbmp.width height = originalbmp.height if width == TILESET_WIDTH && originalbmp.mega? columns = (height / MAX_TEX_SIZE.to_f).ceil if columns * TILESET_WIDTH > MAX_TEX_SIZE raise "Tileset is too long!\n\nSIZE: #{originalbmp.height}px\nHARDWARE LIMIT: #{MAX_TEX_SIZE}px\nBOOSTED LIMIT: #{MAX_TEX_SIZE_BOOSTED}px" end bmp = Bitmap.new(TILESET_WIDTH * columns, MAX_TEX_SIZE) remainder = height % MAX_TEX_SIZE columns.times do |col| srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE) bmp.blt(col * TILESET_WIDTH, 0, originalbmp, srcrect) end return bmp end return originalbmp end def getWrappedRect(src_rect) ret = Rect.new(0, 0, 0, 0) col = (src_rect.y / MAX_TEX_SIZE.to_f).floor ret.x = col * TILESET_WIDTH + src_rect.x.clamp(0, TILESET_WIDTH) ret.y = src_rect.y % MAX_TEX_SIZE ret.width = src_rect.width.clamp(0, TILESET_WIDTH - src_rect.x) ret.height = src_rect.height.clamp(0, MAX_TEX_SIZE) return ret end private def blitWrappedPixels(destX, destY, dest, src, srcrect) if srcrect.y + srcrect.width < MAX_TEX_SIZE # Save the processing power dest.blt(destX, destY, src, srcrect) return end merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE) srcrect_mod = getWrappedRect(srcrect) if merge # FIXME won't work on heights longer than two columns, but nobody should need # more than 32k pixels high at once anyway side = { :a => MAX_TEX_SIZE - srcrect_mod.y, :b => srcrect_mod.height - MAX_TEX_SIZE + srcrect_mod.y } dest.blt(destX, destY, src, Rect.new(srcrect_mod.x, srcrect_mod.y, srcrect_mod.width, side[:a])) dest.blt(destX, destY + side[:a], src, Rect.new(srcrect_mod.x + TILESET_WIDTH, 0, srcrect_mod.width, side[:b])) else dest.blt(destX, destY, src, srcrect_mod) end end def stretchBlitWrappedPixels(destrect, dest, src, srcrect) if srcrect.y + srcrect.width < MAX_TEX_SIZE # Save the processing power dest.stretch_blt(destrect, src, srcrect) return end # Does a regular blit to a non-megasurface, then stretch_blts that to # the destination. Yes it is slow tmp = Bitmap.new(srcrect.width, srcrect.height) blitWrappedPixels(0, 0, tmp, src, srcrect) dest.stretch_blt(destrect, tmp, Rect.new(0, 0, srcrect.width, srcrect.height)) end end end