11-21-2018, 04:48 AM
(This post was last modified: 11-21-2018, 04:51 AM by DerVVulfman.)
Spritesheet Generator Conversion Script
Version: 1.0
Version: 1.0
Introduction
For those using an Animated Battler script that needs a battler with a single row of mutiple poses like the Minkoff style. This script lets you convert battler graphics from RPGMaker MV and RPGMaker 2003 formats for use.
Features
- Hopefully simple to use
- Keeps the alpha channel(transparency) intact
- Still a WIP (that's Work in Progress, guys)
Demo
None (yet).
Script
The Script
Code:
#==============================================================================
# ** Spritesheet Generator Conversion Script
# by DerVVulfman
# 11-20-2018 (mm-dd-yyyy)
#------------------------------------------------------------------------------
#
# How to use?
# Probably the FASTEST instructions I will give.....
#
# First, let's set up the project:
# 1) Copy this script into your Scripts Library
# 2) Make an event on your map. Hey! Put a character there to talk to!!!
# 3) In the event, make a script call: $scene = Scene_SpritesheetConv.new
#
# Now, let's do something:
# 1) Get some non-Minkoffish battler. Like, make it an RMMV battler
# 2) Paste it in this project's root directory. Remmember it's name.
# 3) Go into this script's config and put the file's name in the SOURCE value
# 4) Set the SETSTYLE value to 1 .... that means it will convert an RMMV file
# 5) Run the project and talk to your event to make this script run
#
# That should do it. I'll see about making an interface system later. Maybe
# even something to adjust which pose goes where.
#
#------------------------------------------------------------------------------
#
# A bit of Q&A before I get any...
# --------------------------------
# Q: HEY! My output isn't all lined up!
# A: Did you set it for the right style of battler? (RMMV or RM2K3)
# Q: Yes. It's an RMMV Battler I found and I set SETSTYLE to 1
# A: If some sections are being trimmed or cut off abruptly, the artist
# may not have paid attention to lining up his individual sprite cels.
# Q: Hey, are there any pre-rendered configs for these?
# A: Oh, you mean ... When I release the new version of the script. ^_^
#
#==============================================================================
#==============================================================================
# ** Spritesheet Generator Conversion Module
#------------------------------------------------------------------------------
# This is the configuration system for the script. Beta format for now, it
# is where you set the filename for both the source and target images.
# You also select the format for the conversion.
#==============================================================================
module SS_Gen
# -------------------------------------------------------------------------
# Predefined Style Set Options --------------------------------------------
STYLE = {}
# Style by ID Style Name R. P. F. P. F.
# =========== ============= == == == == ==
STYLE[1] = [ 'RMMV to Single', 3, 18, 3, 18, 3]
STYLE[2] = [ 'RM2K3 to Single', 2, 16, 3, 11, 3]
# -------------------------------------------------------------------------
# SET STYLE
# =========
# Choose a style setting. Currently, there are only 2 settings (1 or 2)
# which match the two predefine styles above.
# 1 = RMMV Conversion / 2 = RM2K3 Conversion
#
SETSTYLE = 2
# SOURCE
# ======
# This is the filename for the source image to convert.
# It is a file in the project's root directory (where you find Game.Exe)
# Do not supply any .png to the end of the filename.
#
SOURCE = 'Source'
# OUTPUT
# ======
# This is the filename for the target image to generate.
# The file will appear in the project's root directory
# Do not supply any .png to the end of the filename.
#
OUTPUT = 'Output2'
end
#==============================================================================
# ** Zlib::Png_File
#------------------------------------------------------------------------------
# This is a module adds PNG_File class to save Bitmap's to PNG Files
# =MACL=
#==============================================================================
module Zlib
class Png_File < GzipWriter
#------------------------------------------------------------------------
# * Make PNG
# bitmap_Fx : Bitmap Effects
# mode : Mode
#------------------------------------------------------------------------
def make_png(bitmap, mode)
@mode = mode
@bitmap = bitmap
self.write(make_header)
self.write(make_ihdr)
self.write(make_idat)
self.write(make_iend)
end
#------------------------------------------------------------------------
# * Make PNG Header
#------------------------------------------------------------------------
def make_header
return [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].pack("C*")
end
#------------------------------------------------------------------------
# * Make Image Information Header
#------------------------------------------------------------------------
def make_ihdr
ih_size = [13].pack("N")
ih_sign = 'IHDR'
ih_width = [@bitmap.width].pack('N')
ih_height = [@bitmap.height].pack('N')
ih_bit_depth = [8].pack('C')
ih_color_type = [6].pack('C')
ih_compression_method = [0].pack('C')
ih_filter_method = [0].pack('C')
ih_interlace_method = [0].pack('C')
string = ih_sign + ih_width + ih_height + ih_bit_depth +
ih_color_type + ih_compression_method +
ih_filter_method + ih_interlace_method
ih_crc = [Zlib.crc32(string)].pack('N')
return ih_size + string + ih_crc
end
#------------------------------------------------------------------------
# * Make Image Data
#------------------------------------------------------------------------
def make_idat
header = "\x49\x44\x41\x54"
data = @mode == 0 ? make_bitmap_data0 : make_bitmap_data1
data = Zlib::Deflate.deflate(data, 8)
crc = [Zlib.crc32(header + data)].pack('N')
size = [data.length].pack('N')
return size + header + data + crc
end
#------------------------------------------------------------------------
# * Create bitmap data (Mode 0)
#------------------------------------------------------------------------
def make_bitmap_data0
# Create a temporary GZ file
gz = Zlib::GzipWriter.open('hoge.gz')
# Clear frame counter
t_Fx = 0
# Obtain bitmap dimensions and clear temp data
w = @bitmap.width
h = @bitmap.height
data = []
# Cycle through image vertically
for y in 0...h
data.push(0)
# Cycle horizontally
for x in 0...w
# Add to timer FX count
t_Fx += 1
# Update Graphics every interval
Graphics.update if t_Fx % 10000 == 0
# Write data at intervals
if t_Fx % 100000 == 0
s = data.pack("C*")
gz.write(s)
data.clear
end
# Obtain pixel attributes
color = @bitmap.get_pixel(x, y)
red = color.red
green = color.green
blue = color.blue
alpha = color.alpha
# Store attributes in data
data.push(red)
data.push(green)
data.push(blue)
data.push(alpha)
end
end
# Write, Close and clear data
s = data.pack("C*")
gz.write(s)
gz.close
data.clear
# Obtain formatted data from Temp File
gz = Zlib::GzipReader.open('hoge.gz')
data = gz.read
gz.close
# Delete file and return data
File.delete('hoge.gz')
return data
end
#--------------------------------------------------------------------------
# * Create bitmap data (Mode 1)
#--------------------------------------------------------------------------
def make_bitmap_data1
# Obtain bitmap dimensions and clear temp data
w = @bitmap.width
h = @bitmap.height
data = []
# Cycle through image vertically
for y in 0...h
data.push(0)
# Cycle horizontally
for x in 0...w
color = @bitmap.get_pixel(x, y)
# Obtain pixel attributes
red = color.red
green = color.green
blue = color.blue
alpha = color.alpha
# Store attributes in data
data.push(red)
data.push(green)
data.push(blue)
data.push(alpha)
end
end
# Return data
return data.pack("C*")
end
#------------------------------------------------------------------------
# * Make Image End/EOF Data
#------------------------------------------------------------------------
def make_iend
ie_size = [0].pack("N")
ie_sign = "IEND"
ie_crc = [Zlib.crc32(ie_sign)].pack("N")
return ie_size + ie_sign + ie_crc
end
end
end
#==============================================================================
# ** Bitmap
#------------------------------------------------------------------------------
# The bitmap class. Bitmaps are expressions of so-called graphics. Sprites
# (Sprite) and other objects must be used to display bitmaps on the screen.
#==============================================================================
class Bitmap
#--------------------------------------------------------------------------
# * Make PNG (from the MACL)
# name : Name of filename
# path : Directory in Game Folder
# mode : Mode of Writing
#--------------------------------------------------------------------------
def make_png(name="like", path="", mode=0)
# Create the folder path if supplied
make_dir(path) if path != ""
Zlib::Png_File.open("temp.gz") {|gz| gz.make_png(self, mode) }
Zlib::GzipReader.open("temp.gz") {|gz| $read = gz.read }
f = File.open(path + name + ".png","wb")
f.write($read)
f.close
File.delete('temp.gz')
end
#--------------------------------------------------------------------------
# * Make Directory Path (Extended from the MACL)
# path : Directory in Game Folder
#--------------------------------------------------------------------------
def make_dir(path)
dir = path.split("/")
dir.each_index {|i|
next if dir == "."
add_dir = dir[0..i].join("/")
begin
Dir.mkdir(add_dir)
rescue
end
}
end
end
#==============================================================================
# ** Scene_Title
#------------------------------------------------------------------------------
# This class performs spritesheet conversion processing.
#==============================================================================
class Scene_SpritesheetConv
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
dispose_tempfolder # Erase temp folder if still exists
generate_cels # Generate individual animation cels
generate_spritesheet # Generate spritesheet from celse
dispose_tempfolder # Erase temp folder
$scene = Scene_Map.new # Return to map
exit
end
#--------------------------------------------------------------------------
# * Get number of rows in source image
#--------------------------------------------------------------------------
def source_rows
SS_Gen::STYLE[SS_Gen::SETSTYLE][1]
end
#--------------------------------------------------------------------------
# * Get number of poses in source image
#--------------------------------------------------------------------------
def source_poses
SS_Gen::STYLE[SS_Gen::SETSTYLE][2]
end
#--------------------------------------------------------------------------
# * Get number of frames for each pose in source image
#--------------------------------------------------------------------------
def source_frames
SS_Gen::STYLE[SS_Gen::SETSTYLE][3]
end
#--------------------------------------------------------------------------
# * Get number of poses to create in target image
#--------------------------------------------------------------------------
def target_poses
SS_Gen::STYLE[SS_Gen::SETSTYLE][4]
end
#--------------------------------------------------------------------------
# * Get number of frames per pose in target image
#--------------------------------------------------------------------------
def target_frames
# If not entered, same as source
if SS_Gen::STYLE[SS_Gen::SETSTYLE][5].nil?
return SS_Gen::STYLE[SS_Gen::SETSTYLE][3]
end
SS_Gen::STYLE[SS_Gen::SETSTYLE][5]
end
#--------------------------------------------------------------------------
# * Get total number of frames within each row
#--------------------------------------------------------------------------
def frames_per_row
return source_rows * source_frames
end
#--------------------------------------------------------------------------
# * Get total number of poses within each row
#--------------------------------------------------------------------------
def poses_per_row
source_poses / source_rows
end
#--------------------------------------------------------------------------
# * Generate Cels
#--------------------------------------------------------------------------
def generate_cels
# Initialize the method
bitmap = Bitmap.new(SS_Gen::SOURCE)
count = 0
cell_width = bitmap.width / frames_per_row
cell_height = bitmap.height / poses_per_row
# Sort through the original image
( 0...source_rows).each { |z|
( 0...poses_per_row).each { |y|
( 0...source_frames).each { |x|
# Calculate X-Origin in original Multi-Row Spritesheet
x2 = (x * cell_width) + ((z * source_frames) * cell_width)
# Cel Count
count += 1
# Create temporary image for cel
temp_cel = Bitmap.new(cell_width, cell_height)
# Create Source Rect Area based on cell position in spriesheet
rect = Rect.new( x2, y * cell_height, cell_width, cell_height)
# Generate Name
name = 'temp_img' + sprintf("%5.5d", count)
# Paste/Blit cel into bitmap
temp_cel.blt(0, 0, bitmap, rect)
# Save Bitmap into Temporary Storage Folder
temp_cel.make_png(name, 'ImgConvertDir' + '/')
# Ensure Graphics Module updates (Prevent Lock/Freeze error
Graphics.update if count % 80 == 0
}
}
}
end
#--------------------------------------------------------------------------
# * Generate Spritesheet
#--------------------------------------------------------------------------
def generate_spritesheet
# Initialize the method
files = Dir.entries('ImgConvertDir') - ['.', '..']
files.collect! {|filename| Bitmap.new("#{'ImgConvertDir'}/#{filename}") }
w = files[0].width
h = files[0].height
# Create temporary image for spritesheet
temp_image = Bitmap.new(w * target_frames, h * target_poses)
# Sort through all files
files.each_with_index {|img, i|
x = (i % target_frames) * w
y = (i / target_frames) * h
# Paste/Blit cel into spritesheet bitmap
temp_image.blt(x, y, img, Rect.new(0, 0, w, h))
# Ensure Graphics Module updates (Prevent Lock/Freeze error
Graphics.update if (i % 80) == 0
}
# Save Generated Bitmap
temp_image.make_png(SS_Gen::OUTPUT, '')
end
#--------------------------------------------------------------------------
# * Dispose Temp Folder and all contents
#--------------------------------------------------------------------------
def dispose_tempfolder
# Run test for existing directory filenames
begin
files = Dir.entries('ImgConvertDir') - ['.', '..']
rescue
return
end
files.each{ |img| File.delete("#{'ImgConvertDir'}/#{img}") }
Dir.delete('ImgConvertDir')
end
end
Instructions
They're within the script. But I expect that you only alter the SOURCE, the OUTPUT and the SETSTYLE values in the configuration section. Nothing else should be touched. The source graphics must be placed in the root directory of your project, and the output will show up there when done.
SAMPLE GRAPHIC
Want an example? I made this simple test battler from The Charas Project, and with it...
...and made this.
FAQ
This utilizes a number of features from the MACL, specifically the ZLib PNG system.
Compatibility
I wrote this with RPGMaker XP in mind. However, it may just work with VX and VXAce with a bit of minor tweaking.
Terms and Conditions
Free for use. It's not expected to be in any actual game. It's a tool afterall
RM2K3_Style.png (Size: 7.8 KB / Downloads: 27)
Output2.png (Size: 10.65 KB / Downloads: 27)
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links