Generate frames to incrementally increase fps.

This commit is contained in:
David Himmelstrup 2019-09-08 16:03:47 +08:00
commit 2e482aba82
15 changed files with 134 additions and 73 deletions

View file

@ -24,9 +24,9 @@ description:
data-files: viewer/build/*.js data-files: viewer/build/*.js
viewer/build/*.html viewer/build/*.html
viewer/build/static/js/2.772a56e7.chunk.js viewer/build/static/js/2.772a56e7.chunk.js
viewer/build/static/js/main.db22f45d.chunk.js viewer/build/static/js/main.2d848b69.chunk.js
viewer/build/static/js/runtime~main.9eb600ee.js viewer/build/static/js/runtime~main.9eb600ee.js
viewer/build/static/css/main.6efe09fd.chunk.css viewer/build/static/css/main.f7ad3e9b.chunk.css
data/CIExyz.csv data/CIExyz.csv
data/cone_sensitivity_lms.csv data/cone_sensitivity_lms.csv

View file

@ -1,15 +1,17 @@
module Reanimate.Driver ( reanimate ) where module Reanimate.Driver ( reanimate ) where
import Control.Concurrent (MVar, forkIO, killThread, modifyMVar_, import Control.Concurrent (MVar, forkIO, killThread, modifyMVar_,
newEmptyMVar, putMVar) newEmptyMVar, putMVar, takeMVar)
import Control.Exception (finally) import Control.Exception (finally)
import Control.Monad.Fix (fix) import Control.Monad.Fix (fix)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Read as T
import Network.WebSockets import Network.WebSockets
import System.Directory (findFile, listDirectory) import System.Directory (findFile, listDirectory)
import System.Environment (getArgs, getProgName) import System.Environment (getArgs, getProgName)
import System.FilePath import System.FilePath
import System.FSNotify import System.FSNotify
import System.Exit
import System.IO (BufferMode (..), hPutStrLn, hSetBuffering, import System.IO (BufferMode (..), hPutStrLn, hSetBuffering,
stderr, stdin) stderr, stdin)
@ -18,7 +20,7 @@ import Paths_reanimate
import Reanimate.Misc (runCmdLazy, runCmd_, withTempDir, import Reanimate.Misc (runCmdLazy, runCmd_, withTempDir,
withTempFile) withTempFile)
import Reanimate.Monad (Animation) import Reanimate.Monad (Animation)
import Reanimate.Render (renderSvgs, render) import Reanimate.Render (render, renderSvgs)
import Web.Browser (openBrowser) import Web.Browser (openBrowser)
opts = defaultConnectionOptions opts = defaultConnectionOptions
@ -56,26 +58,11 @@ reanimate animation = do
sendTextData conn (T.pack "Compiling") sendTextData conn (T.pack "Compiling")
putStrLn "Killing and respawning..." putStrLn "Killing and respawning..."
killThread tid killThread tid
tid <- forkIO $ withTempFile ".exe" $ \tmpExecutable -> do tid <- forkIO $ slaveHandler conn self tmpDir
ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions tmpDir ++ [self, "-o", tmpExecutable]
case ret of
Left err ->
sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err))
Right{} -> do
getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M200M", "-RTS"]
flip fix [] $ \loop acc -> do
frame <- getFrame
case frame of
Left "" -> do
sendTextData conn (T.pack "Done")
-- insertCache msg (reverse acc)
Left err -> do
-- _ <- getChanContents queue
sendTextData conn $ T.pack $ "Error" ++ err
Right frame -> do
sendTextData conn frame
loop (frame : acc)
return tid return tid
killSlave = do
tid <- takeMVar slave
killThread tid
putStrLn "Found self. Listening..." putStrLn "Found self. Listening..."
stop <- watchFile watch self handler stop <- watchFile watch self handler
putMVar slave =<< forkIO (return ()) putMVar slave =<< forkIO (return ())
@ -83,7 +70,38 @@ reanimate animation = do
fps <- receiveData conn :: IO T.Text fps <- receiveData conn :: IO T.Text
handler handler
loop loop
loop `finally` stop loop `finally` (killSlave >> stop)
slaveHandler conn self tmpDir = withTempFile ".exe" $ \tmpExecutable -> do
ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions tmpDir ++ [self, "-o", tmpExecutable]
case ret of
Left err ->
sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err))
Right{} -> do
getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M1G", "-RTS"]
(frameCount,_) <- expectFrame =<< getFrame
-- sendTextData conn (T.pack "Compiled")
sendTextData conn (T.pack $ show frameCount)
fix $ \loop -> do
(frameIdx, frame) <- expectFrame =<< getFrame
sendTextData conn (T.pack $ show frameIdx)
sendTextData conn frame
loop
where
expectFrame (Left "") = do
sendTextData conn (T.pack "Done")
exitWith ExitSuccess
expectFrame (Left err) = do
sendTextData conn $ T.pack $ "Error" ++ err
exitWith (ExitFailure 1)
expectFrame (Right frame) =
case T.decimal frame of
Left err -> do
hPutStrLn stderr (T.unpack frame)
hPutStrLn stderr $ "expectFrame: " ++ err
sendTextData conn $ T.pack $ "Error" ++ err
exitWith (ExitFailure 1)
Right (frameNumber, rest) -> pure (frameNumber, rest)
watchFile watch file action = watchDir watch (takeDirectory file) check (const action) watchFile watch file action = watchDir watch (takeDirectory file) check (const action)
where where

View file

@ -23,16 +23,38 @@ import Text.Printf (printf)
renderSvgs :: Animation -> IO () renderSvgs :: Animation -> IO ()
renderSvgs ani = do renderSvgs ani = do
let renderedFrames = map (T.concat . T.lines . T.pack . nthFrame) frames print frameCount
mapM_ T.putStrLn (renderedFrames `using` parBuffer 16 rdeepseq) lock <- newMVar ()
-- let renderedFrames = map (T.concat . T.lines . T.pack . nthFrame) frames
-- mapM_ T.putStrLn (renderedFrames `using` parBuffer 16 rdeepseq)
concurrentForM_ (frameOrder rate frameCount) $ \nth -> do
let -- frame = frameAt (recip (fromIntegral rate-1) * fromIntegral nth) ani
now = (duration ani / (fromIntegral frameCount-1)) * fromIntegral nth
frame = frameAt (if frameCount<=1 then 0 else now) ani
svg = renderSvg Nothing Nothing frame
evaluate (length svg)
withMVar lock $ \_ -> do
putStr (show nth)
T.putStrLn $ T.concat . T.lines . T.pack $ svg
hFlush stdout
where where
frames = [0..frameCount-1] frames = [0..frameCount-1]
rate = 60 rate = 60
nthFrame nth = renderSvg Nothing Nothing $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani nthFrame nth = renderSvg Nothing Nothing $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani
frameCount = round (duration ani * fromIntegral rate) :: Int frameCount = round (duration ani * fromIntegral rate) :: Int
nameTemplate :: String
nameTemplate = "render-%05d.svg"
frameOrder :: Int -> Int -> [Int]
frameOrder fps nFrames = worker [] fps
where
worker seen 0 = []
worker seen nthFrame =
filterFrameList seen nthFrame nFrames ++
worker (nthFrame : seen) (nthFrame `div` 2)
filterFrameList seen nthFrame nFrames =
filter (not.isSeen) $ [0, nthFrame .. nFrames-1]
where
isSeen x = any (\y -> x `mod` y == 0) seen
data Format = RenderMp4 | RenderGif | RenderWebm | RenderBlank data Format = RenderMp4 | RenderGif | RenderWebm | RenderBlank

View file

@ -1,13 +1,13 @@
{ {
"main.css": "./static/css/main.6efe09fd.chunk.css", "main.css": "./static/css/main.f7ad3e9b.chunk.css",
"main.js": "./static/js/main.db22f45d.chunk.js", "main.js": "./static/js/main.2d848b69.chunk.js",
"main.js.map": "./static/js/main.db22f45d.chunk.js.map", "main.js.map": "./static/js/main.2d848b69.chunk.js.map",
"runtime~main.js": "./static/js/runtime~main.9eb600ee.js", "runtime~main.js": "./static/js/runtime~main.9eb600ee.js",
"runtime~main.js.map": "./static/js/runtime~main.9eb600ee.js.map", "runtime~main.js.map": "./static/js/runtime~main.9eb600ee.js.map",
"static/js/2.772a56e7.chunk.js": "./static/js/2.772a56e7.chunk.js", "static/js/2.772a56e7.chunk.js": "./static/js/2.772a56e7.chunk.js",
"static/js/2.772a56e7.chunk.js.map": "./static/js/2.772a56e7.chunk.js.map", "static/js/2.772a56e7.chunk.js.map": "./static/js/2.772a56e7.chunk.js.map",
"index.html": "./index.html", "index.html": "./index.html",
"precache-manifest.15b8d497ab10704d87b84878b92d08cf.js": "./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js", "precache-manifest.ecac8766a6ef020d2fc520bbf4682e03.js": "./precache-manifest.ecac8766a6ef020d2fc520bbf4682e03.js",
"service-worker.js": "./service-worker.js", "service-worker.js": "./service-worker.js",
"static/css/main.6efe09fd.chunk.css.map": "./static/css/main.6efe09fd.chunk.css.map" "static/css/main.f7ad3e9b.chunk.css.map": "./static/css/main.f7ad3e9b.chunk.css.map"
} }

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="./manifest.json"/><title>Reanimate Playground</title><link href="./static/css/main.6efe09fd.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="./";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="./static/js/2.772a56e7.chunk.js"></script><script src="./static/js/main.db22f45d.chunk.js"></script></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="./manifest.json"/><title>Reanimate Playground</title><link href="./static/css/main.f7ad3e9b.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="./";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="./static/js/2.772a56e7.chunk.js"></script><script src="./static/js/main.2d848b69.chunk.js"></script></body></html>

View file

@ -4,19 +4,19 @@ self.__precacheManifest = [
"url": "./static/js/runtime~main.9eb600ee.js" "url": "./static/js/runtime~main.9eb600ee.js"
}, },
{ {
"revision": "db22f45d36ec0c1e28c1", "revision": "2d848b69f66deb18ce2a",
"url": "./static/js/main.db22f45d.chunk.js" "url": "./static/js/main.2d848b69.chunk.js"
}, },
{ {
"revision": "772a56e764e5091f7538", "revision": "772a56e764e5091f7538",
"url": "./static/js/2.772a56e7.chunk.js" "url": "./static/js/2.772a56e7.chunk.js"
}, },
{ {
"revision": "db22f45d36ec0c1e28c1", "revision": "2d848b69f66deb18ce2a",
"url": "./static/css/main.6efe09fd.chunk.css" "url": "./static/css/main.f7ad3e9b.chunk.css"
}, },
{ {
"revision": "8912fe90ce5c625516525c7cd80ee665", "revision": "c119ec4d7ef35b6c6c46fd0e9dcca5ce",
"url": "./index.html" "url": "./index.html"
} }
]; ];

View file

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js");
importScripts( importScripts(
"./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js" "./precache-manifest.ecac8766a6ef020d2fc520bbf4682e03.js"
); );
workbox.clientsClaim(); workbox.clientsClaim();

View file

@ -1,2 +1,2 @@
body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.App{height:100vh;background-color:#282c34;color:#fff;display:grid;grid-template-columns:1fr;grid-template-rows:auto;grid-auto-flow:column;-webkit-align-items:center;align-items:center;overflow:hidden}.controls{text-align:center}.controls svg{padding-left:5px;padding-right:5px}.viewer{position:static}.viewer svg{max-width:100vw;max-height:100vh;margin-top:auto;margin-bottom:auto}div.messages{position:fixed;top:0;width:100%;background:#282c34}div.messages pre{margin:0}.home{color:#fff;text-align:center;float:right;margin-right:2em} body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.App{height:100vh;background-color:#282c34;color:#fff;display:grid;grid-template-columns:1fr;grid-template-rows:auto;grid-auto-flow:column;-webkit-align-items:center;align-items:center;overflow:hidden}.controls{text-align:center}.controls svg{padding-left:5px;padding-right:5px}.viewer{position:static}.viewer svg{max-width:100vw;max-height:100vh;margin-top:auto;margin-bottom:auto}div.messages{position:fixed;top:0;width:100%;background:#282c34}div.messages pre{margin:0}.home{color:#fff;text-align:center;float:right;margin-right:2em}
/*# sourceMappingURL=main.6efe09fd.chunk.css.map */ /*# sourceMappingURL=main.f7ad3e9b.chunk.css.map */

View file

@ -1 +1 @@
{"version":3,"sources":["/home/lemmih/Coding/Haskell/reanimate/viewer/src/index.css","main.6efe09fd.chunk.css","/home/lemmih/Coding/Haskell/reanimate/viewer/src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAA,CACA,SAAA,CACA,mICEY,CDCZ,kCAAA,CACA,iCCCF,CDEA,KACE,uECEF,CCbA,KAGE,YAAA,CACA,wBAAA,CACA,UAAA,CACA,YAAA,CACA,yBAAA,CACA,uBAAA,CAEA,qBAAA,CACA,0BAAA,CAAA,kBAAA,CACA,eDiBF,CCZA,UACE,iBDiBF,CCfA,cACE,gBAAA,CACA,iBDiBF,CCfA,QACE,eDiBF,CCfA,YACE,eAAA,CACA,gBAAA,CACA,eAAA,CACA,kBDiBF,CCfA,aACE,cAAA,CACA,KAAA,CACA,UAAA,CACA,kBDiBF,CCfA,iBACE,QDiBF,CCfA,MACE,UAAA,CACA,iBAAA,CACA,WAAA,CACA,gBDiBF","file":"main.6efe09fd.chunk.css","sourcesContent":["body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n","body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\n.App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n -webkit-align-items: center;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n\n",".App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n"]} {"version":3,"sources":["/home/lemmih/Coding/Haskell/reanimate/viewer/src/index.css","main.f7ad3e9b.chunk.css","/home/lemmih/Coding/Haskell/reanimate/viewer/src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAA,CACA,SAAA,CACA,mICEY,CDCZ,kCAAA,CACA,iCCCF,CDEA,KACE,uECEF,CCbA,KAGE,YAAA,CACA,wBAAA,CACA,UAAA,CACA,YAAA,CACA,yBAAA,CACA,uBAAA,CAEA,qBAAA,CACA,0BAAA,CAAA,kBAAA,CACA,eDiBF,CCZA,UACE,iBDiBF,CCfA,cACE,gBAAA,CACA,iBDiBF,CCfA,QACE,eDiBF,CCfA,YACE,eAAA,CACA,gBAAA,CACA,eAAA,CACA,kBDiBF,CCfA,aACE,cAAA,CACA,KAAA,CACA,UAAA,CACA,kBDiBF,CCfA,iBACE,QDiBF,CCfA,MACE,UAAA,CACA,iBAAA,CACA,WAAA,CACA,gBDiBF","file":"main.f7ad3e9b.chunk.css","sourcesContent":["body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n","body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\n.App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n -webkit-align-items: center;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n#editor {\n\n}\n\n",".App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n#editor {\n\n}\n"]}

View file

@ -0,0 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{10:function(e,t,n){e.exports=n(18)},16:function(e,t,n){},17:function(e,t,n){},18:function(e,t,n){"use strict";n.r(t);var a=n(0),s=n.n(a),o=n(4),r=n.n(o),c=(n(16),n(2)),i=n(5),u=n(6),m=n(9),l=n(7),f=n(1),g=n(8),d=(n(17),function(e){function t(e){var n;Object(i.a)(this,t),(n=Object(m.a)(this,Object(l.a)(t).call(this,e))).connect=function(){var e=new WebSocket("ws://localhost:9161");e.onopen=function(t){n.setState(function(e){return Object(c.a)({},e,{message:"Connected."})}),e.send("60")},e.onclose=function(e){n.setState(function(e){return Object(c.a)({},e,{message:"Disconnected."})}),setTimeout(n.connect,1e3)},e.onmessage=function(e){if("Success!"===e.data)console.log("Success");else if("Compiling"===e.data)n.setState({message:"Compiling..."}),n.status="compiling",n.svgs=[],n.frame_count=0,n.next_frame=0;else if("Done"===e.data)n.setState({message:""}),console.log("Done"),n.start=Date.now();else if(e.data.startsWith("Error"))console.log("Error",e.data.substring(5)),n.setState({message:e.data.substring(5)});else{var t=parseInt(e.data);if(isNaN(t)){var a=document.createElement("div");a.innerHTML=e.data,n.svgs[n.next_frame]=a;var s=0;n.svgs.forEach(function(e){return s++}),console.log("Received",n.next_frame,n.frame_count,s)}else"compiling"===n.status?(n.setState({message:"Rendering..."}),n.frame_count=t,n.status="rendering",n.start=Date.now(),n.svgs=[],n.svgs[n.frame_count-1]=void 0):"rendering"===n.status?n.next_frame=t:console.log("Bad state change: received number")}},n.setState(function(t){return Object(c.a)({},t,{socket:e,message:"Connecting..."})})},n.onLoad=function(e){setTimeout(function(){e.resize()},0)},n.state={},setTimeout(n.connect,0),n.svgs=[],n.start=Date.now(),n.status="",n.frame_count=0,n.next_frame=0;var a=Object(f.a)(n);return requestAnimationFrame(function e(){var t=Date.now(),s=a.frame_count,o=a.frame_count/60,r=Math.round((t-n.start)/1e3*60)%s,c=0;if(n.svgs.forEach(function(e){return c++}),s){if(a.svgs[r]){for(n.setState({message:r+"/"+a.frame_count+" "+Math.round(c/o)+" fps"});a.svg.firstChild;)a.svg.removeChild(a.svg.firstChild);a.svg.appendChild(a.svgs[r])}}else a.svg.innerText="";requestAnimationFrame(e)}),n}return Object(g.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.state.message;return s.a.createElement("div",{className:"App"},s.a.createElement("div",{className:"viewer"},s.a.createElement("div",{ref:function(t){return e.svg=t}}),s.a.createElement("div",{className:"messages"},s.a.createElement("pre",null,t))))}}]),t}(a.Component));Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/));r.a.render(s.a.createElement(d,null),document.getElementById("root")),"serviceWorker"in navigator&&navigator.serviceWorker.ready.then(function(e){e.unregister()})}},[[10,1,2]]]);
//# sourceMappingURL=main.2d848b69.chunk.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{10:function(e,n,t){e.exports=t(18)},16:function(e,n,t){},17:function(e,n,t){},18:function(e,n,t){"use strict";t.r(n);var s=t(0),a=t.n(s),o=t(4),r=t.n(o),i=(t(16),t(2)),c=t(5),l=t(6),m=t(9),g=t(7),u=t(1),d=t(8),v=(t(17),function(e){function n(e){var t;Object(c.a)(this,n),(t=Object(m.a)(this,Object(g.a)(n).call(this,e))).connect=function(){var e=new WebSocket("ws://localhost:9161");e.onopen=function(n){t.setState(function(e){return Object(i.a)({},e,{message:"Connected."})}),e.send("60")},e.onclose=function(e){t.setState(function(e){return Object(i.a)({},e,{message:"Disconnected."})}),setTimeout(t.connect,1e3)},e.onmessage=function(e){if("Success!"===e.data)console.log("Success");else if("Compiling"===e.data)t.setState({message:"Compiling..."});else if("Rendering"===e.data)t.setState({message:"Rendering..."}),t.nFrames_new=0,t.svgs_new=[];else if("Done"===e.data)t.setState({message:""}),console.log("Done"),t.nFrames=t.nFrames_new,t.svgs=t.svgs_new,t.nFrames_new=0,t.svgs_new=[],t.start=Date.now();else if(e.data.startsWith("Error"))console.log("Error"),t.setState({message:e.data.substring(5)});else{t.setState({message:"Rendering: ".concat(t.nFrames_new)}),t.nFrames_new++;var n=document.createElement("div");n.innerHTML=e.data,t.svgs_new.push(n)}},t.setState(function(n){return Object(i.a)({},n,{socket:e,message:"Connecting..."})})},t.onLoad=function(e){setTimeout(function(){e.resize()},0)},t.state={},setTimeout(t.connect,0),t.nFrames_new=0,t.svgs_new=[],t.nFrames=0,t.svgs=[],t.start=Date.now();var s=Object(u.a)(t);return requestAnimationFrame(function e(){var n=Date.now(),a=s.nFrames,o=Math.round((n-t.start)/1e3*60)%a;if(s.svgs_new.length){for(;s.svg.firstChild;)s.svg.removeChild(s.svg.firstChild);s.svg.appendChild(s.svgs_new[s.svgs_new.length-1])}else if(a){for(;s.svg.firstChild;)s.svg.removeChild(s.svg.firstChild);s.svg.appendChild(s.svgs[o])}else s.svg.innerText="";requestAnimationFrame(e)}),t}return Object(d.a)(n,e),Object(l.a)(n,[{key:"render",value:function(){var e=this,n=this.state.message;return a.a.createElement("div",{className:"App"},a.a.createElement("div",{className:"viewer"},a.a.createElement("div",{ref:function(n){return e.svg=n}}),a.a.createElement("div",{className:"messages"},a.a.createElement("pre",null,n))))}}]),n}(s.Component));Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/));r.a.render(a.a.createElement(v,null),document.getElementById("root")),"serviceWorker"in navigator&&navigator.serviceWorker.ready.then(function(e){e.unregister()})}},[[10,1,2]]]);
//# sourceMappingURL=main.db22f45d.chunk.js.map

File diff suppressed because one or more lines are too long

View file

@ -47,7 +47,6 @@ div.messages pre {
margin-right: 2em; margin-right: 2em;
} }
#editor { #editor {
} }

View file

@ -25,27 +25,46 @@ class App extends Component {
console.log("Success"); console.log("Success");
} else if (event.data === "Compiling") { } else if (event.data === "Compiling") {
this.setState({message: "Compiling..."}); this.setState({message: "Compiling..."});
} else if (event.data === "Rendering") { this.status = 'compiling';
this.setState({message: "Rendering..."}); this.svgs = [];
this.nFrames_new = 0; this.frame_count = 0;
this.svgs_new = []; this.next_frame = 0;
} else if (event.data === "Done") { } else if (event.data === "Done") {
this.setState({message: ""}); this.setState({message: ""});
console.log("Done"); console.log("Done");
this.nFrames = this.nFrames_new;
this.svgs = this.svgs_new;
this.nFrames_new = 0;
this.svgs_new = [];
this.start = Date.now(); this.start = Date.now();
} else if (event.data.startsWith("Error")) { } else if (event.data.startsWith("Error")) {
console.log("Error"); console.log("Error", event.data.substring(5));
this.setState({message: event.data.substring(5)}); this.setState({message: event.data.substring(5)});
} else { } else {
this.setState({message: `Rendering: ${this.nFrames_new}`}); const num = parseInt(event.data);
this.nFrames_new++; if(isNaN(num)) {
const div = document.createElement('div'); // this.setState({message: `Rendering: ${this.nFrames_new}`});
div.innerHTML = event.data; // this.nFrames_new++;
this.svgs_new.push(div); // const div = document.createElement('div');
// div.innerHTML = event.data;
// this.svgs_new.push(div);
const div = document.createElement('div');
div.innerHTML = event.data;
this.svgs[this.next_frame] = div;
var count = 0;
this.svgs.forEach(_ => count++);
console.log('Received', this.next_frame, this.frame_count, count);
} else {
if( this.status === 'compiling' ) {
this.setState({message: `Rendering...`});
this.frame_count = num;
this.status = 'rendering';
this.start = Date.now();
this.svgs = [];
this.svgs[this.frame_count-1] = undefined;
} else if( this.status === 'rendering' ) {
this.next_frame = num;
} else {
console.log("Bad state change: received number");
}
}
} }
} }
this.setState(state => ({ this.setState(state => ({
@ -60,30 +79,33 @@ class App extends Component {
this.state = { this.state = {
}; };
setTimeout(this.connect, 0); setTimeout(this.connect, 0);
this.nFrames_new = 0;
this.svgs_new = [];
this.nFrames = 0;
this.svgs = []; this.svgs = [];
this.start = Date.now(); this.start = Date.now();
this.status = '';
this.frame_count = 0;
this.next_frame = 0;
const self = this; const self = this;
const animate = () => { const animate = () => {
const now = Date.now(); const now = Date.now();
const nFrames = self.nFrames; const nFrames = self.frame_count;
const aniDuration = self.frame_count/60;
const thisFrame = (Math.round((now - this.start) / 1000 * 60)) % nFrames const thisFrame = (Math.round((now - this.start) / 1000 * 60)) % nFrames
// const thisFrame = 0; console.log('Animation frame:', thisFrame, nFrames); // const thisFrame = 0; console.log('Animation frame:', thisFrame, nFrames);
if (self.svgs_new.length) { var count = 0;
while (self.svg.firstChild) this.svgs.forEach(_ => count++);
self.svg.removeChild(self.svg.firstChild); if (nFrames) {
self.svg.appendChild(self.svgs_new[self.svgs_new.length-1]); // self.svg.innerHTML = self.svgs[thisFrame];
} else { if(self.svgs[thisFrame]) {
if (nFrames) { // self.hud.innerText = '' + thisFrame + '/' + self.frame_count;
// self.svg.innerHTML = self.svgs[thisFrame]; this.setState({message: '' + thisFrame + '/' + self.frame_count + ' ' + Math.round(count/aniDuration) + ' fps'});
while (self.svg.firstChild) while (self.svg.firstChild)
self.svg.removeChild(self.svg.firstChild); self.svg.removeChild(self.svg.firstChild);
self.svg.appendChild(self.svgs[thisFrame]); self.svg.appendChild(self.svgs[thisFrame]);
} else {
self.svg.innerText = "";
} }
} else {
self.svg.innerText = "";
} }
requestAnimationFrame(animate); requestAnimationFrame(animate);
}; };