=begin
==============================================================================
** Bitmap.memory
------------------------------------------------------------------------------
Description:
------------
Specialized Methods for tbe bitmap class for remembering text. Also includes
a non-laggy draw_text method based on the original draw text which stores the
text in memory and calls blt instead of draw_text if it is needed again. One
thing to remember is to call Bitmap.clear_text_memory
Bitmap.clear_formatted_text_memory to dispose of all memorized sprites
when you are finished (preferably at the end of a scene).
When Benchmarked drawing the string 'Hello World '*5 100 times the results
draw_text_memory around 0.266 seconds
draw_wrap_text_memory around 1.969 seconds
draw_formatted_text_memory around 0.266 seconds
draw_text around 6.235 seconds
Method List:
------------
Bitmap.clear_text_memory
Bitmap.clear_formatted_text_memory
clear_memory
cleat_to_memory
draw_formatted_text_memory
draw_text_memory
draw_wrap_text_memory
get_formatted_size (from Bitmap.text)
set_memory
Support Methods:
-------------
class Hash
contains_key?
get_value
class Font
== (comparision equals)
==============================================================================
=end
MACL::Loaded << 'Bitmap.memory'
class Bitmap
#--------------------------------------------------------------------------
# * Class Variables
#--------------------------------------------------------------------------
class_reader :text_memory, :formatted_text_memory
#-------------------------------------------------------------------------
# * Class Variables
#-------------------------------------------------------------------------
@@text_memory, @@formatted_text_memory = {}, {}
#-------------------------------------------------------------------------
# Name : Clear Text Memory
# Info : Clears Text Memory
# Author : Trickster
# Call Info : No Arguments
# Comment : Should be called at the end of every scene where
# draw_text_memory or draw_wrap_text_memory is used
#-------------------------------------------------------------------------
def self.clear_text_memory
# Run Through Each Bitmap In Text Memory and dispose
@@text_memory.each_value {|bitmap| bitmap.dispose}
# Clear
@@text_memory.clear
end
#-------------------------------------------------------------------------
# Name : Clear Formatted Text Memory
# Info : Clears Formatted Text Memory
# Author : Trickster
# Call Info : No Arguments
# Returns : Nothing
# Comment : Should be called at the end of every scene where
# draw_formatted_text_memory is used
#-------------------------------------------------------------------------
def self.clear_formatted_text_memory
# Run Through Each Bitmap In Text Memory and dispose
@@formatted_text_memory.each_value {|bitmap| bitmap.dispose}
# Clear
@@formatted_text_memory.clear
end
#-------------------------------------------------------------------------
# Name : Clear Memory
# Info : Clears Bitmap Memory
# Author : Trickster
# Call Info : No Arguments
#-------------------------------------------------------------------------
def clear_memory
# Dispose Memory
@memory.dispose
# Set To nil
@memory = nil
end
#-------------------------------------------------------------------------
# Name : Clear To Memory
# Info : Clears to Bitmap Memory
# Author : Trickster
# Call Info : No Arguments
#-------------------------------------------------------------------------
def clear_to_memory
# Clear Bitmap
clear
# Draw Memory if it is a Bitmap
blt(0, 0, @memory, rect) if @memory.is_a?(Bitmap)
end
#-------------------------------------------------------------------------
# Name : Draw Formatted Text Memory
# Info : Draws Formatted Wrapped Text from Memory
# Author : Trickster
# Call Info : Five Arguments
# Integer Offset_x and Offset_Y, define starting position
# Integer Width, defines the width of the text rectangle
# Integer Height, defines the height of the text drawn
# String Text, The text to be drawn
# Comment : C[rrggbb] -> Change Color values are in hex
# C[N] -> Change Color to Normal Color
# B[] -> Turns on/off Bold
# I[] -> Turns on/off Italics
# T[] -> Tab (4 Spaces)
# N[] -> Newline
#-------------------------------------------------------------------------
def draw_formatted_text_memory(x, y, width, height, text)
# If Already drawn
if @@formatted_text_memory.has_key?(text)
# Get Bitmap
bitmap = @@formatted_text_memory[text]
# Draw Bitmap
blt(x, y, bitmap, bitmap.rect)
else
# Get Height of Text Drawn
height = get_formatted_size(x, y, width, height, text).height
# Create Text Bitmap
text_bitmap = Bitmap.new(width, height)
# Initialize X and Y
cx, cy = 0, 0
# Setup Font Color
text_bitmap.font.color = Color.new(255, 255, 255)
# Setup Save String
string = text.dup
# Make a Copy of Text
text = text.dup
# Replace C[Hex+] or C[N] with \001[Matched]
text.gsub!(/[Cc]\[([A-F a-f 0-9]+|N)\]/) {" \001[#{$1}] "}
# Replace B[] with \002
text.gsub!(/[Bb]\[\]/) {" \002 "}
# Replace I[] with \003
text.gsub!(/[Ii]\[\]/) {" \003 "}
# Replace T[] with \004
text.gsub!(/[Tt]\[\]/) {" \004 "}
# Replace N[] with \005
text.gsub!(/[Nn]\[\]/) {" \005 "}
# Run Through each text
text.split(/\s/).each do |word|
# If String \001 is included
if word.include?("\001")
# Slice from String
word.slice!("\001")
# Change text color
word.sub!(/[Cc]\[([A-F a-f 0-9]+|N)\]/, '')
# If matched is not nil and size of match is > 1
if $1 != nil and $1.size > 1
# Create Color
color = Color.new($1[0..1].hex, $1[2..3].hex, $1[4..5].hex)
else
# Normal Color
color = Color.new(255, 255, 255)
end
# Set Color
self.font.color = color
# Go to next text
next
end
# If String \002 is included
if word.include?("\002")
# Invert Bold Status
self.font.bold = !self.font.bold
# Go to next text
next
end
# If String \003 is included
if word.include?("\003")
# Invert Italic Status
self.font.italic = !self.font.italic
# Go to next text
next
end
# If String \004 is included
if word.include?("\004")
# Add Four Spaces
x += text_size(' ').width
# Go to next text
next
end
# If String \005 is included
if word.include?("\005")
# Move to new line
cy = cx / width + 1
# Move to start
cx = cy * width
# Go to next text
next
end
# Get Word Width
word_width = text_size("#{word} ").width
# If can't fit on line
if (cx + word_width) % width < x % width
# Move to new line
cy = cx / width + 1
# Move to start
cx = cy * width
end
# Get Draw X
dx = cx % width + x
# Get Draw Y
dy = cx / width * height + y
# Draw Text
text_bitmap.draw_text(dx, dy, word_width, 32, word)
# Increase by Word Width
cx += word_width
end
# Save Copy of Bitmap
@@formatted_text_memory[string] = text_bitmap
# Draw onto Bitmap
blt(x, y, text_bitmap, text_bitmap.rect)
end
end
#-------------------------------------------------------------------------
# Name : Draw Text Memory
# Info : Draws Text and Saves it to Text_Memory
# Author : Trickster
# Call Info : Two,Three,Five or Six Arguments
# Two Arguments: rect, str
# Rect rect for the text to be drawn
# String str text to be drawn
# Three Arguments: rect, str, align
# Rect rect for the text to be drawn
# String str text to be drawn
# Integer align 0: left 1: center 2:right
# Five Arguments: x,y,width,height,str
# Integer X and Y, Defines Position
# Width and Height, Defines Width and Hieght of the text drawn
# String str text to be drawn
# Six Arguments: x,y,width,height,str,align
# Integer X and Y, Defines Position
# Width and Height, Defines Width and Hieght of the text drawn
# String str text to be drawn
# Integer align 0: left 1: center 2:right
#-------------------------------------------------------------------------
def draw_text_memory(*args)
# If Two Arguments Sent
if args.size == 2
# Default align, Rect and String were sent
align, rect, str = 0, *args
# If Three Arguments Sent
elsif args.size == 3
# All Were Sent Rect String and Alignment
rect, str, align = args
# If Five Arguments Sent
elsif args.size == 5
# Create Rect from (X,Y,Width,Height), Set String, Default align
rect, str, align = Rect.new(*args[0, 4]), args[4], 0
# If Six Arguments Sent
elsif args.size == 6
# Create Rect from (X,Y,Width,Height), Set String and align
rect, str, align = Rect.new(*args[0, 4]), *args[4, 2]
end
# Create Text Rect from Rect
txt_rect = Rect.new(0, 0, rect.width, rect.height)
# If Key is contained
if @@text_memory.contains_key?([font, txt_rect, str])
# Get Bitmap
bitmap = @@text_memory.get_value([font, txt_rect, str])
# Draw Bitmap by getting value from hash
blt(rect.x, rect.y, bitmap, txt_rect)
else
# Create Bitmap
bitmap = Bitmap.new(rect.width, rect.height)
# Make A Copy of the Font
bitmap.font = font.dup
# Draw Text on bitmap
bitmap.draw_text(txt_rect, str, align)
# Draw Bitmap
blt(rect.x, rect.y, bitmap, txt_rect)
# Set Text Memory
@@text_memory[[font.dup, txt_rect, str]] = bitmap
end
end
#-------------------------------------------------------------------------
# Name : Draw Wrapped Text From Memory
# Info : Draws Text with Text Wrap and Saves it
# Author : Trickster
# Call Info : Five
# Integer X and Y, Define Position
# Integer Width, defines the width of the text rectangle
# Integer Height, defines the height of the text
# String Text, Text to be drawn
#-------------------------------------------------------------------------
def draw_wrap_text_memory(x, y, width, height, text)
# Get Array of Text
strings = text.split
# Run Through Array of Strings
strings.each do |string|
# Get Word
word = string + ' '
# Get Word Width
word_width = text_size(word).width
# If Can't Fit on Line move to next one
x, y = 0, y + height if x + word_width > width
# Draw Text Memory
draw_text_memory(x, y, word_width, height, word)
# Add To X
x += word_width
end
end
#-------------------------------------------------------------------------
# Name : Get Formatted Text Size
# Info : Gets Rect information for drawing formatted text
# The Rect Object Returned will have this information
# x, x coordinate where drawing ends
# y, y coordinate where drawing ends
# width, the width sent to this method
# height, the height of all of the text drawn
# Author : Trickster
# Call Info : Five
# Integer X and Y, Define Position
# Integer Width, defines the width of the text rectangle
# Integer Height, defines the height of the text
# String Text, Text to get information for
#-------------------------------------------------------------------------
def get_formatted_size(x, y, width, height, text)
# Make a Copy and Save
text = text.dup
# Replace C[Hex+ or N] I[] B[] with nothing
text.gsub!(/[BbIiCc]\[([A-F a-f 0-9]+|N)*\]/) {''}
# Replace T[] with \004
text.gsub!(/[Tt]\[\]/) {" \004 "}
# Replace N[] with \005
text.gsub!(/[Nn]\[\]/) {" \005 "}
# Setup Cx and Cy
cx, cy = 0, 0
# Declare Dx and Dx as local variables
dx, dy = 0, 0
# Run Through each text
text.split(/\s/).each do |word|
# If \004 is included
if word.include?("\004")
# Add Four Spaces
x += text_size(' '*4).width
# Go to Next Text
next
end
# If \005 is included
if word.include?("\005")
# Move to new line
cy = cx / width + 1
# Move to start
cx = cy * width
# Go to Next Text
next
end
# Get Word Width
word_width = text_size("#{word} ").width
# If can't fit on line
if (cx + word_width) % width < x % width
# Move to new line
cy = cx / width + 1
# Move to start
cx = cy * width
end
# Add Width to X
cx += word_width
# Get Draw X and Y
dx = cx % width + x
dy = cx / width * height + y
end
# Return Rect Object
return Rect.new(dx, dy, width, (dy - y + height).to_i)
end
#-------------------------------------------------------------------------
# Name : Set Memory
# Info : Sets Bitmap Memory
# Author : Trickster
# Call Info : No Arguments
# Comment : Use with Clear To Memory
#-------------------------------------------------------------------------
def set_memory
# Make A Clone of itself
@memory = self.dup
end
end
class Hash
#-------------------------------------------------------------------------
# Name : Contains Key?
# Info : Compares all Keys using == similiar to has_key?
# Author : Trickster
# Call Info : One, Key an Object
#-------------------------------------------------------------------------
def contains_key?(key)
# Run Through and Return true if keys are equal
each_key {|other_key| return true if key == other_key}
# Return false
return false
end
#-------------------------------------------------------------------------
# Name : Get Value
# Info : Gets Value using == similiar to []
# Author : Trickster
# Call Info : One, Key an Object
#-------------------------------------------------------------------------
def get_value(key)
# Run Through and Return Key if equal
each_key {|other_key| return self[other_key] if key == other_key}
# If Default Proc is undefined return default else call proc
return default_proc.nil? ? default : default_proc.call(self, key)
end
end
class Font
#-------------------------------------------------------------------------
# Name : == (Comparision Equals)
# Info : Compares two Fonts
# Author : Trickster
# Call Info : One Argument Font other, Font to Check
#-------------------------------------------------------------------------
def ==(other)
return false unless (name == other.name && size == other.size &&
color == other.color && bold == other.bold && italic == other.italic)
instance_variables.each do |var|
var = var[1...var.size]
return false if method(var).call != other.method(var).call
end
return true
end
end