This commit is contained in:
Smie 2016-11-26 13:32:23 -07:00
commit a65eeee2e0
5 changed files with 72 additions and 14 deletions

View File

@ -1,8 +1,8 @@
(function () { (function () {
var ns = $.namespace('pskl.model.frame'); var ns = $.namespace('pskl.model.frame');
// 10 * 60 * 1000 = 10 minutes // Maximum number of cache entries
var DEFAULT_CLEAR_INTERVAL = 10 * 60 * 1000; var MAX_CACHE_ENTRIES = 100;
var DEFAULT_FRAME_PROCESSOR = function (frame) { var DEFAULT_FRAME_PROCESSOR = function (frame) {
return pskl.utils.FrameUtils.toImage(frame); return pskl.utils.FrameUtils.toImage(frame);
@ -12,14 +12,16 @@
var DEFAULT_NAMESPACE = '__cache_default__'; var DEFAULT_NAMESPACE = '__cache_default__';
ns.CachedFrameProcessor = function (cacheResetInterval) { ns.CachedFrameProcessor = function () {
// Cache object.
this.cache_ = {}; this.cache_ = {};
this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL;
// Array of [namespace, key] for each cached frame.
this.cacheQueue_ = [];
this.frameProcessor = DEFAULT_FRAME_PROCESSOR; this.frameProcessor = DEFAULT_FRAME_PROCESSOR;
this.outputCloner = DEFAULT_OUTPUT_CLONER; this.outputCloner = DEFAULT_OUTPUT_CLONER;
this.defaultNamespace = DEFAULT_NAMESPACE; this.defaultNamespace = DEFAULT_NAMESPACE;
window.setInterval(this.clear.bind(this), this.cacheResetInterval);
}; };
ns.CachedFrameProcessor.prototype.clear = function () { ns.CachedFrameProcessor.prototype.clear = function () {
@ -69,6 +71,11 @@
} else { } else {
processedFrame = this.frameProcessor(frame); processedFrame = this.frameProcessor(frame);
cache[cacheKey] = processedFrame; cache[cacheKey] = processedFrame;
this.cacheQueue_.unshift([namespace, cacheKey]);
if (this.cacheQueue_.length > MAX_CACHE_ENTRIES) {
var oldestItem = this.cacheQueue_.pop();
this.cache_[oldestItem[0]][oldestItem[1]] = null;
}
} }
return processedFrame; return processedFrame;

View File

@ -10,11 +10,16 @@
this.cachedFrameProcessor = new pskl.model.frame.AsyncCachedFrameProcessor(); this.cachedFrameProcessor = new pskl.model.frame.AsyncCachedFrameProcessor();
this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this));
this.throttledUpdateCurrentColors_ = pskl.utils.FunctionUtils.throttle(
this.updateCurrentColors_.bind(this),
1000
);
this.paletteService = pskl.app.paletteService; this.paletteService = pskl.app.paletteService;
}; };
ns.CurrentColorsService.prototype.init = function () { ns.CurrentColorsService.prototype.init = function () {
$.subscribe(Events.HISTORY_STATE_SAVED, this.updateCurrentColors_.bind(this)); $.subscribe(Events.HISTORY_STATE_SAVED, this.throttledUpdateCurrentColors_);
$.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this)); $.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this));
}; };

View File

@ -24,6 +24,9 @@
// Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming) // Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming)
ns.HistoryService.LOAD_STATE_INTERVAL = 50; ns.HistoryService.LOAD_STATE_INTERVAL = 50;
// Maximum number of states that can be recorded.
ns.HistoryService.MAX_SAVED_STATES = 500;
ns.HistoryService.prototype.init = function () { ns.HistoryService.prototype.init = function () {
$.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this));
@ -58,6 +61,13 @@
state.piskel = this.serializer.serialize(piskel); state.piskel = this.serializer.serialize(piskel);
} }
// If the new state pushes over MAX_SAVED_STATES, erase all states between the first and
// second snapshot states.
if (this.stateQueue.length > ns.HistoryService.MAX_SAVED_STATES) {
var firstSnapshotIndex = this.getNextSnapshotIndex_(1);
this.stateQueue.splice(0, firstSnapshotIndex);
this.currentIndex = this.currentIndex - firstSnapshotIndex;
}
this.stateQueue.push(state); this.stateQueue.push(state);
$.publish(Events.HISTORY_STATE_SAVED); $.publish(Events.HISTORY_STATE_SAVED);
}; };
@ -92,6 +102,13 @@
return index; return index;
}; };
ns.HistoryService.prototype.getNextSnapshotIndex_ = function (index) {
while (this.stateQueue[index] && !this.stateQueue[index].piskel) {
index = index + 1;
}
return index;
};
ns.HistoryService.prototype.loadState = function (index) { ns.HistoryService.prototype.loadState = function (index) {
try { try {
if (this.isLoadStateAllowed_(index)) { if (this.isLoadStateAllowed_(index)) {

View File

@ -2,6 +2,9 @@
var ns = $.namespace('pskl.utils'); var ns = $.namespace('pskl.utils');
ns.FunctionUtils = { ns.FunctionUtils = {
/**
* Returns a memoized version of the provided function.
*/
memo : function (fn, cache, scope) { memo : function (fn, cache, scope) {
var memoized = function () { var memoized = function () {
var key = Array.prototype.join.call(arguments, '-'); var key = Array.prototype.join.call(arguments, '-');
@ -11,6 +14,27 @@
return cache[key]; return cache[key];
}; };
return memoized; return memoized;
},
/**
* Returns a throttled version of the provided method, that will be called at most
* every X milliseconds, where X is the provided interval.
*/
throttle : function (fn, interval) {
var last, timer;
return function () {
var now = Date.now();
if (last && now < last + interval) {
clearTimeout(timer);
timer = setTimeout(function () {
last = now;
fn();
}, interval);
} else {
last = now;
fn();
}
};
} }
}; };
})(); })();

View File

@ -11,25 +11,30 @@
* @param {Function} onError NOT USED YET * @param {Function} onError NOT USED YET
*/ */
loadFromFile : function (file, onSuccess, onError) { loadFromFile : function (file, onSuccess, onError) {
pskl.utils.FileUtils.readFileAsArrayBuffer(file, function (content) { pskl.utils.FileUtils.readFile(file, function (content) {
var rawPiskel = pskl.utils.Base64.toText(content);
ns.PiskelFileUtils.decodePiskelFile( ns.PiskelFileUtils.decodePiskelFile(
content, rawPiskel,
function (piskel, extra) { function (piskel, descriptor, fps) {
// if using Node-Webkit, store the savePath on load // if using Node-Webkit, store the savePath on load
// Note: the 'path' property is unique to Node-Webkit, and holds the full path // Note: the 'path' property is unique to Node-Webkit, and holds the full path
if (pskl.utils.Environment.detectNodeWebkit()) { if (pskl.utils.Environment.detectNodeWebkit()) {
piskel.savePath = file.path; piskel.savePath = file.path;
} }
onSuccess(piskel, extra); onSuccess(piskel, descriptor, fps);
}, },
onError onError
); );
}); });
}, },
decodePiskelFile : function (serializedPiskel, onSuccess, onError) { decodePiskelFile : function (rawPiskel, onSuccess, onError) {
pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel, extra) { var serializedPiskel = JSON.parse(rawPiskel);
onSuccess(piskel, extra); var fps = serializedPiskel.piskel.fps;
var piskel = serializedPiskel.piskel;
var descriptor = new pskl.model.piskel.Descriptor(piskel.name, piskel.description, true);
pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) {
onSuccess(piskel, descriptor, fps);
}); });
} }
}; };