Updates tilemap renderer for extra autotiles

This commit is contained in:
chardub
2025-04-19 13:05:42 -04:00
parent d559b813ed
commit 05bb3f0d76
19 changed files with 258 additions and 159 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -126,6 +126,10 @@ class Game_Map
return @map.data; return @map.data;
end end
def tileset_id;
return @map.tileset_id;
end
def name def name
ret = pbGetMessage(MessageTypes::MapNames, @map_id) ret = pbGetMessage(MessageTypes::MapNames, @map_id)
ret.gsub!(/\\PN/, $Trainer.name) if $Trainer ret.gsub!(/\\PN/, $Trainer.name) if $Trainer

View File

@@ -47,7 +47,11 @@ class Spriteset_Map
def initialize(map=nil) def initialize(map=nil)
@map = (map) ? map : $game_map @map = (map) ? map : $game_map
$scene.map_renderer.add_tileset(@map.tileset_name) $scene.map_renderer.add_tileset(@map.tileset_name)
@map.autotile_names.each { |filename| $scene.map_renderer.add_autotile(filename) } @map.autotile_names.each do |filename|
$scene.map_renderer.add_autotile(filename)
$scene.map_renderer.add_extra_autotiles(@map.tileset_id)
end
@panorama = AnimatedPlane.new(@@viewport0) @panorama = AnimatedPlane.new(@@viewport0)
@fog = AnimatedPlane.new(@@viewport1) @fog = AnimatedPlane.new(@@viewport1)
@fog.z = 3000 @fog.z = 3000
@@ -77,7 +81,10 @@ class Spriteset_Map
def dispose def dispose
if $scene.is_a?(Scene_Map) if $scene.is_a?(Scene_Map)
$scene.map_renderer.remove_tileset(@map.tileset_name) $scene.map_renderer.remove_tileset(@map.tileset_name)
@map.autotile_names.each { |filename| $scene.map_renderer.remove_autotile(filename) } @map.autotile_names.each do |filename|
$scene.map_renderer.remove_autotile(filename)
$scene.map_renderer.remove_extra_autotiles(@map.tileset_id)
end
end end
@panorama.dispose @panorama.dispose
@fog.dispose @fog.dispose

View File

@@ -15,6 +15,8 @@ class TilemapRenderer
DISPLAY_TILE_HEIGHT = Game_Map::TILE_HEIGHT rescue 32 DISPLAY_TILE_HEIGHT = Game_Map::TILE_HEIGHT rescue 32
SOURCE_TILE_WIDTH = 32 SOURCE_TILE_WIDTH = 32
SOURCE_TILE_HEIGHT = 32 SOURCE_TILE_HEIGHT = 32
ZOOM_X = DISPLAY_TILE_WIDTH / SOURCE_TILE_WIDTH
ZOOM_Y = DISPLAY_TILE_HEIGHT / SOURCE_TILE_HEIGHT
TILESET_TILES_PER_ROW = 8 TILESET_TILES_PER_ROW = 8
AUTOTILES_COUNT = 8 # Counting the blank tile as an autotile AUTOTILES_COUNT = 8 # Counting the blank tile as an autotile
TILES_PER_AUTOTILE = 48 TILES_PER_AUTOTILE = 48
@@ -23,6 +25,30 @@ class TilemapRenderer
# seconds instead. # seconds instead.
AUTOTILE_FRAME_DURATION = 5 # In 1/20ths of a second AUTOTILE_FRAME_DURATION = 5 # In 1/20ths of a second
# Filenames of extra autotiles for each tileset. Each tileset's entry is an
# array containing two other arrays (you can leave either of those empty, but
# they must be defined):
# - The first sub-array is for large autotiles, i.e. ones with 48 different
# tile layouts. For example, "Brick path" and "Sea".
# - The second is for single tile autotiles. For example, "Flowers1" and
# "Waterfall"
# The top tiles of the tileset will instead use these autotiles. Large
# autotiles come first, in the same 8x6 layout as you see when you double-
# click on a real autotile in RMXP. After that are the single tile autotiles.
# Extra autotiles are only useful if the tiles are animated, because otherwise
# you just have some tiles which belong in the tileset instead.
# Examples:
# 1 => [["Sand shore"], ["Flowers2"]],
# 2 => [[], ["Flowers2", "Waterfall", "Waterfall crest", "Waterfall bottom"]],
# 6 => [["Water rock", "Sea deep"], []]
EXTRA_AUTOTILES = {
# 23 => {
# 384 => "flowers_pink",
# }
}
#============================================================================= #=============================================================================
# #
#============================================================================= #=============================================================================
@@ -34,6 +60,7 @@ class TilemapRenderer
@bitmaps = {} @bitmaps = {}
@bitmap_wraps = {} # Whether each tileset is a mega texture and has multiple columns @bitmap_wraps = {} # Whether each tileset is a mega texture and has multiple columns
@load_counts = {} @load_counts = {}
@bridge = 0
@changed = true @changed = true
end end
@@ -105,7 +132,7 @@ class TilemapRenderer
@frame_counts = {} # Number of frames in each autotile @frame_counts = {} # Number of frames in each autotile
@frame_durations = {} # How long each frame lasts per autotile @frame_durations = {} # How long each frame lasts per autotile
@current_frames = {} # Which frame each autotile is currently showing @current_frames = {} # Which frame each autotile is currently showing
@timer = 0.0 @timer = 0.0#System.uptime
end end
def []=(filename, value) def []=(filename, value)
@@ -151,7 +178,7 @@ class TilemapRenderer
bitmap = @bitmaps[filename] bitmap = @bitmaps[filename]
@frame_counts[filename] = [bitmap.width / SOURCE_TILE_WIDTH, 1].max @frame_counts[filename] = [bitmap.width / SOURCE_TILE_WIDTH, 1].max
if bitmap.height > SOURCE_TILE_HEIGHT && @bitmap_wraps[filename] if bitmap.height > SOURCE_TILE_HEIGHT && @bitmap_wraps[filename]
@frame_counts[filename] /= 2 if @bitmap_wraps[filename] @frame_counts[filename] /= 2
end end
end end
return @frame_counts[filename] return @frame_counts[filename]
@@ -162,9 +189,7 @@ class TilemapRenderer
end end
def current_frame(filename) def current_frame(filename)
if !@current_frames[filename] set_current_frame(filename) if !@current_frames[filename]
set_current_frame(filename)
end
return @current_frames[filename] return @current_frames[filename]
end end
@@ -180,7 +205,6 @@ class TilemapRenderer
def set_src_rect(tile, tile_id) def set_src_rect(tile, tile_id)
return if nil_or_empty?(tile.filename) return if nil_or_empty?(tile.filename)
return if !@bitmaps[tile.filename] return if !@bitmaps[tile.filename]
return if tile_id < TILES_PER_AUTOTILE # Blank tile
frame = current_frame(tile.filename) frame = current_frame(tile.filename)
if @bitmaps[tile.filename].height == SOURCE_TILE_HEIGHT if @bitmaps[tile.filename].height == SOURCE_TILE_HEIGHT
tile.src_rect.x = frame * SOURCE_TILE_WIDTH tile.src_rect.x = frame * SOURCE_TILE_WIDTH
@@ -202,7 +226,7 @@ class TilemapRenderer
super super
@timer += Graphics.delta_s @timer += Graphics.delta_s
# Update the current frame for each autotile # Update the current frame for each autotile
@bitmaps.keys.each do |filename| @bitmaps.each_key do |filename|
next if !@bitmaps[filename] || @bitmaps[filename].disposed? next if !@bitmaps[filename] || @bitmaps[filename].disposed?
old_frame = @current_frames[filename] old_frame = @current_frames[filename]
set_current_frame(filename) set_current_frame(filename)
@@ -216,6 +240,7 @@ class TilemapRenderer
#============================================================================= #=============================================================================
class TileSprite < Sprite class TileSprite < Sprite
attr_accessor :filename attr_accessor :filename
attr_accessor :tile_id
attr_accessor :is_autotile attr_accessor :is_autotile
attr_accessor :animated attr_accessor :animated
attr_accessor :priority attr_accessor :priority
@@ -223,10 +248,13 @@ class TilemapRenderer
attr_accessor :bridge attr_accessor :bridge
attr_accessor :need_refresh attr_accessor :need_refresh
def set_bitmap(filename, autotile, animated, priority, bitmap) def set_bitmap(filename, tile_id, autotile, animated, priority, bitmap)
self.bitmap = bitmap self.bitmap = bitmap
self.src_rect = Rect.new(0, 0, DISPLAY_TILE_WIDTH, DISPLAY_TILE_HEIGHT) self.src_rect = Rect.new(0, 0, SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT)
self.zoom_x = ZOOM_X
self.zoom_y = ZOOM_Y
@filename = filename @filename = filename
@tile_id = tile_id
@is_autotile = autotile @is_autotile = autotile
@animated = animated @animated = animated
@priority = priority @priority = priority
@@ -237,9 +265,8 @@ class TilemapRenderer
end end
end end
#============================================================================= #-----------------------------------------------------------------------------
#
#=============================================================================
def initialize(viewport) def initialize(viewport)
@tilesets = TilesetBitmaps.new @tilesets = TilesetBitmaps.new
@autotiles = AutotileBitmaps.new @autotiles = AutotileBitmaps.new
@@ -297,7 +324,7 @@ class TilemapRenderer
return @disposed return @disposed
end end
#============================================================================= #-----------------------------------------------------------------------------
def add_tileset(filename) def add_tileset(filename)
@tilesets.add(filename) @tilesets.add(filename)
@@ -315,28 +342,60 @@ class TilemapRenderer
@autotiles.remove(filename) @autotiles.remove(filename)
end end
#============================================================================= def add_extra_autotiles(tileset_id)
return if !EXTRA_AUTOTILES[tileset_id]
EXTRA_AUTOTILES[tileset_id].each do |arr|
arr.each { |filename| add_autotile(filename) }
end
end
def remove_extra_autotiles(tileset_id)
return if !EXTRA_AUTOTILES[tileset_id]
EXTRA_AUTOTILES[tileset_id].each do |arr|
arr.each { |filename| remove_autotile(filename) }
end
end
#-----------------------------------------------------------------------------
def refresh def refresh
@need_refresh = true @need_refresh = true
end end
def refresh_tile_bitmap(tile, map, tile_id) def refresh_tile_bitmap(tile, map, tile_id)
tile.tile_id = tile_id
if tile_id < TILES_PER_AUTOTILE if tile_id < TILES_PER_AUTOTILE
tile.set_bitmap("", false, false, 0, nil) tile.set_bitmap("", tile_id, false, false, 0, nil)
tile.shows_reflection = false tile.shows_reflection = false
tile.bridge = false tile.bridge = false
else else
terrain_tag = map.terrain_tags[tile_id] || 0 terrain_tag = map.terrain_tags[tile_id] || 0
terrain_tag_data = GameData::TerrainTag.try_get(terrain_tag) terrain_tag_data = GameData::TerrainTag.try_get(terrain_tag)
priority = map.priorities[tile_id] || 0 priority = map.priorities[tile_id] || 0
if tile_id < TILESET_START_ID single_autotile_start_id = TILESET_START_ID
filename = map.autotile_names[tile_id / TILES_PER_AUTOTILE - 1] true_tileset_start_id = TILESET_START_ID
tile.set_bitmap(filename, true, @autotiles.animated?(filename), extra_autotile_arrays = EXTRA_AUTOTILES[map.tileset_id]
if extra_autotile_arrays
large_autotile_count = extra_autotile_arrays[0].length
single_autotile_count = extra_autotile_arrays[1].length
single_autotile_start_id += large_autotile_count * TILES_PER_AUTOTILE
true_tileset_start_id += large_autotile_count * TILES_PER_AUTOTILE
true_tileset_start_id += single_autotile_count
end
if tile_id < true_tileset_start_id
filename = ""
if tile_id < TILESET_START_ID # Real autotiles
filename = map.autotile_names[(tile_id / TILES_PER_AUTOTILE) - 1]
elsif tile_id < single_autotile_start_id # Large extra autotiles
filename = extra_autotile_arrays[0][(tile_id - TILESET_START_ID) / TILES_PER_AUTOTILE]
else # Single extra autotiles
filename = extra_autotile_arrays[1][tile_id - single_autotile_start_id]
end
tile.set_bitmap(filename, tile_id, true, @autotiles.animated?(filename),
priority, @autotiles[filename]) priority, @autotiles[filename])
else else
filename = map.tileset_name filename = map.tileset_name
tile.set_bitmap(filename, false, false, priority, @tilesets[filename]) tile.set_bitmap(filename, tile_id, false, false, priority, @tilesets[filename])
end end
tile.shows_reflection = terrain_tag_data&.shows_reflections tile.shows_reflection = terrain_tag_data&.shows_reflections
tile.bridge = terrain_tag_data&.bridge tile.bridge = terrain_tag_data&.bridge
@@ -345,7 +404,7 @@ class TilemapRenderer
end end
def refresh_tile_src_rect(tile, tile_id) def refresh_tile_src_rect(tile, tile_id)
if tile_id < TILESET_START_ID if tile.is_autotile
@autotiles.set_src_rect(tile, tile_id) @autotiles.set_src_rect(tile, tile_id)
else else
@tilesets.set_src_rect(tile, tile_id) @tilesets.set_src_rect(tile, tile_id)
@@ -360,8 +419,8 @@ class TilemapRenderer
# x and y are the positions of tile within @tiles, not a map x/y # x and y are the positions of tile within @tiles, not a map x/y
def refresh_tile_coordinates(tile, x, y) def refresh_tile_coordinates(tile, x, y)
tile.x = x * DISPLAY_TILE_WIDTH - @pixel_offset_x tile.x = (x * DISPLAY_TILE_WIDTH) - @pixel_offset_x
tile.y = y * DISPLAY_TILE_HEIGHT - @pixel_offset_y tile.y = (y * DISPLAY_TILE_HEIGHT) - @pixel_offset_y
end end
def refresh_tile_z(tile, map, y, layer, tile_id) def refresh_tile_z(tile, map, y, layer, tile_id)
@@ -382,7 +441,7 @@ class TilemapRenderer
tile.need_refresh = false tile.need_refresh = false
end end
#============================================================================= #-----------------------------------------------------------------------------
def check_if_screen_moved def check_if_screen_moved
ret = false ret = false
@@ -391,20 +450,21 @@ class TilemapRenderer
if MapFactoryHelper.hasConnections?(@current_map_id) if MapFactoryHelper.hasConnections?(@current_map_id)
offsets = $MapFactory.getRelativePos(@current_map_id, 0, 0, $game_map.map_id, 0, 0) offsets = $MapFactory.getRelativePos(@current_map_id, 0, 0, $game_map.map_id, 0, 0)
if offsets if offsets
@tile_offset_x += offsets[0] @tile_offset_x -= offsets[0]
@tile_offset_y += offsets[1] @tile_offset_y -= offsets[1]
else else
ret = true # Need a full refresh ret = true # Need a full refresh
end end
else
ret = true
end end
@current_map_id = $game_map.map_id @current_map_id = $game_map.map_id
ret = true
end end
# Check for tile movement # Check for tile movement
current_map_display_x = ($game_map.display_x.to_f / Game_Map::X_SUBPIXELS).round current_map_display_x = ($game_map.display_x.to_f / Game_Map::X_SUBPIXELS).round
current_map_display_y = ($game_map.display_y.to_f / Game_Map::Y_SUBPIXELS).round current_map_display_y = ($game_map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
new_tile_offset_x = current_map_display_x / DISPLAY_TILE_WIDTH new_tile_offset_x = (current_map_display_x / SOURCE_TILE_WIDTH) * ZOOM_X
new_tile_offset_y = current_map_display_y / DISPLAY_TILE_HEIGHT new_tile_offset_y = (current_map_display_y / SOURCE_TILE_HEIGHT) * ZOOM_Y
if new_tile_offset_x != @tile_offset_x if new_tile_offset_x != @tile_offset_x
if new_tile_offset_x > @tile_offset_x if new_tile_offset_x > @tile_offset_x
# Take tile stacks off the right and insert them at the beginning (left) # Take tile stacks off the right and insert them at the beginning (left)
@@ -453,8 +513,8 @@ class TilemapRenderer
@tile_offset_y = new_tile_offset_y @tile_offset_y = new_tile_offset_y
end end
# Check for pixel movement # Check for pixel movement
new_pixel_offset_x = current_map_display_x % SOURCE_TILE_WIDTH new_pixel_offset_x = (current_map_display_x % SOURCE_TILE_WIDTH) * ZOOM_X
new_pixel_offset_y = current_map_display_y % SOURCE_TILE_HEIGHT new_pixel_offset_y = (current_map_display_y % SOURCE_TILE_HEIGHT) * ZOOM_Y
if new_pixel_offset_x != @pixel_offset_x if new_pixel_offset_x != @pixel_offset_x
@screen_moved = true @screen_moved = true
@pixel_offset_x = new_pixel_offset_x @pixel_offset_x = new_pixel_offset_x
@@ -467,7 +527,7 @@ class TilemapRenderer
return ret return ret
end end
#============================================================================= #-----------------------------------------------------------------------------
def update def update
# Update tone # Update tone
@@ -483,7 +543,7 @@ class TilemapRenderer
if @old_color != @color if @old_color != @color
@tiles.each do |col| @tiles.each do |col|
col.each do |coord| col.each do |coord|
coord.each { |tile| tile.color = @tone } coord.each { |tile| tile.color = @color }
end end
end end
@old_color = @color.clone @old_color = @color.clone
@@ -500,6 +560,10 @@ class TilemapRenderer
# Check whether the screen has moved since the last update # Check whether the screen has moved since the last update
@screen_moved = false @screen_moved = false
@screen_moved_vertically = false @screen_moved_vertically = false
if $PokemonGlobal.bridge != @bridge
@bridge = $PokemonGlobal.bridge
@screen_moved_vertically = true # To update bridge tiles' z values
end
do_full_refresh = true if check_if_screen_moved do_full_refresh = true if check_if_screen_moved
# Update all tile sprites # Update all tile sprites
visited = [] visited = []
@@ -510,7 +574,9 @@ class TilemapRenderer
$MapFactory.maps.each do |map| $MapFactory.maps.each do |map|
# Calculate x/y ranges of tile sprites that represent them # Calculate x/y ranges of tile sprites that represent them
map_display_x = (map.display_x.to_f / Game_Map::X_SUBPIXELS).round map_display_x = (map.display_x.to_f / Game_Map::X_SUBPIXELS).round
map_display_x = ((map_display_x + (Graphics.width / 2)) * ZOOM_X) - (Graphics.width / 2) if ZOOM_X != 1
map_display_y = (map.display_y.to_f / Game_Map::Y_SUBPIXELS).round map_display_y = (map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
map_display_y = ((map_display_y + (Graphics.height / 2)) * ZOOM_Y) - (Graphics.height / 2) if ZOOM_Y != 1
map_display_x_tile = map_display_x / DISPLAY_TILE_WIDTH map_display_x_tile = map_display_x / DISPLAY_TILE_WIDTH
map_display_y_tile = map_display_y / DISPLAY_TILE_HEIGHT map_display_y_tile = map_display_y / DISPLAY_TILE_HEIGHT
start_x = [-map_display_x_tile, 0].max start_x = [-map_display_x_tile, 0].max
@@ -521,13 +587,13 @@ class TilemapRenderer
end_y = [end_y, map.height - map_display_y_tile - 1].min end_y = [end_y, map.height - map_display_y_tile - 1].min
next if start_x > end_x || start_y > end_y || end_x < 0 || end_y < 0 next if start_x > end_x || start_y > end_y || end_x < 0 || end_y < 0
# Update all tile sprites representing this map # Update all tile sprites representing this map
for i in start_x..end_x (start_x..end_x).each do |i|
tile_x = i + map_display_x_tile tile_x = i + map_display_x_tile
for j in start_y..end_y (start_y..end_y).each do |j|
tile_y = j + map_display_y_tile tile_y = j + map_display_y_tile
@tiles[i][j].each_with_index do |tile, layer| @tiles[i][j].each_with_index do |tile, layer|
tile_id = map.data[tile_x, tile_y, layer] tile_id = map.data[tile_x, tile_y, layer]
if do_full_refresh || tile.need_refresh if do_full_refresh || tile.need_refresh || tile.tile_id != tile_id
refresh_tile(tile, i, j, map, layer, tile_id) refresh_tile(tile, i, j, map, layer, tile_id)
else else
refresh_tile_frame(tile, tile_id) if tile.animated && @autotiles.changed refresh_tile_frame(tile, tile_id) if tile.animated && @autotiles.changed
@@ -547,7 +613,7 @@ class TilemapRenderer
col.each_with_index do |coord, j| col.each_with_index do |coord, j|
next if visited[i][j] next if visited[i][j]
coord.each do |tile| coord.each do |tile|
tile.set_bitmap("", false, false, 0, nil) tile.set_bitmap("", 0, false, false, 0, nil)
tile.shows_reflection = false tile.shows_reflection = false
tile.bridge = false tile.bridge = false
end end

View File

@@ -1,13 +1,13 @@
#======================================================================= #===============================================================================
# This module is a little fix that works around PC hardware limitations. # This module is a little fix that works around PC hardware limitations. Since
# Since Essentials isn't working with software rendering anymore, it now # Essentials isn't working with software rendering anymore, it now has to deal
# has to deal with the limits of the GPU. For the most part this is no # with the limits of the GPU. For the most part this is no big deal, but people
# big deal, but people do have some really big tilesets. # do have some really big tilesets.
# #
# The fix is simple enough: If your tileset is too big, a new # The fix is simple enough: If your tileset is too big, a new bitmap will be
# bitmap will be constructed with all the excess pixels sent to the # constructed with all the excess pixels sent to the image's right side. This
# image's right side. This basically means that you now have a limit # basically means that you now have a limit far higher than you should ever
# far higher than you should ever actually need. # actually need.
# #
# Hardware limit -> max tileset length: # Hardware limit -> max tileset length:
# 1024px -> 4096px # 1024px -> 4096px
@@ -15,15 +15,13 @@
# 4096px -> 65536px (enough to load pretty much any tileset) # 4096px -> 65536px (enough to load pretty much any tileset)
# 8192px -> 262144px # 8192px -> 262144px
# 16384px -> 1048576px (what most people have at this point) # 16384px -> 1048576px (what most people have at this point)
#===============================================================================
# ~Roza/Zoroark
#=======================================================================
class TilemapRenderer class TilemapRenderer
module TilesetWrapper module TilesetWrapper
TILESET_WIDTH = SOURCE_TILE_WIDTH * TILESET_TILES_PER_ROW TILESET_WIDTH = SOURCE_TILE_WIDTH * TILESET_TILES_PER_ROW
# Looks useless, but covers weird numbers given to mkxp.json or a funky driver # 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 = (Bitmap.max_size / 1024) * 1024
MAX_TEX_SIZE_BOOSTED = MAX_TEX_SIZE**2 / TILESET_WIDTH MAX_TEX_SIZE_BOOSTED = (MAX_TEX_SIZE**2) / TILESET_WIDTH
module_function module_function
@@ -37,6 +35,7 @@ class TilemapRenderer
end end
bmp = Bitmap.new(TILESET_WIDTH * columns, MAX_TEX_SIZE) bmp = Bitmap.new(TILESET_WIDTH * columns, MAX_TEX_SIZE)
remainder = height % MAX_TEX_SIZE remainder = height % MAX_TEX_SIZE
remainder = MAX_TEX_SIZE if remainder == 0
columns.times do |col| columns.times do |col|
srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE) srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE)
bmp.blt(col * TILESET_WIDTH, 0, originalbmp, srcrect) bmp.blt(col * TILESET_WIDTH, 0, originalbmp, srcrect)
@@ -49,13 +48,15 @@ class TilemapRenderer
def getWrappedRect(src_rect) def getWrappedRect(src_rect)
ret = Rect.new(0, 0, 0, 0) ret = Rect.new(0, 0, 0, 0)
col = (src_rect.y / MAX_TEX_SIZE.to_f).floor col = (src_rect.y / MAX_TEX_SIZE.to_f).floor
ret.x = col * TILESET_WIDTH + src_rect.x.clamp(0, TILESET_WIDTH) ret.x = (col * TILESET_WIDTH) + src_rect.x.clamp(0, TILESET_WIDTH)
ret.y = src_rect.y % MAX_TEX_SIZE ret.y = src_rect.y % MAX_TEX_SIZE
ret.width = src_rect.width.clamp(0, TILESET_WIDTH - src_rect.x) ret.width = src_rect.width.clamp(0, TILESET_WIDTH - src_rect.x)
ret.height = src_rect.height.clamp(0, MAX_TEX_SIZE) ret.height = src_rect.height.clamp(0, MAX_TEX_SIZE)
return ret return ret
end end
#---------------------------------------------------------------------------
private private
def blitWrappedPixels(destX, destY, dest, src, srcrect) def blitWrappedPixels(destX, destY, dest, src, srcrect)
@@ -67,7 +68,7 @@ class TilemapRenderer
merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE) merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE)
srcrect_mod = getWrappedRect(srcrect) srcrect_mod = getWrappedRect(srcrect)
if merge if merge
# FIXME won't work on heights longer than two columns, but nobody should need # FIXME: won't work on heights longer than two columns, but nobody should need
# more than 32k pixels high at once anyway # more than 32k pixels high at once anyway
side = { side = {
:a => MAX_TEX_SIZE - srcrect_mod.y, :a => MAX_TEX_SIZE - srcrect_mod.y,

View File

@@ -1,3 +1,6 @@
#===============================================================================
#
#===============================================================================
class TilemapRenderer class TilemapRenderer
module AutotileExpander module AutotileExpander
MAX_TEXTURE_SIZE = (Bitmap.max_size / 1024) * 1024 MAX_TEXTURE_SIZE = (Bitmap.max_size / 1024) * 1024
@@ -36,11 +39,11 @@ class TilemapRenderer
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT)) SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 2 # Top right corner when 2 # Top right corner
new_bitmap.blt(dest_x, dest_y, bitmap, new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(SOURCE_TILE_WIDTH + frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 4, Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 4,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT)) SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 4 # Bottom right corner when 4 # Bottom right corner
new_bitmap.blt(dest_x, dest_y, bitmap, new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(SOURCE_TILE_WIDTH + frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 5, Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 5,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT)) SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 8 # Bottom left corner when 8 # Bottom left corner
new_bitmap.blt(dest_x, dest_y, bitmap, new_bitmap.blt(dest_x, dest_y, bitmap,

View File

@@ -1,20 +1,23 @@
#===============================================================================
#
#===============================================================================
class TileDrawingHelper class TileDrawingHelper
attr_accessor :tileset attr_accessor :tileset
attr_accessor :autotiles attr_accessor :autotiles
AUTOTILE_PATTERNS = [ AUTOTILE_PATTERNS = [
[ [27, 28, 33, 34], [ 5, 28, 33, 34], [27, 6, 33, 34], [ 5, 6, 33, 34], [[27, 28, 33, 34], [5, 28, 33, 34], [27, 6, 33, 34], [5, 6, 33, 34],
[27, 28, 33, 12], [ 5, 28, 33, 12], [27, 6, 33, 12], [ 5, 6, 33, 12] ], [27, 28, 33, 12], [5, 28, 33, 12], [27, 6, 33, 12], [5, 6, 33, 12]],
[ [27, 28, 11, 34], [ 5, 28, 11, 34], [27, 6, 11, 34], [ 5, 6, 11, 34], [[27, 28, 11, 34], [5, 28, 11, 34], [27, 6, 11, 34], [5, 6, 11, 34],
[27, 28, 11, 12], [ 5, 28, 11, 12], [27, 6, 11, 12], [ 5, 6, 11, 12] ], [27, 28, 11, 12], [5, 28, 11, 12], [27, 6, 11, 12], [5, 6, 11, 12]],
[ [25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12], [[25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12],
[15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12] ], [15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12]],
[ [29, 30, 35, 36], [29, 30, 11, 36], [ 5, 30, 35, 36], [ 5, 30, 11, 36], [[29, 30, 35, 36], [29, 30, 11, 36], [5, 30, 35, 36], [5, 30, 11, 36],
[39, 40, 45, 46], [ 5, 40, 45, 46], [39, 6, 45, 46], [ 5, 6, 45, 46] ], [39, 40, 45, 46], [5, 40, 45, 46], [39, 6, 45, 46], [5, 6, 45, 46]],
[ [25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12], [[25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
[17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [ 5, 42, 47, 48] ], [17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [5, 42, 47, 48]],
[ [37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44], [[37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
[37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [ 1, 2, 7, 8] ] [37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [1, 2, 7, 8]]
] ]
# converts neighbors returned from tableNeighbors to tile indexes # converts neighbors returned from tableNeighbors to tile indexes
@@ -37,15 +40,20 @@ class TileDrawingHelper
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0 36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
] ]
def self.tableNeighbors(data,x,y) def self.tableNeighbors(data, x, y, layer = nil)
return 0 if x < 0 || x >= data.xsize return 0 if x < 0 || x >= data.xsize
return 0 if y < 0 || y >= data.ysize return 0 if y < 0 || y >= data.ysize
t = data[x,y] if layer.nil?
t = data[x, y]
else
t = data[x, y, layer]
end
xp1 = [x + 1, data.xsize - 1].min xp1 = [x + 1, data.xsize - 1].min
yp1 = [y + 1, data.ysize - 1].min yp1 = [y + 1, data.ysize - 1].min
xm1 = [x - 1, 0].max xm1 = [x - 1, 0].max
ym1 = [y - 1, 0].max ym1 = [y - 1, 0].max
i = 0 i = 0
if layer.nil?
i |= 0x01 if data[ x, ym1] == t # N i |= 0x01 if data[ x, ym1] == t # N
i |= 0x02 if data[xp1, ym1] == t # NE i |= 0x02 if data[xp1, ym1] == t # NE
i |= 0x04 if data[xp1, y] == t # E i |= 0x04 if data[xp1, y] == t # E
@@ -54,18 +62,30 @@ class TileDrawingHelper
i |= 0x20 if data[xm1, yp1] == t # SW i |= 0x20 if data[xm1, yp1] == t # SW
i |= 0x40 if data[xm1, y] == t # W i |= 0x40 if data[xm1, y] == t # W
i |= 0x80 if data[xm1, ym1] == t # NW i |= 0x80 if data[xm1, ym1] == t # NW
else
i |= 0x01 if data[ x, ym1, layer] == t # N
i |= 0x02 if data[xp1, ym1, layer] == t # NE
i |= 0x04 if data[xp1, y, layer] == t # E
i |= 0x08 if data[xp1, yp1, layer] == t # SE
i |= 0x10 if data[ x, yp1, layer] == t # S
i |= 0x20 if data[xm1, yp1, layer] == t # SW
i |= 0x40 if data[xm1, y, layer] == t # W
i |= 0x80 if data[xm1, ym1, layer] == t # NW
end
return i return i
end end
def self.fromTileset(tileset) def self.fromTileset(tileset)
bmtileset=pbGetTileset(tileset.tileset_name) bmtileset = pbGetTileset(tileset.tileset_name)
bmautotiles=[] bmautotiles = []
for i in 0...7 7.times do |i|
bmautotiles.push(pbGetAutotile(tileset.autotile_names[i])) bmautotiles.push(pbGetAutotile(tileset.autotile_names[i]))
end end
return self.new(bmtileset,bmautotiles) return self.new(bmtileset, bmautotiles)
end end
#-----------------------------------------------------------------------------
def initialize(tileset, autotiles) def initialize(tileset, autotiles)
if tileset.mega? if tileset.mega?
@tileset = TilemapRenderer::TilesetWrapper.wrapTileset(tileset) @tileset = TilemapRenderer::TilesetWrapper.wrapTileset(tileset)
@@ -79,17 +99,17 @@ class TileDrawingHelper
end end
def dispose def dispose
@tileset.dispose if @tileset @tileset&.dispose
@tileset = nil @tileset = nil
for i in 0...@autotiles.length @autotiles.each_with_index do |autotile, i|
@autotiles[i].dispose autotile.dispose
@autotiles[i] = nil @autotiles[i] = nil
end end
end end
def bltSmallAutotile(bitmap,x,y,cxTile,cyTile,id,frame) def bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
return if id >= 384 || frame < 0 || !@autotiles return if id >= 384 || frame < 0 || !@autotiles
autotile = @autotiles[id / 48 - 1] autotile = @autotiles[(id / 48) - 1]
return if !autotile || autotile.disposed? return if !autotile || autotile.disposed?
cxTile = [cxTile / 2, 1].max cxTile = [cxTile / 2, 1].max
cyTile = [cyTile / 2, 1].max cyTile = [cyTile / 2, 1].max
@@ -102,23 +122,23 @@ class TileDrawingHelper
id %= 48 id %= 48
tiles = AUTOTILE_PATTERNS[id >> 3][id & 7] tiles = AUTOTILE_PATTERNS[id >> 3][id & 7]
src = Rect.new(0, 0, 0, 0) src = Rect.new(0, 0, 0, 0)
for i in 0...4 4.times do |i|
tile_position = tiles[i] - 1 tile_position = tiles[i] - 1
src.set(tile_position % 6 * 16 + anim, tile_position / 6 * 16, 16, 16) src.set(((tile_position % 6) * 16) + anim, (tile_position / 6) * 16, 16, 16)
bitmap.stretch_blt(Rect.new(i % 2 * cxTile + x, i / 2 * cyTile + y, cxTile, cyTile), bitmap.stretch_blt(Rect.new((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, cxTile, cyTile),
autotile, src) autotile, src)
end end
end end
end end
def bltSmallRegularTile(bitmap,x,y,cxTile,cyTile,id) def bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
return if id < 384 || !@tileset || @tileset.disposed? return if id < 384 || !@tileset || @tileset.disposed?
rect = Rect.new((id - 384) % 8 * 32, (id - 384) / 8 * 32, 32, 32) rect = Rect.new(((id - 384) % 8) * 32, ((id - 384) / 8) * 32, 32, 32)
rect = TilemapRenderer::TilesetWrapper.getWrappedRect(rect) if @shouldWrap rect = TilemapRenderer::TilesetWrapper.getWrappedRect(rect) if @shouldWrap
bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect) bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect)
end end
def bltSmallTile(bitmap,x,y,cxTile,cyTile,id,frame=0) def bltSmallTile(bitmap, x, y, cxTile, cyTile, id, frame = 0)
if id >= 384 if id >= 384
bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id) bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
elsif id > 0 elsif id > 0
@@ -126,15 +146,15 @@ class TileDrawingHelper
end end
end end
def bltAutotile(bitmap,x,y,id,frame) def bltAutotile(bitmap, x, y, id, frame)
bltSmallAutotile(bitmap, x, y, 32, 32, id, frame) bltSmallAutotile(bitmap, x, y, 32, 32, id, frame)
end end
def bltRegularTile(bitmap,x,y,id) def bltRegularTile(bitmap, x, y, id)
bltSmallRegularTile(bitmap, x, y, 32, 32, id) bltSmallRegularTile(bitmap, x, y, 32, 32, id)
end end
def bltTile(bitmap,x,y,id,frame=0) def bltTile(bitmap, x, y, id, frame = 0)
if id >= 384 if id >= 384
bltRegularTile(bitmap, x, y, id) bltRegularTile(bitmap, x, y, id)
elsif id > 0 elsif id > 0
@@ -147,82 +167,80 @@ end
# #
#=============================================================================== #===============================================================================
def createMinimap(mapid) def createMinimap(mapid)
map=load_data(sprintf("Data/Map%03d.rxdata",mapid)) rescue nil map = load_data(sprintf("Data/Map%03d.rxdata", mapid)) rescue nil
return BitmapWrapper.new(32,32) if !map return Bitmap.new(32, 32) if !map
bitmap=BitmapWrapper.new(map.width*4,map.height*4) bitmap = Bitmap.new(map.width * 4, map.height * 4)
black=Color.new(0,0,0) black = Color.black
tilesets=$data_tilesets tilesets = $data_tilesets
tileset=tilesets[map.tileset_id] tileset = tilesets[map.tileset_id]
return bitmap if !tileset return bitmap if !tileset
helper=TileDrawingHelper.fromTileset(tileset) helper = TileDrawingHelper.fromTileset(tileset)
for y in 0...map.height map.height.times do |y|
for x in 0...map.width map.width.times do |x|
for z in 0..2 3.times do |z|
id=map.data[x,y,z] id = map.data[x, y, z]
id=0 if !id id = 0 if !id
helper.bltSmallTile(bitmap,x*4,y*4,4,4,id) helper.bltSmallTile(bitmap, x * 4, y * 4, 4, 4, id)
end end
end end
end end
bitmap.fill_rect(0,0,bitmap.width,1,black) bitmap.fill_rect(0, 0, bitmap.width, 1, black)
bitmap.fill_rect(0,bitmap.height-1,bitmap.width,1,black) bitmap.fill_rect(0, bitmap.height - 1, bitmap.width, 1, black)
bitmap.fill_rect(0,0,1,bitmap.height,black) bitmap.fill_rect(0, 0, 1, bitmap.height, black)
bitmap.fill_rect(bitmap.width-1,0,1,bitmap.height,black) bitmap.fill_rect(bitmap.width - 1, 0, 1, bitmap.height, black)
return bitmap return bitmap
end end
def bltMinimapAutotile(dstBitmap,x,y,srcBitmap,id) def bltMinimapAutotile(dstBitmap, x, y, srcBitmap, id)
return if id>=48 || !srcBitmap || srcBitmap.disposed? return if id >= 48 || !srcBitmap || srcBitmap.disposed?
anim=0 anim = 0
cxTile=3 cxTile = 3
cyTile=3 cyTile = 3
tiles = TileDrawingHelper::AUTOTILE_PATTERNS[id>>3][id&7] tiles = TileDrawingHelper::AUTOTILE_PATTERNS[id >> 3][id & 7]
src=Rect.new(0,0,0,0) src = Rect.new(0, 0, 0, 0)
for i in 0...4 4.times do |i|
tile_position = tiles[i] - 1 tile_position = tiles[i] - 1
src.set( src.set((tile_position % 6 * cxTile) + anim,
tile_position % 6 * cxTile + anim,
tile_position / 6 * cyTile, cxTile, cyTile) tile_position / 6 * cyTile, cxTile, cyTile)
dstBitmap.blt(i%2*cxTile+x,i/2*cyTile+y, srcBitmap, src) dstBitmap.blt((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, srcBitmap, src)
end end
end end
def passable?(passages,tile_id) def passable?(passages, tile_id)
return false if tile_id == nil return false if tile_id.nil?
passage = passages[tile_id] passage = passages[tile_id]
return (passage && passage<15) return (passage && passage < 15)
end end
# Unused # Unused
def getPassabilityMinimap(mapid) def getPassabilityMinimap(mapid)
map = load_data(sprintf("Data/Map%03d.rxdata",mapid)) map = load_data(sprintf("Data/Map%03d.rxdata", mapid))
tileset = $data_tilesets[map.tileset_id] tileset = $data_tilesets[map.tileset_id]
minimap = AnimatedBitmap.new("Graphics/Pictures/minimap_tiles") minimap = AnimatedBitmap.new("Graphics/UI/minimap_tiles")
ret = Bitmap.new(map.width*6,map.height*6) ret = Bitmap.new(map.width * 6, map.height * 6)
passtable = Table.new(map.width,map.height) passtable = Table.new(map.width, map.height)
passages = tileset.passages passages = tileset.passages
for i in 0...map.width map.width.times do |i|
for j in 0...map.height map.height.times do |j|
pass=true pass = true
for z in [2,1,0] [2, 1, 0].each do |z|
if !passable?(passages,map.data[i,j,z]) if !passable?(passages, map.data[i, j, z])
pass=false pass = false
break break
end end
end end
passtable[i,j]=pass ? 1 : 0 passtable[i, j] = pass ? 1 : 0
end end
end end
neighbors=TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX neighbors = TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX
for i in 0...map.width map.width.times do |i|
for j in 0...map.height map.height.times do |j|
if passtable[i,j]==0 next if passtable[i, j] != 0
nb=TileDrawingHelper.tableNeighbors(passtable,i,j) nb = TileDrawingHelper.tableNeighbors(passtable, i, j)
tile=neighbors[nb] tile = neighbors[nb]
bltMinimapAutotile(ret,i*6,j*6,minimap.bitmap,tile) bltMinimapAutotile(ret, i * 6, j * 6, minimap.bitmap, tile)
end end
end end
end minimap.dispose
minimap.disposes
return ret return ret
end end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.