mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-13 07:54:59 +00:00
Added animation editor's particle list
This commit is contained in:
@@ -34,11 +34,14 @@ class AnimationEditor
|
||||
SIDE_PANE_Y = CANVAS_Y
|
||||
SIDE_PANE_WIDTH = WINDOW_WIDTH - SIDE_PANE_X - BORDER_THICKNESS
|
||||
SIDE_PANE_HEIGHT = CANVAS_HEIGHT + (32 * 2)
|
||||
PARTICLE_LIST_X = 0
|
||||
PARTICLE_LIST_Y = SIDE_PANE_Y + SIDE_PANE_HEIGHT + (BORDER_THICKNESS * 2)
|
||||
PARTICLE_LIST_WIDTH = WINDOW_WIDTH
|
||||
PARTICLE_LIST_HEIGHT = WINDOW_HEIGHT - PARTICLE_LIST_Y
|
||||
|
||||
def initialize(anim_id, anim)
|
||||
@anim_id = anim_id
|
||||
@anim = anim
|
||||
@keyframe = 0
|
||||
@particle = -1
|
||||
@viewport = Viewport.new(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
|
||||
@viewport.z = 99999
|
||||
@@ -50,7 +53,7 @@ class AnimationEditor
|
||||
@canvas.y = CANVAS_Y
|
||||
@canvas.bitmap = RPG::Cache.load_bitmap("Graphics/Battlebacks/", "field_bg")
|
||||
# Side panes
|
||||
@keyframe_particle_pane = ControlPane.new(SIDE_PANE_X, SIDE_PANE_Y, SIDE_PANE_WIDTH, SIDE_PANE_HEIGHT)
|
||||
@keyframe_particle_pane = UIControls::ControlsContainer.new(SIDE_PANE_X, SIDE_PANE_Y, SIDE_PANE_WIDTH, SIDE_PANE_HEIGHT)
|
||||
# TODO: Make more side panes for:
|
||||
# - colour/tone editor (accessed from keyframe_particle_pane via a
|
||||
# button; has Apply/Cancel buttons to only apply all its values at
|
||||
@@ -63,7 +66,14 @@ class AnimationEditor
|
||||
# shake, etc.)
|
||||
# - keyframe properties (shift all later particle commands forward/
|
||||
# backward).
|
||||
# Timeline/particle list
|
||||
@particle_list = UIControls::AnimationParticleList.new(
|
||||
PARTICLE_LIST_X, PARTICLE_LIST_Y, PARTICLE_LIST_WIDTH, PARTICLE_LIST_HEIGHT, @viewport
|
||||
)
|
||||
@particle_list.set_interactive_rects
|
||||
@captured = nil
|
||||
set_side_panes_contents
|
||||
set_particle_list_contents
|
||||
refresh
|
||||
end
|
||||
|
||||
@@ -71,9 +81,18 @@ class AnimationEditor
|
||||
@screen_bitmap.dispose
|
||||
@canvas.dispose
|
||||
@keyframe_particle_pane.dispose
|
||||
@particle_list.dispose
|
||||
@viewport.dispose
|
||||
end
|
||||
|
||||
def keyframe
|
||||
return @particle_list.keyframe
|
||||
end
|
||||
|
||||
def particle_index
|
||||
return @particle_list.particle_index
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def set_keyframe_particle_pane_contents
|
||||
@@ -116,6 +135,10 @@ class AnimationEditor
|
||||
set_keyframe_particle_pane_contents
|
||||
end
|
||||
|
||||
def set_particle_list_contents
|
||||
@particle_list.set_particles(@anim[:particles])
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def draw_editor_background
|
||||
@@ -131,79 +154,39 @@ class AnimationEditor
|
||||
@screen_bitmap.bitmap.outline_rect(SIDE_PANE_X - 1, SIDE_PANE_Y - 1, SIDE_PANE_WIDTH + 2, SIDE_PANE_HEIGHT + 2, Color.white)
|
||||
# Fill the side pane with white
|
||||
@screen_bitmap.bitmap.fill_rect(SIDE_PANE_X, SIDE_PANE_Y, SIDE_PANE_WIDTH, SIDE_PANE_HEIGHT, Color.white)
|
||||
end
|
||||
|
||||
def get_keyframe_particle_value(particle, frame, property)
|
||||
if !GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.include?(property)
|
||||
raise _INTL("Couldn't get default value for property {1} for particle {2}.",
|
||||
property, particle[:name])
|
||||
end
|
||||
ret = [GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES[property], false]
|
||||
if particle[property]
|
||||
# NOTE: The commands are already in keyframe order, so we can just run
|
||||
# through them in order, applying their changes until we reach
|
||||
# frame.
|
||||
particle[property].each do |cmd|
|
||||
break if cmd[0] > frame # Command is in the future; no more is needed
|
||||
break if cmd[0] == frame && cmd[1] > 0 # Start of a "MoveXYZ" command; won't have changed yet
|
||||
if cmd[0] + cmd[1] <= frame # Command has finished; use its end value
|
||||
ret[0] = cmd[2]
|
||||
next
|
||||
end
|
||||
# In a "MoveXYZ" command; need to interpolate
|
||||
ret[0] = lerp(ret[0], cmd[2], cmd[1], cmd[0], frame).to_i
|
||||
ret[1] = true # Interpolating
|
||||
break
|
||||
end
|
||||
end
|
||||
# NOTE: Particles are assumed to be not visible at the start of the
|
||||
# animation, and automatically become visible when the particle has
|
||||
# its first command. This does not apply to the "User" and "Target"
|
||||
# particles, which start the animation visible.
|
||||
if property == :visible
|
||||
first_cmd = (["User", "Target"].include?(particle[:name])) ? 0 : -1
|
||||
first_visible_cmd = -1
|
||||
if first_cmd < 0
|
||||
particle.each_pair do |prop, value|
|
||||
next if !value.is_a?(Array) || value.length == 0
|
||||
first_cmd = value[0][0] if first_cmd < 0 || first_cmd > value[0][0]
|
||||
first_visible_cmd = value[0][0] if prop == :visible && (first_visible_cmd < 0 || first_visible_cmd > value[0][0])
|
||||
end
|
||||
end
|
||||
ret[0] = true if first_cmd >= 0 && first_cmd <= frame &&
|
||||
(first_visible_cmd < 0 || frame < first_visible_cmd)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def get_all_keyframe_particle_values(particle, frame)
|
||||
ret = {}
|
||||
GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.each_pair do |prop, default|
|
||||
ret[prop] = get_keyframe_particle_value(particle, frame, prop)
|
||||
end
|
||||
return ret
|
||||
# Outline around timeline/particle list
|
||||
@screen_bitmap.bitmap.outline_rect(PARTICLE_LIST_X - 3, PARTICLE_LIST_Y - 3, PARTICLE_LIST_WIDTH + 6, PARTICLE_LIST_HEIGHT + 6, Color.white)
|
||||
@screen_bitmap.bitmap.outline_rect(PARTICLE_LIST_X - 2, PARTICLE_LIST_Y - 2, PARTICLE_LIST_WIDTH + 4, PARTICLE_LIST_HEIGHT + 4, Color.black)
|
||||
@screen_bitmap.bitmap.outline_rect(PARTICLE_LIST_X - 1, PARTICLE_LIST_Y - 1, PARTICLE_LIST_WIDTH + 2, PARTICLE_LIST_HEIGHT + 2, Color.white)
|
||||
end
|
||||
|
||||
def refresh_keyframe_particle_pane
|
||||
if @particle < 0 || !@anim[:particles][@particle]
|
||||
if !keyframe || keyframe < 0 || !particle_index || particle_index < 0 ||
|
||||
!@anim[:particles][particle_index]
|
||||
@keyframe_particle_pane.visible = false
|
||||
else
|
||||
@keyframe_particle_pane.visible = true
|
||||
new_vals = get_all_keyframe_particle_values(@anim[:particles][@particle], @keyframe)
|
||||
new_vals = AnimationEditor::ParticleDataHelper.get_all_keyframe_particle_values(@anim[:particles][particle_index], keyframe)
|
||||
# TODO: Need to do something special for :color, :tone and :graphic/:frame
|
||||
# which all have button controls.
|
||||
@keyframe_particle_pane.controls.each do |ctrl|
|
||||
next if !new_vals.include?(ctrl[0])
|
||||
ctrl.value = new_vals[ctrl[0]][0]
|
||||
ctrl[1].value = new_vals[ctrl[0]][0] if ctrl[1].respond_to?("value=")
|
||||
# TODO: new_vals[ctrl[0]][1] is whether the value is being interpolated,
|
||||
# which should be indicated somehow in ctrl.
|
||||
# which should be indicated somehow in ctrl[1].
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_particle_list
|
||||
@particle_list.refresh
|
||||
end
|
||||
|
||||
def refresh
|
||||
# Set all side pane controls to values from animation
|
||||
refresh_keyframe_particle_pane
|
||||
# Set particle list's contents
|
||||
refresh_particle_list
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -216,6 +199,7 @@ class AnimationEditor
|
||||
|
||||
def update_keyframe_particle_pane
|
||||
@keyframe_particle_pane.update
|
||||
@captured = :keyframe_particle_pane if @keyframe_particle_pane.busy?
|
||||
if @keyframe_particle_pane.changed?
|
||||
# TODO: Make undo/redo snapshot.
|
||||
values = @keyframe_particle_pane.values
|
||||
@@ -233,9 +217,38 @@ class AnimationEditor
|
||||
end
|
||||
end
|
||||
|
||||
def update_particle_list
|
||||
old_keyframe = keyframe
|
||||
old_particle_index = particle_index
|
||||
@particle_list.update
|
||||
@captured = :particle_list if @particle_list.busy?
|
||||
if @particle_list.changed?
|
||||
refresh_keyframe_particle_pane if keyframe != old_keyframe || particle_index != old_particle_index
|
||||
# TODO: Lots of stuff here.
|
||||
@particle_list.clear_changed
|
||||
end
|
||||
@particle_list.repaint
|
||||
end
|
||||
|
||||
def update
|
||||
update_canvas
|
||||
update_keyframe_particle_pane
|
||||
if @captured
|
||||
# TODO: There must be a better way to do this.
|
||||
case @captured
|
||||
when :canvas
|
||||
update_canvas
|
||||
@captured = nil if !@canvas.busy?
|
||||
when :keyframe_particle_pane
|
||||
update_keyframe_particle_pane
|
||||
@captured = nil if !@keyframe_particle_pane.busy?
|
||||
when :particle_list
|
||||
update_particle_list
|
||||
@captured = nil if !@particle_list.busy?
|
||||
end
|
||||
else
|
||||
update_canvas
|
||||
update_keyframe_particle_pane
|
||||
update_particle_list
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user