#=============================================================================
# ? Fullscreen
#-----------------------------------------------------------------------------
# @author : Gabriel "Gab!" Teles
# @date : 2014-09-27
# @version : 0.9.2
#-----------------------------------------------------------------------------
# TODO:
# - Transições por imagens
#-----------------------------------------------------------------------------
# Créditos:
# Scripter Desconhecido no Pastebin (http://pastebin.com/sM2MNJZj)
# Esrever : Map viewport/scroll fix
# Zeus81 : FPS Display
#-----------------------------------------------------------------------------
# Permite utilizar fullscreen real (sem redimensionamento de tela), e alterar
# o limite da função Graphics.resize_screen para a resolução máxima do monitor
# ou um valor próximo.
#=============================================================================
# Módulo Graphics
class << Graphics
# API
User32 = DL.dlopen('user32')
Kernel32 = DL.dlopen('kernel32')
GetActiveWindow = DL::CFunc.new( User32['GetActiveWindow' ], DL::TYPE_LONG)
GetSystemMetrics = DL::CFunc.new( User32['GetSystemMetrics'], DL::TYPE_LONG)
GetWindowRect = DL::CFunc.new( User32['GetWindowRect' ], DL::TYPE_LONG)
SetWindowLong = DL::CFunc.new( User32['SetWindowLong' ], DL::TYPE_LONG)
SetWindowPos = DL::CFunc.new( User32['SetWindowPos' ], DL::TYPE_LONG)
GetModuleHandle = DL::CFunc.new(Kernel32['GetModuleHandle' ], DL::TYPE_LONG)
# DLL sendo utilizada
_DLLName = DL::CPtr.malloc(140)
s = DL::CFunc.new(Kernel32['GetPrivateProfileString'], DL::TYPE_LONG).call([
DL::CPtr["Game"].to_i,
DL::CPtr["Library"].to_i,
0,
_DLLName.to_i,
140,
DL::CPtr["./Game.ini"].to_i
])
@@DLLName = File.basename(_DLLName.to_s(s))
# Verifica se é uma RGSS3xx.dll
if @@DLLName.match(/^RGSS3(\d{2})\.dll$/)
@@DLLVersion = $1.to_i
# Verifica se a versão é 0 ou 1.
if @@DLLVersion.between?(0, 1)
# Flag de fullscreen
@@inFullscreen = false
# Instância da DLL. *Necessariamente* a RGSS300.dll ou RGSS301.dll, visto
# que o trabalho com memória a seguir é específico.
@@DLLHandle = GetModuleHandle.call([DL::CPtr[@@DLLName].to_i])
# Instância da janela de jogo
@@hWnd = GetActiveWindow.call([])
# Tamanho da tela
@@screenSize = [
GetSystemMetrics.call([0]),
GetSystemMetrics.call([1])
]
# Calcula o próximo tamanho divisível por 32 para fazer a limitação
width, height = @@screenSize
width += (32 - (width % 32)) unless (width % 32).zero?
height += (32 - (height % 32)) unless (height % 32).zero?
puts "Limitando para: #{width}x#{height}" if $TEST
#-----------------------------------------------------------------------
# Bruxaria de scripter desconhecido. Remove a limitação de tamanho para
# o método Graphics.resize_screen (640x480)
#
# Base retirada de: http://pastebin.com/sM2MNJZj
#
# Adaptações para a RGSS300.dll e início do mapeamento dos endereços
# utilizados por Gab!
#-----------------------------------------------------------------------
# Número para string
wh = ->(w, h, off = 0){
[w + off, h + off].pack('l2').scan(/..../)
}
# Altera um valor na memória relativa à DLL
mod = ->(adr, val){
adr += @@OFF if @@DLLVersion.zero?
DL::CPtr.new(@@DLLHandle + adr)[0, val.size] = val
}
# Valores úteis
wt, ht = width.divmod(32), height.divmod(32)
w, h = wh.(width, height)
ww, hh = wh.(width, height, 32)
www, hhh = wh.(wt.first, ht.first, 1)
zero = [0].pack('l')
# Faz as alterações na memória
# Graphics
@@OFF = 0
mod.(0x195F, "\x90"*5) # ???
mod.(0x19A4, h ) # ???
mod.(0x19A9, w ) # ???
mod.(0x1A56, h ) # ???
mod.(0x1A5B, w ) # ???
mod.(0x20F6, w ) # Max width (?)
mod.(0x20FF, w ) # Max width (?)
mod.(0x2106, h ) # Max height (?)
mod.(0x210F, h ) # Max height (?)
# Plane (?) Class
@@OFF = -0xC0
Graphics::PlaneSpeedUp = true
# Setando para false não é necessário reescrever classe Plane. No
# entanto, o mapa fica MUITO lento.
mod.(0x1C5E3, Graphics::PlaneSpeedUp ? zero : h) # Max height
mod.(0x1C5E8, Graphics::PlaneSpeedUp ? zero : w) # Max width
# ???
@@OFF = 0x20
mod.(0x1F477, h ) # ???
mod.(0x1F47C, w ) # ???
# Tilemap Class
@@OFF = 0x1E0
mod.(0x211FF, hh ) # Tilemap render height
mod.(0x21204, ww ) # Tilemap render width
mod.(0x21D7D, hhh[0]) # Tilemap max tiles on screen height
mod.(0x21E01, www[0]) # Tilemap max tiles on screen width
# ???
@@OFF = 0x140
mod.(0x10DEA8, h ) # ???
mod.(0x10DEAD, w ) # ???
mod.(0x10DEDF, h ) # ???
mod.(0x10DEE3, w ) # ???
mod.(0x10DF14, h ) # ???
mod.(0x10DF18, w ) # ???
mod.(0x10DF48, h ) # ???
mod.(0x10DF4C, w ) # ???
mod.(0x10E6A7, w ) # ???
mod.(0x10E6C3, h ) # ???
mod.(0x10EEA9, w ) # ???
mod.(0x10EEB9, h ) # ???
#-------------------------------------------------------------------------
# Fim da bruxaria
#-------------------------------------------------------------------------
# Sprite de transição de tela
@@TransitionSprite = Sprite.new
@@TransitionSprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
@@TransitionSprite.bitmap.fill_rect(@@TransitionSprite.bitmap.rect, Color.new(0, 0, 0))
@@TransitionSprite.opacity = 0
@@TransitionSprite.z = 0x7FFFFFFF
# Bitmap da tela no momento do Graphics.freeze
@@FrozenBitmap = Bitmap.new(Graphics.width, Graphics.height)
@@FrozenBitmap.fill_rect(@@FrozenBitmap.rect, Color.new(0, 0, 0))
# Realiza a transição de tela
# Nota: Não é possível realizar transição de tela com imagens
alias oldFullscreenResTransition transition
def transition(time, image='', vague=40)
@@TransitionSprite.bitmap.dispose
@@TransitionSprite.dispose
@@TransitionSprite = Sprite.new
@@TransitionSprite.bitmap = @@FrozenBitmap
@@TransitionSprite.opacity = 255
@@TransitionSprite.z = 0x7FFFFFFF
oldFullscreenResTransition(0)
dec = (255.0 / time)
time.times {
@@TransitionSprite.opacity -= dec
Graphics.update
}
end
# Fadein
def fadein(time)
@@FrozenBitmap = Bitmap.new(Graphics.width, Graphics.height)
@@FrozenBitmap.fill_rect(@@FrozenBitmap.rect, Color.new(0, 0, 0))
transition(time)
end
# Fadeout
def fadeout(time)
inc = (255.0 / time)
time.times {
@@TransitionSprite.opacity += inc
Graphics.update
}
end
# Armazena a imagem da tela
alias oldFullscreenResFreeze freeze
def freeze(*a, &b)
oldFullscreenResFreeze(*a, &b)
@@FrozenBitmap = Graphics.snap_to_bitmap
end
# Realiza o redimensionamento de tela
alias gabFullscreenOldResizeScreen resize_screen
def resize_screen(*a, &b)
# Redimensiona normalmente
gabFullscreenOldResizeScreen(*a, &b)
# Redimensiona o sprite de transição
@@TransitionSprite.bitmap.dispose
@@TransitionSprite.bitmap = Bitmap.new(*Graphics.size)
@@TransitionSprite.bitmap.fill_rect(@@TransitionSprite.bitmap.rect, Color.new(0, 0, 0))
if Graphics::PlaneSpeedUp
# Manda o sinal de atualização para todas as instâncias da classe Plane
ObjectSpace.each_object(Plane){|plane|
plane.send(:recreateBitmap)
}
end
end
# Altera para fullscreen
def fullscreen
# Retorna se já estiver em fullscreen
return if @@inFullscreen
# Tamanho antes do fullscreen
rect = DL::CPtr.malloc(16)
rect[0, 16] = 0.chr * 16
GetWindowRect.call([@@hWnd, rect])
@@windowSize = rect[0, 16].unpack("l*")
@@windowSize[2] -= @@windowSize[0]
@@windowSize[3] -= @@windowSize[1]
@@windowResolution = Graphics.size
# Muda o tamanho da tela
Graphics.resize_screen(*@@screenSize)
# Remover bordas da janela
SetWindowLong.call([@@hWnd, -16, 0x14000000])
# Coloca a janela acima de todas as outras
SetWindowPos.call([@@hWnd, -1, 0, 0, *@@screenSize, 0])
# Modifica a flag de fullscreen
@@inFullscreen = true
# Espera alguns frames para terminar o processamento
Graphics.wait(5)
end
# Altera para modo janela
def windowed
# Retorna se não estiver em fullscreen
return unless @@inFullscreen
# Muda o tamanho da tela
Graphics.resize_screen(*@@windowResolution)
# Recoloca bordas da janela
SetWindowLong.call([@@hWnd, -16, 0x14CA0000])
# Coloca a janela na posição x,y,z comum e ajusta seu tamanho
SetWindowPos.call([@@hWnd, 0, *@@windowSize, 0])
# Modifica a flag de fullscreen
@@inFullscreen = false
# Espera alguns frames para terminar o processamento
Graphics.wait(5)
end
# Tamanho da tela
def size
[self.width, self.height]
end
# Verifica se a janela está no modo fullscreen
def fullscreen?
return @@inFullscreen
end
# Verifica se a janela está no modo janela
def windowed?
return !@@inFullscreen
end
# Alterna entre os modos fullscreen e janela
def toggleFullscreen
@@inFullscreen ? self.windowed : self.fullscreen
end
end
end
end
if Graphics::PlaneSpeedUp
# Remove a classe Plane Anterior
Object.send(:remove_const, :Plane)
# Redefinição da classe Plane
class Plane
attr_reader :viewport
attr_reader :bitmap
attr_reader :ox
attr_reader :oy
attr_reader :opacity
attr_reader :blend_type
attr_reader :color
attr_reader :tone
attr_reader :visible
attr_reader :zoom_x
attr_reader :zoom_y
attr_reader :z
# Inicialização do objeto
def initialize(viewport = nil)
# É necessário verificar se um viewport foi enviado. Desse modo, ao mudar a
# resolução da tela, deve-se mudar também a rect do viewport para que o
# Plane que ocupava a tela toda continue
@defaultViewport = !viewport.is_a?(Viewport)
@viewport = @defaultViewport ? Viewport.new(0, 0, *Graphics.size) : viewport
@sprite = Sprite.new(@viewport)
@bitmap = nil
@ox = @sprite.ox # 0
@oy = @sprite.oy # 0
@opacity = @sprite.opacity # 255
@blend_type = @sprite.blend_type # 0
@color = @sprite.color # Color.new(0, 0, 0, 0)
@tone = @sprite.tone # Tone.new(0, 0, 0, 0)
@visible = @sprite.visible # true
@z = @sprite.z # 0
@zoom_x = @sprite.zoom_x # 1.0
@zoom_y = @sprite.zoom_y # 1.0
end
def bitmap=(bitmap)
return unless bitmap.is_a?(Bitmap)
@bitmap = bitmap
self.recreateBitmap(true)
end
def ox=(value)
@ox = value
return unless @bitmap
@sprite.ox = (value % @bitmap.width)
end
def oy=(value)
@oy = value
return unless @bitmap
@sprite.oy = (value % @bitmap.height)
end
def opacity=(value)
@sprite.opacity = value
@opacity = @sprite.opacity
end
def blend_type=(value)
@sprite.blend_type = value
@blend_type = @sprite.blend_type
end
def color=(value)
@sprite.color = value
@color = @sprite.color
end
def tone=(value)
@sprite.tone = value
@tone = @sprite.tone
end
def viewport=(value)
@defaultViewport &= (value == @sprite.viewport)
@sprite.viewport = value
@viewport = @sprite.viewport
end
def visible=(value)
@sprite.visible = value
@visible = sprite.visible
end
def z=(value)
@sprite.z = value
@z = @sprite.z
end
def zoom_x=(value)
@sprite.zoom_x = value
@zoom_x = @sprite.zoom_x
self.recreateBitmap
end
def zoom_y=(value)
@sprite.zoom_y = value
@zoom_y = @sprite.zoom_y
self.recreateBitmap
end
def disposed?
return @sprite.disposed?
end
def dispose
@sprite.dispose
end
protected
def recreateBitmap(forceRefresh = false)
cw, ch = Graphics.width * (2.0/@zoom_x), Graphics.height * (2.0/@zoom_y)
needRefresh = true
if @defaultViewport
@viewport.rect.width, @viewport.rect.height = *Graphics.size
end
if @sprite.bitmap.nil? or @sprite.bitmap.disposed?
newBitmap = Bitmap.new(cw, ch)
else
if (cw == @sprite.bitmap.width) and (ch == @sprite.bitmap.height) and (!forceRefresh)
return
end
newBitmap = Bitmap.new(cw, ch)
if (cw < @sprite.bitmap.width) and (ch < @sprite.bitmap.height)
newBitmap.blt(0, 0, @sprite.bitmap, @sprite.bitmap.rect)
@sprite.bitmap.dispose
needRefresh = false
end
end
@sprite.bitmap = newBitmap
self.refreshBitmap if needRefresh or forceRefresh
end
def refreshBitmap
# Limpa o bitmap
b = @sprite.bitmap
b.clear
return if @bitmap.nil?
# Quantia de espaços para blt
tx = (b.width / @bitmap.width.to_f )
ty = (b.height / @bitmap.height.to_f)
b.blt(0, 0, @bitmap, @bitmap.rect)
return if tx + ty == 2
# Preenche 1 linha
basePow = @bitmap.width
baseRct = Rect.new(0, 0, @bitmap.width, @bitmap.height)
Math.log2(tx).floor.times{
b.blt(basePow, 0, b, baseRct)
baseRct.width += basePow
basePow *= 2
}
# Último bitmap da linha
baseRct.width = (b.width - baseRct.width)
b.blt(basePow, 0, b, baseRct)
# Preenche o restante das linhas
basePow = @bitmap.height
baseRct = Rect.new(0, 0, b.width, @bitmap.height)
Math.log2(ty).floor.times{
b.blt(0, basePow, b, baseRct)
baseRct.height += basePow
basePow *= 2
}
# Última linha
baseRct.height = b.height - baseRct.height
b.blt(basePow, 0, b, baseRct)
end
end
end
class Game_Map
# Número de tiles horizontais na tela
def screen_tile_x
(Graphics.width / 32.0).ceil
end
# Número de tiles verticais na tela
def screen_tile_y
(Graphics.height / 32.0).ceil
end
end
# Contador de FPS para o modo Fullscreen
if $TEST
# FPS Display // Zeus81
# http://forums.rpgmakerweb.com/index.php?/topic/3738-fps-display-isnt-very-accurate/#entry40350
module Graphics
@fps, @fps_tmp = 0, []
class << self
attr_reader :fps
alias fps_update update unless method_defined?(:fps_update)
def update
t = Time.now
fps_update
@fps_tmp[frame_count % frame_rate] = Time.now != t
@fps = 0
frame_rate.times {|i| @fps += 1 if @fps_tmp[i]}
fps_sprite.src_rect.y = @fps * 16
end
def fps_sprite
if !@fps_sprite or @fps_sprite.disposed?
@fps_sprite = Sprite.new
@fps_sprite.z = 0x7FFFFFFF
@fps_sprite.bitmap = Bitmap.new(24, 16*120)
@fps_sprite.bitmap.font.name = "Arial"
@fps_sprite.bitmap.font.size = 16
@fps_sprite.bitmap.font.color.set(255, 255, 255)
@fps_sprite.bitmap.fill_rect(@fps_sprite.bitmap.rect, Color.new(0, 0, 0, 127))
120.times {|i|
@fps_sprite.bitmap.draw_text(0, i*16, 24, 16, "% 3d"%i, 1)
}
@fps_sprite.src_rect.height = 16
end
return @fps_sprite
end
end
end
end
#==============================================================================
# ? Viewports/Map Fix for Modified RGSS300.dll File
# Origin of Code: Yanfly Engine Ace - Ace Core Engine v1.06
# -- Last Updated: 2011.12.26
# -- Level: Easy, Normal
# -- Requires: n/a
#==============================================================================
#==============================================================================
# ? Game_Map
#==============================================================================
class Game_Map
#--------------------------------------------------------------------------
# overwrite method: scroll_down
#--------------------------------------------------------------------------
def scroll_down(distance)
if loop_vertical?
@display_y += distance
@display_y %= @map.height * 256
@parallax_y += distance
else
last_y = @display_y
dh = Graphics.height > height * 32 ? height : screen_tile_y
@display_y = [@display_y + distance, height - dh].min
@parallax_y += @display_y - last_y
end
end
#--------------------------------------------------------------------------
# overwrite method: scroll_right
#--------------------------------------------------------------------------
def scroll_right(distance)
if loop_horizontal?
@display_x += distance
@display_x %= @map.width * 256
@parallax_x += distance
else
last_x = @display_x
dw = Graphics.width > width * 32 ? width : screen_tile_x
@display_x = [@display_x + distance, width - dw].min
@parallax_x += @display_x - last_x
end
end
end # Game_Map
#==============================================================================
# ? Spriteset_Map
#==============================================================================
class Spriteset_Map
#--------------------------------------------------------------------------
# overwrite method: create_viewports
#--------------------------------------------------------------------------
def create_viewports
if Graphics.width > $game_map.width * 32 && !$game_map.loop_horizontal?
dx = (Graphics.width - $game_map.width * 32) / 2
else
dx = 0
end
dw = [Graphics.width, $game_map.width * 32].min
dw = Graphics.width if $game_map.loop_horizontal?
if Graphics.height > $game_map.height * 32 && !$game_map.loop_vertical?
dy = (Graphics.height - $game_map.height * 32) / 2
else
dy = 0
end
dh = [Graphics.height, $game_map.height * 32].min
dh = Graphics.height if $game_map.loop_vertical?
@viewport1 = Viewport.new(dx, dy, dw, dh)
@viewport2 = Viewport.new(dx, dy, dw, dh)
@viewport3 = Viewport.new(dx, dy, dw, dh)
@viewport2.z = 50
@viewport3.z = 100
end
#--------------------------------------------------------------------------
# new method: update_viewport_sizes
#--------------------------------------------------------------------------
def update_viewport_sizes
if Graphics.width > $game_map.width * 32 && !$game_map.loop_horizontal?
dx = (Graphics.width - $game_map.width * 32) / 2
else
dx = 0
end
dw = [Graphics.width, $game_map.width * 32].min
dw = Graphics.width if $game_map.loop_horizontal?
if Graphics.height > $game_map.height * 32 && !$game_map.loop_vertical?
dy = (Graphics.height - $game_map.height * 32) / 2
else
dy = 0
end
dh = [Graphics.height, $game_map.height * 32].min
dh = Graphics.height if $game_map.loop_vertical?
rect = Rect.new(dx, dy, dw, dh)
for viewport in [@viewport1, @viewport2, @viewport3]
viewport.rect = rect
end
end
end # Spriteset_Map
#==============================================================================
# ? Scene_Map
#==============================================================================
class Scene_Map < Scene_Base
#--------------------------------------------------------------------------
# alias method: post_transfer
#--------------------------------------------------------------------------
alias scene_map_post_transfer_ace post_transfer
def post_transfer
@spriteset.update_viewport_sizes
scene_map_post_transfer_ace
end
end # Scene_Map
#==============================================================================
# ? Game_Event
#==============================================================================
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# overwrite method: near_the_screen?
#--------------------------------------------------------------------------
def near_the_screen?(dx = nil, dy = nil)
dx = [Graphics.width, $game_map.width * 256].min/32 - 5 if dx.nil?
dy = [Graphics.height, $game_map.height * 256].min/32 - 5 if dy.nil?
ax = $game_map.adjust_x(@real_x) - Graphics.width / 2 / 32
ay = $game_map.adjust_y(@real_y) - Graphics.height / 2 / 32
ax >= -dx && ax <= dx && ay >= -dy && ay <= dy
end
end # Game_Event
# Chama o método que realiza a mudança de tamanho
# Graphics.fullscreen
Graphics.resize_screen(1632, 832)
__END__
# TESTES
# Graphics.windowed
x = Bitmap.new(50, 50)
x.gradient_fill_rect(0, 0, 50, 25, Color.new(255, 0, 0), Color.new(0, 255, 0))
x.gradient_fill_rect(0, 25, 50, 25, Color.new(0, 255, 0), Color.new(0, 0, 255))
y = Plane.new
y.bitmap = x
y.zoom_x = 3
y.zoom_y = 3
#Graphics.fullscreen
#Graphics.windowed
loop do
Graphics.update
y.ox += 1
y.oy += 1
end