diff --git a/hpc_index.html b/hpc_index.html index beca84b..e1f9a65 100644 --- a/hpc_index.html +++ b/hpc_index.html @@ -98,7 +98,7 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 15%2/13
0%0/17
11%52/443
  module reanimate-0.4.2.0-inplace/Reanimate.Render -5%1/19
0%0/50
4%39/826
+5%1/19
0%0/53
4%39/852
  module reanimate-0.4.2.0-inplace/Reanimate.Scene 30%40/130
60%15/25
36%545/1483
@@ -125,5 +125,5 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 100%6/6
50%1/2
95%43/45
  Program Coverage Total -31%248/798
16%131/815
30%4682/15530
+31%248/798
16%131/818
30%4682/15556
diff --git a/hpc_index_alt.html b/hpc_index_alt.html index 5a491da..d0a9ab0 100644 --- a/hpc_index_alt.html +++ b/hpc_index_alt.html @@ -98,7 +98,7 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 15%2/13
0%0/17
11%52/443
  module reanimate-0.4.2.0-inplace/Reanimate.Render -5%1/19
0%0/50
4%39/826
+5%1/19
0%0/53
4%39/852
  module reanimate-0.4.2.0-inplace/Reanimate.Svg.Unuse 33%1/3
0%0/14
21%28/128
@@ -125,5 +125,5 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 15%3/20
- 0/0 14%7/49
  Program Coverage Total -31%248/798
16%131/815
30%4682/15530
+31%248/798
16%131/818
30%4682/15556
diff --git a/hpc_index_exp.html b/hpc_index_exp.html index eb62d04..6520ec9 100644 --- a/hpc_index_exp.html +++ b/hpc_index_exp.html @@ -86,7 +86,7 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 33%4/12
11%1/9
7%12/167
  module reanimate-0.4.2.0-inplace/Reanimate.Render -5%1/19
0%0/50
4%39/826
+5%1/19
0%0/53
4%39/852
  module reanimate-0.4.2.0-inplace/Reanimate.Driver 8%1/12
1%1/55
3%9/246
@@ -125,5 +125,5 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 0%0/1
0%0/4
0%0/61
  Program Coverage Total -31%248/798
16%131/815
30%4682/15530
+31%248/798
16%131/818
30%4682/15556
diff --git a/hpc_index_fun.html b/hpc_index_fun.html index e515911..f9470c6 100644 --- a/hpc_index_fun.html +++ b/hpc_index_fun.html @@ -92,7 +92,7 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 8%7/82
5%4/79
2%58/2494
  module reanimate-0.4.2.0-inplace/Reanimate.Render -5%1/19
0%0/50
4%39/826
+5%1/19
0%0/53
4%39/852
  module reanimate-0.4.2.0-inplace/Reanimate.Cache 0%0/8
0%0/12
0%0/160
@@ -125,5 +125,5 @@ table.dashboard { border-collapse: collapse ; border: solid 1px black } 0%0/1
0%0/4
0%0/61
  Program Coverage Total -31%248/798
16%131/815
30%4682/15530
+31%248/798
16%131/818
30%4682/15556
diff --git a/playground/elm.js b/playground/elm.js index ce6fc1d..9eff070 100644 --- a/playground/elm.js +++ b/playground/elm.js @@ -784,11 +784,11 @@ function _Debug_crash_UNUSED(identifier, fact1, fact2, fact3, fact4) function _Debug_regionToString(region) { - if (region.O.E === region.T.E) + if (region.P.E === region.U.E) { - return 'on line ' + region.O.E; + return 'on line ' + region.P.E; } - return 'on lines ' + region.O.E + ' through ' + region.T.E; + return 'on lines ' + region.P.E + ' through ' + region.U.E; } @@ -1857,9 +1857,9 @@ var _Platform_worker = F4(function(impl, flagDecoder, debugMetadata, args) return _Platform_initialize( flagDecoder, args, - impl.aD, - impl.aL, - impl.aJ, + impl.aE, + impl.aM, + impl.aK, function() { return function() {} } ); }); @@ -2705,8 +2705,8 @@ var _VirtualDom_mapEventRecord = F2(function(func, record) { return { p: func(record.p), - P: record.P, - M: record.M + Q: record.Q, + N: record.N } }); @@ -2975,10 +2975,10 @@ function _VirtualDom_makeCallback(eventNode, initialHandler) var value = result.a; var message = !tag ? value : tag < 3 ? value.a : value.p; - var stopPropagation = tag == 1 ? value.b : tag == 3 && value.P; + var stopPropagation = tag == 1 ? value.b : tag == 3 && value.Q; var currentEventNode = ( stopPropagation && event.stopPropagation(), - (tag == 2 ? value.b : tag == 3 && value.M) && event.preventDefault(), + (tag == 2 ? value.b : tag == 3 && value.N) && event.preventDefault(), eventNode ); var tagger; @@ -3928,11 +3928,11 @@ var _Browser_element = _Debugger_element || F4(function(impl, flagDecoder, debug return _Platform_initialize( flagDecoder, args, - impl.aD, - impl.aL, - impl.aJ, + impl.aE, + impl.aM, + impl.aK, function(sendToApp, initialModel) { - var view = impl.aM; + var view = impl.aN; /**/ var domNode = args['node']; //*/ @@ -3964,12 +3964,12 @@ var _Browser_document = _Debugger_document || F4(function(impl, flagDecoder, deb return _Platform_initialize( flagDecoder, args, - impl.aD, - impl.aL, - impl.aJ, + impl.aE, + impl.aM, + impl.aK, function(sendToApp, initialModel) { - var divertHrefToApp = impl.N && impl.N(sendToApp) - var view = impl.aM; + var divertHrefToApp = impl.O && impl.O(sendToApp) + var view = impl.aN; var title = _VirtualDom_doc.title; var bodyNode = _VirtualDom_doc.body; var currNode = _VirtualDom_virtualize(bodyNode); @@ -3977,12 +3977,12 @@ var _Browser_document = _Debugger_document || F4(function(impl, flagDecoder, deb { _VirtualDom_divertHrefToApp = divertHrefToApp; var doc = view(model); - var nextNode = _VirtualDom_node('body')(_List_Nil)(doc.at); + var nextNode = _VirtualDom_node('body')(_List_Nil)(doc.au); var patches = _VirtualDom_diff(currNode, nextNode); bodyNode = _VirtualDom_applyPatches(bodyNode, currNode, patches, sendToApp); currNode = nextNode; _VirtualDom_divertHrefToApp = 0; - (title !== doc.aK) && (_VirtualDom_doc.title = title = doc.aK); + (title !== doc.aL) && (_VirtualDom_doc.title = title = doc.aL); }); } ); @@ -4038,12 +4038,12 @@ function _Browser_makeAnimator(model, draw) function _Browser_application(impl) { - var onUrlChange = impl.aE; - var onUrlRequest = impl.aF; + var onUrlChange = impl.aF; + var onUrlRequest = impl.aG; var key = function() { key.a(onUrlChange(_Browser_getUrl())); }; return _Browser_document({ - N: function(sendToApp) + O: function(sendToApp) { key.a = sendToApp; _Browser_window.addEventListener('popstate', key); @@ -4059,9 +4059,9 @@ function _Browser_application(impl) var next = $elm$url$Url$fromString(href).a; sendToApp(onUrlRequest( (next - && curr.aH === next.aH - && curr.X === next.X - && curr.ad.a === next.ad.a + && curr.aI === next.aI + && curr.Y === next.Y + && curr.ae.a === next.ae.a ) ? $elm$browser$Browser$Internal(next) : $elm$browser$Browser$External(href) @@ -4069,13 +4069,13 @@ function _Browser_application(impl) } }); }, - aD: function(flags) + aE: function(flags) { - return A3(impl.aD, flags, _Browser_getUrl(), key); + return A3(impl.aE, flags, _Browser_getUrl(), key); }, + aN: impl.aN, aM: impl.aM, - aL: impl.aL, - aJ: impl.aJ + aK: impl.aK }); } @@ -4141,17 +4141,17 @@ var _Browser_decodeEvent = F2(function(decoder, event) function _Browser_visibilityInfo() { return (typeof _VirtualDom_doc.hidden !== 'undefined') - ? { aB: 'hidden', au: 'visibilitychange' } + ? { aC: 'hidden', av: 'visibilitychange' } : (typeof _VirtualDom_doc.mozHidden !== 'undefined') - ? { aB: 'mozHidden', au: 'mozvisibilitychange' } + ? { aC: 'mozHidden', av: 'mozvisibilitychange' } : (typeof _VirtualDom_doc.msHidden !== 'undefined') - ? { aB: 'msHidden', au: 'msvisibilitychange' } + ? { aC: 'msHidden', av: 'msvisibilitychange' } : (typeof _VirtualDom_doc.webkitHidden !== 'undefined') - ? { aB: 'webkitHidden', au: 'webkitvisibilitychange' } - : { aB: 'hidden', au: 'visibilitychange' }; + ? { aC: 'webkitHidden', av: 'webkitvisibilitychange' } + : { aC: 'hidden', av: 'visibilitychange' }; } @@ -4232,12 +4232,12 @@ var _Browser_call = F2(function(functionName, id) function _Browser_getViewport() { return { - aj: _Browser_getScene(), - am: { - ao: _Browser_window.pageXOffset, - ap: _Browser_window.pageYOffset, - an: _Browser_doc.documentElement.clientWidth, - W: _Browser_doc.documentElement.clientHeight + ak: _Browser_getScene(), + an: { + ap: _Browser_window.pageXOffset, + aq: _Browser_window.pageYOffset, + ao: _Browser_doc.documentElement.clientWidth, + X: _Browser_doc.documentElement.clientHeight } }; } @@ -4247,8 +4247,8 @@ function _Browser_getScene() var body = _Browser_doc.body; var elem = _Browser_doc.documentElement; return { - an: Math.max(body.scrollWidth, body.offsetWidth, elem.scrollWidth, elem.offsetWidth, elem.clientWidth), - W: Math.max(body.scrollHeight, body.offsetHeight, elem.scrollHeight, elem.offsetHeight, elem.clientHeight) + ao: Math.max(body.scrollWidth, body.offsetWidth, elem.scrollWidth, elem.offsetWidth, elem.clientWidth), + X: Math.max(body.scrollHeight, body.offsetHeight, elem.scrollHeight, elem.offsetHeight, elem.clientHeight) }; } @@ -4271,15 +4271,15 @@ function _Browser_getViewportOf(id) return _Browser_withNode(id, function(node) { return { - aj: { - an: node.scrollWidth, - W: node.scrollHeight + ak: { + ao: node.scrollWidth, + X: node.scrollHeight }, - am: { - ao: node.scrollLeft, - ap: node.scrollTop, - an: node.clientWidth, - W: node.clientHeight + an: { + ap: node.scrollLeft, + aq: node.scrollTop, + ao: node.clientWidth, + X: node.clientHeight } }; }); @@ -4309,18 +4309,18 @@ function _Browser_getElement(id) var x = _Browser_window.pageXOffset; var y = _Browser_window.pageYOffset; return { - aj: _Browser_getScene(), - am: { - ao: x, - ap: y, - an: _Browser_doc.documentElement.clientWidth, - W: _Browser_doc.documentElement.clientHeight + ak: _Browser_getScene(), + an: { + ap: x, + aq: y, + ao: _Browser_doc.documentElement.clientWidth, + X: _Browser_doc.documentElement.clientHeight }, - ay: { - ao: x + rect.left, - ap: y + rect.top, - an: rect.width, - W: rect.height + az: { + ap: x + rect.left, + aq: y + rect.top, + ao: rect.width, + X: rect.height } }; }); @@ -4905,7 +4905,7 @@ var $elm$url$Url$Http = 0; var $elm$url$Url$Https = 1; var $elm$url$Url$Url = F6( function (protocol, host, port_, path, query, fragment) { - return {V: fragment, X: host, ab: path, ad: port_, aH: protocol, ag: query}; + return {W: fragment, Y: host, ac: path, ae: port_, aI: protocol, ah: query}; }); var $elm$core$String$contains = _String_contains; var $elm$core$String$length = _String_length; @@ -5214,13 +5214,13 @@ var $bburdette$websocket$WebSocket$encodeCmd = function (wsc) { $elm$json$Json$Encode$string('connect')), _Utils_Tuple2( 'name', - $elm$json$Json$Encode$string(msg._)), + $elm$json$Json$Encode$string(msg.aa)), _Utils_Tuple2( 'address', - $elm$json$Json$Encode$string(msg.ar)), + $elm$json$Json$Encode$string(msg.as)), _Utils_Tuple2( 'protocol', - $elm$json$Json$Encode$string(msg.aH)) + $elm$json$Json$Encode$string(msg.aI)) ])); case 1: var msg = wsc.a; @@ -5232,10 +5232,10 @@ var $bburdette$websocket$WebSocket$encodeCmd = function (wsc) { $elm$json$Json$Encode$string('send')), _Utils_Tuple2( 'name', - $elm$json$Json$Encode$string(msg._)), + $elm$json$Json$Encode$string(msg.aa)), _Utils_Tuple2( 'content', - $elm$json$Json$Encode$string(msg.av)) + $elm$json$Json$Encode$string(msg.aw)) ])); default: var msg = wsc.a; @@ -5247,7 +5247,7 @@ var $bburdette$websocket$WebSocket$encodeCmd = function (wsc) { $elm$json$Json$Encode$string('close')), _Utils_Tuple2( 'name', - $elm$json$Json$Encode$string(msg._)) + $elm$json$Json$Encode$string(msg.aa)) ])); } }; @@ -5271,7 +5271,7 @@ var $author$project$Main$connectCommand = A2( $bburdette$websocket$WebSocket$send, $author$project$Ports$sendSocketCommand, $bburdette$websocket$WebSocket$Connect( - {ar: $author$project$Main$wsBackend, _: 'TheSocket', aH: ''})); + {as: $author$project$Main$wsBackend, aa: 'TheSocket', aI: ''})); var $author$project$Main$init = function (_v0) { return _Utils_Tuple2($author$project$Main$Disconnected, $author$project$Main$connectCommand); }; @@ -5296,7 +5296,7 @@ var $elm$time$Time$Every = F2( }); var $elm$time$Time$State = F2( function (taggers, processes) { - return {af: processes, al: taggers}; + return {ag: processes, am: taggers}; }); var $elm$core$Dict$RBEmpty_elm_builtin = {$: -2}; var $elm$core$Dict$empty = $elm$core$Dict$RBEmpty_elm_builtin; @@ -5588,7 +5588,7 @@ var $elm$time$Time$spawnHelp = F3( }); var $elm$time$Time$onEffects = F3( function (router, subs, _v0) { - var processes = _v0.af; + var processes = _v0.ag; var rightStep = F3( function (_v6, id, _v7) { var spawns = _v7.a; @@ -5657,7 +5657,7 @@ var $elm$time$Time$millisToPosix = $elm$core$Basics$identity; var $elm$time$Time$now = _Time_now($elm$time$Time$millisToPosix); var $elm$time$Time$onSelfMsg = F3( function (router, interval, state) { - var _v0 = A2($elm$core$Dict$get, interval, state.al); + var _v0 = A2($elm$core$Dict$get, interval, state.am); if (_v0.$ === 1) { return $elm$core$Task$succeed(state); } else { @@ -5709,7 +5709,7 @@ var $elm$browser$Browser$AnimationManager$Delta = function (a) { }; var $elm$browser$Browser$AnimationManager$State = F3( function (subs, request, oldTime) { - return {L: oldTime, ai: request, ak: subs}; + return {M: oldTime, aj: request, al: subs}; }); var $elm$browser$Browser$AnimationManager$init = $elm$core$Task$succeed( A3($elm$browser$Browser$AnimationManager$State, _List_Nil, $elm$core$Maybe$Nothing, 0)); @@ -5717,8 +5717,8 @@ var $elm$browser$Browser$AnimationManager$now = _Browser_now(0); var $elm$browser$Browser$AnimationManager$rAF = _Browser_rAF(0); var $elm$browser$Browser$AnimationManager$onEffects = F3( function (router, subs, _v0) { - var request = _v0.ai; - var oldTime = _v0.L; + var request = _v0.aj; + var oldTime = _v0.M; var _v1 = _Utils_Tuple2(request, subs); if (_v1.a.$ === 1) { if (!_v1.b.b) { @@ -5764,8 +5764,8 @@ var $elm$browser$Browser$AnimationManager$onEffects = F3( }); var $elm$browser$Browser$AnimationManager$onSelfMsg = F3( function (router, newTime, _v0) { - var subs = _v0.ak; - var oldTime = _v0.L; + var subs = _v0.al; + var oldTime = _v0.M; var send = function (sub) { if (!sub.$) { var tagger = sub.a; @@ -5873,7 +5873,7 @@ var $bburdette$websocket$WebSocket$decodeMsg = A2( F2( function (a, b) { return $bburdette$websocket$WebSocket$Error( - {az: b, _: a}); + {aA: b, aa: a}); }), A2($elm$json$Json$Decode$field, 'name', $elm$json$Json$Decode$string), A2($elm$json$Json$Decode$field, 'error', $elm$json$Json$Decode$string)); @@ -5883,7 +5883,7 @@ var $bburdette$websocket$WebSocket$decodeMsg = A2( F2( function (a, b) { return $bburdette$websocket$WebSocket$Data( - {aw: b, _: a}); + {ax: b, aa: a}); }), A2($elm$json$Json$Decode$field, 'name', $elm$json$Json$Decode$string), A2($elm$json$Json$Decode$field, 'data', $elm$json$Json$Decode$string)); @@ -6085,14 +6085,15 @@ var $author$project$Main$initAnimation = function (frameCount) { J: $author$project$Fps$init, t: 0, y: $elm$core$Dict$empty, - m: $author$project$Main$Playing(0) + m: $author$project$Main$Playing(0), + K: $elm$core$Maybe$Nothing }; }; var $elm$core$String$lines = _String_lines; var $author$project$Main$processMessage = F2( function (data, model) { var _v0 = $elm$core$String$lines(data); - _v0$6: + _v0$7: while (true) { if (_v0.b) { switch (_v0.a) { @@ -6100,13 +6101,13 @@ var $author$project$Main$processMessage = F2( if (!_v0.b.b) { return $author$project$Main$Connected; } else { - break _v0$6; + break _v0$7; } case 'connection failed': if (!_v0.b.b) { return $author$project$Main$Problem($author$project$Main$ConnectionFailed); } else { - break _v0$6; + break _v0$7; } case 'status': if (_v0.b.b && (!_v0.b.b.b)) { @@ -6122,20 +6123,39 @@ var $author$project$Main$processMessage = F2( $author$project$Main$UnexpectedMessage('Unknown status: \'' + (status + '\''))); } } else { - break _v0$6; + break _v0$7; } case 'error': var errorLines = _v0.b; return $author$project$Main$Problem( $author$project$Main$CompilationError( A2($elm$core$String$join, '\n', errorLines))); - case 'frame_count': + case 'warning': if (_v0.b.b && (!_v0.b.b.b)) { var _v3 = _v0.b; - var n = _v3.a; - var _v4 = $elm$core$String$toInt(n); - if (!_v4.$) { - var frameCount = _v4.a; + var warning = _v3.a; + if (model.$ === 3) { + var animation = model.a; + return $author$project$Main$Animating( + _Utils_update( + animation, + { + K: $elm$core$Maybe$Just(warning) + })); + } else { + return $author$project$Main$Problem( + $author$project$Main$CompilationError(warning)); + } + } else { + break _v0$7; + } + case 'frame_count': + if (_v0.b.b && (!_v0.b.b.b)) { + var _v5 = _v0.b; + var n = _v5.a; + var _v6 = $elm$core$String$toInt(n); + if (!_v6.$) { + var frameCount = _v6.a; return $author$project$Main$Animating( $author$project$Main$initAnimation(frameCount)); } else { @@ -6143,17 +6163,17 @@ var $author$project$Main$processMessage = F2( $author$project$Main$UnexpectedMessage('frame_count wasn\'t number, but \'' + (n + '\''))); } } else { - break _v0$6; + break _v0$7; } case 'frame': if ((_v0.b.b && _v0.b.b.b) && (!_v0.b.b.b.b)) { - var _v5 = _v0.b; - var n = _v5.a; - var _v6 = _v5.b; - var svgUrl = _v6.a; - var _v7 = $elm$core$String$toInt(n); - if (!_v7.$) { - var frameIndex = _v7.a; + var _v7 = _v0.b; + var n = _v7.a; + var _v8 = _v7.b; + var svgUrl = _v8.a; + var _v9 = $elm$core$String$toInt(n); + if (!_v9.$) { + var frameIndex = _v9.a; if (model.$ === 3) { var animation = model.a; return $author$project$Main$Animating( @@ -6171,13 +6191,13 @@ var $author$project$Main$processMessage = F2( $author$project$Main$UnexpectedMessage('Frame index wasn\'t number, but \'' + (n + '\''))); } } else { - break _v0$6; + break _v0$7; } default: - break _v0$6; + break _v0$7; } } else { - break _v0$6; + break _v0$7; } } return $author$project$Main$Problem( @@ -6192,11 +6212,11 @@ var $author$project$Main$processResult = F2( } else { var wsMsg = result.a; if (!wsMsg.$) { - var error = wsMsg.a.az; + var error = wsMsg.a.aA; return $author$project$Main$Problem( $author$project$Main$UnexpectedMessage(error)); } else { - var data = wsMsg.a.aw; + var data = wsMsg.a.ax; return A2($author$project$Main$processMessage, data, model); } } @@ -6209,7 +6229,7 @@ var $author$project$Main$sendSource = function (txt) { $bburdette$websocket$WebSocket$send, $author$project$Ports$sendSocketCommand, $bburdette$websocket$WebSocket$Send( - {av: txt, _: 'TheSocket'})); + {aw: txt, aa: 'TheSocket'})); }; var $author$project$Fps$addToHead = F2( function (dt, fps) { @@ -6480,6 +6500,7 @@ var $elm$html$Html$Attributes$stringProperty = F2( var $elm$html$Html$Attributes$class = $elm$html$Html$Attributes$stringProperty('className'); var $elm$html$Html$div = _VirtualDom_node('div'); var $elm$html$Html$img = _VirtualDom_node('img'); +var $elm$html$Html$span = _VirtualDom_node('span'); var $elm$html$Html$Attributes$src = function (url) { return A2( $elm$html$Html$Attributes$stringProperty, @@ -6496,31 +6517,49 @@ var $author$project$Main$webBackend = function () { return 'http://localhost:10162/'; } }(); -var $author$project$Main$frameView = function (bestFrame) { - var image = function () { - if (!bestFrame.$) { - var svgUrl = bestFrame.a; - return A2( - $elm$html$Html$img, - _List_fromArray( - [ - $elm$html$Html$Attributes$src( - _Utils_ap($author$project$Main$webBackend, svgUrl)) - ]), - _List_Nil); - } else { - return $elm$html$Html$text(''); - } - }(); - return A2( - $elm$html$Html$div, - _List_fromArray( - [ - $elm$html$Html$Attributes$class('viewer') - ]), - _List_fromArray( - [image])); -}; +var $author$project$Main$frameView = F2( + function (bestFrame, mbWarning) { + var warn = function () { + if (!mbWarning.$) { + var txt = mbWarning.a; + return A2( + $elm$html$Html$span, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('warning') + ]), + _List_fromArray( + [ + $elm$html$Html$text(txt) + ])); + } else { + return A2($elm$html$Html$span, _List_Nil, _List_Nil); + } + }(); + var image = function () { + if (!bestFrame.$) { + var svgUrl = bestFrame.a; + return A2( + $elm$html$Html$img, + _List_fromArray( + [ + $elm$html$Html$Attributes$src( + _Utils_ap($author$project$Main$webBackend, svgUrl)) + ]), + _List_Nil); + } else { + return $elm$html$Html$text(''); + } + }(); + return A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('viewer') + ]), + _List_fromArray( + [image, warn])); + }); var $elm$html$Html$Attributes$id = $elm$html$Html$Attributes$stringProperty('id'); var $elm$html$Html$h1 = _VirtualDom_node('h1'); var $elm$html$Html$pre = _VirtualDom_node('pre'); @@ -6595,13 +6634,14 @@ var $author$project$Main$view = function (model) { return $author$project$Main$problemView(problem); default: var bestFrame = model.a.C; - return $author$project$Main$frameView(bestFrame); + var warning = model.a.K; + return A2($author$project$Main$frameView, bestFrame, warning); } }() ])) ])); }; var $author$project$Main$main = $elm$browser$Browser$element( - {aD: $author$project$Main$init, aJ: $author$project$Main$subscriptions, aL: $author$project$Main$update, aM: $author$project$Main$view}); + {aE: $author$project$Main$init, aK: $author$project$Main$subscriptions, aM: $author$project$Main$update, aN: $author$project$Main$view}); _Platform_export({'Main':{'init':$author$project$Main$main( $elm$json$Json$Decode$succeed(0))(0)}});}(this)); \ No newline at end of file diff --git a/playground/playground.js b/playground/playground.js index 175f227..4a70acd 100644 --- a/playground/playground.js +++ b/playground/playground.js @@ -58,6 +58,7 @@ function playgroundInit(elt) { node: elt }); app.ports.sendSocketCommand.subscribe(sendSocketCommand); + var tHandler = setTimeout(function(){},0); return { play: function () { app.ports.receiveControlMsg.send('play'); @@ -78,8 +79,11 @@ function playgroundInit(elt) { app.ports.receiveControlMsg.send('seek-10'); }, newCode: function(code) { - lastScript = code; - app.ports.receiveEditorMsg.send(code); + clearTimeout(tHandler); + tHandler = setTimeout(function() { + lastScript = code; + app.ports.receiveEditorMsg.send(code); + }, 500); } }; } diff --git a/playground/snippets.js b/playground/snippets.js index e9b8326..9adc059 100644 --- a/playground/snippets.js +++ b/playground/snippets.js @@ -9,4 +9,4 @@ const snippets = [{"title": "Hello World","url": "https://reanimate.clozecards.c ,{"title": "Object Positions","url": "https://reanimate.clozecards.com/PHaVM0ar3yF/195.svg","code": "env =\n addStatic (mkBackground \"white\") .\n mapA (withStrokeColor \"black\")\n\nanimation :: Animation\nanimation = env $\n sceneAnimation $ do\n -- Configure objects\n txt <- newText \"Center\"\n top <- newText \"Top\"\n oModifyS top $ \n oTopY .= screenTop\n topR <- newText \"Top right\"\n oModifyS topR $ do\n oTopY .= screenTop\n oRightX .= screenRight\n botR <- newText \"Bottom right\"\n oModifyS botR $ do\n oTranslate .= (0, screenBottom+0.5)\n oRightX .= screenRight\n botL <- newText \"Bottom left\"\n oModifyS botL $ do\n oTranslate .= (0, screenBottom+0.5)\n oLeftX .= screenLeft\n topL <- newText \"Top left\"\n oModifyS topL $ do\n oTopY .= screenTop\n oLeftX .= screenLeft\n -- Show objects\n oShow txt\n wait 1\n switchTo txt top\n switchTo top topR\n switchTo topR botR\n switchTo botR botL\n switchTo botL topL\n switchTo topL txt\n\nswitchTo src dst = do\n fork $ oFadeOut src 1\n oModify dst $ oOpacity .~ 1\n oFadeIn dst 1\n wait 1\n\nnewText txt =\n newObject $ scale 1.5 $ center $ latex txt\n"} ,{"title": "Camera","url": "https://reanimate.clozecards.com/CD5Bg7AwVkF/150.svg","code": "animation :: Animation\nanimation = docEnv $ mapA (withFillOpacity 1) $ sceneAnimation $ do\n cam <- newObject Camera\n\n txt <- newObject $ center $ latex \"Fixed (non-cam)\"\n oModifyS txt $ do\n oTopY .= screenTop \n oZIndex .= 2\n\n circle <- newObject $ Circle 1\n cameraAttach cam circle\n oModify circle $ oContext .~ withFillColor \"blue\"\n circleRight <- oRead circle oRightX\n\n box <- newObject $ Rectangle 2 2\n cameraAttach cam box\n oModify box $ oContext .~ withFillColor \"green\"\n oModify box $ oLeftX .~ circleRight\n boxCenter <- oRead box oCenterXY\n\n small <- newObject $ center $ latex \"This text is very small\"\n cameraAttach cam small\n oModifyS small $ do\n oCenterXY .= boxCenter\n oScale .= 0.1\n \n oShow txt\n oShow small\n oShow circle\n oShow box\n\n wait 1\n\n cameraFocus cam boxCenter\n waitOn $ do\n fork $ cameraPan cam 3 boxCenter\n fork $ cameraZoom cam 3 15\n \n wait 2\n cameraZoom cam 3 1\n cameraPan cam 1 (0,0)\n"} ]; -const playgroundVersion = "2020-08-28 (39297)"; +const playgroundVersion = "2020-08-28 (917dc)"; diff --git a/reanimate-0.4.2.0-inplace/Reanimate.Render.hs.html b/reanimate-0.4.2.0-inplace/Reanimate.Render.hs.html index cc4c724..43c5802 100644 --- a/reanimate-0.4.2.0-inplace/Reanimate.Render.hs.html +++ b/reanimate-0.4.2.0-inplace/Reanimate.Render.hs.html @@ -33,7 +33,7 @@ span.spaces { background: white } 14 ( render 15 , renderSvgs 16 , renderSnippets -- :: Animation -> IO () - 17 , renderOneFrame + 17 , renderLimitedFrames 18 , Format(..) 19 , Raster(..) 20 , Width, Height, FPS @@ -101,336 +101,344 @@ span.spaces { background: white } 82 hPutStrLn stderr msg 83 exitWith (ExitFailure 1) 84 - 85 -- | Select a single frame that doesn't already exist in the output - 86 -- folder and render it. If all frames have been rendered, print "Done". - 87 renderOneFrame :: FilePath -> Int -> Bool -> Int -> Animation -> IO () - 88 renderOneFrame folder offset _prettyPrint rate ani = - 89 worker (frameOrder rate frameCount) + 85 -- | Render as many frames as possible in 2 seconds. Limited to 20 frames. + 86 renderLimitedFrames :: FilePath -> Int -> Bool -> Int -> Animation -> IO () + 87 renderLimitedFrames folder offset _prettyPrint rate ani = do + 88 now <- getCurrentTime + 89 worker (addUTCTime timeLimit now) frameLimit (frameOrder rate frameCount) 90 where - 91 worker [] = putStrLn "Done" - 92 worker (x:xs) = do - 93 let nth = (x+offset) `mod` frameCount - 94 now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth - 95 frame = frameAt (if frameCount <= 1 then 0 else now) ani - 96 svg = renderSvg Nothing Nothing frame - 97 path = folder </> show nth <.> "svg" - 98 tmpPath = path <.> "tmp" - 99 haveFile <- doesFileExist path - 100 if haveFile - 101 then worker xs - 102 else do - 103 writeFile tmpPath svg - 104 renameOrCopyFile tmpPath path - 105 print nth - 106 frameCount = round (duration ani * fromIntegral rate) :: Int - 107 - 108 -- XXX: Merge with 'renderSvgs' - 109 -- | Render 10 frames and print them to stdout. Used for testing. - 110 -- - 111 -- XXX: Not related to the snippets in the playground. - 112 renderSnippets :: Animation -> IO () - 113 renderSnippets ani = forM_ [0 .. frameCount - 1] $ \nth -> do - 114 let now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth - 115 frame = frameAt now ani - 116 svg = renderSvg Nothing Nothing frame - 117 putStr (show nth) - 118 T.putStrLn $ T.concat . T.lines . T.pack $ svg - 119 where frameCount = 10 :: Integer - 120 - 121 frameOrder :: Int -> Int -> [Int] - 122 frameOrder fps nFrames = worker [] fps - 123 where - 124 worker _seen 0 = [] - 125 worker seen nthFrame = filterFrameList seen nthFrame nFrames - 126 ++ worker (nthFrame : seen) (nthFrame `div` 2) - 127 - 128 filterFrameList :: [Int] -> Int -> Int -> [Int] - 129 filterFrameList seen nthFrame nFrames = filter (not . isSeen) - 130 [0, nthFrame .. nFrames - 1] - 131 where isSeen x = any (\y -> x `mod` y == 0) seen - 132 - 133 -- | Video formats supported by reanimate. - 134 data Format = RenderMp4 | RenderGif | RenderWebm - 135 deriving (Show) - 136 - 137 mp4Arguments :: FPS -> FilePath -> FilePath -> FilePath -> [String] - 138 mp4Arguments fps progress template target = - 139 [ "-r" - 140 , show fps - 141 , "-i" - 142 , template - 143 , "-y" - 144 , "-c:v" - 145 , "libx264" - 146 , "-vf" - 147 , "fps=" ++ show fps - 148 , "-preset" - 149 , "slow" - 150 , "-crf" - 151 , "18" - 152 , "-movflags" - 153 , "+faststart" - 154 , "-progress" - 155 , progress - 156 , "-pix_fmt" - 157 , "yuv420p" - 158 , target - 159 ] - 160 - 161 -- gifArguments :: FPS -> FilePath -> FilePath -> FilePath -> [String] - 162 -- gifArguments fps progress template target = - 163 - 164 -- | Render animation to a video file with given parameters. - 165 render - 166 :: Animation - 167 -> FilePath - 168 -> Raster - 169 -> Format - 170 -> Width - 171 -> Height - 172 -> FPS - 173 -> Bool - 174 -> IO () - 175 render ani target raster format width height fps partial = do - 176 printf "Starting render of animation: %.1f\n" (duration ani) - 177 ffmpeg <- requireExecutable "ffmpeg" - 178 generateFrames raster ani width height fps partial $ \template -> - 179 withTempFile "txt" $ \progress -> do - 180 writeFile progress "" - 181 progressH <- openFile progress ReadMode - 182 hSetBuffering progressH NoBuffering - 183 allFinished <- newEmptyMVar - 184 void $ forkIO $ do - 185 progressPrinter "rendered" (animationFrameCount ani fps) - 186 $ \done -> fix $ \loop -> do - 187 eof <- hIsEOF progressH - 188 if eof - 189 then threadDelay 1000000 >> loop - 190 else do - 191 l <- try (hGetLine progressH) - 192 case l of - 193 Left SomeException{} -> return () - 194 Right str -> - 195 case take 6 str of - 196 "frame=" -> do - 197 void $ swapMVar done (read (drop 6 str)) - 198 loop - 199 _ | str == "progress=end" -> return () - 200 _ -> loop - 201 putMVar allFinished () - 202 case format of - 203 RenderMp4 -> runCmd ffmpeg (mp4Arguments fps progress template target) - 204 RenderGif -> withTempFile "png" $ \palette -> do - 205 runCmd - 206 ffmpeg - 207 [ "-i" - 208 , template - 209 , "-y" - 210 , "-vf" - 211 , "fps=" - 212 ++ show fps - 213 ++ ",scale=" - 214 ++ show width - 215 ++ ":" - 216 ++ show height - 217 ++ ":flags=lanczos,palettegen" - 218 , "-t" - 219 , showFFloat Nothing (duration ani) "" - 220 , palette - 221 ] - 222 runCmd - 223 ffmpeg - 224 [ "-framerate" - 225 , show fps - 226 , "-i" - 227 , template - 228 , "-y" - 229 , "-i" - 230 , palette - 231 , "-progress" - 232 , progress - 233 , "-filter_complex" - 234 , "fps=" - 235 ++ show fps - 236 ++ ",scale=" - 237 ++ show width - 238 ++ ":" - 239 ++ show height - 240 ++ ":flags=lanczos[x];[x][1:v]paletteuse" - 241 , "-t" - 242 , showFFloat Nothing (duration ani) "" - 243 , target - 244 ] - 245 RenderWebm -> runCmd - 246 ffmpeg - 247 [ "-r" - 248 , show fps - 249 , "-i" - 250 , template - 251 , "-y" - 252 , "-progress" - 253 , progress - 254 , "-c:v" - 255 , "libvpx-vp9" - 256 , "-vf" - 257 , "fps=" ++ show fps - 258 , target - 259 ] - 260 takeMVar allFinished - 261 - 262 --------------------------------------------------------------------------------- - 263 -- Helpers - 264 - 265 progressPrinter :: String -> Int -> (MVar Int -> IO ()) -> IO () - 266 progressPrinter typeName maxCount action = do - 267 printf "\rFrames %s: 0/%d" typeName maxCount - 268 putStr $ clearFromCursorToLineEndCode ++ "\r" - 269 done <- newMVar (0 :: Int) - 270 start <- getCurrentTime - 271 let bgThread = forever $ do - 272 nDone <- readMVar done - 273 now <- getCurrentTime - 274 let spent = diffUTCTime now start - 275 remaining = - 276 (spent / (fromIntegral nDone / fromIntegral maxCount)) - spent - 277 printf "\rFrames %s: %d/%d" typeName nDone maxCount - 278 putStr $ ", time spent: " ++ ppDiff spent - 279 unless (nDone == 0) $ do - 280 putStr $ ", time remaining: " ++ ppDiff remaining - 281 putStr $ ", total time: " ++ ppDiff (remaining + spent) - 282 putStr $ clearFromCursorToLineEndCode ++ "\r" - 283 hFlush stdout - 284 threadDelay 1000000 - 285 withBackgroundThread bgThread $ action done - 286 now <- getCurrentTime - 287 let spent = diffUTCTime now start - 288 printf "\rFrames %s: %d/%d" typeName maxCount maxCount - 289 putStr $ ", time spent: " ++ ppDiff spent - 290 putStr $ clearFromCursorToLineEndCode ++ "\n" - 291 - 292 animationFrameCount :: Animation -> FPS -> Int - 293 animationFrameCount ani rate = round (duration ani * fromIntegral rate) :: Int - 294 - 295 generateFrames - 296 :: Raster -> Animation -> Width -> Height -> FPS -> Bool -> (FilePath -> IO a) -> IO a - 297 generateFrames raster ani width_ height_ rate partial action = withTempDir $ \tmp -> do - 298 let frameName nth = tmp </> printf nameTemplate nth - 299 setRootDirectory tmp - 300 progressPrinter "generated" frameCount - 301 $ \done -> handle h $ concurrentForM_ frames $ \n -> do - 302 writeFile (frameName n) $ renderSvg width height $ nthFrame n - 303 modifyMVar_ done $ \nDone -> return (nDone + 1) - 304 - 305 when (isValidRaster raster) - 306 $ progressPrinter "rastered" frameCount - 307 $ \done -> handle h $ concurrentForM_ frames $ \n -> do - 308 applyRaster raster (frameName n) - 309 modifyMVar_ done $ \nDone -> return (nDone + 1) - 310 - 311 action (tmp </> rasterTemplate raster) - 312 where - 313 isValidRaster RasterNone = False - 314 isValidRaster RasterAuto = False - 315 isValidRaster _ = True - 316 - 317 width = Just $ Px $ fromIntegral width_ - 318 height = Just $ Px $ fromIntegral height_ - 319 h UserInterrupt | partial = do - 320 hPutStrLn - 321 stderr - 322 "\nCtrl-C detected. Trying to generate video with available frames. \ - 323 \Hit ctrl-c again to abort." - 324 return () - 325 h other = throwIO other - 326 -- frames = [0..frameCount-1] - 327 frames = frameOrder rate frameCount - 328 nthFrame nth = frameAt (recip (fromIntegral rate) * fromIntegral nth) ani - 329 frameCount = animationFrameCount ani rate - 330 nameTemplate :: String - 331 nameTemplate = "render-%05d.svg" - 332 - 333 withBackgroundThread :: IO () -> IO a -> IO a - 334 withBackgroundThread t = bracket (forkIO t) killThread . const - 335 - 336 ppDiff :: NominalDiffTime -> String - 337 ppDiff diff | hours == 0 && mins == 0 = show secs ++ "s" - 338 | hours == 0 = printf "%.2d:%.2d" mins secs - 339 | otherwise = printf "%.2d:%.2d:%.2d" hours mins secs - 340 where - 341 (osecs, secs) = round diff `divMod` (60 :: Int) - 342 (hours, mins) = osecs `divMod` 60 + 91 timeLimit = 2 + 92 frameLimit = 20 :: Int + 93 worker _ 0 _ = return () + 94 worker _ _ [] = putStrLn "Done" + 95 worker localTimeLimit l (x:xs) = do + 96 curTime <- getCurrentTime + 97 if curTime > localTimeLimit + 98 then return () + 99 else do + 100 let nth = (x+offset) `mod` frameCount + 101 now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth + 102 frame = frameAt (if frameCount <= 1 then 0 else now) ani + 103 svg = renderSvg Nothing Nothing frame + 104 path = folder </> show nth <.> "svg" + 105 tmpPath = path <.> "tmp" + 106 haveFile <- doesFileExist path + 107 if haveFile + 108 then worker localTimeLimit l xs + 109 else do + 110 writeFile tmpPath svg + 111 renameOrCopyFile tmpPath path + 112 print nth + 113 worker localTimeLimit (l-1) xs + 114 frameCount = round (duration ani * fromIntegral rate) :: Int + 115 + 116 -- XXX: Merge with 'renderSvgs' + 117 -- | Render 10 frames and print them to stdout. Used for testing. + 118 -- + 119 -- XXX: Not related to the snippets in the playground. + 120 renderSnippets :: Animation -> IO () + 121 renderSnippets ani = forM_ [0 .. frameCount - 1] $ \nth -> do + 122 let now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth + 123 frame = frameAt now ani + 124 svg = renderSvg Nothing Nothing frame + 125 putStr (show nth) + 126 T.putStrLn $ T.concat . T.lines . T.pack $ svg + 127 where frameCount = 10 :: Integer + 128 + 129 frameOrder :: Int -> Int -> [Int] + 130 frameOrder fps nFrames = worker [] fps + 131 where + 132 worker _seen 0 = [] + 133 worker seen nthFrame = filterFrameList seen nthFrame nFrames + 134 ++ worker (nthFrame : seen) (nthFrame `div` 2) + 135 + 136 filterFrameList :: [Int] -> Int -> Int -> [Int] + 137 filterFrameList seen nthFrame nFrames = filter (not . isSeen) + 138 [0, nthFrame .. nFrames - 1] + 139 where isSeen x = any (\y -> x `mod` y == 0) seen + 140 + 141 -- | Video formats supported by reanimate. + 142 data Format = RenderMp4 | RenderGif | RenderWebm + 143 deriving (Show) + 144 + 145 mp4Arguments :: FPS -> FilePath -> FilePath -> FilePath -> [String] + 146 mp4Arguments fps progress template target = + 147 [ "-r" + 148 , show fps + 149 , "-i" + 150 , template + 151 , "-y" + 152 , "-c:v" + 153 , "libx264" + 154 , "-vf" + 155 , "fps=" ++ show fps + 156 , "-preset" + 157 , "slow" + 158 , "-crf" + 159 , "18" + 160 , "-movflags" + 161 , "+faststart" + 162 , "-progress" + 163 , progress + 164 , "-pix_fmt" + 165 , "yuv420p" + 166 , target + 167 ] + 168 + 169 -- gifArguments :: FPS -> FilePath -> FilePath -> FilePath -> [String] + 170 -- gifArguments fps progress template target = + 171 + 172 -- | Render animation to a video file with given parameters. + 173 render + 174 :: Animation + 175 -> FilePath + 176 -> Raster + 177 -> Format + 178 -> Width + 179 -> Height + 180 -> FPS + 181 -> Bool + 182 -> IO () + 183 render ani target raster format width height fps partial = do + 184 printf "Starting render of animation: %.1f\n" (duration ani) + 185 ffmpeg <- requireExecutable "ffmpeg" + 186 generateFrames raster ani width height fps partial $ \template -> + 187 withTempFile "txt" $ \progress -> do + 188 writeFile progress "" + 189 progressH <- openFile progress ReadMode + 190 hSetBuffering progressH NoBuffering + 191 allFinished <- newEmptyMVar + 192 void $ forkIO $ do + 193 progressPrinter "rendered" (animationFrameCount ani fps) + 194 $ \done -> fix $ \loop -> do + 195 eof <- hIsEOF progressH + 196 if eof + 197 then threadDelay 1000000 >> loop + 198 else do + 199 l <- try (hGetLine progressH) + 200 case l of + 201 Left SomeException{} -> return () + 202 Right str -> + 203 case take 6 str of + 204 "frame=" -> do + 205 void $ swapMVar done (read (drop 6 str)) + 206 loop + 207 _ | str == "progress=end" -> return () + 208 _ -> loop + 209 putMVar allFinished () + 210 case format of + 211 RenderMp4 -> runCmd ffmpeg (mp4Arguments fps progress template target) + 212 RenderGif -> withTempFile "png" $ \palette -> do + 213 runCmd + 214 ffmpeg + 215 [ "-i" + 216 , template + 217 , "-y" + 218 , "-vf" + 219 , "fps=" + 220 ++ show fps + 221 ++ ",scale=" + 222 ++ show width + 223 ++ ":" + 224 ++ show height + 225 ++ ":flags=lanczos,palettegen" + 226 , "-t" + 227 , showFFloat Nothing (duration ani) "" + 228 , palette + 229 ] + 230 runCmd + 231 ffmpeg + 232 [ "-framerate" + 233 , show fps + 234 , "-i" + 235 , template + 236 , "-y" + 237 , "-i" + 238 , palette + 239 , "-progress" + 240 , progress + 241 , "-filter_complex" + 242 , "fps=" + 243 ++ show fps + 244 ++ ",scale=" + 245 ++ show width + 246 ++ ":" + 247 ++ show height + 248 ++ ":flags=lanczos[x];[x][1:v]paletteuse" + 249 , "-t" + 250 , showFFloat Nothing (duration ani) "" + 251 , target + 252 ] + 253 RenderWebm -> runCmd + 254 ffmpeg + 255 [ "-r" + 256 , show fps + 257 , "-i" + 258 , template + 259 , "-y" + 260 , "-progress" + 261 , progress + 262 , "-c:v" + 263 , "libvpx-vp9" + 264 , "-vf" + 265 , "fps=" ++ show fps + 266 , target + 267 ] + 268 takeMVar allFinished + 269 + 270 --------------------------------------------------------------------------------- + 271 -- Helpers + 272 + 273 progressPrinter :: String -> Int -> (MVar Int -> IO ()) -> IO () + 274 progressPrinter typeName maxCount action = do + 275 printf "\rFrames %s: 0/%d" typeName maxCount + 276 putStr $ clearFromCursorToLineEndCode ++ "\r" + 277 done <- newMVar (0 :: Int) + 278 start <- getCurrentTime + 279 let bgThread = forever $ do + 280 nDone <- readMVar done + 281 now <- getCurrentTime + 282 let spent = diffUTCTime now start + 283 remaining = + 284 (spent / (fromIntegral nDone / fromIntegral maxCount)) - spent + 285 printf "\rFrames %s: %d/%d" typeName nDone maxCount + 286 putStr $ ", time spent: " ++ ppDiff spent + 287 unless (nDone == 0) $ do + 288 putStr $ ", time remaining: " ++ ppDiff remaining + 289 putStr $ ", total time: " ++ ppDiff (remaining + spent) + 290 putStr $ clearFromCursorToLineEndCode ++ "\r" + 291 hFlush stdout + 292 threadDelay 1000000 + 293 withBackgroundThread bgThread $ action done + 294 now <- getCurrentTime + 295 let spent = diffUTCTime now start + 296 printf "\rFrames %s: %d/%d" typeName maxCount maxCount + 297 putStr $ ", time spent: " ++ ppDiff spent + 298 putStr $ clearFromCursorToLineEndCode ++ "\n" + 299 + 300 animationFrameCount :: Animation -> FPS -> Int + 301 animationFrameCount ani rate = round (duration ani * fromIntegral rate) :: Int + 302 + 303 generateFrames + 304 :: Raster -> Animation -> Width -> Height -> FPS -> Bool -> (FilePath -> IO a) -> IO a + 305 generateFrames raster ani width_ height_ rate partial action = withTempDir $ \tmp -> do + 306 let frameName nth = tmp </> printf nameTemplate nth + 307 setRootDirectory tmp + 308 progressPrinter "generated" frameCount + 309 $ \done -> handle h $ concurrentForM_ frames $ \n -> do + 310 writeFile (frameName n) $ renderSvg width height $ nthFrame n + 311 modifyMVar_ done $ \nDone -> return (nDone + 1) + 312 + 313 when (isValidRaster raster) + 314 $ progressPrinter "rastered" frameCount + 315 $ \done -> handle h $ concurrentForM_ frames $ \n -> do + 316 applyRaster raster (frameName n) + 317 modifyMVar_ done $ \nDone -> return (nDone + 1) + 318 + 319 action (tmp </> rasterTemplate raster) + 320 where + 321 isValidRaster RasterNone = False + 322 isValidRaster RasterAuto = False + 323 isValidRaster _ = True + 324 + 325 width = Just $ Px $ fromIntegral width_ + 326 height = Just $ Px $ fromIntegral height_ + 327 h UserInterrupt | partial = do + 328 hPutStrLn + 329 stderr + 330 "\nCtrl-C detected. Trying to generate video with available frames. \ + 331 \Hit ctrl-c again to abort." + 332 return () + 333 h other = throwIO other + 334 -- frames = [0..frameCount-1] + 335 frames = frameOrder rate frameCount + 336 nthFrame nth = frameAt (recip (fromIntegral rate) * fromIntegral nth) ani + 337 frameCount = animationFrameCount ani rate + 338 nameTemplate :: String + 339 nameTemplate = "render-%05d.svg" + 340 + 341 withBackgroundThread :: IO () -> IO a -> IO a + 342 withBackgroundThread t = bracket (forkIO t) killThread . const 343 - 344 rasterTemplate :: Raster -> String - 345 rasterTemplate RasterNone = "render-%05d.svg" - 346 rasterTemplate RasterAuto = "render-%05d.svg" - 347 rasterTemplate _ = "render-%05d.png" - 348 - 349 -- | Resolve RasterNone and RasterAuto. If no valid raster can - 350 -- be found, exit with an error message. - 351 requireRaster :: Raster -> IO Raster - 352 requireRaster raster = do - 353 raster' <- selectRaster (if raster == RasterNone then RasterAuto else raster) - 354 case raster' of - 355 RasterNone -> do - 356 hPutStrLn - 357 stderr - 358 "Raster required but none could be found. \ - 359 \Please install either inkscape, imagemagick, or rsvg-convert." - 360 exitWith (ExitFailure 1) - 361 _ -> pure raster' - 362 - 363 -- | Resolve RasterNone and RasterAuto. If no valid raster can - 364 -- be found, return RasterNone. - 365 selectRaster :: Raster -> IO Raster - 366 selectRaster RasterAuto = do - 367 rsvg <- hasRSvg - 368 ink <- hasInkscape - 369 magick <- hasMagick - 370 if - 371 | isRight rsvg -> pure RasterRSvg - 372 | isRight ink -> pure RasterInkscape - 373 | isRight magick -> pure RasterMagick - 374 | otherwise -> pure RasterNone - 375 selectRaster r = pure r - 376 - 377 -- | Convert SVG file to a PNG file with selected raster engine. If - 378 -- raster engine is RasterAuto or RasterNone, do nothing. - 379 applyRaster :: Raster -> FilePath -> IO () - 380 applyRaster RasterNone _ = return () - 381 applyRaster RasterAuto _ = return () - 382 applyRaster RasterInkscape path = runCmd - 383 "inkscape" - 384 [ "--without-gui" - 385 , "--file=" ++ path - 386 , "--export-png=" ++ replaceExtension path "png" - 387 ] - 388 applyRaster RasterRSvg path = runCmd - 389 "rsvg-convert" - 390 [path, "--unlimited", "--output", replaceExtension path "png"] - 391 applyRaster RasterMagick path = - 392 runCmd magickCmd [path, replaceExtension path "png"] - 393 - 394 concurrentForM_ :: [a] -> (a -> IO ()) -> IO () - 395 concurrentForM_ lst action = do - 396 n <- getNumCapabilities - 397 sem <- newQSemN n - 398 eVar <- newEmptyMVar - 399 forM_ lst $ \elt -> do - 400 waitQSemN sem 1 - 401 emp <- isEmptyMVar eVar - 402 if emp - 403 then - 404 void - 405 $ forkIO - 406 ( catch (action elt) (void . tryPutMVar eVar) - 407 `finally` signalQSemN sem 1 - 408 ) - 409 else signalQSemN sem 1 - 410 waitQSemN sem n - 411 mbE <- tryTakeMVar eVar - 412 case mbE of - 413 Nothing -> return () - 414 Just e -> throwIO (e :: SomeException) + 344 ppDiff :: NominalDiffTime -> String + 345 ppDiff diff | hours == 0 && mins == 0 = show secs ++ "s" + 346 | hours == 0 = printf "%.2d:%.2d" mins secs + 347 | otherwise = printf "%.2d:%.2d:%.2d" hours mins secs + 348 where + 349 (osecs, secs) = round diff `divMod` (60 :: Int) + 350 (hours, mins) = osecs `divMod` 60 + 351 + 352 rasterTemplate :: Raster -> String + 353 rasterTemplate RasterNone = "render-%05d.svg" + 354 rasterTemplate RasterAuto = "render-%05d.svg" + 355 rasterTemplate _ = "render-%05d.png" + 356 + 357 -- | Resolve RasterNone and RasterAuto. If no valid raster can + 358 -- be found, exit with an error message. + 359 requireRaster :: Raster -> IO Raster + 360 requireRaster raster = do + 361 raster' <- selectRaster (if raster == RasterNone then RasterAuto else raster) + 362 case raster' of + 363 RasterNone -> do + 364 hPutStrLn + 365 stderr + 366 "Raster required but none could be found. \ + 367 \Please install either inkscape, imagemagick, or rsvg-convert." + 368 exitWith (ExitFailure 1) + 369 _ -> pure raster' + 370 + 371 -- | Resolve RasterNone and RasterAuto. If no valid raster can + 372 -- be found, return RasterNone. + 373 selectRaster :: Raster -> IO Raster + 374 selectRaster RasterAuto = do + 375 rsvg <- hasRSvg + 376 ink <- hasInkscape + 377 magick <- hasMagick + 378 if + 379 | isRight rsvg -> pure RasterRSvg + 380 | isRight ink -> pure RasterInkscape + 381 | isRight magick -> pure RasterMagick + 382 | otherwise -> pure RasterNone + 383 selectRaster r = pure r + 384 + 385 -- | Convert SVG file to a PNG file with selected raster engine. If + 386 -- raster engine is RasterAuto or RasterNone, do nothing. + 387 applyRaster :: Raster -> FilePath -> IO () + 388 applyRaster RasterNone _ = return () + 389 applyRaster RasterAuto _ = return () + 390 applyRaster RasterInkscape path = runCmd + 391 "inkscape" + 392 [ "--without-gui" + 393 , "--file=" ++ path + 394 , "--export-png=" ++ replaceExtension path "png" + 395 ] + 396 applyRaster RasterRSvg path = runCmd + 397 "rsvg-convert" + 398 [path, "--unlimited", "--output", replaceExtension path "png"] + 399 applyRaster RasterMagick path = + 400 runCmd magickCmd [path, replaceExtension path "png"] + 401 + 402 concurrentForM_ :: [a] -> (a -> IO ()) -> IO () + 403 concurrentForM_ lst action = do + 404 n <- getNumCapabilities + 405 sem <- newQSemN n + 406 eVar <- newEmptyMVar + 407 forM_ lst $ \elt -> do + 408 waitQSemN sem 1 + 409 emp <- isEmptyMVar eVar + 410 if emp + 411 then + 412 void + 413 $ forkIO + 414 ( catch (action elt) (void . tryPutMVar eVar) + 415 `finally` signalQSemN sem 1 + 416 ) + 417 else signalQSemN sem 1 + 418 waitQSemN sem n + 419 mbE <- tryTakeMVar eVar + 420 case mbE of + 421 Nothing -> return () + 422 Just e -> throwIO (e :: SomeException)