* Taseditor: Config->Combine consecutive Recordings/Draws

* Taseditor: rightclick menu appears only after click on selected row
* Taseditor: refactoring
This commit is contained in:
ansstuff 2012-03-22 16:49:33 +00:00
parent eca6e6e279
commit 66504dc115
25 changed files with 1414 additions and 1158 deletions

View File

@ -1,5 +1,31 @@
22-Mar-2012 - AnS - Config->Combine consecutive Recordings/Draws
18-Mar-2012 - AnS - new hotkey "Cancel Seeking (TAS Editor)" (Esc)
18-Mar-2012 - AnS - Taseditor: Config->Autopause at the end of Movie
17-Mar-2012 - CaH4e3 - varous bugfixes, xstring trimming functions logic bugs, etc
17-Mar-2012 - AnS - Taseditor: showing row_last_clicked when Shift or Alt is held
17-Mar-2012 - AnS - Taseditor: no more "allow keys in Piano Roll"; new accelerators: Ctrl + arrows, Shift + arrows, Home/End/Page Up/Page Down, Ctrl + Home/End, Shift + Home/End
17-Mar-2012 - AnS - Taseditor: selection by dragging from Frame#
17-Mar-2012 - AnS - Taseditor: set/pick Markers by doubleclick, throw Markers away
14-Mar-2012 - AnS - Taseditor: drawing input; holding Shift when drawing
14-Mar-2012 - AnS - Taseditor: fixed known WinXP bug with scrollbar arrows
14-Mar-2012 - AnS - Taseditor: moving Markers by drag'n'drop, "Marker Drag" and "Marker Swap" operations
14-Mar-2012 - AnS - Taseditor: dragging blue arrow (moving Playback cursor)
14-Mar-2012 - AnS - Taseditor: observing Piano Roll by dragging cursor outside
11-Mar-2012 - AnS - Taseditor: double-tapping Shift/Ctrl scrolls Piano Roll to respective cursor
09-Mar-2012 - AnS - Taseditor: Config->Deselect on doubleclick
09-Mar-2012 - AnS - Taseditor: checking ROM checksum when saving/loading projects
09-Mar-2012 - AnS - Taseditor: TAS Editor can have mouse wheel input even when keyboard focus is on FCEUX window
09-Mar-2012 - AnS - disabled FCEUX context menu when TAS Editor is engaged
06-mar-2012 - prg - fceux no longer segfaults when opening gamepadconfig with GTK < 2.24 - a message is printed to the console
06-mar-2012 - prg - supports loading of configuration files in $FCEUXDIR/cfg.d/*
01-Mar-2012 - AnS - Taseditor: changing history size doesn't reset history
28-feb-2012 - AnS - Taseditor: "Deselect" option in menus
26-feb-2012 - AnS - Small save/load state speedup, noticeable only in TAS Editor or lua bots
21-feb-2012 - AnS - Taseditor: header lights on mouseover
21-feb-2012 - AnS - Taseditor: registering click at buttondown; Alt+click on input = set pattern
20-feb-2012 - AnS - Taseditor: Right button + wheel = Playback rewind/forward; Shift/Ctrl + wheel = jump via Markers with Playback/Selection cursor
20-feb-2012 - AnS - Taseditor: middle button pauses/unpauses emulation
18-feb-2012 - AnS - PATTERNS menu, loading data from "tools\taseditor_patterns.txt"
18-feb-2012 - AnS - "Use pattern" checkbox in Recorder; Config->ColumnSet Pattern skips Lag
18-feb-2012 - AnS - Taseditor: "Frame#" lights when Alt key is being held, not entering menu by Alt

View File

@ -318,7 +318,7 @@ static CFGSTRUCT fceuconfig[] = {
AC(taseditor_config.show_branch_descr),
AC(taseditor_config.bind_markers),
AC(taseditor_config.empty_marker_notes),
AC(taseditor_config.combine_consecutive_rec),
AC(taseditor_config.combine_consecutive),
AC(taseditor_config.use_1p_rec),
AC(taseditor_config.columnset_by_keys),
AC(taseditor_config.superimpose_affects_paste),

View File

@ -39,6 +39,7 @@ RECORDER recorder;
GREENZONE greenzone;
MARKERS_MANAGER markers_manager;
BOOKMARKS bookmarks;
BRANCHES branches;
POPUP_DISPLAY popup_display;
PIANO_ROLL piano_roll;
TASEDITOR_LUA taseditor_lua;
@ -94,6 +95,7 @@ bool EnterTasEditor()
markers_manager.init();
project.init();
bookmarks.init();
branches.init();
popup_display.init();
history.init();
taseditor_lua.init();
@ -150,6 +152,7 @@ bool ExitTasEditor()
markers_manager.free();
greenzone.free();
bookmarks.free();
branches.free();
popup_display.free();
history.free();
playback.SeekingStop();
@ -194,6 +197,7 @@ void UpdateTasEditor()
markers_manager.update();
playback.update();
bookmarks.update();
branches.update();
popup_display.update();
selection.update();
splicer.update();
@ -317,6 +321,7 @@ void NewProject()
playback.reset();
playback.StartFromZero();
bookmarks.reset();
branches.reset();
history.reset();
piano_roll.reset();
selection.reset();

View File

@ -9,7 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
------------------------------------------------------------------------------------
Bookmark - Single Bookmark data
* stores all info of one specific Bookmark-Branch: movie snapshot, a savestate of 1 frame, a screenshot of the frame, an info about relations of this Branch, a state of flashing for this Bookmark's row
* stores all info of one specific Bookmark: movie snapshot, a savestate of 1 frame, a screenshot of the frame, a state of flashing for this Bookmark's row
* saves and loads the data from a project file. On error: sends warning to caller
* implements procedure of "Bookmark set": creating movie snapshot, setting key frame on current Playback position, copying savestate from Greenzone, making and compressing screenshot, launching flashing animation
* launches respective flashings for "Bookmark jump" and "Branch deploy"
@ -34,7 +34,6 @@ void BOOKMARK::init()
not_empty = false;
flash_type = flash_phase = 0;
snapshot.jump_frame = -1;
parent_branch = -1; // -1 = root (cloud)
}
void BOOKMARK::set()
@ -78,8 +77,6 @@ void BOOKMARK::save(EMUFILE *os)
if (not_empty)
{
write8le(1, os);
// write parent_branch
write32le(parent_branch, os);
// write snapshot
snapshot.save(os);
// write savestate
@ -100,8 +97,6 @@ bool BOOKMARK::load(EMUFILE *is)
not_empty = tmp != 0;
if (not_empty)
{
// read parent_branch
if (!read32le(&parent_branch, is)) return true;
// read snapshot
if (snapshot.load(is)) return true;
// read savestate

View File

@ -30,7 +30,8 @@ public:
SNAPSHOT snapshot;
std::vector<uint8> savestate;
std::vector<uint8> saved_screenshot;
int parent_branch;
//int parent_branch;
// not saved vars
int flash_phase;

File diff suppressed because it is too large Load Diff

View File

@ -17,83 +17,15 @@ enum COMMANDS
COMMAND_JUMP = 1,
COMMAND_DEPLOY = 2,
COMMAND_DELETE = 3, // not implemented, probably useless
TOTAL_COMMANDS
};
#define ITEM_UNDER_MOUSE_NONE -2
#define ITEM_UNDER_MOUSE_CLOUD -1
#define BOOKMARKS_FLASH_TICK 100 // in milliseconds
#define BRANCHES_ANIMATION_TICK 50 // animate at 20FPS
#define BRANCHES_TRANSITION_MAX 8
// branches bitmap
#define BRANCHES_BITMAP_WIDTH 170
#define BRANCHES_BITMAP_HEIGHT 145
#define BRANCHES_ANIMATION_FRAMES 12
#define BRANCHES_BITMAP_FRAMENUM_X 2
#define BRANCHES_BITMAP_FRAMENUM_Y 1
#define BRANCHES_BITMAP_TIME_X 2
#define BRANCHES_BITMAP_TIME_Y BRANCHES_BITMAP_HEIGHT - 17
#define BRANCHES_TEXT_SHADOW_COLOR 0xFFFFFF
#define BRANCHES_TEXT_COLOR 0x7F0000
// constants for drawing branches tree
#define BRANCHES_CANVAS_WIDTH 146
#define BRANCHES_CANVAS_HEIGHT 130
#define BRANCHES_CLOUD_X 14
#define BRANCHES_CLOUD_Y 72
#define BRANCHES_GRID_MIN_WIDTH 14
#define BRANCHES_GRID_MAX_WIDTH 30
#define MIN_CLOUD_LINE_LENGTH 19
#define BRANCHES_GRID_MIN_HALFHEIGHT 8
#define BRANCHES_GRID_MAX_HALFHEIGHT 12
#define EMPTY_BRANCHES_X -6
#define EMPTY_BRANCHES_Y_BASE 8
#define EMPTY_BRANCHES_Y_FACTOR 14
#define MAX_NUM_CHILDREN_ON_CANVAS_HEIGHT 9
#define MAX_CHAIN_LEN 10
#define MAX_GRID_Y_POS 8
// spritesheet
#define DIGIT_BITMAP_WIDTH 9
#define DIGIT_BITMAP_HALFWIDTH DIGIT_BITMAP_WIDTH/2
#define DIGIT_BITMAP_HEIGHT 13
#define DIGIT_BITMAP_HALFHEIGHT DIGIT_BITMAP_HEIGHT/2
#define BLUE_DIGITS_SPRITESHEET_DX DIGIT_BITMAP_WIDTH*TOTAL_BOOKMARKS
#define MOUSEOVER_DIGITS_SPRITESHEET_DY DIGIT_BITMAP_HEIGHT
#define DIGIT_RECT_WIDTH 11
#define DIGIT_RECT_WIDTH_COLLISION (DIGIT_RECT_WIDTH + 2)
#define DIGIT_RECT_HALFWIDTH DIGIT_RECT_WIDTH/2
#define DIGIT_RECT_HALFWIDTH_COLLISION (DIGIT_RECT_HALFWIDTH + 1)
#define DIGIT_RECT_HEIGHT 15
#define DIGIT_RECT_HEIGHT_COLLISION (DIGIT_RECT_HEIGHT + 2)
#define DIGIT_RECT_HALFHEIGHT DIGIT_RECT_HEIGHT/2
#define DIGIT_RECT_HALFHEIGHT_COLLISION (DIGIT_RECT_HALFHEIGHT + 1)
#define BRANCHES_CLOUD_WIDTH 26
#define BRANCHES_CLOUD_HALFWIDTH BRANCHES_CLOUD_WIDTH/2
#define BRANCHES_CLOUD_HEIGHT 15
#define BRANCHES_CLOUD_HALFHEIGHT BRANCHES_CLOUD_HEIGHT/2
#define BRANCHES_CLOUD_SPRITESHEET_X 180
#define BRANCHES_CLOUD_SPRITESHEET_Y 0
#define BRANCHES_FIREBALL_WIDTH 10
#define BRANCHES_FIREBALL_HALFWIDTH BRANCHES_FIREBALL_WIDTH/2
#define BRANCHES_FIREBALL_HEIGHT 10
#define BRANCHES_FIREBALL_HALFHEIGHT BRANCHES_FIREBALL_HEIGHT/2
#define BRANCHES_FIREBALL_SPRITESHEET_X 0
#define BRANCHES_FIREBALL_SPRITESHEET_Y 26
#define BRANCHES_FIREBALL_MAX_SIZE 5
#define BRANCHES_FIREBALL_SPRITESHEET_END_X 160
#define BRANCHES_CORNER_WIDTH 7
#define BRANCHES_CORNER_HALFWIDTH BRANCHES_CORNER_WIDTH/2
#define BRANCHES_CORNER_HEIGHT 7
#define BRANCHES_CORNER_HALFHEIGHT BRANCHES_CORNER_HEIGHT/2
#define BRANCHES_CORNER1_SPRITESHEET_X 206
#define BRANCHES_CORNER1_SPRITESHEET_Y 0
#define BRANCHES_CORNER2_SPRITESHEET_X 213
#define BRANCHES_CORNER2_SPRITESHEET_Y 0
#define BRANCHES_CORNER3_SPRITESHEET_X 206
#define BRANCHES_CORNER3_SPRITESHEET_Y 7
#define BRANCHES_CORNER4_SPRITESHEET_X 213
#define BRANCHES_CORNER4_SPRITESHEET_Y 7
#define BRANCHES_CORNER_BASE_SHIFT 6
// listview columns
enum
{
@ -120,7 +52,7 @@ public:
void save(EMUFILE *os, bool really_save = true);
bool load(EMUFILE *is);
void command(int command_id, int slot);
void command(int command_id, int slot = -1);
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
LONG CustomDraw(NMLVCUSTOMDRAW* msg);
@ -128,85 +60,40 @@ public:
void RightClick(int column_index, int row_index);
int FindBookmarkAtFrame(int frame);
int GetCurrentBranch();
void RedrawBookmarksCaption();
void RedrawBookmarksList();
void RedrawChangedBookmarks(int frame);
void RedrawBookmarksRow(int index);
void RedrawBranchesTree();
void PaintBranchesBitmap(HDC hdc);
void MouseMove(int new_x, int new_y);
void CheckMousePos();
void ChangesMadeSinceBranch();
void RecalculateBranchesTree();
void RecursiveAddHeight(int branch_num, int amount);
void RecursiveSetYPos(int parent, int parentY);
void FindItemUnderMouse();
// saved vars
std::vector<BOOKMARK> bookmarks_array;
// not saved vars
int branch_row_top;
int branch_row_left;
int branch_row_height;
int edit_mode;
bool must_check_item_under_mouse;
bool mouse_over_bitmap, mouse_over_bookmarkslist;
int item_under_mouse;
TRACKMOUSEEVENT tme, list_tme;
HWND hwndBookmarksList, hwndBranchesBitmap, hwndBookmarks;
private:
void set(int slot);
void jump(int slot);
void deploy(int slot);
void SetCurrentPosTime();
// also saved vars
int current_branch;
bool changes_since_current_branch;
char cloud_time[TIME_DESC_LENGTH];
char current_pos_time[TIME_DESC_LENGTH];
// not saved vars
std::vector<int> commands;
int check_flash_shedule;
int edit_mode;
int animation_frame;
int next_animation_time;
bool must_check_item_under_mouse;
bool must_redraw_branches_tree;
bool must_recalculate_branches_tree;
std::vector<int> BranchX; // in pixels
std::vector<int> BranchY;
std::vector<int> BranchPrevX;
std::vector<int> BranchPrevY;
std::vector<int> BranchCurrX;
std::vector<int> BranchCurrY;
int CloudX, CloudPrevX, cloud_x;
int CursorX, CursorPrevX, CursorY, CursorPrevY;
int transition_phase;
int fireball_size;
int mouse_x, mouse_y;
HWND hwndBookmarksList, hwndBookmarks;
HWND hwndBranchesBitmap;
int list_row_top;
int list_row_left;
int list_row_height;
// GDI stuff
HFONT hBookmarksFont;
HBRUSH normal_brush;
RECT temp_rect;
HPEN normal_pen, select_pen;
HBITMAP branches_hbitmap, hOldBitmap, buffer_hbitmap, hOldBitmap1, branchesSpritesheet, hOldBitmap2;
HDC hBitmapDC, hBufferDC, hSpritesheetDC;
// temps
std::vector<int> GridX; // in grid units
std::vector<int> GridY;
std::vector<int> GridHeight;
std::vector<std::vector<uint8>> Children;
};

View File

@ -0,0 +1,944 @@
/* ---------------------------------------------------------------------------------
Implementation file of Branches class
Copyright (c) 2011-2012 AnS
(The MIT License)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------------
Branches - Manager of Branches
[Singleton]
* stores info about Branches (relations of Bookmarks) and the id of current Branch
* also stores the time of the last modification (see fireball) and the time of the root of Branches Tree (see cloudlet)
* finds best place for every new Bookmark in the Branches Tree
* saves and loads the data from a project file. On error: sends warning to caller
* implements the working of Branches Tree: creating, recalculating relations, animating, redrawing, mouseover
* on demand: reacts on project changes and recalculates Branches Tree
* regularly updates animations in Branches Tree
* stores resources: coordinates for building Branches Tree, animation timings
------------------------------------------------------------------------------------ */
#include "taseditor_project.h"
#include "utils/xstring.h"
#include "zlib.h"
#pragma comment(lib, "msimg32.lib")
LRESULT APIENTRY BranchesBitmapWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC hwndBranchesBitmap_oldWndProc;
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern POPUP_DISPLAY popup_display;
extern PLAYBACK playback;
extern SELECTION selection;
extern GREENZONE greenzone;
extern TASEDITOR_PROJECT project;
extern HISTORY history;
extern PIANO_ROLL piano_roll;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern COLORREF bookmark_flash_colors[TOTAL_COMMANDS][FLASH_PHASE_MAX+1];
// resources
// corners cursor animation
int corners_cursor_shift[BRANCHES_ANIMATION_FRAMES] = {0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0 };
BRANCHES::BRANCHES()
{
}
void BRANCHES::init()
{
free();
// subclass BranchesBitmap
hwndBranchesBitmap_oldWndProc = (WNDPROC)SetWindowLong(bookmarks.hwndBranchesBitmap, GWL_WNDPROC, (LONG)BranchesBitmapWndProc);
// init arrays
BranchX.resize(TOTAL_BOOKMARKS+1);
BranchY.resize(TOTAL_BOOKMARKS+1);
BranchPrevX.resize(TOTAL_BOOKMARKS+1);
BranchPrevY.resize(TOTAL_BOOKMARKS+1);
BranchCurrX.resize(TOTAL_BOOKMARKS+1);
BranchCurrY.resize(TOTAL_BOOKMARKS+1);
// init GDI stuff
HDC win_hdc = GetWindowDC(bookmarks.hwndBranchesBitmap);
hBitmapDC = CreateCompatibleDC(win_hdc);
branches_hbitmap = CreateCompatibleBitmap(win_hdc, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_WIDTH);
hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, branches_hbitmap);
hBufferDC = CreateCompatibleDC(win_hdc);
buffer_hbitmap = CreateCompatibleBitmap(win_hdc, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_WIDTH);
hOldBitmap1 = (HBITMAP)SelectObject(hBufferDC, buffer_hbitmap);
normal_brush = CreateSolidBrush(0x000000);
// prepare branches spritesheet
branchesSpritesheet = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BRANCH_SPRITESHEET));
hSpritesheetDC = CreateCompatibleDC(win_hdc);
hOldBitmap2 = (HBITMAP)SelectObject(hSpritesheetDC, branchesSpritesheet);
// create pens
normal_pen = CreatePen(PS_SOLID, 1, 0x0);
select_pen = CreatePen(PS_SOLID, 2, 0xFF9080);
reset();
next_animation_time = 0;
update();
}
void BRANCHES::free()
{
parents.resize(0);
BranchX.resize(0);
BranchY.resize(0);
BranchPrevX.resize(0);
BranchPrevY.resize(0);
BranchCurrX.resize(0);
BranchCurrY.resize(0);
// free GDI stuff
if (hOldBitmap && hBitmapDC)
{
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
hBitmapDC = NULL;
}
if (branches_hbitmap)
{
DeleteObject(branches_hbitmap);
branches_hbitmap = NULL;
}
if (hOldBitmap1 && hBufferDC)
{
SelectObject(hBufferDC, hOldBitmap1);
DeleteDC(hBufferDC);
hBufferDC = NULL;
}
if (buffer_hbitmap)
{
DeleteObject(buffer_hbitmap);
buffer_hbitmap = NULL;
}
if (hOldBitmap2 && hSpritesheetDC)
{
SelectObject(hSpritesheetDC, hOldBitmap2);
DeleteDC(hSpritesheetDC);
hSpritesheetDC = NULL;
}
if (branchesSpritesheet)
{
DeleteObject(branchesSpritesheet);
branchesSpritesheet = NULL;
}
}
void BRANCHES::reset()
{
parents.resize(TOTAL_BOOKMARKS);
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
parents[i] = ITEM_UNDER_MOUSE_CLOUD;
// set positions of slots to default coordinates
for (int i = TOTAL_BOOKMARKS; i >= 0; i--)
{
BranchX[i] = BranchPrevX[i] = BranchCurrX[i] = EMPTY_BRANCHES_X;
BranchY[i] = BranchPrevY[i] = BranchCurrY[i] = EMPTY_BRANCHES_Y_BASE + EMPTY_BRANCHES_Y_FACTOR * ((i + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS);
}
CursorX = CursorPrevX = CloudX = CloudPrevX = BRANCHES_CLOUD_X;
CursorY = CursorPrevY = BRANCHES_CLOUD_Y;
reset_vars();
current_branch = ITEM_UNDER_MOUSE_CLOUD;
changes_since_current_branch = false;
fireball_size = 0;
// set cloud_time and current_pos_time
SetCurrentPosTime();
strcpy(cloud_time, current_pos_time);
}
void BRANCHES::reset_vars()
{
transition_phase = animation_frame = 0;
must_recalculate_branches_tree = must_redraw_branches_tree = true;
next_animation_time = clock() + BRANCHES_ANIMATION_TICK;
}
void BRANCHES::update()
{
if (must_recalculate_branches_tree)
RecalculateBranchesTree();
// once per 50 milliseconds update branches_bitmap
if (clock() > next_animation_time)
{
// animate branches_bitmap
next_animation_time = clock() + BRANCHES_ANIMATION_TICK;
animation_frame = (animation_frame + 1) % BRANCHES_ANIMATION_FRAMES;
if (bookmarks.edit_mode == EDIT_MODE_BRANCHES)
{
// grow or shrink fireball size
if (changes_since_current_branch)
{
fireball_size++;
if (fireball_size > BRANCHES_FIREBALL_MAX_SIZE) fireball_size = BRANCHES_FIREBALL_MAX_SIZE;
} else
{
fireball_size--;
if (fireball_size < 0) fireball_size = 0;
}
// also update transition from old to new tree
if (transition_phase)
{
transition_phase--;
// recalculate current positions of branch items
for (int i = 0; i <= TOTAL_BOOKMARKS; ++i)
{
BranchCurrX[i] = (BranchX[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevX[i] * transition_phase) / BRANCHES_TRANSITION_MAX;
BranchCurrY[i] = (BranchY[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevY[i] * transition_phase) / BRANCHES_TRANSITION_MAX;
}
cloud_x = (CloudX * (BRANCHES_TRANSITION_MAX - transition_phase) + CloudPrevX * transition_phase) / BRANCHES_TRANSITION_MAX;
must_redraw_branches_tree = true;
bookmarks.must_check_item_under_mouse = true;
} else if (!must_redraw_branches_tree)
{
// just update sprites
InvalidateRect(bookmarks.hwndBranchesBitmap, 0, FALSE);
}
if (must_redraw_branches_tree)
RedrawBranchesTree();
}
}
}
void BRANCHES::save(EMUFILE *os)
{
// write cloud time
os->fwrite(cloud_time, TIME_DESC_LENGTH);
// write current branch and flag of changes since it
write32le(current_branch, os);
if (changes_since_current_branch)
write8le((uint8)1, os);
else
write8le((uint8)0, os);
// write current_position time
os->fwrite(current_pos_time, TIME_DESC_LENGTH);
// write all 10 parents
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
write32le(parents[i], os);
}
// returns true if couldn't load
bool BRANCHES::load(EMUFILE *is)
{
// read cloud time
if ((int)is->fread(cloud_time, TIME_DESC_LENGTH) < TIME_DESC_LENGTH) goto error;
// read current branch and flag of changes since it
uint8 tmp;
if (!read32le(&current_branch, is)) goto error;
if (!read8le(&tmp, is)) goto error;
changes_since_current_branch = (tmp != 0);
// read current_position time
if ((int)is->fread(current_pos_time, TIME_DESC_LENGTH) < TIME_DESC_LENGTH) goto error;
// read all 10 parents
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
if (!read32le(&parents[i], is)) goto error;
// all ok
reset_vars();
return false;
error:
FCEU_printf("Error loading branches\n");
return true;
}
// ----------------------------------------------------------
void BRANCHES::RedrawBranchesTree()
{
// draw background gradient
TRIVERTEX vertex[2] ;
vertex[0].x = 0;
vertex[0].y = 0;
vertex[0].Red = 0xC700;
vertex[0].Green = 0xE700;
vertex[0].Blue = 0xF300;
vertex[0].Alpha = 0x0000;
vertex[1].x = BRANCHES_BITMAP_WIDTH;
vertex[1].y = BRANCHES_BITMAP_HEIGHT;
vertex[1].Red = 0xEB00;
vertex[1].Green = 0xFA00;
vertex[1].Blue = 0xF800;
vertex[1].Alpha = 0x0000;
GRADIENT_RECT gRect;
gRect.UpperLeft = 0;
gRect.LowerRight = 1;
GradientFill(hBitmapDC, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H);
// lines
int branch_x, branch_y, parent_x, parent_y, child_id;
SelectObject(hBitmapDC, normal_pen);
for (int t = Children.size() - 1; t >= 0; t--)
{
if (t > 0)
{
parent_x = BranchCurrX[t-1];
parent_y = BranchCurrY[t-1];
} else
{
parent_x = cloud_x;
parent_y = BRANCHES_CLOUD_Y;
}
for (int i = Children[t].size() - 1; i >= 0; i--)
{
child_id = Children[t][i];
if (child_id < TOTAL_BOOKMARKS)
{
MoveToEx(hBitmapDC, parent_x, parent_y, 0);
LineTo(hBitmapDC, BranchCurrX[child_id], BranchCurrY[child_id]);
}
}
}
// lines for item under mouse
SelectObject(hBitmapDC, select_pen);
int branch = bookmarks.item_under_mouse;
if (branch == TOTAL_BOOKMARKS)
branch = current_branch;
while (branch >= 0)
{
branch_x = BranchCurrX[branch];
branch_y = BranchCurrY[branch];
MoveToEx(hBitmapDC, branch_x, branch_y, 0);
branch = parents[branch];
if (branch >= 0)
{
branch_x = BranchCurrX[branch];
branch_y = BranchCurrY[branch];
} else
{
branch_x = cloud_x;
branch_y = BRANCHES_CLOUD_Y;
}
LineTo(hBitmapDC, branch_x, branch_y);
}
if (changes_since_current_branch)
{
if (bookmarks.item_under_mouse != TOTAL_BOOKMARKS)
SelectObject(hBitmapDC, normal_pen);
if (current_branch >= 0)
{
parent_x = BranchCurrX[current_branch];
parent_y = BranchCurrY[current_branch];
} else
{
parent_x = cloud_x;
parent_y = BRANCHES_CLOUD_Y;
}
MoveToEx(hBitmapDC, parent_x, parent_y, 0);
branch_x = BranchCurrX[TOTAL_BOOKMARKS];
branch_y = BranchCurrY[TOTAL_BOOKMARKS];
LineTo(hBitmapDC, branch_x, branch_y);
}
// cloud
TransparentBlt(hBitmapDC, cloud_x - BRANCHES_CLOUD_HALFWIDTH, BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT, BRANCHES_CLOUD_WIDTH, BRANCHES_CLOUD_HEIGHT, hSpritesheetDC, BRANCHES_CLOUD_SPRITESHEET_X, BRANCHES_CLOUD_SPRITESHEET_Y, BRANCHES_CLOUD_WIDTH, BRANCHES_CLOUD_HEIGHT, 0x00FF00);
// branches rectangles
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
{
temp_rect.left = BranchCurrX[i] - DIGIT_RECT_HALFWIDTH;
temp_rect.top = BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT;
temp_rect.right = temp_rect.left + DIGIT_RECT_WIDTH;
temp_rect.bottom = temp_rect.top + DIGIT_RECT_HEIGHT;
if (bookmarks.bookmarks_array[i].flash_phase)
{
// draw colored rect
HBRUSH color_brush = CreateSolidBrush(bookmark_flash_colors[bookmarks.bookmarks_array[i].flash_type][bookmarks.bookmarks_array[i].flash_phase]);
FillRect(hBitmapDC, &temp_rect, color_brush);
DeleteObject(color_brush);
} else
{
// draw black rect
FillRect(hBitmapDC, &temp_rect, normal_brush);
}
}
// digits
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
{
branch_x = BranchCurrX[i] - DIGIT_BITMAP_HALFWIDTH;
branch_y = BranchCurrY[i] - DIGIT_BITMAP_HALFHEIGHT;
if(i == current_branch)
{
if (i == bookmarks.item_under_mouse)
BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH + BLUE_DIGITS_SPRITESHEET_DX, MOUSEOVER_DIGITS_SPRITESHEET_DY, SRCCOPY);
else
BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH + BLUE_DIGITS_SPRITESHEET_DX, 0, SRCCOPY);
} else
{
if (i == bookmarks.item_under_mouse)
BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH, MOUSEOVER_DIGITS_SPRITESHEET_DY, SRCCOPY);
else
BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH, 0, SRCCOPY);
}
}
SetBkMode(hBitmapDC, TRANSPARENT);
// jump_frame of item under cursor (except cloud - it doesn't have particular frame)
if (bookmarks.item_under_mouse > ITEM_UNDER_MOUSE_CLOUD)
{
char framenum_string[DIGITS_IN_FRAMENUM+1] = {0};
if (bookmarks.item_under_mouse < TOTAL_BOOKMARKS)
U32ToDecStr(framenum_string, bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.jump_frame, DIGITS_IN_FRAMENUM);
else
U32ToDecStr(framenum_string, currFrameCounter, DIGITS_IN_FRAMENUM);
SetTextColor(hBitmapDC, BRANCHES_TEXT_SHADOW_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_FRAMENUM_X + 1, BRANCHES_BITMAP_FRAMENUM_Y + 1, (LPCSTR)framenum_string, DIGITS_IN_FRAMENUM);
SetTextColor(hBitmapDC, BRANCHES_TEXT_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_FRAMENUM_X, BRANCHES_BITMAP_FRAMENUM_Y, (LPCSTR)framenum_string, DIGITS_IN_FRAMENUM);
}
// time of item under cursor
if (bookmarks.item_under_mouse > ITEM_UNDER_MOUSE_NONE)
{
if (bookmarks.item_under_mouse == ITEM_UNDER_MOUSE_CLOUD)
{
// draw shadow of text
SetTextColor(hBitmapDC, BRANCHES_TEXT_SHADOW_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X + 1, BRANCHES_BITMAP_TIME_Y + 1, (LPCSTR)cloud_time, TIME_DESC_LENGTH-1);
SetTextColor(hBitmapDC, BRANCHES_TEXT_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X, BRANCHES_BITMAP_TIME_Y, (LPCSTR)cloud_time, TIME_DESC_LENGTH-1);
} else if (bookmarks.item_under_mouse < TOTAL_BOOKMARKS)
{
SetTextColor(hBitmapDC, BRANCHES_TEXT_SHADOW_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X + 1, BRANCHES_BITMAP_TIME_Y + 1, (LPCSTR)bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.description, TIME_DESC_LENGTH-1);
SetTextColor(hBitmapDC, BRANCHES_TEXT_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X, BRANCHES_BITMAP_TIME_Y, (LPCSTR)bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.description, TIME_DESC_LENGTH-1);
} else // fireball - current_pos_time
{
SetTextColor(hBitmapDC, BRANCHES_TEXT_SHADOW_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X + 1, BRANCHES_BITMAP_TIME_Y + 1, (LPCSTR)current_pos_time, TIME_DESC_LENGTH-1);
SetTextColor(hBitmapDC, BRANCHES_TEXT_COLOR);
TextOut(hBitmapDC, BRANCHES_BITMAP_TIME_X, BRANCHES_BITMAP_TIME_Y, (LPCSTR)current_pos_time, TIME_DESC_LENGTH-1);
}
}
// finished
must_redraw_branches_tree = false;
InvalidateRect(bookmarks.hwndBranchesBitmap, 0, FALSE);
}
// this is called by wndproc on WM_PAINT
void BRANCHES::PaintBranchesBitmap(HDC hdc)
{
int branch_x, branch_y;
// "bg"
BitBlt(hBufferDC, 0, 0, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_HEIGHT, hBitmapDC, 0, 0, SRCCOPY);
// "sprites"
// fireball
if (fireball_size)
{
branch_x = BranchCurrX[TOTAL_BOOKMARKS] - BRANCHES_FIREBALL_HALFWIDTH;
branch_y = BranchCurrY[TOTAL_BOOKMARKS] - BRANCHES_FIREBALL_HALFHEIGHT;
if (fireball_size >= BRANCHES_FIREBALL_MAX_SIZE)
{
TransparentBlt(hBufferDC, branch_x, branch_y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, hSpritesheetDC, animation_frame * BRANCHES_FIREBALL_WIDTH + BRANCHES_FIREBALL_SPRITESHEET_X, BRANCHES_FIREBALL_SPRITESHEET_Y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, 0x00FF00);
} else
{
TransparentBlt(hBufferDC, branch_x, branch_y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, hSpritesheetDC, BRANCHES_FIREBALL_SPRITESHEET_END_X - fireball_size * BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_SPRITESHEET_Y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, 0x00FF00);
}
}
// corners cursor
branch_x = (CursorX * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevX * transition_phase) / BRANCHES_TRANSITION_MAX;
branch_y = (CursorY * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevY * transition_phase) / BRANCHES_TRANSITION_MAX;
int current_corners_cursor_shift = BRANCHES_CORNER_BASE_SHIFT + corners_cursor_shift[animation_frame];
int corner_x, corner_y;
// upper left
corner_x = branch_x - current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH;
corner_y = branch_y - current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT;
TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER1_SPRITESHEET_X, BRANCHES_CORNER1_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00);
// upper right
corner_x = branch_x + current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH;
corner_y = branch_y - current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT;
TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER2_SPRITESHEET_X, BRANCHES_CORNER2_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00);
// lower left
corner_x = branch_x - current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH;
corner_y = branch_y + current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT;
TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER3_SPRITESHEET_X, BRANCHES_CORNER3_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00);
// lower right
corner_x = branch_x + current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH;
corner_y = branch_y + current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT;
TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER4_SPRITESHEET_X, BRANCHES_CORNER4_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00);
// finish - paste buffer bitmap to screen
BitBlt(hdc, 0, 0, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_HEIGHT, hBufferDC, 0, 0, SRCCOPY);
}
// ----------------------------------------------------------------------------------------
int BRANCHES::GetCurrentBranch()
{
return current_branch;
}
// this function finds best place for a new Bookmark in the Branches Tree
void BRANCHES::HandleBookmarkSet(int slot, char* slot_time)
{
if (slot != current_branch)
{
// inherit current branch, forget previous parent
int parent = parents[slot];
if (parent == ITEM_UNDER_MOUSE_CLOUD && slot_time[0])
{
// check if this was the only child of cloud parent, if so then set cloud time to the saved_time
int i = 0;
for (; i < TOTAL_BOOKMARKS; ++i)
{
if (bookmarks.bookmarks_array[i].not_empty && parents[i] == ITEM_UNDER_MOUSE_CLOUD && i != slot)
break;
}
if (i >= TOTAL_BOOKMARKS)
// didn't find another child of cloud, so after this slot disconnects, cloud will have 0 children
// it will mean that old cloud disappears and new cloud is formed where the slot was
strcpy(cloud_time, slot_time);
}
// before disconnecting from old parent, connect all childs to the old parent
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
{
if (bookmarks.bookmarks_array[i].not_empty && parents[i] == slot)
parents[i] = parent;
}
parents[slot] = current_branch;
}
// if parent is invalid (first_change < parent.jump_frame) then find better parent
int factor = 0;
// also if parent == cloud, then try to find better parent
int parent = parents[slot];
if (parent != ITEM_UNDER_MOUSE_CLOUD)
factor = bookmarks.bookmarks_array[slot].snapshot.findFirstChange(bookmarks.bookmarks_array[parent].snapshot);
if (parent == ITEM_UNDER_MOUSE_CLOUD || (factor >= 0 && factor < bookmarks.bookmarks_array[parent].snapshot.jump_frame))
{
// find highest frame of change
std::vector<int> DecisiveFactor(TOTAL_BOOKMARKS);
int best_branch = ITEM_UNDER_MOUSE_CLOUD;
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
{
if (i != slot && i != parent && bookmarks.bookmarks_array[i].not_empty && bookmarks.bookmarks_array[slot].snapshot.size >= bookmarks.bookmarks_array[i].snapshot.jump_frame)
{
factor = bookmarks.bookmarks_array[slot].snapshot.findFirstChange(bookmarks.bookmarks_array[i].snapshot);
if (factor < 0)
{
// this branch is identical to this slot
DecisiveFactor[i] = 2 * bookmarks.bookmarks_array[i].snapshot.size;
} else if (factor >= bookmarks.bookmarks_array[i].snapshot.jump_frame)
{
// hey, this branch could be our new parent...
DecisiveFactor[i] = 2 * factor;
} else
DecisiveFactor[i] = 0;
} else
{
DecisiveFactor[i] = 0;
}
}
// add +1 as a bonus to current parents and grandparents (a bit of nepotism here)
while (parent >= 0)
{
if (DecisiveFactor[parent])
DecisiveFactor[parent]++;
parent = parents[parent];
}
// find max
factor = 0;
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
{
if (DecisiveFactor[i] && DecisiveFactor[i] > factor)
{
factor = DecisiveFactor[i];
best_branch = i;
}
}
parent = parents[slot];
if (parent != best_branch)
{
// before disconnecting from old parent, connect all childs to the old parent
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
{
if (bookmarks.bookmarks_array[i].not_empty && parents[i] == slot)
parents[i] = parent;
}
// found new parent
parents[slot] = best_branch;
must_recalculate_branches_tree = true;
}
}
// switch current branch to this branch
if (slot != current_branch || changes_since_current_branch)
must_recalculate_branches_tree = true;
current_branch = slot;
changes_since_current_branch = false;
}
void BRANCHES::HandleBookmarkDeploy(int slot)
{
current_branch = slot;
changes_since_current_branch = false;
must_recalculate_branches_tree = true;
}
void BRANCHES::ChangesMadeSinceBranch()
{
bool prev_changes_since_current_branch = changes_since_current_branch;
changes_since_current_branch = true;
SetCurrentPosTime();
// recalculate branch tree if previous_changes = false
if (!prev_changes_since_current_branch)
must_recalculate_branches_tree = true;
else if (bookmarks.item_under_mouse == TOTAL_BOOKMARKS)
must_redraw_branches_tree = true; // to redraw fireball's time
}
void BRANCHES::FindItemUnderMouse(int mouse_x, int mouse_y)
{
int prev_item_under_mouse = bookmarks.item_under_mouse;
bookmarks.item_under_mouse = ITEM_UNDER_MOUSE_NONE;
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
if (bookmarks.item_under_mouse == ITEM_UNDER_MOUSE_NONE && mouse_x >= BranchCurrX[i] - DIGIT_RECT_HALFWIDTH_COLLISION && mouse_x < BranchCurrX[i] - DIGIT_RECT_HALFWIDTH_COLLISION + DIGIT_RECT_WIDTH_COLLISION && mouse_y >= BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT_COLLISION && mouse_y < BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT_COLLISION + DIGIT_RECT_HEIGHT_COLLISION)
bookmarks.item_under_mouse = i;
if (bookmarks.item_under_mouse == ITEM_UNDER_MOUSE_NONE && mouse_x >= cloud_x - BRANCHES_CLOUD_HALFWIDTH && mouse_x < cloud_x - BRANCHES_CLOUD_HALFWIDTH + BRANCHES_CLOUD_WIDTH && mouse_y >= BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT && mouse_y < BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT + BRANCHES_CLOUD_HEIGHT)
bookmarks.item_under_mouse = ITEM_UNDER_MOUSE_CLOUD;
if (bookmarks.item_under_mouse == ITEM_UNDER_MOUSE_NONE && changes_since_current_branch && mouse_x >= BranchCurrX[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFWIDTH_COLLISION && mouse_x < BranchCurrX[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFWIDTH_COLLISION + DIGIT_RECT_WIDTH_COLLISION && mouse_y >= BranchCurrY[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFHEIGHT_COLLISION && mouse_y < BranchCurrY[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFHEIGHT_COLLISION + DIGIT_RECT_HEIGHT_COLLISION)
bookmarks.item_under_mouse = TOTAL_BOOKMARKS;
if (prev_item_under_mouse != bookmarks.item_under_mouse)
must_redraw_branches_tree = true;
}
void BRANCHES::SetCurrentPosTime()
{
time_t raw_time;
time(&raw_time);
struct tm * timeinfo = localtime(&raw_time);
strftime(current_pos_time, TIME_DESC_LENGTH, "%H:%M:%S", timeinfo);
}
void BRANCHES::RecalculateBranchesTree()
{
// save previous values
for (int i = TOTAL_BOOKMARKS; i >= 0; i--)
{
BranchPrevX[i] = (BranchX[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevX[i] * transition_phase) / BRANCHES_TRANSITION_MAX;
BranchPrevY[i] = (BranchY[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevY[i] * transition_phase) / BRANCHES_TRANSITION_MAX;
}
CloudPrevX = (CloudX * (BRANCHES_TRANSITION_MAX - transition_phase) + CloudPrevX * transition_phase) / BRANCHES_TRANSITION_MAX;
CursorPrevX = (CursorX * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevX * transition_phase) / BRANCHES_TRANSITION_MAX;
CursorPrevY = (CursorY * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevY * transition_phase) / BRANCHES_TRANSITION_MAX;
transition_phase = BRANCHES_TRANSITION_MAX;
// 0. Prepare arrays
GridX.resize(0);
GridY.resize(0);
Children.resize(0);
GridHeight.resize(0);
GridX.resize(TOTAL_BOOKMARKS+1);
GridY.resize(TOTAL_BOOKMARKS+1);
Children.resize(TOTAL_BOOKMARKS+2); // 0th subvector is for cloud's children
GridHeight.resize(TOTAL_BOOKMARKS+1);
for (int i = TOTAL_BOOKMARKS; i >= 0; i--)
GridHeight[i] = 1;
// 1. Define GridX of branches (distribute to levels) and GridHeight of branches
int current_grid_x = 0;
std::vector<std::vector<int>> BranchesLevels;
std::vector<uint8> UndistributedBranches;
UndistributedBranches.resize(TOTAL_BOOKMARKS);
for (int i = UndistributedBranches.size()-1; i >= 0; i--)
UndistributedBranches[i] = i;
// remove all empty branches
for (int i = UndistributedBranches.size()-1; i >= 0; i--)
{
if (!bookmarks.bookmarks_array[UndistributedBranches[i]].not_empty)
UndistributedBranches.erase(UndistributedBranches.begin() + i);
}
// highest level: cloud (id = -1)
BranchesLevels.resize(current_grid_x+1);
BranchesLevels[current_grid_x].resize(1);
BranchesLevels[current_grid_x][0] = ITEM_UNDER_MOUSE_CLOUD;
// go lower until all branches are arranged to levels
int current_parent;
while(UndistributedBranches.size())
{
current_grid_x++;
BranchesLevels.resize(current_grid_x+1);
BranchesLevels[current_grid_x].resize(0);
for (int t = BranchesLevels[current_grid_x-1].size()-1; t >= 0; t--)
{
current_parent = BranchesLevels[current_grid_x-1][t];
for (int i = UndistributedBranches.size()-1; i >= 0; i--)
{
if (parents[UndistributedBranches[i]] == current_parent)
{
// assign this branch to current level
GridX[UndistributedBranches[i]] = current_grid_x;
BranchesLevels[current_grid_x].push_back(UndistributedBranches[i]);
// also add it to parent's Children array
Children[current_parent+1].push_back(UndistributedBranches[i]);
UndistributedBranches.erase(UndistributedBranches.begin() + i);
}
}
if (current_parent >= 0)
{
GridHeight[current_parent] = Children[current_parent+1].size();
if (Children[current_parent+1].size() > 1)
RecursiveAddHeight(parents[current_parent], GridHeight[current_parent] - 1);
else
GridHeight[current_parent] = 1; // its own height
}
}
}
if (changes_since_current_branch)
{
// also define "current_pos" GridX
if (current_branch >= 0)
{
if (Children[current_branch+1].size() < MAX_NUM_CHILDREN_ON_CANVAS_HEIGHT)
{
// "current_pos" becomes a child of current_branch
GridX[TOTAL_BOOKMARKS] = GridX[current_branch] + 1;
if ((int)BranchesLevels.size() <= GridX[TOTAL_BOOKMARKS])
BranchesLevels.resize(GridX[TOTAL_BOOKMARKS] + 1);
BranchesLevels[GridX[TOTAL_BOOKMARKS]].push_back(TOTAL_BOOKMARKS); // ID of "current_pos" = number of bookmarks
Children[current_branch+1].push_back(TOTAL_BOOKMARKS);
if (Children[current_branch+1].size() > 1)
RecursiveAddHeight(current_branch, 1);
} else
{
// special case 0: if there's too many children on one level (more than canvas can show)
// then "current_pos" becomes special branch above current_branch
GridX[TOTAL_BOOKMARKS] = GridX[current_branch];
GridY[TOTAL_BOOKMARKS] = GridY[current_branch] - 7;
}
} else
{
// special case 1: one and (presumably) only child of "cloud"
GridX[TOTAL_BOOKMARKS] = 1;
GridY[TOTAL_BOOKMARKS] = 0;
if ((int)BranchesLevels.size() <= GridX[TOTAL_BOOKMARKS])
BranchesLevels.resize(GridX[TOTAL_BOOKMARKS] + 1);
BranchesLevels[GridX[TOTAL_BOOKMARKS]].push_back(TOTAL_BOOKMARKS);
}
}
// define grid_width
int grid_width, cloud_prefix = 0;
if (BranchesLevels.size()-1 > 0)
{
grid_width = BRANCHES_CANVAS_WIDTH / (BranchesLevels.size()-1);
if (grid_width < BRANCHES_GRID_MIN_WIDTH)
grid_width = BRANCHES_GRID_MIN_WIDTH;
else if (grid_width > BRANCHES_GRID_MAX_WIDTH)
grid_width = BRANCHES_GRID_MAX_WIDTH;
} else grid_width = BRANCHES_GRID_MAX_WIDTH;
if (grid_width < MIN_CLOUD_LINE_LENGTH)
cloud_prefix = MIN_CLOUD_LINE_LENGTH - grid_width;
// 2. Define GridY of branches
RecursiveSetYPos(ITEM_UNDER_MOUSE_CLOUD, 0);
// define grid_halfheight
int grid_halfheight;
int totalHeight = 0;
for (int i = Children[0].size()-1; i >= 0; i--)
totalHeight += GridHeight[Children[0][i]];
if (totalHeight)
{
grid_halfheight = BRANCHES_CANVAS_HEIGHT / (2 * totalHeight);
if (grid_halfheight < BRANCHES_GRID_MIN_HALFHEIGHT)
grid_halfheight = BRANCHES_GRID_MIN_HALFHEIGHT;
else if (grid_halfheight > BRANCHES_GRID_MAX_HALFHEIGHT)
grid_halfheight = BRANCHES_GRID_MAX_HALFHEIGHT;
} else grid_halfheight = BRANCHES_GRID_MAX_HALFHEIGHT;
// special case 2: if chain of branches is too long, last item (normally it's fireball) goes up
if (changes_since_current_branch)
{
if (GridX[TOTAL_BOOKMARKS] > MAX_CHAIN_LEN)
{
GridX[TOTAL_BOOKMARKS] = MAX_CHAIN_LEN;
GridY[TOTAL_BOOKMARKS] -= 2;
}
}
// special case 3: if some branch crosses upper or lower border
int parent;
for (int t = TOTAL_BOOKMARKS; t >= 0; t--)
{
if (GridY[t] > MAX_GRID_Y_POS)
{
if (t < TOTAL_BOOKMARKS)
parent = parents[t];
else
parent = current_branch;
int pos = MAX_GRID_Y_POS;
for (int i = 0; i < (int)Children[parent+1].size(); ++i)
{
GridY[Children[parent+1][i]] = pos;
pos -= 2;
}
} else if (GridY[t] < -MAX_GRID_Y_POS)
{
if (t < TOTAL_BOOKMARKS)
parent = parents[t];
else
parent = current_branch;
int pos = -MAX_GRID_Y_POS;
for (int i = Children[parent+1].size()-1; i >= 0; i--)
{
GridY[Children[parent+1][i]] = pos;
pos += 2;
}
}
}
// special case 4: if cloud has all 10 children, then one child will be out of canvas
if (Children[0].size() == TOTAL_BOOKMARKS)
{
// find this child and move it to be visible
for (int t = TOTAL_BOOKMARKS - 1; t >= 0; t--)
{
if (GridY[t] > MAX_GRID_Y_POS)
{
GridY[t] = MAX_GRID_Y_POS;
GridX[t] -= 2;
// also move fireball to position near this branch
if (changes_since_current_branch && current_branch == t)
{
GridY[TOTAL_BOOKMARKS] = GridY[t];
GridX[TOTAL_BOOKMARKS] = GridX[t] + 1;
}
break;
} else if (GridY[t] < -MAX_GRID_Y_POS)
{
GridY[t] = -MAX_GRID_Y_POS;
GridX[t] -= 2;
// also move fireball to position near this branch
if (changes_since_current_branch && current_branch == t)
{
GridY[TOTAL_BOOKMARKS] = GridY[t];
GridX[TOTAL_BOOKMARKS] = GridX[t] + 1;
}
break;
}
}
}
// 3. Set pixel positions of branches
int max_x = 0;
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
{
if (bookmarks.bookmarks_array[i].not_empty)
{
BranchX[i] = cloud_prefix + GridX[i] * grid_width;
BranchY[i] = BRANCHES_CLOUD_Y + GridY[i] * grid_halfheight;
} else
{
BranchX[i] = EMPTY_BRANCHES_X;
BranchY[i] = EMPTY_BRANCHES_Y_BASE + EMPTY_BRANCHES_Y_FACTOR * ((i + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS);
}
if (max_x < BranchX[i]) max_x = BranchX[i];
}
if (changes_since_current_branch)
{
// also set pixel position of "current_pos"
BranchX[TOTAL_BOOKMARKS] = cloud_prefix + GridX[TOTAL_BOOKMARKS] * grid_width;
BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y + GridY[TOTAL_BOOKMARKS] * grid_halfheight;
} else if (current_branch >= 0)
{
BranchX[TOTAL_BOOKMARKS] = cloud_prefix + GridX[current_branch] * grid_width;
BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y + GridY[current_branch] * grid_halfheight;
} else
{
BranchX[TOTAL_BOOKMARKS] = 0;
BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y;
}
if (max_x < BranchX[TOTAL_BOOKMARKS]) max_x = BranchX[TOTAL_BOOKMARKS];
// align whole tree horizontally
CloudX = (BRANCHES_BITMAP_WIDTH + 1 - max_x) / 2;
if (CloudX < 0) CloudX = 0;
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
if (bookmarks.bookmarks_array[i].not_empty)
BranchX[i] += CloudX;
BranchX[TOTAL_BOOKMARKS] += CloudX;
// target cursor
CursorX = BranchX[TOTAL_BOOKMARKS];
CursorY = BranchY[TOTAL_BOOKMARKS];
// finished recalculating
must_recalculate_branches_tree = false;
must_redraw_branches_tree = true;
}
void BRANCHES::RecursiveAddHeight(int branch_num, int amount)
{
if (branch_num >= 0)
{
GridHeight[branch_num] += amount;
if (parents[branch_num] >= 0)
RecursiveAddHeight(parents[branch_num], amount);
}
}
void BRANCHES::RecursiveSetYPos(int parent, int parentY)
{
if (Children[parent+1].size())
{
// find total height of children
int totalHeight = 0;
for (int i = Children[parent+1].size()-1; i >= 0; i--)
totalHeight += GridHeight[Children[parent+1][i]];
// set Y of children and subchildren
for (int i = Children[parent+1].size()-1; i >= 0; i--)
{
int child_id = Children[parent+1][i];
GridY[child_id] = parentY + GridHeight[child_id] - totalHeight;
RecursiveSetYPos(child_id, GridY[child_id]);
parentY += 2 * GridHeight[child_id];
}
}
}
// ----------------------------------------------------------------------------------------
LRESULT APIENTRY BranchesBitmapWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
extern BRANCHES branches;
switch(msg)
{
case WM_MOUSEMOVE:
{
if (!bookmarks.mouse_over_bitmap)
{
bookmarks.mouse_over_bitmap = true;
bookmarks.tme.hwndTrack = hWnd;
TrackMouseEvent(&bookmarks.tme);
}
bookmarks.MouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
}
case WM_MOUSELEAVE:
{
bookmarks.mouse_over_bitmap = false;
bookmarks.MouseMove(-1, -1);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
branches.PaintBranchesBitmap(BeginPaint(hWnd, &ps));
EndPaint(hWnd, &ps);
return 0;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
return 0;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}
case WM_MOUSEWHEEL:
return SendMessage(piano_roll.hwndList, msg, wParam, lParam);
}
return CallWindowProc(hwndBranchesBitmap_oldWndProc, hWnd, msg, wParam, lParam);
}

View File

@ -0,0 +1,146 @@
// Specification file for Branches class
#define BRANCHES_ANIMATION_TICK 50 // animate at 20FPS
#define BRANCHES_TRANSITION_MAX 8
// branches bitmap
#define BRANCHES_BITMAP_WIDTH 170
#define BRANCHES_BITMAP_HEIGHT 145
#define BRANCHES_ANIMATION_FRAMES 12
#define BRANCHES_BITMAP_FRAMENUM_X 2
#define BRANCHES_BITMAP_FRAMENUM_Y 1
#define BRANCHES_BITMAP_TIME_X 2
#define BRANCHES_BITMAP_TIME_Y BRANCHES_BITMAP_HEIGHT - 17
#define BRANCHES_TEXT_SHADOW_COLOR 0xFFFFFF
#define BRANCHES_TEXT_COLOR 0x7F0000
// constants for drawing branches tree
#define BRANCHES_CANVAS_WIDTH 146
#define BRANCHES_CANVAS_HEIGHT 130
#define BRANCHES_CLOUD_X 14
#define BRANCHES_CLOUD_Y 72
#define BRANCHES_GRID_MIN_WIDTH 14
#define BRANCHES_GRID_MAX_WIDTH 30
#define MIN_CLOUD_LINE_LENGTH 19
#define BRANCHES_GRID_MIN_HALFHEIGHT 8
#define BRANCHES_GRID_MAX_HALFHEIGHT 12
#define EMPTY_BRANCHES_X -6
#define EMPTY_BRANCHES_Y_BASE 8
#define EMPTY_BRANCHES_Y_FACTOR 14
#define MAX_NUM_CHILDREN_ON_CANVAS_HEIGHT 9
#define MAX_CHAIN_LEN 10
#define MAX_GRID_Y_POS 8
// spritesheet
#define DIGIT_BITMAP_WIDTH 9
#define DIGIT_BITMAP_HALFWIDTH DIGIT_BITMAP_WIDTH/2
#define DIGIT_BITMAP_HEIGHT 13
#define DIGIT_BITMAP_HALFHEIGHT DIGIT_BITMAP_HEIGHT/2
#define BLUE_DIGITS_SPRITESHEET_DX DIGIT_BITMAP_WIDTH*TOTAL_BOOKMARKS
#define MOUSEOVER_DIGITS_SPRITESHEET_DY DIGIT_BITMAP_HEIGHT
#define DIGIT_RECT_WIDTH 11
#define DIGIT_RECT_WIDTH_COLLISION (DIGIT_RECT_WIDTH + 2)
#define DIGIT_RECT_HALFWIDTH DIGIT_RECT_WIDTH/2
#define DIGIT_RECT_HALFWIDTH_COLLISION (DIGIT_RECT_HALFWIDTH + 1)
#define DIGIT_RECT_HEIGHT 15
#define DIGIT_RECT_HEIGHT_COLLISION (DIGIT_RECT_HEIGHT + 2)
#define DIGIT_RECT_HALFHEIGHT DIGIT_RECT_HEIGHT/2
#define DIGIT_RECT_HALFHEIGHT_COLLISION (DIGIT_RECT_HALFHEIGHT + 1)
#define BRANCHES_CLOUD_WIDTH 26
#define BRANCHES_CLOUD_HALFWIDTH BRANCHES_CLOUD_WIDTH/2
#define BRANCHES_CLOUD_HEIGHT 15
#define BRANCHES_CLOUD_HALFHEIGHT BRANCHES_CLOUD_HEIGHT/2
#define BRANCHES_CLOUD_SPRITESHEET_X 180
#define BRANCHES_CLOUD_SPRITESHEET_Y 0
#define BRANCHES_FIREBALL_WIDTH 10
#define BRANCHES_FIREBALL_HALFWIDTH BRANCHES_FIREBALL_WIDTH/2
#define BRANCHES_FIREBALL_HEIGHT 10
#define BRANCHES_FIREBALL_HALFHEIGHT BRANCHES_FIREBALL_HEIGHT/2
#define BRANCHES_FIREBALL_SPRITESHEET_X 0
#define BRANCHES_FIREBALL_SPRITESHEET_Y 26
#define BRANCHES_FIREBALL_MAX_SIZE 5
#define BRANCHES_FIREBALL_SPRITESHEET_END_X 160
#define BRANCHES_CORNER_WIDTH 7
#define BRANCHES_CORNER_HALFWIDTH BRANCHES_CORNER_WIDTH/2
#define BRANCHES_CORNER_HEIGHT 7
#define BRANCHES_CORNER_HALFHEIGHT BRANCHES_CORNER_HEIGHT/2
#define BRANCHES_CORNER1_SPRITESHEET_X 206
#define BRANCHES_CORNER1_SPRITESHEET_Y 0
#define BRANCHES_CORNER2_SPRITESHEET_X 213
#define BRANCHES_CORNER2_SPRITESHEET_Y 0
#define BRANCHES_CORNER3_SPRITESHEET_X 206
#define BRANCHES_CORNER3_SPRITESHEET_Y 7
#define BRANCHES_CORNER4_SPRITESHEET_X 213
#define BRANCHES_CORNER4_SPRITESHEET_Y 7
#define BRANCHES_CORNER_BASE_SHIFT 6
class BRANCHES
{
public:
BRANCHES();
void init();
void free();
void reset();
void reset_vars();
void update();
void save(EMUFILE *os);
bool load(EMUFILE *is);
int GetCurrentBranch();
void RedrawBranchesTree();
void PaintBranchesBitmap(HDC hdc);
void HandleBookmarkSet(int slot, char* slot_time);
void HandleBookmarkDeploy(int slot);
void ChangesMadeSinceBranch();
void FindItemUnderMouse(int mouse_x, int mouse_y);
void RecalculateBranchesTree();
void RecursiveAddHeight(int branch_num, int amount);
void RecursiveSetYPos(int parent, int parentY);
// saved vars
std::vector<int> parents;
// not saved vars
bool must_redraw_branches_tree;
bool must_recalculate_branches_tree;
private:
void SetCurrentPosTime();
// also saved vars
int current_branch;
bool changes_since_current_branch;
char cloud_time[TIME_DESC_LENGTH];
char current_pos_time[TIME_DESC_LENGTH];
// not saved vars
int animation_frame;
int next_animation_time;
std::vector<int> BranchX; // in pixels
std::vector<int> BranchY;
std::vector<int> BranchPrevX;
std::vector<int> BranchPrevY;
std::vector<int> BranchCurrX;
std::vector<int> BranchCurrY;
int CloudX, CloudPrevX, cloud_x;
int CursorX, CursorPrevX, CursorY, CursorPrevY;
int transition_phase;
int fireball_size;
// GDI stuff
HBRUSH normal_brush;
RECT temp_rect;
HPEN normal_pen, select_pen;
HBITMAP branches_hbitmap, hOldBitmap, buffer_hbitmap, hOldBitmap1, branchesSpritesheet, hOldBitmap2;
HDC hBitmapDC, hBufferDC, hSpritesheetDC;
// temps
std::vector<int> GridX; // in grid units
std::vector<int> GridY;
std::vector<int> GridHeight;
std::vector<std::vector<uint8>> Children;
};

View File

@ -152,7 +152,7 @@ bool EDITOR::ReadString(EMUFILE *is, std::string& dest)
}
// ----------------------------------------------------------------------------------------------
// following functions use function parameters to determine range of frames
void EDITOR::InputToggle(int start, int end, int joy, int button)
void EDITOR::InputToggle(int start, int end, int joy, int button, int consecutive_tag)
{
if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return;
@ -173,16 +173,16 @@ void EDITOR::InputToggle(int start, int end, int joy, int button)
// clear range
for (int i = start; i <= end; ++i)
currMovieData.records[i].clearBit(joy, button);
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, start, end));
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, start, end, NULL, consecutive_tag));
} else
{
// set range
for (int i = start; i <= end; ++i)
currMovieData.records[i].setBit(joy, button);
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, start, end));
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, start, end, NULL, consecutive_tag));
}
}
void EDITOR::InputSetPattern(int start, int end, int joy, int button)
void EDITOR::InputSetPattern(int start, int end, int joy, int button, int consecutive_tag)
{
if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return;
@ -209,7 +209,7 @@ void EDITOR::InputSetPattern(int start, int end, int joy, int button)
if (pattern_offset >= (int)autofire_patterns[current_pattern].size())
pattern_offset -= autofire_patterns[current_pattern].size();
}
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_PATTERN, start, end, autofire_patterns_names[current_pattern].c_str()));
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_PATTERN, start, end, autofire_patterns_names[current_pattern].c_str(), consecutive_tag));
}
// following functions use current Selection to determine range of frames

View File

@ -9,8 +9,8 @@ public:
void reset();
void update();
void InputToggle(int start, int end, int joy, int button);
void InputSetPattern(int start, int end, int joy, int button);
void InputToggle(int start, int end, int joy, int button, int consecutive_tag = 0);
void InputSetPattern(int start, int end, int joy, int button, int consecutive_tag = 0);
bool FrameColumnSet();
bool FrameColumnSetPattern();

View File

@ -29,6 +29,7 @@ extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern BRANCHES branches;
extern PLAYBACK playback;
extern SELECTION selection;
extern GREENZONE greenzone;
@ -130,6 +131,8 @@ void HISTORY::reset()
inp.init(currMovieData, taseditor_config.enable_hot_changes);
strcat(inp.description, modCaptions[MODTYPE_INIT]);
inp.jump_frame = -1;
inp.start_frame = 0;
inp.end_frame = inp.size - 1;
AddSnapshotToHistory(inp);
UpdateHistoryList();
RedrawHistoryList();
@ -224,13 +227,13 @@ int HISTORY::jump(int new_pos)
{
snapshots[real_pos].toMovie(currMovieData, first_change);
selection.must_find_current_marker = playback.must_find_current_marker = true;
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
// and Piano Roll will be redrawn by greenzone invalidation
} else if (markers_changed)
{
markers_manager.update();
selection.must_find_current_marker = playback.must_find_current_marker = true;
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
piano_roll.RedrawList();
piano_roll.FollowUndo();
} else if (taseditor_config.enable_hot_changes)
@ -287,12 +290,11 @@ void HISTORY::AddSnapshotToHistory(SNAPSHOT &inp)
}
// returns frame of first actual change
int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comment)
int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comment, int consecutive_tag)
{
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = mod_type;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start, end);
@ -300,7 +302,8 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
{
// differences found
// fill description:
strcat(inp.description, modCaptions[mod_type]);
inp.mod_type = mod_type;
strcat(inp.description, modCaptions[inp.mod_type]);
switch (mod_type)
{
case MODTYPE_SET:
@ -323,53 +326,97 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
break;
}
}
// add upper and lower frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
strcat(inp.description, framenum);
if (end > start)
{
_itoa(end, framenum, 10);
strcat(inp.description, "-");
strcat(inp.description, framenum);
}
// add comment if there is one specified
if (comment)
inp.start_frame = start;
inp.end_frame = end;
inp.consecutive_tag = consecutive_tag;
if (consecutive_tag && taseditor_config.combine_consecutive && snapshots[real_pos].mod_type == inp.mod_type && snapshots[real_pos].consecutive_tag == inp.consecutive_tag)
{
// combine with previous snapshot
if (inp.jump_frame > snapshots[real_pos].jump_frame)
inp.jump_frame = snapshots[real_pos].jump_frame;
if (inp.start_frame > snapshots[real_pos].start_frame)
inp.start_frame = snapshots[real_pos].start_frame;
if (inp.end_frame < snapshots[real_pos].end_frame)
inp.end_frame = snapshots[real_pos].end_frame;
// add upper and lower frame to description
char framenum[11];
strcat(inp.description, " ");
strncat(inp.description, comment, SNAPSHOT_DESC_MAX_LENGTH - strlen(inp.description) - 1);
}
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
// inherit previous hotchanges and set new changes
switch (mod_type)
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
if (inp.end_frame > inp.start_frame)
{
case MODTYPE_DELETE:
inp.inheritHotChanges_DeleteSelection(&snapshots[real_pos]);
break;
case MODTYPE_INSERT:
case MODTYPE_CLONE:
inp.inheritHotChanges_InsertSelection(&snapshots[real_pos]);
break;
case MODTYPE_SET:
case MODTYPE_UNSET:
case MODTYPE_CLEAR:
case MODTYPE_CUT:
case MODTYPE_PASTE:
case MODTYPE_PATTERN:
inp.inheritHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], first_changes, end);
break;
case MODTYPE_TRUNCATE:
inp.copyHotChanges(&snapshots[real_pos]);
// do not add new hotchanges and do not fade old hotchanges, because there was nothing added
break;
strcat(inp.description, "-");
_itoa(inp.end_frame, framenum, 10);
strcat(inp.description, framenum);
}
// add comment if there is one specified
if (comment)
{
strcat(inp.description, " ");
strncat(inp.description, comment, SNAPSHOT_DESC_MAX_LENGTH - strlen(inp.description) - 1);
}
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
inp.copyHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], first_changes, end);
}
// replace current snapshot with this cloned snapshot and truncate history here
snapshots[real_pos] = inp;
history_total_items = history_cursor_pos+1;
UpdateHistoryList();
RedrawHistoryList();
} else
{
// don't combine
// add upper and lower frame to description
char framenum[11];
strcat(inp.description, " ");
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
if (inp.end_frame > inp.start_frame)
{
strcat(inp.description, "-");
_itoa(inp.end_frame, framenum, 10);
strcat(inp.description, framenum);
}
// add comment if there is one specified
if (comment)
{
strcat(inp.description, " ");
strncat(inp.description, comment, SNAPSHOT_DESC_MAX_LENGTH - strlen(inp.description) - 1);
}
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
// inherit previous hotchanges and set new changes
switch (mod_type)
{
case MODTYPE_DELETE:
inp.inheritHotChanges_DeleteSelection(&snapshots[real_pos]);
break;
case MODTYPE_INSERT:
case MODTYPE_CLONE:
inp.inheritHotChanges_InsertSelection(&snapshots[real_pos]);
break;
case MODTYPE_SET:
case MODTYPE_UNSET:
case MODTYPE_CLEAR:
case MODTYPE_CUT:
case MODTYPE_PASTE:
case MODTYPE_PATTERN:
inp.inheritHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], first_changes, end);
break;
case MODTYPE_TRUNCATE:
inp.copyHotChanges(&snapshots[real_pos]);
// do not add new hotchanges and do not fade old hotchanges, because there was nothing added
break;
}
}
AddSnapshotToHistory(inp);
}
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
}
return first_changes;
}
@ -378,7 +425,6 @@ int HISTORY::RegisterInsertNum(int start, int frames)
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_INSERTNUM;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start);
@ -386,21 +432,24 @@ int HISTORY::RegisterInsertNum(int start, int frames)
{
// differences found
// fill description:
inp.mod_type = MODTYPE_INSERTNUM;
strcat(inp.description, modCaptions[inp.mod_type]);
inp.jump_frame = start;
inp.start_frame = start;
inp.end_frame = start + frames - 1;
char framenum[11];
// add number of inserted frames to description
_itoa(frames, framenum, 10);
strcat(inp.description, framenum);
// add upper frame to description
_itoa(start, framenum, 10);
strcat(inp.description, " ");
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
inp.inheritHotChanges_InsertNum(&snapshots[real_pos], start, frames);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
}
return first_changes;
}
@ -409,7 +458,6 @@ int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_PASTEINSERT;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start);
@ -417,19 +465,22 @@ int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
{
// differences found
// fill description:
inp.mod_type = MODTYPE_PASTEINSERT;
strcat(inp.description, modCaptions[inp.mod_type]);
// for PasteInsert user prefers to see frame of attempted change (selection beginning), not frame of actual differences
inp.jump_frame = start;
inp.start_frame = start;
inp.end_frame = -1;
// add upper frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
inp.inheritHotChanges_PasteInsert(&snapshots[real_pos], inserted_set);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
}
return first_changes;
}
@ -438,16 +489,18 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = mod_type;
// fill description:
inp.mod_type = mod_type;
strcat(inp.description, modCaptions[mod_type]);
inp.jump_frame = start;
inp.start_frame = start;
inp.end_frame = end;
// add the frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
if (end > start || mod_type == MODTYPE_MARKER_DRAG || mod_type == MODTYPE_MARKER_SWAP)
if (inp.end_frame > inp.start_frame || mod_type == MODTYPE_MARKER_DRAG || mod_type == MODTYPE_MARKER_SWAP)
{
if (mod_type == MODTYPE_MARKER_DRAG)
strcat(inp.description, "=>");
@ -455,7 +508,7 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
strcat(inp.description, "<=>");
else
strcat(inp.description, "-");
_itoa(end, framenum, 10);
_itoa(inp.end_frame, framenum, 10);
strcat(inp.description, framenum);
}
// add comment if there is one specified
@ -468,7 +521,7 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
if (taseditor_config.enable_hot_changes)
inp.copyHotChanges(&GetCurrentSnapshot());
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
project.SetProjectChanged();
}
void HISTORY::RegisterBranching(int mod_type, int first_change, int slot)
@ -481,6 +534,8 @@ void HISTORY::RegisterBranching(int mod_type, int first_change, int slot)
strcat(inp.description, modCaptions[mod_type]);
strcat(inp.description, bookmarks.bookmarks_array[slot].snapshot.description);
inp.jump_frame = first_change;
inp.start_frame = first_change;
inp.end_frame = -1;
if (taseditor_config.enable_hot_changes)
{
if (mod_type < MODTYPE_BRANCH_MARKERS_0)
@ -509,18 +564,21 @@ void HISTORY::RegisterRecording(int frame_of_change)
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.fillJoypadsDiff(snapshots[real_pos], frame_of_change);
// fill description:
inp.mod_type = MODTYPE_RECORD;
strcat(inp.description, modCaptions[MODTYPE_RECORD]);
char framenum[11];
// check if current snapshot is also Recording and maybe it is consecutive recording
if (taseditor_config.combine_consecutive_rec
if (taseditor_config.combine_consecutive
&& snapshots[real_pos].mod_type == MODTYPE_RECORD // a) also Recording
&& snapshots[real_pos].rec_end_frame+1 == frame_of_change // b) consecutive
&& snapshots[real_pos].consecutive_tag == frame_of_change - 1 // b) consecutive (previous frame)
&& snapshots[real_pos].rec_joypad_diff_bits == inp.rec_joypad_diff_bits) // c) recorded same set of joysticks
{
// clone this snapshot and continue chain of recorded frames
inp.jump_frame = snapshots[real_pos].jump_frame;
inp.rec_end_frame = frame_of_change;
inp.start_frame = snapshots[real_pos].jump_frame;
inp.end_frame = frame_of_change;
inp.consecutive_tag = frame_of_change;
// add info which joypads were affected
int num = joysticks_per_frame[inp.input_type];
uint32 current_mask = 1;
@ -531,11 +589,11 @@ void HISTORY::RegisterRecording(int frame_of_change)
current_mask <<= 1;
}
// add upper and lower frame to description
_itoa(inp.jump_frame, framenum, 10);
strcat(inp.description, " ");
_itoa(inp.start_frame, framenum, 10);
strcat(inp.description, framenum);
_itoa(frame_of_change, framenum, 10);
strcat(inp.description, "-");
_itoa(inp.end_frame, framenum, 10);
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
@ -551,7 +609,7 @@ void HISTORY::RegisterRecording(int frame_of_change)
} else
{
// not consecutive - add new snapshot to history
inp.jump_frame = inp.rec_end_frame = frame_of_change;
inp.jump_frame = inp.start_frame = inp.end_frame = inp.consecutive_tag = frame_of_change;
// add info which joypads were affected
int num = joysticks_per_frame[inp.input_type];
uint32 current_mask = 1;
@ -562,8 +620,8 @@ void HISTORY::RegisterRecording(int frame_of_change)
current_mask <<= 1;
}
// add upper frame to description
_itoa(frame_of_change, framenum, 10);
strcat(inp.description, " ");
_itoa(frame_of_change, framenum, 10);
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
@ -573,7 +631,7 @@ void HISTORY::RegisterRecording(int frame_of_change)
}
AddSnapshotToHistory(inp);
}
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
}
void HISTORY::RegisterImport(MovieData& md, char* filename)
{
@ -586,9 +644,11 @@ void HISTORY::RegisterImport(MovieData& md, char* filename)
if (first_changes >= 0)
{
// differences found
inp.mod_type = MODTYPE_IMPORT;
inp.jump_frame = first_changes;
inp.start_frame = 0;
inp.end_frame = inp.size - 1;
// fill description:
inp.mod_type = MODTYPE_IMPORT;
strcat(inp.description, modCaptions[inp.mod_type]);
// add filename to description
strcat(inp.description, " ");
@ -601,7 +661,7 @@ void HISTORY::RegisterImport(MovieData& md, char* filename)
AddSnapshotToHistory(inp);
inp.toMovie(currMovieData);
piano_roll.UpdateItemCount();
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
project.SetProjectChanged();
greenzone.InvalidateAndCheck(first_changes);
} else
@ -614,7 +674,6 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_LUA_CHANGE;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start);
@ -622,6 +681,7 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
{
// differences found
// fill description:
inp.mod_type = MODTYPE_LUA_CHANGE;
if (name[0])
{
// user provided custom name of operation
@ -633,10 +693,12 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
strcat(inp.description, modCaptions[inp.mod_type]);
}
inp.jump_frame = first_changes;
inp.start_frame = start;
inp.end_frame = -1;
// add upper frame to description
char framenum[11];
_itoa(first_changes, framenum, 10);
strcat(inp.description, " ");
_itoa(first_changes, framenum, 10);
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
@ -669,7 +731,7 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
}
}
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
branches.ChangesMadeSinceBranch();
}
return first_changes;
}

View File

@ -79,7 +79,7 @@ public:
void undo();
void redo();
int RegisterChanges(int mod_type, int start = 0, int end =-1, const char* comment = 0);
int RegisterChanges(int mod_type, int start = 0, int end =-1, const char* comment = NULL, int consecutive_tag = 0);
int RegisterInsertNum(int start, int frames);
int RegisterPasteInsert(int start, SelectionFrames& inserted_set);
void RegisterMarkersChange(int mod_type, int start = 0, int end =-1, const char* comment = 0);

View File

@ -550,7 +550,8 @@ void PIANO_ROLL::update()
int row_index, column_index, joy, bit;
int min_row_index = currMovieData.getNumRecords(), max_row_index = -1;
bool changes_made = false;
for (double len = 0; len < total_len; len += DRAWING_MIN_LINE_LEN)
int drawing_min_line_len = list_row_height; // = min(list_row_width, list_row_height) in pixels
for (double len = 0; len < total_len; len += drawing_min_line_len)
{
// perform hit test
info.pt.x = p.x + (len / total_len) * total_dx;
@ -580,9 +581,9 @@ void PIANO_ROLL::update()
if (changes_made)
{
if (drag_mode == DRAG_MODE_SET)
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, min_row_index, max_row_index));
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, min_row_index, max_row_index, NULL, drawing_start_time));
else
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, min_row_index, max_row_index));
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, min_row_index, max_row_index, NULL, drawing_start_time));
}
drawing_last_x = drawing_current_x;
drawing_last_y = drawing_current_y;
@ -1301,34 +1302,34 @@ LONG PIANO_ROLL::HeaderCustomDraw(NMLVCUSTOMDRAW* msg)
// ----------------------------------------------------
void PIANO_ROLL::RightClick(LVHITTESTINFO& info)
{
SelectionFrames* current_selection = selection.MakeStrobe();
if (current_selection->size() == 0)
return;
HMENU sub = GetSubMenu(hrmenu, 0);
// inspect current selection and disable inappropriate menu items
SelectionFrames::iterator current_selection_begin(current_selection->begin());
SelectionFrames::iterator current_selection_end(current_selection->end());
bool set_found = false, unset_found = false;
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
if (selection.CheckFrameSelected(info.iItem))
{
if(markers_manager.GetMarker(*it))
set_found = true;
else
unset_found = true;
}
if (set_found)
EnableMenuItem(sub, ID_SELECTED_REMOVEMARKER, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(sub, ID_SELECTED_REMOVEMARKER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
if (unset_found)
EnableMenuItem(sub, ID_SELECTED_SETMARKER, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(sub, ID_SELECTED_SETMARKER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
SelectionFrames* current_selection = selection.MakeStrobe();
HMENU sub = GetSubMenu(hrmenu, 0);
// inspect current selection and disable inappropriate menu items
SelectionFrames::iterator current_selection_begin(current_selection->begin());
SelectionFrames::iterator current_selection_end(current_selection->end());
bool set_found = false, unset_found = false;
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
{
if(markers_manager.GetMarker(*it))
set_found = true;
else
unset_found = true;
}
if (set_found)
EnableMenuItem(sub, ID_SELECTED_REMOVEMARKER, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(sub, ID_SELECTED_REMOVEMARKER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
if (unset_found)
EnableMenuItem(sub, ID_SELECTED_SETMARKER, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(sub, ID_SELECTED_SETMARKER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
POINT pt = info.pt;
ClientToScreen(hwndList, &pt);
TrackPopupMenu(sub, 0, pt.x, pt.y, 0, taseditor_window.hwndTasEditor, 0);
POINT pt = info.pt;
ClientToScreen(hwndList, &pt);
TrackPopupMenu(sub, 0, pt.x, pt.y, 0, taseditor_window.hwndTasEditor, 0);
}
}
// -------------------------------------------------------------------------
LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
@ -1510,12 +1511,13 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
}
// toggle input
piano_roll.drawing_start_time = clock();
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
if (alt_pressed)
editor.InputSetPattern(piano_roll.row_last_clicked, row_index, joy, button);
editor.InputSetPattern(piano_roll.row_last_clicked, row_index, joy, button, piano_roll.drawing_start_time);
else
editor.InputToggle(piano_roll.row_last_clicked, row_index, joy, button);
editor.InputToggle(piano_roll.row_last_clicked, row_index, joy, button, piano_roll.drawing_start_time);
// and start dragging/drawing
if (piano_roll.drag_mode == DRAG_MODE_NONE)
{

View File

@ -26,8 +26,6 @@
#define MARKER_DRAG_MAX_SPEED 70
#define MARKER_DRAG_GRAVITY 2
#define DRAWING_MIN_LINE_LEN 14 // = min(list_row_width, list_row_height) in pixels
#define DRAG_SCROLLING_BORDER_SIZE 10 // in pixels
#define DOUBLETAP_COUNT 3 // 1:quick press, 2 - quick release, 3 - quick press
@ -194,6 +192,7 @@ public:
int marker_drag_countdown;
int marker_drag_framenum;
int drawing_last_x, drawing_last_y;
int drawing_start_time;
int drag_selection_starting_frame;
int drag_selection_ending_frame;

View File

@ -9,8 +9,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
------------------------------------------------------------------------------------
Snapshot - Snapshot of all edited data
* stores the data of specific snapshot of the movie: size, input data (commands and joysticks), Markers at the moment of creating the snapshot, keyframe, type and description of the snapshot (including the time of creation)
* also stores info about sequential recording of input
* stores the data of specific snapshot of the movie: size, input data (commands and joysticks), Markers at the moment of creating the snapshot, keyframe, start and end frame of operation, type of operation and description of the snapshot (including the time of creation)
* also stores info about sequential recording/drawing of input
* optionally can store map of Hot Changes
* implements snapshot creation: copying input, copying Hot Changes, copying Markers, setting time of creation
* implements full/partial restoring of data from snapshot: input, Hot Changes, Markers
@ -189,7 +189,9 @@ void SNAPSHOT::save(EMUFILE *os)
write32le(size, os);
write8le(input_type, os);
write32le(jump_frame, os);
write32le(rec_end_frame, os);
write32le(start_frame, os);
write32le(end_frame, os);
write32le(consecutive_tag, os);
write32le(rec_joypad_diff_bits, os);
write32le(mod_type, os);
if (has_hot_changes) write8le((uint8)1, os); else write8le((uint8)0, os);
@ -224,7 +226,9 @@ bool SNAPSHOT::load(EMUFILE *is)
if (!read8le(&tmp, is)) return true;
input_type = tmp;
if (!read32le(&jump_frame, is)) return true;
if (!read32le(&rec_end_frame, is)) return true;
if (!read32le(&start_frame, is)) return true;
if (!read32le(&end_frame, is)) return true;
if (!read32le(&consecutive_tag, is)) return true;
if (!read32le(&rec_joypad_diff_bits, is)) return true;
if (!read32le(&mod_type, is)) return true;
if (!read8le(&tmp, is)) return true;
@ -283,7 +287,9 @@ bool SNAPSHOT::skipLoad(EMUFILE *is)
if (is->fseek(sizeof(int) + // size
sizeof(uint8) + // input_type
sizeof(int) + // jump_frame
sizeof(int) + // rec_end_frame
sizeof(int) + // start_frame
sizeof(int) + // end_frame
sizeof(int) + // consecutive_tag
sizeof(int) + // rec_joypad_diff_bits
sizeof(int) + // mod_type
sizeof(uint8) // has_hot_changes

View File

@ -64,7 +64,11 @@ public:
std::vector<uint8> commands; // Format: commands-for-frame0, commands-for-frame1, ...
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
int jump_frame; // for jumping when making undo
int rec_end_frame; // for consecutive Recordings
int start_frame; // for consecutive Draws
int end_frame; // for consecutive Draws
int consecutive_tag; // for consecutive Recordings and Draws
uint32 rec_joypad_diff_bits; // for consecutive Recordings
int mod_type;
char description[SNAPSHOT_DESC_MAX_LENGTH];

View File

@ -44,7 +44,7 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG()
follow_note_context = true;
bind_markers = true;
empty_marker_notes = true;
combine_consecutive_rec = false;
combine_consecutive = false;
use_1p_rec = true;
columnset_by_keys = false;
superimpose = 0; // SUPERIMPOSE_UNCHECKED

View File

@ -42,7 +42,7 @@ public:
bool follow_note_context;
bool bind_markers;
bool empty_marker_notes;
bool combine_consecutive_rec;
bool combine_consecutive;
bool use_1p_rec;
bool columnset_by_keys;
int superimpose;

View File

@ -23,6 +23,7 @@ extern TASEDITOR_WINDOW taseditor_window;
extern HISTORY history;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern BRANCHES branches;
extern RECORDER recorder;
extern PLAYBACK playback;
extern GREENZONE greenzone;
@ -191,7 +192,7 @@ void TASEDITOR_LUA::setnote(int index, const char* newtext)
int TASEDITOR_LUA::getcurrentbranch()
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
return bookmarks.GetCurrentBranch();
return branches.GetCurrentBranch();
else
return -1;
}

View File

@ -13,6 +13,7 @@
#include "recorder.h"
#include "greenzone.h"
#include "bookmarks.h"
#include "branches.h"
#include "piano_roll.h"
#include "taseditor_lua.h"
#include "splicer.h"

View File

@ -437,7 +437,7 @@ void TASEDITOR_WINDOW::UpdateCheckedItems()
CheckMenuItem(hmenu, ID_CONFIG_HUDINBRANCHSCREENSHOTS, taseditor_config.branch_scr_hud?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_BINDMARKERSTOINPUT, taseditor_config.bind_markers?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_EMPTYNEWMARKERNOTES, taseditor_config.empty_marker_notes?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_COMBINECONSECUTIVERECORDINGS, taseditor_config.combine_consecutive_rec?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_COMBINECONSECUTIVERECORDINGS, taseditor_config.combine_consecutive?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_USE1PFORRECORDING, taseditor_config.use_1p_rec?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_USEINPUTKEYSFORCOLUMNSET, taseditor_config.columnset_by_keys?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE, taseditor_config.superimpose_affects_paste?MF_CHECKED : MF_UNCHECKED);
@ -1032,7 +1032,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_COMBINECONSECUTIVERECORDINGS:
taseditor_config.combine_consecutive_rec ^= 1;
taseditor_config.combine_consecutive ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_USE1PFORRECORDING:

View File

@ -876,7 +876,7 @@ static void CommandStateSave(void)
{
#ifdef WIN32
if (execcmd == EMUCMD_SAVE_STATE)
bookmarks.command(COMMAND_SET, bookmarks.GetCurrentBranch());
bookmarks.command(COMMAND_SET);
else if(execcmd >= EMUCMD_SAVE_STATE_SLOT_0 && execcmd <= EMUCMD_SAVE_STATE_SLOT_9)
bookmarks.command(COMMAND_SET, execcmd - EMUCMD_SAVE_STATE_SLOT_0);
#endif
@ -900,7 +900,7 @@ static void CommandStateLoad(void)
{
#ifdef WIN32
if (execcmd == EMUCMD_LOAD_STATE)
bookmarks.command(COMMAND_DEPLOY, bookmarks.GetCurrentBranch());
bookmarks.command(COMMAND_DEPLOY);
else if(execcmd >= EMUCMD_LOAD_STATE_SLOT_0 && execcmd <= EMUCMD_LOAD_STATE_SLOT_9)
bookmarks.command(COMMAND_DEPLOY, execcmd - EMUCMD_LOAD_STATE_SLOT_0);
#endif

View File

@ -422,6 +422,7 @@
<ClCompile Include="..\src\drivers\win\taseditor.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\bookmark.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\bookmarks.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\branches.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\editor.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\greenzone.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\history.cpp" />
@ -749,6 +750,7 @@
<ClInclude Include="..\src\drivers\win\taseditor.h" />
<ClInclude Include="..\src\drivers\win\taseditor\bookmark.h" />
<ClInclude Include="..\src\drivers\win\taseditor\bookmarks.h" />
<ClInclude Include="..\src\drivers\win\taseditor\branches.h" />
<ClInclude Include="..\src\drivers\win\taseditor\editor.h" />
<ClInclude Include="..\src\drivers\win\taseditor\greenzone.h" />
<ClInclude Include="..\src\drivers\win\taseditor\history.h" />

View File

@ -958,6 +958,9 @@
<ClCompile Include="..\src\drivers\win\taseditor\editor.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\branches.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\cart.h">
@ -1408,9 +1411,6 @@
<ClInclude Include="..\src\drivers\win\taseditor\taseditor_window.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\popup_display.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\recorder.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
@ -1450,6 +1450,12 @@
<ClInclude Include="..\src\drivers\win\taseditor\editor.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\branches.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\popup_display.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\src\drivers\win\res.rc">