agentscript0
agentscript0 copied to clipboard
Rendering module
Not for merging! Currently just for sparking discussion.
This is the beginning of an attempt to isolate canvas/rendering logic in a single class, CanvasView
. The goal is to easily be able to swap out renderers (Canvas, CanvasTile, WebGL) of an agentscript model.
So far, the changes have all been pretty straightforward cutting/pasting Model
functions over to CanvasView
.
I left setWorld()
in Model
for the time being because it seems model-related, although a lot of the calculations it performs are specifically for rendering.
Still need to figure out how to deal with lingering references to model.contexts
:
- In
AgentSet
,show()
,hide()
show: -> o.hidden = false for o in @; @draw(@model.contexts[@name])
hide: -> o.hidden = true for o in @; @draw(@model.contexts[@name])
Should AgentSets emit 'changed' events to alert the renderer to redraw them?
And:
- In
Patches
,usePixels()
,setPixels()
,installDrawing()
usePixels: (@drawWithPixels=true) ->
ctx = @model.contexts.patches
u.setCtxSmoothing ctx, not @drawWithPixels
setPixels: ->
if @size is 1
then @usePixels(); @pixelsCtx = @model.contexts.patches
else @pixelsCtx = u.createCtx @numX, @numY
@pixelsImageData = @pixelsCtx.getImageData(0, 0, @numX, @numY)
@pixelsData = @pixelsImageData.data
if @pixelsData instanceof Uint8Array # Check for typed arrays
@pixelsData32 = new Uint32Array @pixelsData.buffer
@pixelsAreLittleEndian = u.isLittleEndian()
installDrawing: (img, [email protected]) ->
u.setIdentity ctx
ctx.drawImage img, 0, 0, ctx.canvas.width, ctx.canvas.height
ctx.restore()
Can these be made into aliases for functionality in CanvasView?
I really like the renderer idea.
I think you can remove/ignore the hide/show stunt in agentset, I don't think its used to hide/show an entire agentset anywhere. It should simply make the canvas transparent anyway, I think. Don't know why I included it.
This may have an impact on my converting patches to be entirely pixel based rather than a performance option.
My plan is to simply have an image/imagedata in Patches where the individual patch colors live. I'd remove color from individual Patch objects and when a patch color is set, it would directly set the correct pixel in the imagedata object.
This along with the idea of removing x,y from individual Patches will save a lot of space and likely be far more performant. It does depend on converting colors to pixels, but the new Color module does this, and if a color map is used, there is zero overhead to fetch the pixel.
Lets hangout, 'cause if we make this a separate module, there may be ideas/issues that come up with the patch re-design.
-- Owen
On Mon, Nov 3, 2014 at 11:48 AM, Benny Lichtner [email protected] wrote:
Not for merging! Currently just for sparking discussion.
This is the beginning of an attempt to isolate canvas/rendering logic in a single class, CanvasView. The goal is to easily be able to swap out renderers (Canvas, CanvasTile, WebGL) of an agentscript model.
So far, the changes have all been pretty straightforward cutting/pasting Model functions over to CanvasView.
I left setWorld() in Model for the time being because it seems model-related, although a lot of the calculations it performs are specifically for rendering.
Still need to figure out how to deal with lingering references to model.contexts:
- In AgentSet, show(), hide()
show: -> o.hidden = false for o in @; @draw(@model.contexts[@name]) hide: -> o.hidden = true for o in @; @draw(@model.contexts[@name])
Should AgentSets emit 'changed' events to alert the renderer to redraw them?
And:
- In Patches, usePixels(), setPixels(), installDrawing()
usePixels: (@drawWithPixels=true) -> ctx = @model.contexts.patches u.setCtxSmoothing ctx, not @drawWithPixels
setPixels: -> if @size is 1 then @usePixels(); @pixelsCtx = @model.contexts.patches else @pixelsCtx = u.createCtx @numX, @numY @pixelsImageData = @pixelsCtx.getImageData(0, 0, @numX, @numY) @pixelsData = @pixelsImageData.data if @pixelsData instanceof Uint8Array # Check for typed arrays @pixelsData32 = new Uint32Array @pixelsData.buffer @pixelsAreLittleEndian = u.isLittleEndian()
installDrawing: (img, [email protected]) -> u.setIdentity ctx ctx.drawImage img, 0, 0, ctx.canvas.width, ctx.canvas.height ctx.restore()
Can these be made into aliases for functionality in CanvasView?
You can merge this Pull Request by running
git pull https://github.com/backspaces/agentscript render-module
Or view, comment on, or merge it at:
https://github.com/backspaces/agentscript/pull/69 Commit Summary
- Simplify support for deprecated constructor
- Remove old code
- Start migrating canvas context and rendering logic to class CanvasView
- Add canvasview to gulpfile
File Changes
- M Gulpfile.js https://github.com/backspaces/agentscript/pull/69/files#diff-0 (2)
- A src/canvasview.coffee https://github.com/backspaces/agentscript/pull/69/files#diff-1 (85)
- M src/model.coffee https://github.com/backspaces/agentscript/pull/69/files#diff-2 (86)
Patch Links:
- https://github.com/backspaces/agentscript/pull/69.patch
- https://github.com/backspaces/agentscript/pull/69.diff
— Reply to this email directly or view it on GitHub https://github.com/backspaces/agentscript/pull/69.
In reply to: https://github.com/RedfishGroup/seismogram-app/pull/12#issuecomment-90251595
I think the way we currently do headless in AS is kind of a hack. I think my goal at the time was to allow AS models to run without a canvas stack while making as few changes to the codebase as possible (as opposed to making changes that were as good-for-the-future-of-AS as possible).
Ideally (?) we can do away with the headless
flag altogether; instead, the Model
constructor would accept a View
class (defaulting to the current one, CanvasView
). Then making a headless model would just be a matter of passing in a null
View (or using some parameter-alias to the same effect, maybe still going by the name headless
).
If we agree that this where we want to go, then I think the next step is to determine what to pull out of existing AS classes (probably from more than just Model
, but hopefully not much more) to move into a new View class. I think I started this process in this PR, but it's definitely not done. I'll look over what's left?
Isn't it kinda strange to pass a view into a model? Normally a model is view-agnostic.
Mmm, yeah, maybe we need to add a Controller
concept to AS, or something else that connects views and models. I keep thinking about Model
as the hub or entry point, but maybe that's a bad habit.
There are only 3 modules with the headless option:
Model: basically wrestling with the options object which we should now make standard. I've got some more ideas on that anyway. It also bypasses making the layer canvases
Animator: lots of subtle stunts if headless. This is the one I want to simplify 'cause of working on the new performance problem with Chrome. Apparently an rAF regreession. A solution is to make the Model default to "multiStep" when headless .. i.e. doing the step in a setTimeout rather than an rAF.
Patches: guards against creating a canvas used in pixel based drawing.
What to do? I'd initially attempt to limit it to Model only. That means converting to the initialization object use (a Good Thing) and "unless @isHeadless" around canvas creation, (currently is) and possibly just setting Model.draw to a no-op.
So basically treat Model as the "control center" of any MVC architecture with a no-draw option.
This definitely is not a no-canvas approach, we just use canvases all over the place.
NL has an example of this: Parameter Scanning. They run models over a range of input parameters (vision radius for flocking, for example) and collect results. During the process, they (generally) do NOT draw the agents etc .. i.e. a no-draw approach.
And, I'd be OK with tossing the headless flag with the programmer being clever enough to set up the right options, (making Model.draw a no-op) .. a step-only model.
On Mon, Apr 6, 2015 at 10:22 PM, Benny Lichtner [email protected] wrote:
Mmm, yeah, maybe we need to add a Controller concept to AS, or something else that connects views and models. I keep thinking about Model as the hub or entry point, but maybe that's a bad habit.
— Reply to this email directly or view it on GitHub https://github.com/backspaces/agentscript/pull/69#issuecomment-90354119.
..although I'd like to figure out how to keep the nifty text version of flock!
On Tue, Apr 7, 2015 at 10:49 AM, Owen Densmore [email protected] wrote:
There are only 3 modules with the headless option:
Model: basically wrestling with the options object which we should now make standard. I've got some more ideas on that anyway. It also bypasses making the layer canvases
Animator: lots of subtle stunts if headless. This is the one I want to simplify 'cause of working on the new performance problem with Chrome. Apparently an rAF regreession. A solution is to make the Model default to "multiStep" when headless .. i.e. doing the step in a setTimeout rather than an rAF.
Patches: guards against creating a canvas used in pixel based drawing.
What to do? I'd initially attempt to limit it to Model only. That means converting to the initialization object use (a Good Thing) and "unless @isHeadless" around canvas creation, (currently is) and possibly just setting Model.draw to a no-op.
So basically treat Model as the "control center" of any MVC architecture with a no-draw option.
This definitely is not a no-canvas approach, we just use canvases all over the place.
NL has an example of this: Parameter Scanning. They run models over a range of input parameters (vision radius for flocking, for example) and collect results. During the process, they (generally) do NOT draw the agents etc .. i.e. a no-draw approach.
And, I'd be OK with tossing the headless flag with the programmer being clever enough to set up the right options, (making Model.draw a no-op) .. a step-only model.
On Mon, Apr 6, 2015 at 10:22 PM, Benny Lichtner [email protected] wrote:
Mmm, yeah, maybe we need to add a Controller concept to AS, or something else that connects views and models. I keep thinking about Model as the hub or entry point, but maybe that's a bad habit.
— Reply to this email directly or view it on GitHub https://github.com/backspaces/agentscript/pull/69#issuecomment-90354119 .
BTW: the AgentSet no longer draws after show/hide .. maybe only in my current working dir but yup we wanna get rid of that.
And in the Patches case, the new color model integration suggests two: a canvas renderer (colors=css strings) and a pixel renderer (colors = pixels). This is all managed with the new colorMixin module via the color's being able to specify a type. (one of "css", "pixel", "typed") where "typed" is an RGBA typed array of 4 Uint8s, all 0-255 ints.
The stunt colorMixin does to be backwards compatible is to use defineParameter on the color which calls a setFooColor/getFooColor (foo being Label for example). Still experimental, but I got called off to resolve several other problems.
AS MVC is basically:
- AgentSet's data is the Model. This includes Patches/Agents/Links and all "breeds". The
owns(names) method should specify all the data used in all these objects but is not yet enforced. We can easily do so. I.e. Patches.own("elevation aspect water"). - View/Renderer: AgentSets also own several colors (7 in P/A/L), "shapes" for Agents, and a draw method. There are a few more (pixel's for patches, for example) but are easily separated. And all colors have a setter/getter pair that are easily moved to a renderer. Ditto for shapes which is a small, separate module, very independent. All color's are now "installed" in agentsets via a mixin so very flexible. (The colorMixin module). So the View components of AgentSets (colors, shapes) should be easily separated.
- Class Model is the "App", a blend of a classic MVC Controller along with setup/configuration. I believe this could easily be split into renderer setup (the several canvases and their info: z, 2d/3d/image/DOM), basically splitting class Model into an app organizer and a setup for renderers.
Our job, then, is to drill down a bit into how we want this architecture to appear. For example, who owns the geometry? I.e. shapes are drawn at an x,y which in turn are defined by the World object. I propose a couple of "completion/success criteria". Ex: Easily add a new layer. I propose removing spotlight and adding as a plugin. Also adding a webGL renderer for a particle layer. I'm sure we each have a few more.
I've just completed two pretty massive overhauls (color, agentsets geometry) which together touched the vast majority of AS. I feel pretty good about being able to restructure/refactor as long as we have a really clear view of what we're after. And I think it'd be fun!
How's about this:
- Finally require Model ctor to take an object rather than multiple args
- Merge into this object the defaults for each key, value pair (if not there)
- Remove isHeadless and use div === null an indicator to not draw
- Fix headlessflock if needed (it already has neither flag!). We definitely want to keep it.
This sorta clarifies things, I think. We will need a stunt to not draw when doing parameter scans etc, but lets wait 'till we implement that to worry about it.
-- Owen
On Tue, Apr 7, 2015 at 10:52 AM, Owen Densmore [email protected] wrote:
..although I'd like to figure out how to keep the nifty text version of flock!
On Tue, Apr 7, 2015 at 10:49 AM, Owen Densmore [email protected] wrote:
There are only 3 modules with the headless option:
Model: basically wrestling with the options object which we should now make standard. I've got some more ideas on that anyway. It also bypasses making the layer canvases
Animator: lots of subtle stunts if headless. This is the one I want to simplify 'cause of working on the new performance problem with Chrome. Apparently an rAF regreession. A solution is to make the Model default to "multiStep" when headless .. i.e. doing the step in a setTimeout rather than an rAF.
Patches: guards against creating a canvas used in pixel based drawing.
What to do? I'd initially attempt to limit it to Model only. That means converting to the initialization object use (a Good Thing) and "unless @isHeadless" around canvas creation, (currently is) and possibly just setting Model.draw to a no-op.
So basically treat Model as the "control center" of any MVC architecture with a no-draw option.
This definitely is not a no-canvas approach, we just use canvases all over the place.
NL has an example of this: Parameter Scanning. They run models over a range of input parameters (vision radius for flocking, for example) and collect results. During the process, they (generally) do NOT draw the agents etc .. i.e. a no-draw approach.
And, I'd be OK with tossing the headless flag with the programmer being clever enough to set up the right options, (making Model.draw a no-op) .. a step-only model.
On Mon, Apr 6, 2015 at 10:22 PM, Benny Lichtner <[email protected]
wrote:
Mmm, yeah, maybe we need to add a Controller concept to AS, or something else that connects views and models. I keep thinking about Model as the hub or entry point, but maybe that's a bad habit.
— Reply to this email directly or view it on GitHub https://github.com/backspaces/agentscript/pull/69#issuecomment-90354119 .
Cool. In response to @mariusnita then, I think it could make sense to pass a View
into our Model
, because really what we call Model
is (from Owen's post above):
the "App", a blend of a classic MVC Controller along with setup/configuration.
What Marius calls Model
is our AgentSet
, I think.
What is the requestAnimationFrame
problem you mentioned, Owen? Is it somehow slower than setTimeout
?
On Mon, Apr 13, 2015 at 10:50 AM, Benny Lichtner [email protected] wrote:
Cool. In response to @mariusnita https://github.com/mariusnita then, I think it could make sense to pass a View into our Model, because really what we call Model is (from Owen's post above):
the "App", a blend of a classic MVC Controller along with setup/configuration.
I think we need to define the "app" which orchestrates the MVC, right? So we'd refactor Model to have a manager which then glues together the MVC. I think. :)
Do we have a definition of a view for simtable etc?
I think I'll get the options w/o headless going and we can stare at that to see how to deal with app/MVC. Interesting that I'd not noticed before that MVC runs within an "app" or master that glues together the MVC architecture.
What Marius calls Model is our AgentSet, I think.
I agree.
What is the requestAnimationFrame problem you mentioned, Owen? Is it somehow slower than setTimeout?
I noticed flock and ants slowed down quite a bit lately so investigated it. I got an older version of AS and an older version of Chromium. Then using the current Chrome showed that Chromium worked fine on the older AS, but Chrome did not, had a considerable reduction in speed .. actually locked up with flock!
So I did a fairly extensive comparison of Chrome, FFox, Safari, Canary against 4 releases of AS.
I used 4 AS versions so as to see if the current one had screwed up. Nope, all showed the problem. There's a table of results in: https://code.google.com/p/chromium/issues/detail?id=468080 Bottom line: Chrome is only modern browser showing regression in speed.
I have added (for now) a trivial option to use setTimeout rather than rAF. Does not seem to help, sigh.
-- Owen