tag:blogger.com,1999:blog-91897167173292330512024-03-15T05:42:47.566+00:00CatflierDiverse research projects, coding bits and bobs.Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.comBlogger43125tag:blogger.com,1999:blog-9189716717329233051.post-38752615469522815462017-02-22T23:42:00.002+00:002017-02-22T23:42:47.935+00:00Graph Evaluation (Again)<div dir="ltr" style="text-align: left;" trbidi="on">
I did not post for a while, it doesn't means I've been doing nothing, actually quite the opposite.<div>
<br /></div>
<div>
Lately I've been reworking a bit of my graph internals (basically read, decouple some bits), and I had lot of ideas and implemented quite a few, so I decided I wanted to share some theory again.</div>
<div>
<br /></div>
<div>
First thing I already spoke about the fact that multi core evaluation is tricky to get right (basically, you need your nodes to do enough work to make it worthwhile, otherwise you gonna have serious issues or just have something slower). </div>
<div>
<br /></div>
<div>
A second thought was to eventually have a compiled form of the graph, while that's a bit of buzzword, I also believe that compiled ones will not always be faster.</div>
<div>
<br /></div>
<div>
Why? Wouldn't removing evaluation overhead make things faster?</div>
<div>
<br /></div>
<div>
Yes, but by still having access to your model, there's a serious lot of optimizations that you can perform, so answer is : not always.</div>
<div>
<br /></div>
<div>
So I'm gonna talk a bit about graph evaluation strategies. (I'll speak of data flows mostly)</div>
<div>
<br /></div>
<div>
Let's take the following simple patch, as you can see, nothing really fancy, but that will perfectly fit</div>
<div>
<br /></div>
<h2 style="text-align: left;">
1/A very basic graph</h2>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhctExM24CajRdwSB4m0vxL-EI0EIl86uEP1HGmSTSwvSGzWTUy7QpV_cTi5S7IQ21NmSHJJgm733sY8TQgv0RuXtYBJ-GFcaRyubLiFZA8vxJV1wOuzlUzf1Kyq6scJmVWBAm4MZxVksFt/s1600/grapheval.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhctExM24CajRdwSB4m0vxL-EI0EIl86uEP1HGmSTSwvSGzWTUy7QpV_cTi5S7IQ21NmSHJJgm733sY8TQgv0RuXtYBJ-GFcaRyubLiFZA8vxJV1wOuzlUzf1Kyq6scJmVWBAm4MZxVksFt/s320/grapheval.png" width="267" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3 style="text-align: left;">
A/Lazy recursion</h3>
<div>
This is by far the simplest to implement (to be honest, you can do it in less than 100 lines of code probably).</div>
<div>
<br /></div>
<div>
Pseudo code:</div>
<div>
Start with NodeFinal</div>
<div>
<br /></div>
<div>
function processnode(node)</div>
<div>
<br /></div>
<div>
if node is already processed </div>
<div>
return</div>
<div>
<br /></div>
<div>
for each input pin </div>
<div>
get upwards node (info is likely stored in a link structure)</div>
<div>
processnode (parent node connected to input pin)</div>
<div>
end for</div>
<div>
end function</div>
<div>
<br /></div>
<div>
process node (some form of update/evaluate call)</div>
<div>
mark node as processed</div>
<div>
<br /></div>
<div>
Yes, that's about it really, simple to understand and very idiomatic.</div>
<div>
<br /></div>
<div>
Now first things that we can notice:</div>
<div>
We will call processnode several times on some of them (for example, Time is used by 3 different nodes)</div>
<div>
<br /></div>
<div>
In our case (Since I did not introduce any form of "graph cutting techniques") we can also see that actually order of execution is immutable (our graph will always run and process nodes in the same order).</div>
<div>
<br /></div>
<div>
So let's optimize that</div>
<div>
<br /></div>
<div>
<br /></div>
<h3 style="text-align: left;">
B/Reversed List</h3>
<div>
Getting the above graph (i add the screenshot again):</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit2nnewoZqMhtjsQLNAOHMFvl35OmUMb2WZQoSUREISltGET3zNJoza6bjb_VIfO8-JfcXcv48mqlRTVjci7rsoz_w-RlqBFDjS7KUUBt_4uMJpTlRQ9X0kLB2DtCvDSSTWvJc864OpZfJ/s1600/grapheval.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit2nnewoZqMhtjsQLNAOHMFvl35OmUMb2WZQoSUREISltGET3zNJoza6bjb_VIfO8-JfcXcv48mqlRTVjci7rsoz_w-RlqBFDjS7KUUBt_4uMJpTlRQ9X0kLB2DtCvDSSTWvJc864OpZfJ/s320/grapheval.png" width="267" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
We can deduce our dependency order (if I consider I'll scan for pins in a left to right fashion)</div>
<div>
<br /></div>
<div>
NodeFinal -> Node12 -> Node1 -> Time -> Node2 -> Time -> Node 9 -> Node 2 -> Time -> Node 5 -> Time</div>
<div>
<br /></div>
<div>
As mentioned, we prevent to execute twice, which gives the following order:</div>
<div>
<br /></div>
<div>
NodeFinal -> Node12 -> Node1 -> Time -> Node2 -> Node 9 -> Node 5</div>
<div>
<br /></div>
<div>
Now we need to transform that into a running order, we could reverse the second list, but that will not work. </div>
<div>
<br /></div>
<div>
Why? Simply because for example Node5 needs Time to run before to be updated.</div>
<div>
<br /></div>
<div>
So let's use the first list, and reverse it:</div>
<div>
Time -> Node5 -> Time -> Node2 -> Node9 -> Time -> Node 2 ->Time -> Node 1 -> Node 12 -> NodeFinal</div>
<div>
<br /></div>
<div>
This list is correct, but replicates some elements, filtered version is :</div>
<div>
Time -> Node 5 -> Node 2 -> Node 9 -> Node 1 -> Node 12 -> Node final</div>
<div>
<br /></div>
<div>
To build the list, we perform a first lazy evaluation pass as seen upwards, but instead of calling Update, we simply add the node to a list.</div>
<div>
<br /></div>
<div>
Once we get that first list, building the reverse order is done as follows:</div>
<div>
<br /></div>
<div>
var reversedList = reverse(dependencylist)</div>
<div>
var executionList = new EmptyList</div>
<div>
foreach node in reversedList</div>
<div>
if not executionList.Contains(node) then executionList.Add(node)</div>
<div>
<br /></div>
<div>
Store that list somewhere, and then graph evaluation becomes:</div>
<div>
<div>
foreach node in executionList</div>
<div>
update(node)</div>
</div>
<div>
<br /></div>
<div>
As you can see, that removes recursion, and actually this is really easily compilable (just generate llvm/il/source code) and compile</div>
<div>
<br /></div>
<div>
Issue is of course that each time the graph changes, you need to preparse it again, which is not always advisable at runtime (the compilation step might severely hurt).</div>
</div>
<div>
<br /></div>
<div>
Now let's add some features in our graph</div>
<div>
<br /></div>
<h2 style="text-align: left;">
2/Lazy pins (and virtual links)</h2>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhCFM1u9uFbabFxlrFSK7-w_WiU2lJr-JlnswfI-Gt2_4Mt0TzsEOucz8WYJWn6IWV2xMcEWy9VXnXLGaIMMCtiLnqZ4bpgY5nlwqxy6sDSWqFalhMYv-63s5O1rOiYVS9sHA4yMyf8BDL/s1600/lazypin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhCFM1u9uFbabFxlrFSK7-w_WiU2lJr-JlnswfI-Gt2_4Mt0TzsEOucz8WYJWn6IWV2xMcEWy9VXnXLGaIMMCtiLnqZ4bpgY5nlwqxy6sDSWqFalhMYv-63s5O1rOiYVS9sHA4yMyf8BDL/s320/lazypin.png" width="289" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
Let's take the following graph.</div>
<div>
<br /></div>
<div>
Here we consider that LargeData and Generator1 nodes are really heavy, and feed some data into builder, but does not need frequent updates.</div>
<div>
<br /></div>
<div>
Builder has been built with first pin to be Lazy (eg: only build upwards if the second pin something like Apply is true (which is dealt somehow by the conditions upwards)</div>
<div>
<br /></div>
<div>
Graph is then decomposed int the following path:</div>
<div>
<br /></div>
<div>
Builder -> And -> Condition1 -> UserInput -> Condition2</div>
<div>
<br /></div>
<div>
If Second pin (eg result of and node) is true</div>
<div>
<br /></div>
<div>
LargeData -> Generator1 -> Time</div>
<div>
<br /></div>
<div>
As you can see, now our evaluation is split into 2 different parts (basically, everything non lazy, then eventually the lazy part is required)</div>
<div>
<br /></div>
<div>
This is suddenly harder to convert into list (and kinda difficult to auto compile).</div>
<div>
So suddenly the idiomatic purely lazy version above is not so bad after all. You only need to add a condition on the node to tell if you want to go upwards or not.</div>
<div>
<br /></div>
<div>
Another version is to have some form of internal link eg:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjE3b9YeBgsq_VJjqGMO-va3WnGoA4fPFAQEwRa6JBFVeWc5ZveRayWxYwFtRKoP_NQBid7G0BN-qrm-j9rGixq2MrlMcuY2nPQ5NbWRo7VEAwUI0qDrTEBv54KfJvsT2FDv-6UmfAg6R6/s1600/switch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjE3b9YeBgsq_VJjqGMO-va3WnGoA4fPFAQEwRa6JBFVeWc5ZveRayWxYwFtRKoP_NQBid7G0BN-qrm-j9rGixq2MrlMcuY2nPQ5NbWRo7VEAwUI0qDrTEBv54KfJvsT2FDv-6UmfAg6R6/s320/switch.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Here the switch node will decide (depending on SwitchValue result) to run either from Part1 or Part2</div>
<div>
<br /></div>
<div>
This can be implemented in 2 ways:</div>
<div>
Use lazy as above.</div>
<div>
<br /></div>
<div>
Rebuild the graph structure (basically if SwitchValue 0, the internal representation of the graph is like this):</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1KjA32lhKSGRJIP3n0Yb-DBpbkFr4s0GBKpu7KoR4OvwhVKwy_yf5bcBbIjUpLruSayDhpYiYtCjd7XNgedryC92qrPs8_pAG60tRWVCuuJW5X6cX1R68ZPSUBiu1N40mjcc2HdofL9hF/s1600/switchcut.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1KjA32lhKSGRJIP3n0Yb-DBpbkFr4s0GBKpu7KoR4OvwhVKwy_yf5bcBbIjUpLruSayDhpYiYtCjd7XNgedryC92qrPs8_pAG60tRWVCuuJW5X6cX1R68ZPSUBiu1N40mjcc2HdofL9hF/s320/switchcut.png" width="320" /></a></div>
<div>
<br /></div>
<div>
As you can see the user "sees" the first version of the graph, but internally the link is removed, so the Part2 node (and above) are now orphans and never run.</div>
<div>
<br /></div>
<div>
This is also really efficient, but of course if you use an optimization technique above, every time the internal representation changes (which can be every frame), you need to rebuild your structure. </div>
<div>
<br /></div>
<div>
So deciding to do so means that you need to decide if it's worth it (does the optimization technique + optimized evaluation is still faster that idiomatic version).</div>
<div>
<br /></div>
<div>
Please note those techniques are always defined on runtime (eg: at some point, some node is granted "power" to cut the graph).</div>
<div>
<br /></div>
<div>
As we have seen, they add some complexity to the evaluation part.</div>
<div>
<br /></div>
<div>
Now let's separate our usage into 2 parts : </div>
<div>
<ul style="text-align: left;">
<li>Authoring : When user is effectively building the patch</li>
<li>Runtime : When we are running</li>
</ul>
<div>
<br /></div>
</div>
<div>
In case you want to deploy your application, you will of course have effective gains by optimizing runtime performance version. </div>
<div>
<br /></div>
<div>
But in many cases we still need fast authoring, even if those are niche scenarios, I always have cases where I need to go modify something very early before a show (or actually , during the show). </div>
<div>
<br /></div>
<div>
Some people will say it's bad, but in cases where it's not avoidable (position some element properly, add a quick animation or whatever some client urgently requires) this becomes critical not to disrupt the render output too much (basically, freeze or lag).</div>
<div>
<br /></div>
<div>
So the whole key is to balance both (of course you can also provide several graph evaluation strategies, so the user can decide depending on his use case).</div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
3/Dual graph</h2>
<div>
One very easy technique to balance this part is to maintain two evaluators, one idiomatic version, and one optimized version.</div>
<div>
<br /></div>
<div>
When patch structure changes, we swap to idiomatic (since it has close to zero rebuild time), and build a new optimized version in background.</div>
<div>
<br /></div>
<div>
When optimized version is ready, switch back to it.</div>
<div>
<br /></div>
<div>
And key if you use c#, keep a reference to your old optimized evaluators somewhere, it's likely that you'll have a Gen 1/2 GC trigger, which is not desirable either,a small "memory increase instead" might be preferred.</div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
4/Determinism</h2>
<div>
Now let's introduce something interesting, since all the above was fairly basic.</div>
<div>
<br /></div>
<div>
Basically, let's consider a node as "Take some input and produce some outputs"</div>
<div>
<br /></div>
<div>
We could consider 3 cases of "output production"</div>
<div>
<ul style="text-align: left;">
<li>Deterministic : This is identical to "pure functions" in functional paradigm. Same inputs will always produce same outputs.</li>
<li>Non deterministic : This will produce varying results (for example, an animaton filter with keep previous frame result and depend on that)</li>
<li>User input, non deterministic: This is the same as above, but is a special case (for example a node that has an editable value)</li>
</ul>
<div>
So let's consider the following patch:</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNYvBCXiY1X4DcU1I23yKyZ-jsUEmcxfE5EgS_0O76P1XOt7oa7u7qmgu1VNAQC0nBN0qf7d6DmpI-z7QiHy2og8b3HI3OHsuaMPa3W-jHwQWwSP-afXV0dJXKYy7ORvkj_xoAxbXVWxL/s1600/constantbase.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNYvBCXiY1X4DcU1I23yKyZ-jsUEmcxfE5EgS_0O76P1XOt7oa7u7qmgu1VNAQC0nBN0qf7d6DmpI-z7QiHy2og8b3HI3OHsuaMPa3W-jHwQWwSP-afXV0dJXKYy7ORvkj_xoAxbXVWxL/s320/constantbase.png" width="268" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Let's say that Constant (and Constant2) nodes are immutable (basically you set the value when you create the node and you are not allowed to modify it).</div>
<div>
<br /></div>
<div>
Other operators are basic (math operators are fully deterministic).</div>
<div>
<br /></div>
<div>
This patch only needs to run once, it will always produce the same results.</div>
<div>
<br /></div>
<div>
You will of course say : I need to animate my data to show on the screen, and I agree, But I can be remotely sure that in large patches, there are a lot of sections like that.</div>
<div>
<br /></div>
<div>
You could of course use a lazy pin as specified above (below finalvalue), but we could be able to just automate this.</div>
<div>
<br /></div>
<div>
Let's take a second example:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgorlay9bacI4lDzPafKGtQ93YbcCQHpaR85Xjh2HDJ6alhilWlairgrTdn9MbLAht2qZBN-m_T0LcBbrYMcSfwOQ_4dwymcEvRuFlQR0YVvNH4ESzkJTZdc8U7sCJ-M9_c077wVOQhIZsW/s1600/timein.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgorlay9bacI4lDzPafKGtQ93YbcCQHpaR85Xjh2HDJ6alhilWlairgrTdn9MbLAht2qZBN-m_T0LcBbrYMcSfwOQ_4dwymcEvRuFlQR0YVvNH4ESzkJTZdc8U7sCJ-M9_c077wVOQhIZsW/s320/timein.png" width="253" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
In that case, only the Constant node is constant, since Time node is non deterministic, there is not much we can do, but then having:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUe3KrC00Qb7KpXPgeH5xeOXQJBtr9dt1GHdsesPukXmNREiToqSHXSEzkh7b6qVGweqY3uySWUlS43Ef-dCahHMqi7RVGaPJO299buk0VVJQC8X4YkF3__fuHEqIafyEBIwdrhAB6lpUC/s1600/splitgroup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="279" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUe3KrC00Qb7KpXPgeH5xeOXQJBtr9dt1GHdsesPukXmNREiToqSHXSEzkh7b6qVGweqY3uySWUlS43Ef-dCahHMqi7RVGaPJO299buk0VVJQC8X4YkF3__fuHEqIafyEBIwdrhAB6lpUC/s320/splitgroup.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Here we can see that all the section in gray can be ran only once and cached, it never needs to run several times.</div>
<div>
<br /></div>
<div>
If now we add user input to the mix:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9FcIlmHjIIArScy3_iaPaO-iSEbwMf_25p_9pxr_FXjSzj4L7Sre8_8JXbDGXpn14dneUZbtT6gyGrxCl1TKIyieug0NfWAMmwJmKYVhN3SfksHz-MAyV1zaowPqZ49NFMkVth5_RM1Tr/s1600/uservalue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9FcIlmHjIIArScy3_iaPaO-iSEbwMf_25p_9pxr_FXjSzj4L7Sre8_8JXbDGXpn14dneUZbtT6gyGrxCl1TKIyieug0NfWAMmwJmKYVhN3SfksHz-MAyV1zaowPqZ49NFMkVth5_RM1Tr/s320/uservalue.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Here the group on the right only changes when user input is changed, so we can also really easily cache results (as user data will not change ever so often).</div>
<div>
<br /></div>
<div>
We do not need to check for user changes manually (generally editors tend to trigger an event).</div>
<div>
<br /></div>
<div>
Pseudo code for evaluation is a tad more complex.</div>
<div>
First when graph is updated, we need to propagate some information downwards as per:</div>
<div>
<br /></div>
<div>
Walk though node recursively, check if it has a Fully non deterministic parent (or a user input based one), mark that in a flag (and in case of user input, store some reference to it).</div>
<div>
<br /></div>
<div>
void ProcessNode(node)</div>
<div>
if node has no deterministic parents, stop here (unless it's the first frame or graph has changed)</div>
<div>
if node has a fully non deterministic parent (anything that depends on Time node in our case), process it</div>
<div>
if node has one "user signal" version, check if user has changed value (some form of dirty flag), and only process it if required.</div>
<div>
<br /></div>
<div>
In our example patch, we can see that unless user is editing value, only FinalValue, +, Add, Divide and Time need to be processed, the rest can be completely ignored most of the time, and this can be automated!</div>
<div>
<br /></div>
<div>
Again, in our example, if we deploy our application, the UserValue node can automatically be changed to a constant node (since user will not have access to editor anymore). So we can also even completely remove the User input, non deterministic case, and stay with only Deterministic of not.</div>
<div>
<br /></div>
<div>
As a side note, in case of deploy, we can also even store the result values we need and just remove the nodes completely.</div>
<div>
<br /></div>
<div>
For example :</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeWDF7Hr2XwOW00-xR-xZnYBwL_qFMGydXYXdImKGRPI7jjwYp221BcGGuX9EfO0mmahWzcV0myhB_XC5DzQY3xsrRCK3hLhDlBTWK1JTwYi_iyd9IUBguYMRljgbJbY31E6u1b5U1lFp6/s1600/uservalue2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeWDF7Hr2XwOW00-xR-xZnYBwL_qFMGydXYXdImKGRPI7jjwYp221BcGGuX9EfO0mmahWzcV0myhB_XC5DzQY3xsrRCK3hLhDlBTWK1JTwYi_iyd9IUBguYMRljgbJbY31E6u1b5U1lFp6/s320/uservalue2.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Can be transformed to:</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB_Gj98O2KREzyCDDBrdj8Y9VJ_NYVtWvFadvA8PU1GJBXfwPezJLc8nMagzlj1P_jkxKojMrwkdJclc35BZKL9WYOF90CuZRmwLuXta0f55nAk96gfOd30Sn788agOIVzf3IM7km9JC-f/s1600/folded.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB_Gj98O2KREzyCDDBrdj8Y9VJ_NYVtWvFadvA8PU1GJBXfwPezJLc8nMagzlj1P_jkxKojMrwkdJclc35BZKL9WYOF90CuZRmwLuXta0f55nAk96gfOd30Sn788agOIVzf3IM7km9JC-f/s320/folded.png" width="320" /></a></div>
<div>
<br /></div>
<div>
Here we store all results that are needed (Sine and Multiplies), and don't need those processors anymore.</div>
<div>
<br /></div>
<div>
Of course, in case nodes operate on large lists, storing results can require some large files, so we can of course keep the option to keep nodes and run it only once (and replace them my constants in the graph right after).</div>
<div>
<br /></div>
<div>
<div>
<br /></div>
<div>
Where is the catch then?</div>
<div>
There is one, every node must be annotated, we need to provide metadata in order to indicate about a node Determinism, this can of course easily be achieved using some attributes (in c# example)</div>
</div>
<div>
<br /></div>
<div>
What's then important is that each node must be "curated", as a Non deterministic node marked as Non Deterministic will prevent downward optimization, opposite scenario is worse, as it will lead to incorrect results (data will not change whereas it should), but adding those is a small cost versus the reward.</div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
5/Conclusion</h2>
<div>
Compiling graphs as flattened structures can feel tempting as first sight, but graph data structure can hold a large amount of "knowledge" which is then lost, so before to decide to do so it can be interesting to take a step back and see if it's worthwhile at all (that for sure, is another debate and there will be pros and cons in each case).</div>
<div>
<br /></div>
<div>
Since this post probably feels long to digest, I'll keep the next section for later, which will include shaders in the mix, so stay tuned.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-2729784122951781262015-10-25T15:42:00.001+00:002015-10-25T15:42:54.730+00:00Intersections Part2 : Id Maps<div dir="ltr" style="text-align: left;" trbidi="on">
In the previous post, I spoke about the ability to perform hit detection using analytical functions.<br />
<br />
This works extremely well when we can restrict our use case to it, but now we have some other cases where this is not as ideal:<br />
<br />
<ul style="text-align: left;">
<li>Perform detection on arbitrary shape/3d model.</li>
<li>User input is not a pointer anymore, but can also be arbitrary (threshold camera texture, Kinect Body Index)</li>
<li>Both previous cases combined together</li>
</ul>
<div>
<br /></div>
<div>
While we can often perform detection for 3d model by using triangle raycast (I'll keep that one for next post), it can be pretty expensive (specially if we perform a 10 touch hit detection, we need to raycast 10 times).</div>
<div>
<br /></div>
<div>
So instead, one easy technique is to use ID map.</div>
<div>
<br /></div>
<div>
Concept is extremely simple, instead of performing hit with a function, we will render our scene into a UInt texture, where each pixel will be object ID.</div>
<div>
<br /></div>
<div>
Of course it means you have to render your scene another time, but in that case you can also easily use the following:</div>
<div>
<ul style="text-align: left;">
<li>Render to a downsized texture (512*512 is often sufficient)</li>
<li>Render either bounding volumes, or simplified versions of our 3d models.</li>
</ul>
<div>
Great thing with this technique, our depth buffer already makes sure that we have closest object ID stored (so we get that for "free").</div>
</div>
<div>
<br /></div>
<div>
So now we have our ID map, picking objectID from pointer is trivial:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="7" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> ObjectIDTexture<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectBuffer <span style="color: #b4b4b4;">:</span> BACKBUFFER<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">float2</span> MousePosition<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">int</span> width <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">512</span><span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">int</span> height <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">424</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> w<span style="color: #b4b4b4;">,</span>h<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> ObjectIDTexture<span style="color: #b4b4b4;">.</span>GetDimensions<span style="color: #b4b4b4;">(</span>w<span style="color: #b4b4b4;">,</span>h<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float2</span> p <span style="color: #b4b4b4;">=</span> MousePosition<span style="color: #b4b4b4;">;</span></li>
<li> p <span style="color: #b4b4b4;">=</span> p <span style="color: #b4b4b4;">*</span> <span style="color: #b5cea8;">0.5f</span> <span style="color: #b4b4b4;">+</span> <span style="color: #b5cea8;">0.5f</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> p<span style="color: #b4b4b4;">.</span>y <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">1.0f</span><span style="color: #b4b4b4;">-</span>p<span style="color: #b4b4b4;">.</span>y<span style="color: #b4b4b4;">;</span></li>
<li> p<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">*=</span> <span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">float</span><span style="color: #b4b4b4;">)</span>w<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> p<span style="color: #b4b4b4;">.</span>y <span style="color: #b4b4b4;">*=</span> <span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">float</span><span style="color: #b4b4b4;">)</span>h<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> obj <span style="color: #b4b4b4;">=</span> ObjectIDTexture<span style="color: #b4b4b4;">.</span>Load<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">int3</span><span style="color: #b4b4b4;">(</span>p<span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">));</span></li>
<li> RWObjectBuffer<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> obj<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li>}</li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
Not much more is involved, we grab the pixel id, store in a buffer that we can retrieve in staging.<br />
<br />
In case we need multiple pointer, we only need to grab N pixels instead, so process stays pretty simple (and we don't need to render scene for each pointer).<br />
<br />
<br />
Now as mentioned before, we might need to perform detection against arbitrary texture.<br />
<br />
As a starter, for simplicity, I will restrict the use case to single user texture.<br />
<br />
So first we render user into a R8_Uint texture , where 0 means no active user and anything else = active.<br />
<br />
We render our object map next in the same resolution.<br />
<br />
We create a buffer (same size as object count, uint), that will store how many user pixel hit an object pixel.<br />
<br />
Dispatch to perform this count.<br />
<br />
Use another Append buffer, that select elements over a minimum account of pixel (this is generally important to avoid noise with camera/kinect textures).<br />
<br />
Accumulating pixel hit count is done this way:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="8" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> ObjectIDTexture<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">float</span><span style="color: #b4b4b4;">></span> InputTexture<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectBuffer <span style="color: #b4b4b4;">:</span> BACKBUFFER<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">float</span> Minvalue<span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">int</span> maxObjectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">8</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">8</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> obj <span style="color: #b4b4b4;">=</span> ObjectIDTexture<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>xy<span style="color: #b4b4b4;">];</span></li>
<li> <span style="color: #569cd6;">float</span> value <span style="color: #b4b4b4;">=</span> InputTexture<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>xy<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>value <span style="color: #b4b4b4;">></span> Minvalue <span style="color: #b4b4b4;">&&</span> obj <span style="color: #b4b4b4;"><</span> maxObjectID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">uint</span> oldValue<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> InterlockedAdd<span style="color: #b4b4b4;">(</span>RWObjectBuffer<span style="color: #b4b4b4;">[</span>obj<span style="color: #b4b4b4;">],</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span>oldValue<span style="color: #b4b4b4;">);</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
Make sure you use InterlockedAdd, as you need atomic operation in that case.<br />
<br />
<br />
Next we can filter elements:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="6" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> HitCountBuffer<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">AppendStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> AppendObjectIDBuffer <span style="color: #b4b4b4;">:</span> BACKBUFFER<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">int</span> minHitCount<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> c<span style="color: #b4b4b4;">,</span>stride<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> HitCountBuffer<span style="color: #b4b4b4;">.</span>GetDimensions<span style="color: #b4b4b4;">(</span>c<span style="color: #b4b4b4;">,</span>stride<span style="color: #b4b4b4;">);</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> c<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">int</span> hitcount <span style="color: #b4b4b4;">=</span> HitCountBuffer<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">];</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>hitcount <span style="color: #b4b4b4;">>=</span> minHitCount<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> AppendObjectIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>tid<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
This is that easy, of course instead of only rendering ObjectID in the map, we can easily add some extra metadata (triangle ID, closest vertexID) for easier lookup.<br />
<br />
<br />
Now in order to perform multi user detection (for example, using Kinect2 body Index texture), process is not much different.<br />
<br />
Instead of having a buffer of ObjectCount, we create it of ObjectCount*UserCount<br />
<br />
Accumulator becomes:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="8" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> ObjectIDTexture<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> UserIDTexture<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectBuffer <span style="color: #b4b4b4;">:</span> BACKBUFFER<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">float</span> Minvalue<span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">int</span> maxObjectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">int</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">8</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">8</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> obj <span style="color: #b4b4b4;">=</span> ObjectIDTexture<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>xy<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> pid <span style="color: #b4b4b4;">=</span> UserIDTexture<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>xy<span style="color: #b4b4b4;">];</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>pid <span style="color: #b4b4b4;">!=</span> <span style="color: #b5cea8;">255</span> <span style="color: #b4b4b4;"><</span> maxObjectID<span style="color: #b4b4b4;">)</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> oldValue<span style="color: #b4b4b4;">;</span></li>
<li> InterlockedAdd<span style="color: #b4b4b4;">(</span>RWObjectBuffer<span style="color: #b4b4b4;">[</span>pid<span style="color: #b4b4b4;">*</span>objectCount<span style="color: #b4b4b4;">+</span>obj<span style="color: #b4b4b4;">],</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span>oldValue<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<br />
And filtering becomes:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="6" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> HitCountBuffer<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">AppendStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint2</span><span style="color: #b4b4b4;">></span> AppendObjectIDBuffer <span style="color: #b4b4b4;">:</span> BACKBUFFER<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">int</span> minHitCount<span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">int</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> c<span style="color: #b4b4b4;">,</span>stride<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> HitCountBuffer<span style="color: #b4b4b4;">.</span>GetDimensions<span style="color: #b4b4b4;">(</span>c<span style="color: #b4b4b4;">,</span>stride<span style="color: #b4b4b4;">);</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> c<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">int</span> hitcount <span style="color: #b4b4b4;">=</span> HitCountBuffer<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">];</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>hitcount <span style="color: #b4b4b4;">>=</span> minHitCount<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">uint2</span> result<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> result<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">=</span> tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">%</span> objectCount<span style="color: #b4b4b4;">;</span> <span style="color: #57a64a;">//objectid;</span></li>
<li> result<span style="color: #b4b4b4;">.</span>y <span style="color: #b4b4b4;">=</span> tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">/</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> AppendObjectIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>result<span style="color: #b4b4b4;">);</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
<br />
We now have a tuple userid/object id instead, as shown in the following screenshot:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6JklsCdU-sQhhBZeDqHncBrYfWK9BR7-ElnHW7fqgUdPvXjQKDy2l_bOpwEujsVug5itTRVFRdSYty0vqWXjX4ZHF73nIlDlJmmWywhdfoQKH_zkeUfbSuLVo4tFuFvizgmRtB9_9kqEQ/s1600/multiplayer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6JklsCdU-sQhhBZeDqHncBrYfWK9BR7-ElnHW7fqgUdPvXjQKDy2l_bOpwEujsVug5itTRVFRdSYty0vqWXjX4ZHF73nIlDlJmmWywhdfoQKH_zkeUfbSuLVo4tFuFvizgmRtB9_9kqEQ/s320/multiplayer.png" width="320" /></a></div>
<br />
<br />
Please also note this technique can also easily be optimized with stencil, setting a bit per user. You get then limited to 8 users tho (7 users in case you also want to reserve one bit for object itself).<br />
<br />
You will need one pass per user also (so 6 pass with proper depth stencil state/reference value).<br />
<br />
If you lucky enough and can run on Windows10/DirectX11.3, and have a card that allows you, you can also simply do :<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">Texture2D</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> BodyIndexTexture <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>t0<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">uint</span> PS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">float4</span> p <span style="color: #b4b4b4;">:</span> SV_Position<span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">:</span> SV_StencilRef</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> id <span style="color: #b4b4b4;">=</span> BodyIndexTexture<span style="color: #b4b4b4;">.</span>Load<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">int3</span><span style="color: #b4b4b4;">(</span>p<span style="color: #b4b4b4;">.</span>xy<span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">));</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>id <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">255</span><span style="color: #b4b4b4;">)</span> <span style="color: #57a64a;">//No user magic value provided by Kinect2</span></li>
<li> <span style="color: #569cd6;">discard</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span> id<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
Here is a simple stencil test rig, to show all of the intermediates:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjwtGGM2Lcy1-m6pnq1QaKwh2TRsBtDNCiwJQnsTfOl8zLgC4jCnrj6xBkUZ3ltYCT8tF_piM119NSFD8hAt-wJpVjtd8WyroCIt2Kh80adKjpcK9Wiu9QeNuE38vcSe4xyt8Hyb1y0r1H/s1600/mpst.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjwtGGM2Lcy1-m6pnq1QaKwh2TRsBtDNCiwJQnsTfOl8zLgC4jCnrj6xBkUZ3ltYCT8tF_piM119NSFD8hAt-wJpVjtd8WyroCIt2Kh80adKjpcK9Wiu9QeNuE38vcSe4xyt8Hyb1y0r1H/s320/mpst.png" width="320" /></a></div>
<br />
That's it for part 2 (that was simple no?)<br />
<br />
For the next (and last) part, I'll explain a few more advanced cases (triangle raycast, scene precull....)<br />
<br />
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com3tag:blogger.com,1999:blog-9189716717329233051.post-3261252833918904992015-10-25T15:00:00.000+00:002015-10-25T15:00:42.544+00:00Intersections Part1<div dir="ltr" style="text-align: left;" trbidi="on">
So last month been working on latest commercial project (nothing involving any extreme creative skills), so back into research mode.<br />
<div>
<br /></div>
<div>
I got plenty of new ideas for rendering, and quite some parts of my engine are undergoing some reasonable cleanup (mostly new binding model to ease dx12 transition later on).</div>
<div>
<br /></div>
<div>
There's different areas in my tool that I'm keen on improving, many new parts will be for other blog posts, but one has lately drawn my attention and I really wanted to get this one sorted.</div>
<div>
<br /></div>
<div>
As many of you know (or don't), I've been working on many interactive installations around, from small to (very) large.</div>
<div>
<br /></div>
<div>
One common requirement for those are some form of Hit Detection, you have some input device (Kinect, Camera, Mouse, Touch, Leap....), and you need to know if you hit some object in your scene in order to have those elements to react.</div>
<div>
<br /></div>
<div>
After many years in the industry, I've been developing a lot of routines in that aspect, so I thought it would be nice to have all of that as a decent library (to just pick when needed).</div>
<div>
<br /></div>
<div>
After a bit of conversation with my top coder Eric, we wanted to do a bit of feature list, what do we expect of an intersection engine, then the following came up:</div>
<div>
<ul style="text-align: left;">
<li>We have various scenarios, some routines are better fit to some use cases, so we don't want a "one mode to rule them all". For example, if our objects are near spherical, we don't want to ray cast mesh triangles, ray cast on bounding sphere is appropriate (and of course much faster).</li>
<li>We want our routines sandboxed, so 4v/flaretic subpatch, it should be one node with inputs/outputs, cooking done properly inside and optimized. That saves us load time, reduce compilation times for shaders (or allow precompiled), and easier to control workflow (if our routine is not needed it costs 0).</li>
<li>We want our library minimal, so actually hit routines should not even create data themselves, they are a better fit as pure behaviours (It also helps to have those routines working in different environments).</li>
<li>We don't want to be gpu only, if a case fits better as CPU, then we should use CPU (if preparing buffers costs more time than performing the test directly, then let's just do it directly in cpu).</li>
</ul>
<div>
<br /></div>
<div>
Next we wanted to decide which type of outputs we needed, this came out:</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>bool/int flag, which indicates if object is hit or not</li>
<li>filtered version for hit objects</li>
<li>filtered version for non hit objects</li>
</ul>
<div>
<br /></div>
</div>
<div>
Then here are the most important hit detection features we require (they cover a large part of our use cases in general)</div>
<div>
<ul style="text-align: left;">
<li>Mouse/Pointer(s) to 2d shape (in most cases we want rectangle, circle).</li>
<li>Pointer(s) to 3d object (with selectable precision, either raycast bounding volume eg sphere/box, or go at triangle level).</li>
<li>Area(s) to shapes (rectangle selection)</li>
<li>Arbitrary texture to shape (most common scenario for this is infrared camera, or kinect body index texture). In that case we also want the ability to differenciate between user id as well as object id.</li>
<li>In any 3d scenario, we also eventually want either closest object or all objects that get from the test.</li>
<li>We also have 3 general cases in 3d : Intersect (ray), Containment (is our object inside another test primitive), Proximity (is our object "close enough" to some place).</li>
</ul>
<div>
So once those requirements are set, to perform hit detection we generally have the 2 main following scenarios, you use analytical function or you use a map.</div>
<div>
<br /></div>
<div>
So let's show some examples, if that first post about it, I'll only speak about analytical functions.</div>
<div>
<br /></div>
<div>
In this case, we generally follow the usual pattern, convert our input into the desired structure (point to ray for example), and every mode follow the current pseudo code (c# version)</div>
<div>
<br /></div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="64" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">bool</span>[] hitResults <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #569cd6;">bool</span>[objectCount];</li>
<li style="background: #0c0c0c;"><span style="color: #4ec9b0;">List</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">int</span><span style="color: #b4b4b4;">></span> hitObjectList <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">List</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">int</span><span style="color: #b4b4b4;">></span>();</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">for</span> (<span style="color: #569cd6;">int</span> i <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0</span>; i <span style="color: #b4b4b4;"><</span> objectCount; i<span style="color: #b4b4b4;">++</span>)</li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">var</span> obj <span style="color: #b4b4b4;">=</span> testObjects[i];</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">bool</span> hr <span style="color: #b4b4b4;">=</span> Performtest(userObject, obj);</li>
<li> hitResults[i] <span style="color: #b4b4b4;">=</span> hr;</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">if</span> (hr)</li>
<li style="background: #0c0c0c;"> {</li>
<li> hitObjectList<span style="color: #b4b4b4;">.</span>Add(i);</li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
<div>
Pretty much all test modes will follow this pattern, only difference after is the test function.<br />
<br />
Obviously when we start to reach a certain number of elements, this can become slow. And many times, our objects might be on our GPU, so we are not gonna load them back into CPU.<br />
<br />
Translating this into hlsl is extremely straightforward, here is some pesudo code for it.<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">bool</span> PerformTest<span style="color: #b4b4b4;">(</span>SomeUserObject userInput<span style="color: #b4b4b4;">,</span> SomeStruct object<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> <span style="color: #57a64a;">//Perform your intersection/containment/proximity routine here</span></li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>SomeStruct<span style="color: #b4b4b4;">></span> ObjectBuffers <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>t0<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectHitResultBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u0<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">AppendStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> AppendObjectHitBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u1<span style="color: #b4b4b4;">);</span></li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectHitBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u1<span style="color: #b4b4b4;">);</span> <span style="color: #57a64a;">//In this case, UAV should have a counter flag</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">cbuffer</span> cbUserInput <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b0<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> SomeStruct userInput<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">cbuffer</span> cbObjectData <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b1<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li>}<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">128</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> i <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> objectCount<span style="color: #b4b4b4;">)</span></li>
<li> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">uint</span> oid <span style="color: #b4b4b4;">=</span> i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> SomeUserObject object <span style="color: #b4b4b4;">=</span> ObjectBuffers<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">bool</span> hitResult <span style="color: #b4b4b4;">=</span> PerformTest<span style="color: #b4b4b4;">(</span>userInput<span style="color: #b4b4b4;">,</span> object<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> RWObjectHitResultBuffer<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> hitResult<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>hitResult<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #57a64a;">//If we use append buffer</span></li>
<li style="background: #0c0c0c;"> AppendObjectHitBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>oid<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #57a64a;">//If we use counter buffer</span></li>
<li> <span style="color: #569cd6;">uint</span> idx <span style="color: #b4b4b4;">=</span> RWObjectHitBuffer<span style="color: #b4b4b4;">.</span>IncrementCounter<span style="color: #b4b4b4;">();</span></li>
<li style="background: #0c0c0c;"> RWObjectHitBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> oid<span style="color: #b4b4b4;">;</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
<br /></div>
<div>
As you can see there's no huge difference into that.<br />
<br />
It's pretty straightforward to perform ray to sphere/triangle/box as a starter.<br />
<br />
Rectangle selection is also extremely simple:<br />
<br />
<ul style="text-align: left;">
<li>Construct a 2d transformation for the screen area to check</li>
<li>Multiply inverse by camera projection</li>
<li>Build a frustrum from this</li>
<li>Perform a object/frustrum test insqtead of ray test.</li>
</ul>
<div>
<span id="goog_1478291015"></span><span id="goog_1478291016"></span>here is a small range test example<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVVC7t7PWkA31njDzyTIA9dYoP7TsFYJmovu6NdvgkDybmNsOx1EK9pOMXTfX6pGeiA82lPg2UoD0VZ4CPw7tJORIg0y5ytBlt-4ih7zlWYcEjWFbCBlKJwgmp-y2v2bd7_PTnETubRq59/s1600/rangehit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVVC7t7PWkA31njDzyTIA9dYoP7TsFYJmovu6NdvgkDybmNsOx1EK9pOMXTfX6pGeiA82lPg2UoD0VZ4CPw7tJORIg0y5ytBlt-4ih7zlWYcEjWFbCBlKJwgmp-y2v2bd7_PTnETubRq59/s320/rangehit.png" width="320" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
Simple no? ;)</div>
<div>
<br /></div>
<div>
Now I can foresee 2 important question that our acute reader is probably already thinking of:</div>
<div>
<ul style="text-align: left;">
<li>How do we get closest object?</li>
<li>What if we perfom several user inputs?</li>
</ul>
<div>
<br /></div>
</div>
<br />
Of course, there are solutions for that.<br />
<br />
Closest object.<br />
<br />
First we will consider that our test function is also capable of returning distance.<br />
<br />
So we modify our code by:<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">struct</span> HitResult</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> objectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> distanceToObject<span style="color: #b4b4b4;">;</span></li>
<li>}<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">bool</span> PerformTest<span style="color: #b4b4b4;">(</span>SomeUserObject userInput<span style="color: #b4b4b4;">,</span> SomeStruct object<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">float</span> distanceToObject<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> <span style="color: #57a64a;">//Perform your intersection/containment/proximity routine here</span></li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>SomeStruct<span style="color: #b4b4b4;">></span> ObjectBuffers <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>t0<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectHitResultBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u0<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">AppendStructuredBuffer</span><span style="color: #b4b4b4;"><</span>HitResult<span style="color: #b4b4b4;">></span> AppendObjectHitBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u1<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">cbuffer</span> cbUserInput <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b0<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> SomeStruct userInput<span style="color: #b4b4b4;">;</span></li>
<li>}<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">cbuffer</span> cbObjectData <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b1<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">128</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> i <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> objectCount<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> oid <span style="color: #b4b4b4;">=</span> i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> SomeUserObject object <span style="color: #b4b4b4;">=</span> ObjectBuffers<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">];</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> d<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">bool</span> hitResult <span style="color: #b4b4b4;">=</span> PerformTest<span style="color: #b4b4b4;">(</span>userInput<span style="color: #b4b4b4;">,</span> object<span style="color: #b4b4b4;">,</span> d<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> RWObjectHitResultBuffer<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> hitResult<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>hitResult<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> HitResult hr<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> hr<span style="color: #b4b4b4;">.</span>objectID <span style="color: #b4b4b4;">=</span> oid<span style="color: #b4b4b4;">;</span></li>
<li> hr<span style="color: #b4b4b4;">.</span>distanceToObject <span style="color: #b4b4b4;">=</span> d<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #57a64a;">//If we use append buffer</span></li>
<li> AppendObjectHitBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>hr<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
Now our buffer also contains our distance to object, the only leftover is to grab the closest element.<br />
<br />
We have 2 ways to work that out:<br />
<br />
<ul style="text-align: left;">
<li>Use Compute shader (Use InterlockedMin to filter closest element, since distance is generally positive there's no float to uint tricks to apply), then perform another pass to check if element distance is equal to minimum.</li>
<li>Use Pipeline ; DepthBuffer is pretty good to keep closest element, so we might as well let him do it for us ;)</li>
</ul>
<div>
Using pipeline is extremely easy as well, process is as follow:</div>
<div>
<ul style="text-align: left;">
<li>Create a 1x1 render target (uint), Associated with a 1x1 depth buffer</li>
</ul>
<div>
Prepare an indirect draw buffer (from the UAV counter), and draw as point list, write to pixel 0 in vertex, and pass distance so it's written to depth buffer, since code speaks more, here it is:<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">struct</span> HitResult</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> objectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> distanceToObject<span style="color: #b4b4b4;">;</span></li>
<li>}<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>HitResult<span style="color: #b4b4b4;">></span> ObjectHitBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u0<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">cbuffer</span> cbObjectData <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b1<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">float</span> invFarPlane<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> VS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> iv<span style="color: #b4b4b4;">:</span> SV_vertexID<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">float4</span> p <span style="color: #b4b4b4;">:</span> SV_Position<span style="color: #b4b4b4;">,</span></li>
<li> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">float</span> objDist <span style="color: #b4b4b4;">:</span> OBJECTDISTANCE<span style="color: #b4b4b4;">,</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">uint</span> objID <span style="color: #b4b4b4;">:</span> OBJECTID<span style="color: #b4b4b4;">)</span></li>
<li>{ </li>
<li style="background: #0c0c0c;"> p <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">float4</span><span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">);</span> <span style="color: #57a64a;">//We render to a 1x1 texture, position is always 0</span></li>
<li> HitResult hr <span style="color: #b4b4b4;">=</span> ObjectHitBuffer<span style="color: #b4b4b4;">[</span>iv<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> </li>
<li> objID <span style="color: #b4b4b4;">=</span> hr<span style="color: #b4b4b4;">.</span>objectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #57a64a;">//Make sure we go in 0-1 range</span></li>
<li> objDist <span style="color: #b4b4b4;">=</span> hr<span style="color: #b4b4b4;">.</span>distanceToObject <span style="color: #b4b4b4;">*</span> invFarPlane<span style="color: #b4b4b4;">;</span> </li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> PS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">float4</span> p <span style="color: #b4b4b4;">:</span> SV_Position<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> objDist <span style="color: #b4b4b4;">:</span> OBJECTDISTANCE<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">uint</span> objID <span style="color: #b4b4b4;">:</span> OBJECTID<span style="color: #b4b4b4;">,</span></li>
<li> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">uint</span> closestObjID <span style="color: #b4b4b4;">:</span> SV_Target0<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">float</span> d <span style="color: #b4b4b4;">:</span> SV_Depth<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #57a64a;">//Just push object id</span></li>
<li style="background: #0c0c0c;"> closestObjID <span style="color: #b4b4b4;">=</span> objID<span style="color: #b4b4b4;">;</span></li>
<li> d <span style="color: #b4b4b4;">=</span> objDist<span style="color: #b4b4b4;">;</span> <span style="color: #57a64a;">//Depth will preserve closest distance</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br /></div>
</div>
<div>
<br /></div>
<div>
Now our pixel contains our closest object (clear to 0xFFFFFFFF so this value will mean "no hit")<br />
<br />
To finish for this first part, let's now add the fact that we have multiple "user Inputs".<br />
<br />
We want to know the closest object per user.<br />
<br />
This is not much more complicated (but of course will cost a test for each user/object).<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">struct</span> HitResult</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> objectID<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> distanceToObject<span style="color: #b4b4b4;">;</span></li>
<li>}<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">bool</span> PerformTest<span style="color: #b4b4b4;">(</span>UserInput userInput<span style="color: #b4b4b4;">,</span> SomeStruct object<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">out</span> <span style="color: #569cd6;">float</span> distanceToObject<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> <span style="color: #57a64a;">//Perform your intersection/containment/proximity routine here</span></li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>SomeStruct<span style="color: #b4b4b4;">></span> ObjectBuffers <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>t0<span style="color: #b4b4b4;">);</span></li>
<li><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>UserInput<span style="color: #b4b4b4;">></span> UserInputBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>t1<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectHitResultBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u0<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span>HitResult<span style="color: #b4b4b4;">></span> RWObjectHitBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u1<span style="color: #b4b4b4;">);</span> <span style="color: #57a64a;">//Counter flag</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWObjectHitUserIDBuffer <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>u2<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">cbuffer</span> cbObjectData <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b0<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> objectCount<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">uint</span> userCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">128</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> objectCount<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> oid <span style="color: #b4b4b4;">=</span> tid<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> SomeUserObject object <span style="color: #b4b4b4;">=</span> ObjectBuffers<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">];</span></li>
<li> <span style="color: #569cd6;">uint</span> hitCount <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">for</span> <span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> i <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">;</span> i <span style="color: #b4b4b4;"><</span> userCount<span style="color: #b4b4b4;">;</span> i<span style="color: #b4b4b4;">++)</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> d<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">bool</span> hitResult <span style="color: #b4b4b4;">=</span> PerformTest<span style="color: #b4b4b4;">(</span>userInput<span style="color: #b4b4b4;">,</span> object<span style="color: #b4b4b4;">,</span> d<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>hitResult<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> hitCount<span style="color: #b4b4b4;">++;</span></li>
<li style="background: #0c0c0c;"> HitResult hr<span style="color: #b4b4b4;">;</span></li>
<li> hr<span style="color: #b4b4b4;">.</span>objectID <span style="color: #b4b4b4;">=</span> oid<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> hr<span style="color: #b4b4b4;">.</span>distanceToObject <span style="color: #b4b4b4;">=</span> d<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> idx <span style="color: #b4b4b4;">=</span> RWObjectHitBuffer<span style="color: #b4b4b4;">.</span>IncrementCounter<span style="color: #b4b4b4;">();</span></li>
<li> RWObjectHitBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> hr<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> RWObjectHitUserIDBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> i<span style="color: #b4b4b4;">;</span></li>
<li> }</li>
<li style="background: #0c0c0c;"> }</li>
<li> RWObjectHitResultBuffer<span style="color: #b4b4b4;">[</span>oid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> hitCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
<br />
Now we have a buffer with every hit from every user (here is a small example screenshot):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsSZgPprdUtFzduLsEMFL1yzChwsNvDMu42n_iIA4asDEbBZScKVHGAlrtNP9LsxZHJxqV5jPVBFMZv4sJD3E1ZIMg2dCgLAQzz_G2E1W5tDhguJsyln5cJIOBlxWWao-hHeOlsExBj4sg/s1600/mrhit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsSZgPprdUtFzduLsEMFL1yzChwsNvDMu42n_iIA4asDEbBZScKVHGAlrtNP9LsxZHJxqV5jPVBFMZv4sJD3E1ZIMg2dCgLAQzz_G2E1W5tDhguJsyln5cJIOBlxWWao-hHeOlsExBj4sg/s320/mrhit.png" width="320" /></a></div>
<br />
<br />
<br />
<br />
So instead of using a 1x1 texture, we use a Nx1 texture (where N is user Input count).<br />
<br />
Process to get closest element is (almost) the same as per the single input.<br />
<br />
Only difference, in Vertex Shader, route the objectID/Distance to the relevant user pixel, and you're set!<br />
<br />
<br />
That's it for first part, next round, I'll explain how the "map technique works", stay tuned.</div>
</div>
</div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-71607121142661103662015-08-12T09:56:00.002+01:002015-08-12T09:56:51.215+01:00DirectX12, First impressions<div dir="ltr" style="text-align: left;" trbidi="on">
So here we go, Windows 10 is out, and so is "officially" DirectX12 (first official samples are finally now available).<br />
<br />
Since I was not part of early access program, I could not see much samples, but setting up pipeline for tests was reasonably easy, even tho you have no idea about "best practices".<br />
I helped a bit fixing some of the remaining issues in SharpDX (and also integrated DirectX11.3 support in there on the way, welcome volume tiled resources and conservative rasterization).<br />
<br />
So way before official samples I managed to have most features I needed running, but official samples helped to finally nail down a bit the "last pieces of the puzzle" (mostly swap chain handling and descriptor heaps best practices).<br />
<br />
First thing we obviously do is to build a small utility library (to remove the boilerplate and be able to prototype fast), and then play :)<br />
<br />
So new API means changes, new approaches, new possibilities, everything that I love.<br />
<br />
As I'm generally not dealing with the "general case" (game engines with ton of assets), eg: lot of procedural geometry, tons of different effects permutations, many different scenes... I will of course speak about what it changes for those scenarios.<br />
<br />
So.... let's go<br />
<br />
<h2 style="text-align: left;">
1/Resources</h2>
<div>
Finally (and really I mean it), a resource is just a resource, eg: some place in memory, there are no restrictions anymore about binding.</div>
<div>
<br /></div>
<div>
Before in DirectX11, you could, for example, not create a resource usable both as Vertex/Index buffer and StructuredBuffer.</div>
<div>
<br /></div>
<div>
For vertex buffer it's okay (can just bind as StructuredBuffer and fetch in Vertex Shader using VertexID), but index buffer can only be bound within the pipeline, so either had to copy to byte address, or mimic Append/Counter features with ByteAddressBuffer.</div>
<div>
<br /></div>
<div>
Now I can create a resource, create an Index buffer view for it, and an append or counter structured view as well, no problem, way it should be.</div>
<div>
<br /></div>
<div>
(Note: From DirectX11.2 it was possible to do it in some ways using Tiled resources, you create 2 "empty resources" (one for index, one for structured), and allocate the same tile mapping to each of those, works but a bit hacky).</div>
<div>
<br /></div>
<div>
This is a huge step forward in my opinion, since now I can construct geometry once and seamlessly use it in pipeline or compute.</div>
<div>
<br /></div>
<h2 style="text-align: left;">
2/Heaps</h2>
<div>
As well as having resource as locations, now we have several ways to create resources. </div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Commited : this is roughly equivalent to DirectX11 style, you create a resource and the runtime allocates backing memory for it</li>
<li>Placed : Now we can create a Heap (eg: some memory), and place resources in there, so several resources can share the same heap (and even overlap, so for small temporary resources this is rather useful)</li>
<li>Reserved : Reserved resources is the Tiled resources equivalent</li>
</ul>
</div>
<div>
Heaps can also be of 3 types:</div>
<div>
<ul style="text-align: left;">
<li>Default : same as previously</li>
<li>Upload : Cpu accessible for writing</li>
<li>Readback : Cpu Accessible for reading</li>
</ul>
<div>
<br /></div>
</div>
<div>
As a side note, the way to upload resources now is totally up to you, recommended way is to allocate an upload resource, write data in there, and use a copy command to copy data to a default resources, since it's mentionned that gpu access to Upload "resources" is slower (which I actually confirmed from some benchmarks).</div>
<div>
<br /></div>
<div>
So you have pretty much full control on how you organize/load your memory (specially as you can have dedicated copy Command Queues, but that one likely for another post).</div>
<div>
<br /></div>
<h2 style="text-align: left;">
3/Queries</h2>
<div>
Queries in DirectX11 were an utter pain (and often some form of disaster waiting to happen).</div>
<div>
<br /></div>
<div>
You had to wait for some point later in the frame, loop until data is available, then get data, Stall party in brief.</div>
<div>
<br /></div>
<div>
Now queries handling is much simpler, you just create a query heap (per query type), which can also contain backing memory for several of those, then use begin/end (except time which now only uses end as it gets gpu timer)</div>
<div>
<br /></div>
<div>
Then when you need to access data, you resolve query in a resource (which can be of any type), so you can either wait for end of frame and readback or also even use that data right away (stream output to indirect draw, I was waiting for this for so long..., bye bye DrawAuto, will no miss you anytime ;)</div>
<div>
<br /></div>
<h2 style="text-align: left;">
4/Uav Counters</h2>
<div>
On the same fashion, uav counters have simply.... (drum rolls) ... disappeared.</div>
<div>
<br /></div>
<div>
Now uav counters are simply backed using a resource, which of course means that you have full read/write control over it in a cpu/gpu fashion (you can even share counter between different resources/uavs, I'm pretty sure I'll find a weird use case for it at some points)</div>
<div>
<br /></div>
<div>
Previously in DirectX11, you could only set initial count before a dispatch in Cpu, which was sometimes quite limiting (quite often just ended up using a small buffer and interlocked functions to mimic append/counter, now all can also be used seamlessly, also a Stream Output query result can now be set as an initial count for an append buffer, which is something I already see myself abusing).</div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
5/Pipeline State Objects</h2>
<div>
PSO are an obvious huge difference in how you set your pipeline.</div>
<div>
<br /></div>
<div>
Before in DirectX11, you have to set several states individually (blend/rasterizer, shaders...), which of course provided a reasonable level of flexibility (really easy to switch from solid to wireframe for example), but at the expense of a performance hit (as well as have to implement state tracking).</div>
<div>
<br /></div>
<div>
Now the whole pipeline (shaders/states/input layout, all except resource binding and render targets) is created up front and sent in a single call.</div>
<div>
<br /></div>
<div>
This offers the obvious advantage of a very big performance gain (since now the card know up front what to do and doesn't need to "reconstruct" the pipeline every draw, but pipeline states are expensive to create, so don't expect to tweak small states and have an immediate feedback (pso creation cost some tenth of milliseconds, please note they can of course be created async).</div>
<div>
<br /></div>
<div>
PSO can also be cached (hence also serialized to disk), so this can improve loading times drastically for applications in runtime mode.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
So that's it for the first overview part, there's of course many more new features and changes, but let's keep those for another post.</div>
<div>
<br /></div>
<div>
</div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-16425881216261457512015-06-15T23:16:00.002+01:002015-06-15T23:18:55.566+01:00Resource Handling with Tiled Resources in DirectX11.2<div dir="ltr" style="text-align: left;" trbidi="on">
After upgrading my particle system, the next part that needs my attention is my deferred renderer.<br />
<br />
It has all type of lights (using compute shader when possible, pixel shaders if light also has shadows), and all the standard usual suspects (HBAO, Dof, Bokeh, Tonemap...)<br />
<br />
Now I started to upgrade my shaders for the next level:<br />
<br />
<ul style="text-align: left;">
<li>Msaa support with subpixel (sample shading)</li>
<li>Allow better AO usage (AO Factor can be set as low quality or each light can have an AO factor)</li>
<li>Better organization of some calculations (to avoid them to be done twice).</li>
<li>Some other cool things ;)</li>
</ul>
<div>
Before I start to revamp the glue code to handle all this, as soon as you start to use Msaa targets (this is no news of course), your memory footprint grows quite drastically.</div>
<div>
<br /></div>
<div>
In my use case, since I'm not dealing with the usual "single level game scenario", I can also have several full HD (or more, or less) which all need to be rendered every frame and composited. </div>
<div>
I looked a bit at my memory usage, and while it's not too bad (reasonably efficient usage of pools and temporary resources), I thought I could start to have a proper think about it before to start coding ;)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
So generally when we render scenes, we have several type of resources lifetimes:</div>
<div>
<ul style="text-align: left;">
<li>"Scene lifetime" : Those are resources which live with your scene, so until you decide to unload your whole scene, those resources must live. A good example is some particle buffers, as they are read write, they need to be persisted across frames.</li>
<li>"Frame lifetime" : Those are the ones that we use for a single frame, often some intermediate results, that needs to be persisted across a sufficiently long part in the frame duration. For example, Linear Depth is quite often required for a long part in your post processing pipeline, since it's used by a decent amount of post processors.</li>
<li>"Scoped lifetime" : Those have a very short lifetime (generally within a unit of work/function call)</li>
</ul>
<div>
When I did a first memory profile test, I could see that actually a lot of my memory footprint is caused by those Scoped resources, so I decided to first focus on those.</div>
</div>
<div>
<br /></div>
<div>
So as a starter, here are my local resources for some of my post processors</div>
<div>
<ul style="text-align: left;">
<li>Depth of field: 1 target for CoC (R16f), 1 target for temp blur (4 channels, format is renderer dependent)</li>
<li>Hbao : 4 targets for AO + blur (2 are R16f, other 2 are R16G16f)</li>
<li>Bokeh : 1 buffer for sprite filtering, 1 target for overdraw (renderer dependent).</li>
</ul>
<div>
<br /></div>
</div>
<div>
Now for those short lived resources, you can handle them in the following way.</div>
<div>
<br /></div>
<div>
<br />
<ul style="text-align: left;">
<li>Create/Dispose : you create resources every time they are needed and release become to leave the function, in c# code, this would look like the traditional use pattern as:</li>
</ul>
</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="246" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">using</span> (<span style="color: #569cd6;">var</span> buffer <span style="color: #b4b4b4;">=</span> <span style="color: #4ec9b0;">DX11StructuredBuffer</span><span style="color: #b4b4b4;">.</span>CreateAppend<span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">float</span><span style="color: #b4b4b4;">></span>(device, <span style="color: #b5cea8;">1024</span>))</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #57a64a;">//Do some work</span></li>
<li style="background: #0c0c0c;"> </li>
<li>} <span style="color: #57a64a;">//Buffer is now disposed</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
While this is a natural pattern in c#, it is not designed to work well with real time graphics (resource creation is expensive, and creating / releasing gpu resources all the time is not such a good idea, memory fragmentation looming).<br />
<br />
<br />
<br />
<ul style="text-align: left;">
<li>Resource Pool : instead of creating resources all the time, to create a small wrapper around it to keep a isLocked flag. This looks this way in c#:</li>
</ul>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="252" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">var</span> buffer <span style="color: #b4b4b4;">=</span> Device<span style="color: #b4b4b4;">.</span>ResourcePool<span style="color: #b4b4b4;">.</span>LockStructuredBuffer<span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">float</span><span style="color: #b4b4b4;">></span>(<span style="color: #b5cea8;">1024</span>);</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #57a64a;">//do something with buffer : buffer.Element.ShaderView;</span></li>
<li style="background: #0c0c0c;"> </li>
<li>buffer<span style="color: #b4b4b4;">.</span>UnLock(); <span style="color: #57a64a;">// Markas free to reuse</span></li>
</ol>
</div>
</div>
</div>
<div>
<br /></div>
<br />
When we request a resource, the pool will check if a buffer with the required flags/stride is available, if this is the case, mark it as "In Use" and return it. If no buffer matching specifications is found, create and return a new one.<br />
<br />
This scheme is quite popular (I've seen this in Unity and many other code bases), has an advantage of being simple, but also has some issues.<br />
<br />
First, you need to keep a pool per resource type, eg: one for textures (of each type), one for buffers.<br />
<br />
Second, the biggest disadvantage (specially for Render Targets), we need an exact size and format.<br />
We can certainly optimize format support using Typeless resources (but you still need to create views in that case), but for size that's a no go (or at least a non practical thing), since we would often need to implement our own sampler (which is not a big deal, except for Anisotropic, but that would badly pollute our shader code base). Also we would need a bit of viewport/scissor gymnastic. Again, not that hard but really not convenient.<br />
<br />
So if you render 3 scenes, each with different resolutions, your pool starts to collect a lot of resources of different sizes, your resource lists become bigger....<br />
<br />
Of course you can clear any unused resources from time to time (eg: Dispose anything that has not been used), add a number of frames since not used and threshold that (yay, let's write a garbage collector for GPU resources, hpmf....).<br />
<br />
Nevertheless, I find that for "Frame lifetime" (and eventually a small subset of "Scene lifetime") resources, this model fits reasonably well, so I'll definitely keep it for a while (I guess DX12 Heaps will change that part, but let's keep DirectX12 for later posts ;)<br />
<br />
So now we have clearly seen the problem, for my scoped resources, if I go back to the ao->dof->bokeh case, I have to create 6 targets + one buffer (one of them can be reused, but lot of intermediates are in different formats depending on which port processing I'm currently applying)<br />
<br />
Adding a second scene with a different resolution, that's of course 12 targets.<br />
<br />
One main thing is, all this post processing is not applied at the same time (since your GPU serializes commands anyway). So all that memory could be happily shared. But we haven't got enough fine tuned access to gpu memory for this (again, resources pointing to the same locations are now trivial in dx12, but here still in dx11). So it looks like a dead end.<br />
<br />
In the mean time in the Windows 8.1 world, some great Samaritan (s) have introduced a few new features, one of them called Tiled Resources.<br />
<br />
Basically a resource created as Tiled has no initial memory, you have to map Tiles (which are 64k chunks of memory) to them. Memory tiles are provided by a buffer created with a tile pool attribute.<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="31" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #4ec9b0;">BufferDescription</span> bdPool <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BufferDescription</span>()</li>
<li style="background: #0c0c0c;">{</li>
<li> BindFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li style="background: #0c0c0c;"> CpuAccessFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">CpuAccessFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li> OptionFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceOptionFlags</span><span style="color: #b4b4b4;">.</span>TilePool,</li>
<li style="background: #0c0c0c;"> SizeInBytes <span style="color: #b4b4b4;">=</span> memSize,</li>
<li> Usage <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceUsage</span><span style="color: #b4b4b4;">.</span>Default</li>
<li style="background: #0c0c0c;">};</li>
</ol>
</div>
</div>
<br />
<br />
So you can create a huge resource with no memory, and assign tiles to some parts of it depending on your scene.<br />
<br />
This of course has a wide use for games (terrain/landscapes streaming, large shadow map rendering), and most examples follow that direction (check for sparse textures if you want documentation about those).<br />
<br />
Then I noticed in one slide (forgot if it was from NVidia or Microsoft), "Tiled resources can eventually be used for more aggressive memory packing of short lived data".<br />
<br />
There was no further explanation, but that sounds like my use case, so obviously, let's remove the "eventually" word and try it (here understand : have it working).<br />
<br />
So in that case we think about it in reverse. Instead of having a large resources backed by a pool and which is partly updated/cleared, We provide a back end, and allocate the same tiles to different resources (of course they need to belong to different unit of work, the ones that need to be used at the same time must not overlap).<br />
<br />
So let's do a first try, and create two Tiled buffers, which point to the same memory location.<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="35" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li>SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">BufferDescription</span> bd <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BufferDescription</span>()</li>
<li style="background: #0c0c0c;">{</li>
<li> BindFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>ShaderResource <span style="color: #b4b4b4;">|</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>UnorderedAccess,</li>
<li style="background: #0c0c0c;"> CpuAccessFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">CpuAccessFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li> OptionFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceOptionFlags</span><span style="color: #b4b4b4;">.</span>BufferAllowRawViews <span style="color: #b4b4b4;">|</span> <span style="color: #b8d7a3;">ResourceOptionFlags</span><span style="color: #b4b4b4;">.</span>Tiled,</li>
<li style="background: #0c0c0c;"> SizeInBytes <span style="color: #b4b4b4;">=</span> memSize,</li>
<li> Usage <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceUsage</span><span style="color: #b4b4b4;">.</span>Default,</li>
<li style="background: #0c0c0c;"> StructureByteStride <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">4</span></li>
<li>};</li>
<li style="background: #0c0c0c;"> </li>
<li>SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">BufferDescription</span> bd2 <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BufferDescription</span>()</li>
<li style="background: #0c0c0c;">{</li>
<li> BindFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>ShaderResource <span style="color: #b4b4b4;">|</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>UnorderedAccess,</li>
<li style="background: #0c0c0c;"> CpuAccessFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">CpuAccessFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li> OptionFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceOptionFlags</span><span style="color: #b4b4b4;">.</span>Tiled,</li>
<li style="background: #0c0c0c;"> SizeInBytes <span style="color: #b4b4b4;">=</span> memSize,</li>
<li> Usage <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceUsage</span><span style="color: #b4b4b4;">.</span>Default,</li>
<li style="background: #0c0c0c;"> StructureByteStride <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">4</span></li>
<li>};</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">var</span> Buffer1 <span style="color: #b4b4b4;">=</span> <span style="color: #4ec9b0;">DX11StructuredBuffer</span><span style="color: #b4b4b4;">.</span>CreateTiled<span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">int</span><span style="color: #b4b4b4;">></span>(device, elemCount);</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">var</span> Buffer2 <span style="color: #b4b4b4;">=</span> <span style="color: #4ec9b0;">DX11StructuredBuffer</span><span style="color: #b4b4b4;">.</span>CreateTiled<span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">int</span><span style="color: #b4b4b4;">></span>(device, elemCount);</li>
</ol>
</div>
</div>
<br />
Here I show the arguments of CreateTiled static constructor, for readability.<br />
<br />
And we need to provide a backend for it:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="58" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li>SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">BufferDescription</span> bdPool <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BufferDescription</span>()</li>
<li style="background: #0c0c0c;">{</li>
<li> BindFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">BindFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li style="background: #0c0c0c;"> CpuAccessFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">CpuAccessFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li> OptionFlags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceOptionFlags</span><span style="color: #b4b4b4;">.</span>TilePool,</li>
<li style="background: #0c0c0c;"> SizeInBytes <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">65536</span>,</li>
<li> Usage <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResourceUsage</span><span style="color: #b4b4b4;">.</span>Default</li>
<li style="background: #0c0c0c;">};</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">var</span> bufferPool <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span>(device, bdPool);</li>
</ol>
</div>
</div>
<br />
<br />
Now we assign the same tile(s) to each buffer like this:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="91" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">var</span> rangeFlags <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #b8d7a3;">TileRangeFlags</span>[] { <span style="color: #b8d7a3;">TileRangeFlags</span><span style="color: #b4b4b4;">.</span>None };</li>
<li style="background: #0c0c0c;">context<span style="color: #b4b4b4;">.</span>Context<span style="color: #b4b4b4;">.</span>UpdateTileMappings(resource, <span style="color: #b5cea8;">1</span>, <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">TiledResourceCoordinate</span>[] { }, <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">TileRegionSize</span>[] { }, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>tilePoolBuffer, <span style="color: #b5cea8;">1</span>, rangeFlags, <span style="color: #569cd6;">new</span> <span style="color: #569cd6;">int</span>[] { <span style="color: #b5cea8;">0</span> }, <span style="color: #569cd6;">new</span> <span style="color: #569cd6;">int</span>[] { }, <span style="color: #b8d7a3;">TileMappingFlags</span><span style="color: #b4b4b4;">.</span>None);</li>
</ol>
</div>
</div>
<br />
<br />
We do this for each buffer<br />
<br />
<br />
Next a simple test for it, create an Immutable resource, with some random data, same size as our tiled buffer (not pool)<br />
<br />
Use copy resource on either Buffer1 or Buffer2 (not both).<br />
<br />
Create two staging resources s1 and s2<br />
<br />
Readback data from buffer1 into s1 and Buffer2 into s2.<br />
<br />
Surprise, we then have data uploaded and copied from our immutable buffer in both s1 and s2.<br />
<br />
So now we have the proof of concept working, we create a small tile pool (with an inital memory allocation).<br />
<br />
Now for each post processor, we register our resources (and update tile offset accordingly to avoid overlap, we also need to eventually pad buffers/textures since our start location needs to be aligned to a full tile).<br />
<br />
Before that, we need to check if our pool is big enough, and resize if required, the beauty of it, this is not destructive (increasing pool size will allocate new Tiles but will preserve mappings of existing ones), so this is done as:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="121" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li> </li>
<li style="background: #0c0c0c;">context<span style="color: #b4b4b4;">.</span>Context<span style="color: #b4b4b4;">.</span>ResizeTilePool(<span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>tilePoolBuffer, newPageCount <span style="color: #b4b4b4;">*</span> PageSize);</li>
</ol>
</div>
</div>
<br />
<br />
And that's more or less it, now our pool size is equal to the largest unit of work instead of adding between them.<br />
<br />
It simply means, in the case above, that our pool size is the sum of the size of the largest effector (which is hbao in the example).<br />
<br />
Adding another post processing chain somewhere else will reuse that same memory for all the short lived objects, so if I start to have 5 scenes rendering that's a quite significant gain.<br />
<br />
As a side note registration looks (for now) this way:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="235" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>BeginCollect();</li>
<li style="background: #0c0c0c;"> </li>
<li>lindepth <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>PlaceRenderTarget(context, DepthTexture<span style="color: #b4b4b4;">.</span>Width, DepthTexture<span style="color: #b4b4b4;">.</span>Height, <span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>R32_Float);</li>
<li style="background: #0c0c0c;">rthbaox <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>PlaceRenderTarget(context,DepthTexture<span style="color: #b4b4b4;">.</span>Width, DepthTexture<span style="color: #b4b4b4;">.</span>Height, <span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>R16_Float);</li>
<li>rthbaoy <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>PlaceRenderTarget(context,DepthTexture<span style="color: #b4b4b4;">.</span>Width, DepthTexture<span style="color: #b4b4b4;">.</span>Height, <span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>R16G16_Float);</li>
<li style="background: #0c0c0c;">rtblurx <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>PlaceRenderTarget(context, DepthTexture<span style="color: #b4b4b4;">.</span>Width, DepthTexture<span style="color: #b4b4b4;">.</span>Height, <span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>R16G16_Float);</li>
<li>rtblury <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>PlaceRenderTarget(context, DepthTexture<span style="color: #b4b4b4;">.</span>Width, DepthTexture<span style="color: #b4b4b4;">.</span>Height, <span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>R16_Float);</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Device<span style="color: #b4b4b4;">.</span>SharedTiledPool<span style="color: #b4b4b4;">.</span>EndCollect();</li>
</ol>
</div>
</div>
<br />
<br />
Now of course I had a performance check Pool vs Pool, which ended up on a draw (so I keep the same performances, no penalty, always a good thing), and here is a small memory profiling.<br />
<br />
I render one scene in full hd + hdr, and a second scene in half hd + hdr<br />
<br />
<br />
Case 1 (old pool only):<br />
<br />
<ul style="text-align: left;">
<li>Global pool : 241 459 200</li>
<li>Tiled Pool: 0</li>
</ul>
<br />
Case 2 (starting to use shared pool):<br />
<br />
<ul style="text-align: left;">
<li>Global pool: 109 670 400</li>
<li>Tiled pool : 58 064 896</li>
<li>Total memory: 167 735 296</li>
</ul>
<div>
<br /></div>
<div>
So ok, 70 megs gain in a day where some people will say that you have 12 gigs of ram in a Titan card is meaningless, but well :</div>
<div>
<ul style="text-align: left;">
<li>Most people don't have a Titan card. (I normally plan on 4gb cards when doing projects).</li>
<li>Adding a new scene will not change the tiled pool size, and increase the global pool in a much smaller fashion.</li>
<li>If you start to add Msaa or render 3x full HD, you can expect a larger gain</li>
<li>When you start to have a few assets in the Mix (like a 2+ gigs car model, never happened to me did it? ;) a hundred meg can make a huge difference.</li>
<li>For cards that don't support tiled resources, the technique is really easily swappable, so it's not a big deal to fallback to global pool if feature is not supported (or leave the user decide).</li>
<li>I applied it quickly as a proof of concept and only on 3 effectors, now this work I can also more aggressively optimize the post processing pipeline chain in the same way (and actually also anything that needs temporary resources in my general rendering, and there's a lot).</li>
</ul>
<div>
That's it for now, as a side note, I have some other pretty cool use cases for this, they will likely end up here when I'll have implemented them.</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-11367030565592440592015-06-09T19:06:00.001+01:002015-06-09T19:06:51.354+01:00Particles revamp Part 3 : Selectors<div dir="ltr" style="text-align: left;" trbidi="on">
In the last 2 posts, I explained how I moved my particle system to have GPU managed counter and to allow regions to have better emission/behaviour control.<br />
<br />
This already offers a pretty great deal of flexibility, but then there are 2 parts that are missing:<br />
<br />
<ul style="text-align: left;">
<li>Now with regions, my valid particles can be scattered within my main buffer, that means emit count is not for the full particle system anymore, but per region.</li>
<li>Many times I want to be able to only apply behaviours to particles that satisfy a particular condition (within an area, only particles that collided at leqst once, any particle within mouse raycast....)</li>
</ul>
<div>
<br /></div>
<div>
In a funny way both problems can be solved using a similar technique... Selectors</div>
<div>
<br /></div>
<div>
So the idea is really simple, you have a predicate function (eg: anything from a particle that returns true or false), if a particle satisfies this predicate, then apply effectors, else do nothing.</div>
<div>
<br /></div>
<div>
As the amount of buffers to copy would be huge, we will do it in the most simple way eg: If a particle satisfies condition then add the particle index into a selection buffer, then create another dispatcher and only process the particles that satisfied the condition.</div>
<div>
<br /></div>
<div>
The only difference now is that behaviours must be aware that they operate either on plain buffer, or on a selection.</div>
<div>
<br /></div>
<div>
So first we need the following data:<br />
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="58" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">ByteAddressBuffer</span> SelectionCountBuffer <span style="color: #b4b4b4;">:</span> SELECTIONCOUNTBUFFER<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> SelectionIDBuffer <span style="color: #b4b4b4;">:</span> SELECTIONIDBUFFER<span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> RWSelectionIDBuffer <span style="color: #b4b4b4;">:</span> RWSELECTIONIDBUFFER<span style="color: #b4b4b4;">;</span> <span style="color: #57a64a;">//Use for deterministic selection count</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">AppendStructuredBuffer</span><span style="color: #b4b4b4;"><</span><span style="color: #569cd6;">uint</span><span style="color: #b4b4b4;">></span> AppendSelectionIDBuffer <span style="color: #b4b4b4;">:</span> APPENDSELECTIONIDBUFFER<span style="color: #b4b4b4;">;</span> <span style="color: #57a64a;">//Use for unordered selection</span></li>
</ol>
</div>
</div>
<div>
<br />
Now we use some helper function:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="151" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">void</span> AppendToSelection<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> id<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">bool</span> predicate<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>predicate<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> AppendSelectionIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>id<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<br />
Next we do a little cooking with our append buffer to generate new dispatch calls.<br />
<br />
Now one difference is that our behaviours also need to fetch data either in a linear fashion (no selector), or using that lookup table, so a couple helper functions and a few defines do a great job for this purpose:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="170" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #9b9b9b;">#if</span> PARTICLE_USE_SELECTION <span style="color: #b4b4b4;">==</span> <span style="color: #b5cea8;">1</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">uint</span> GetParticleIndex<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> tid<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span> SelectionIDBuffer<span style="color: #b4b4b4;">[</span>tid<span style="color: #b4b4b4;">];</span></li>
<li>}</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">bool</span> IsOverBounds<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> tid<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> selectionCount <span style="color: #b4b4b4;">=</span> SelectionCountBuffer<span style="color: #b4b4b4;">.</span>Load<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span> tid <span style="color: #b4b4b4;">>=</span> selectionCount<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
<li style="background: #0c0c0c;"><span style="color: #9b9b9b;">#else</span></li>
<li><span style="color: #569cd6;">uint</span> GetParticleIndex<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> tid<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> tid<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">bool</span> IsOverBounds<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> tid<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span> tid <span style="color: #b4b4b4;">>=</span> EmitCount<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
<li style="background: #0c0c0c;"><span style="color: #9b9b9b;">#endif</span></li>
</ol>
</div>
</div>
<br />
<br />
So for each behaviour, we now have 2 shaders, one to process linearly, one to process using lookup table.<br />
<br />
So now here is an example of a "Within Sphere" selector<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="3" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">float4</span> sphere <span style="color: #b4b4b4;">:</span> SPHERE<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS<span style="color: #b4b4b4;">(</span> <span style="color: #569cd6;">uint3</span> i <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID <span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>IsOverBounds<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">))</span></li>
<li> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">int</span> idx <span style="color: #b4b4b4;">=</span> GetParticleIndex<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">);</span></li>
<li> <span style="color: #569cd6;">float3</span> p <span style="color: #b4b4b4;">=</span> PositionBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> d <span style="color: #b4b4b4;">=</span> length<span style="color: #b4b4b4;">(</span>sphere<span style="color: #b4b4b4;">.</span>xyz <span style="color: #b4b4b4;">-</span> p<span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">-</span> sphere<span style="color: #b4b4b4;">.</span>w<span style="color: #b4b4b4;">;</span></li>
<li> AppendToSelection<span style="color: #b4b4b4;">(</span>idx<span style="color: #b4b4b4;">,</span> d <span style="color: #b4b4b4;"><</span> <span style="color: #b5cea8;">0.0f</span><span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
<br />
As any acute reader will notice, I'm also using the helper functions in the case of a selector, which means a selector can operate on a selection!<br />
<br />
This part means you can stack selectors (in which case you have a "AND" operator. i did not implement that yet, since it might make things overcomplex, but there is also another rationale over it.<br />
<br />
You remember that I said that now with regions my emitted particles are scattered inside the buffer, so that means any selector/global behaviour needs to operate only on emitted particles.<br />
<br />
For global elements, you can call them once per region, but if you have 20 that multiplies your Dispatches a lot.<br />
<br />
So instead, let's think simpler, we can easily for each region create a global lookup table that only contains emitted particles.<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="6" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">cbuffer</span> cbRegionInfo <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b11<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> StartRegionOffset<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> RegionElementCount<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #57a64a;">//This is called once per region</span></li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS_CopyRegionIndices<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">>=</span> EmitCount<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #57a64a;">//Get location in global buffer</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> id <span style="color: #b4b4b4;">=</span> tid<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">+</span> StartRegionOffset<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #57a64a;">//Push particle ID</span></li>
<li style="background: #0c0c0c;"> AppendSelectionIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>id<span style="color: #b4b4b4;">);</span></li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
Yes, it is that simple, we call this shader once per region (we clear Append buffer counter on first call, but preserve it on next iterations), and we have our global emission count.<br />
<br />
So now we can select from within this buffer (which contains global indices, not local ones), and perform our behaviours/display only on emitted elements.<br />
<br />
<br />
So now selectors can be owned by 2 "containers"<br />
<br />
<ul style="text-align: left;">
<li>Within the particle system: We can select particles and apply effectors</li>
<li>Outside of the particle system : So we can select particles to route them to a custom render shader.</li>
</ul>
<div>
Since my selectors don't own any buffers, but are provided contexts, this is really easy.</div>
<div>
<br /></div>
<div>
So of course in case of selectors, you can also have them within a region, or globals, as the screenshot here shows:</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz31sm9fwuVZ72sL7V6GDTpMzHslZMmHKhM7Wi1cICTBjwt8oe8QUAXLKyJerLjvjm3x0dC1C_LH73-rL-CXmMk7K_8-9KFXu1Clo5oicspbDbP3prm69BFLnDI6pRca6Hoa7j-01eNdao/s1600/selr.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz31sm9fwuVZ72sL7V6GDTpMzHslZMmHKhM7Wi1cICTBjwt8oe8QUAXLKyJerLjvjm3x0dC1C_LH73-rL-CXmMk7K_8-9KFXu1Clo5oicspbDbP3prm69BFLnDI6pRca6Hoa7j-01eNdao/s320/selr.jpg" width="320" /></a></div>
<div>
<br /></div>
<br />
You can see the Filter nodes grabs a particle selector for custom display, the Selector node can allow to select elements within the particle system, they both use the same "WithinSphere" node.<br />
<br />
<br />
So this provides a huge amount of flexibility, and still keeps pretty high performances (as stream compaction makes sure that we only operate on needed elements).<br />
<br />
But now we can also see that we operate in "Immediate mode", eg:If the particle satisfies the condition, apply, else , don't. This is done every frame.<br />
<br />
In some cases this is not ideal, we want to say: If the particle has satisfied the condition once (for example , mouse raycast), then apply the effector until we release the button.<br />
<br />
So in that case the switch is simple, as you seen previously, I the particle satisfies a condition, it is pushed into an append buffer.<br />
So now let's change the code by:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="150" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #9b9b9b;">#if</span> PARTICLE_SELECTION_RETAINED <span style="color: #b4b4b4;">==</span> <span style="color: #b5cea8;">0</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> AppendToSelection<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> id<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">bool</span> predicate<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>predicate<span style="color: #b4b4b4;">)</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> AppendSelectionIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>id<span style="color: #b4b4b4;">);</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
<li><span style="color: #9b9b9b;">#else</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> AppendToSelection<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint</span> id<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">bool</span> predicate<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>predicate<span style="color: #b4b4b4;">)</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> RWSelectionIDBuffer<span style="color: #b4b4b4;">[</span>id<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">;</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
<li><span style="color: #9b9b9b;">#endif</span></li>
</ol>
</div>
</div>
<br />
<br />
We just write in a flag in order to tell that we satisfied the condition once.<br />
<br />
Then our selector becomes:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 500px; overflow: auto;">
<ol start="7" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS_Reset<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>IsOverBounds<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">))</span></li>
<li> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">int</span> idx <span style="color: #b4b4b4;">=</span> GetParticleIndex<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> RWSelectionIDBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">;</span></li>
<li>}</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS_Append<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">uint3</span> tid <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>IsOverBounds<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">))</span></li>
<li> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">int</span> idx <span style="color: #b4b4b4;">=</span> GetParticleIndex<span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> isFlagged <span style="color: #b4b4b4;">=</span> SelectionIDBuffer<span style="color: #b4b4b4;">[</span>idx<span style="color: #b4b4b4;">];</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>isFlagged<span style="color: #b4b4b4;">)</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> AppendSelectionIDBuffer<span style="color: #b4b4b4;">.</span>Append<span style="color: #b4b4b4;">(</span>idx<span style="color: #b4b4b4;">);</span></li>
<li> }</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
So we add a second pass, which grabs every particle that has been flagged at least once (until we reset), and we now have our retained collector.<br />
<br />
Here we go, revamping this particle system was actually really fun, allowed to have a reasonable code clean up alongside improvements, and now I got a lot of new funky effectors/emitters and selectors to write ;)<br />
<br />
For the next posts, I'm not too sure yet, maybe some pipeline tricks, but there is something else coming that is much more interesting (hint for readers: read a bit of F# code, that will help you) :)<br />
<br />
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-50476238225585434572015-06-08T20:12:00.002+01:002015-06-08T20:12:43.342+01:00Particles Revamp Part2 : Regions<div dir="ltr" style="text-align: left;" trbidi="on">
So in previous post I explained how to move the count management to be managed purely in GPU.<br />
<br />
That's of course the initial prerequisite to some more interesting concepts.<br />
<br />
So now one common issue is that I need some emitters not to overlap which each other, some behaviours to only apply to some emitters, and some to apply globally.<br />
<br />
So that means I need to define locations where to emit, and also restrict some behaviours/colliders to those locations.<br />
<br />
I could of could manage some offset tables in all my compute shaders, but that means you need to change code in all of them to eventually take that into account.<br />
<br />
So for example, for a simple gravity:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="13" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> CS_Accumulate<span style="color: #b4b4b4;">(</span> <span style="color: #569cd6;">uint3</span> i <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID <span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">></span> EmitCount<span style="color: #b4b4b4;">)</span> { <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span> }</li>
<li> RWForceBuffer<span style="color: #b4b4b4;">[</span>i<span style="color: #b4b4b4;">.</span>x<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">+=</span> g<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
Is now replaced by:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="13" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">cbuffer</span> cbParticleRangeData <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b5<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">uint</span> startOffset<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>numthreads<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">64</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #569cd6;">void</span> CS_Accumulate<span style="color: #b4b4b4;">(</span> <span style="color: #569cd6;">uint3</span> i <span style="color: #b4b4b4;">:</span> SV_DispatchThreadID <span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span>i<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">></span> EmitCount<span style="color: #b4b4b4;">)</span> { <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span> }</li>
<li style="background: #0c0c0c;"> RWForceBuffer<span style="color: #b4b4b4;">[</span>i<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">+</span> startOffset<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">+=</span> g<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
</ol>
</div>
</div>
<br />
This is not a big change, but it needs to be done in every behaviour, so that takes a bit of time.<br />
<br />
Also for emitters the logic is a bit more complex, since you also need to enforce the fact that you don't span regions (eg: don't write a particle in another region location).<br />
<br />
So maybe there must be a way to be able to do that in a more elegant way....<br />
<br />
Of course there is!<br />
<br />
So first, all my particle data is stored in a ParticleDataStore, which contains all buffers, SRV and UAVs. So any particle effector can request to attach any attribute for read or write, depending on use case.<br />
<br />
Also every effector receive a dedicated context which also restricts what the effectors have access to (for example, a collider can't attach attributes for writing, except the collision buffer).<br />
<br />
So now the idea is to create a new data store, which operates on the same global buffers as the main particle system, but are only allowed in a subset of that buffer.<br />
<br />
This is easily possible in DirectX11, which allows to create views for only a part of a buffer.<br />
<br />
When we create a buffer (let's say 1024 elements), we also can create default views, which are done as this :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="118" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>device <span style="color: #b4b4b4;">=</span> device;</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ElementCount <span style="color: #b4b4b4;">=</span> elementcount;</li>
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Stride <span style="color: #b4b4b4;">=</span> stride;</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Buffer <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span>(device<span style="color: #b4b4b4;">.</span>Device, desc);</li>
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ShaderView <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ShaderResourceView</span>(device<span style="color: #b4b4b4;">.</span>Device, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Buffer);</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>BufferMode <span style="color: #b4b4b4;">=</span> buffermode;</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #4ec9b0;">UnorderedAccessViewDescription</span> uavd <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessViewDescription</span>()</li>
<li>{</li>
<li style="background: #0c0c0c;"> Format <span style="color: #b4b4b4;">=</span> SharpDX<span style="color: #b4b4b4;">.</span>DXGI<span style="color: #b4b4b4;">.</span><span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>Unknown,</li>
<li> Dimension <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">UnorderedAccessViewDimension</span><span style="color: #b4b4b4;">.</span>Buffer,</li>
<li style="background: #0c0c0c;"> Buffer <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessViewDescription</span><span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">BufferResource</span>()</li>
<li> {</li>
<li style="background: #0c0c0c;"> ElementCount <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ElementCount,</li>
<li> Flags <span style="color: #b4b4b4;">=</span> (<span style="color: #b8d7a3;">UnorderedAccessViewBufferFlags</span>)buffermode</li>
<li style="background: #0c0c0c;"> }</li>
<li>};</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>UnorderedView <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessView</span>(device<span style="color: #b4b4b4;">.</span>Device, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Buffer,uavd);</li>
</ol>
</div>
</div>
<br />
So in case of shader view, I don't pass a descriptor (which means the view is for the whole buffer).<br />
<br />
In case of UAV I pass a descriptor (since my view can also have an append/counter flag).<br />
<br />
But maybe an acute reader already noticed, there is an ElementCount parameter in the UAC descriptor, so maybe there's also a FirstElement parameter?<br />
<br />
Of course there is.<br />
<br />
So in order to operate on a subset of our buffer, we can instead do:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="26" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">public</span> DX11StructuredBufferRegion(<span style="color: #4ec9b0;">DxDevice</span> device, <span style="color: #4ec9b0;">DX11StructuredBuffer</span> parentBuffer, <span style="color: #569cd6;">int</span> StartOffset, <span style="color: #569cd6;">int</span> ElementCount)</li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Buffer <span style="color: #b4b4b4;">=</span> parentBuffer<span style="color: #b4b4b4;">.</span>Buffer;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ElementCount <span style="color: #b4b4b4;">=</span> ElementCount;</li>
<li> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>Stride <span style="color: #b4b4b4;">=</span> parentBuffer<span style="color: #b4b4b4;">.</span>Stride;</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #4ec9b0;">UnorderedAccessViewDescription</span> uavd <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessViewDescription</span>()</li>
<li style="background: #0c0c0c;"> {</li>
<li> Format <span style="color: #b4b4b4;">=</span> SharpDX<span style="color: #b4b4b4;">.</span>DXGI<span style="color: #b4b4b4;">.</span><span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>Unknown,</li>
<li style="background: #0c0c0c;"> Dimension <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">UnorderedAccessViewDimension</span><span style="color: #b4b4b4;">.</span>Buffer,</li>
<li> Buffer <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessViewDescription</span><span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">BufferResource</span>()</li>
<li style="background: #0c0c0c;"> {</li>
<li> ElementCount <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ElementCount,</li>
<li style="background: #0c0c0c;"> Flags <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">UnorderedAccessViewBufferFlags</span><span style="color: #b4b4b4;">.</span>None,</li>
<li> FirstElement <span style="color: #b4b4b4;">=</span> StartOffset</li>
<li style="background: #0c0c0c;"> }</li>
<li> };</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #4ec9b0;">ShaderResourceViewDescription</span> srvd <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ShaderResourceViewDescription</span>()</li>
<li style="background: #0c0c0c;"> {</li>
<li> Format <span style="color: #b4b4b4;">=</span> SharpDX<span style="color: #b4b4b4;">.</span>DXGI<span style="color: #b4b4b4;">.</span><span style="color: #b8d7a3;">Format</span><span style="color: #b4b4b4;">.</span>Unknown,</li>
<li style="background: #0c0c0c;"> Dimension <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ShaderResourceViewDimension</span><span style="color: #b4b4b4;">.</span>Buffer,</li>
<li> BufferEx <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ShaderResourceViewDescription</span><span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">ExtendedBufferResource</span>()</li>
<li style="background: #0c0c0c;"> {</li>
<li> ElementCount <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ElementCount,</li>
<li style="background: #0c0c0c;"> FirstElement <span style="color: #b4b4b4;">=</span> StartOffset</li>
<li> }</li>
<li style="background: #0c0c0c;"> };</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>ShaderView <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ShaderResourceView</span>(device, parentBuffer<span style="color: #b4b4b4;">.</span>Buffer, srvd);</li>
<li> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>UnorderedView <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessView</span>(device, parentBuffer<span style="color: #b4b4b4;">.</span>Buffer, uavd);</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
We keep the same buffer, but in that case we specify which locations our view are operating on.<br />
<br />
So for example, we can say:<br />
This view operates from element 512, and has 200 elements.<br />
<br />
The pretty neat thing is, now in our shader, when we say for example<br />
<br />
RWForceBuffer[0] = force;<br />
<br />
We are actually operating on element 512!<br />
<br />
Pretty neat no?<br />
<br />
So instead of adding all this crazy offset logic, we just create a new datastore (which operates on he same buffers), but that creates restricted views, and pass that to our effectors, which don't even know they operate on a subset of the data (and they should not even know it).<br />
<br />
So next part was simply to add a region handler (which can accept his own effectors), and a new Particle system which can also accept global effectors (now particle system operation with regions can't accept emitters anymore, we build regions to avoid overlap, so emitters should only be restricted).<br />
<br />
Particle system now, instead of dispatching globals, now has to apply locals pre region, then globals, little bit of extra work but nothing too hard.<br />
<br />
So now here is a small example (super basic rendering but gives the idea):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO67KiAINnb4teDC3JyAlhbogE6G7zNBk11svzi310gwqBzfKcyXmqWZCVAvY9TJgjaLdTrcH7Hhyuk9tl39ioCv1knO-k2VfWocewVI7vqC7vrqHGys7V7Fj-uZW7u_xVvq07ND9kMzgr/s1600/rc2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO67KiAINnb4teDC3JyAlhbogE6G7zNBk11svzi310gwqBzfKcyXmqWZCVAvY9TJgjaLdTrcH7Hhyuk9tl39ioCv1knO-k2VfWocewVI7vqC7vrqHGys7V7Fj-uZW7u_xVvq07ND9kMzgr/s320/rc2.jpg" width="320" /></a></div>
<br />
<br />
Here random emitter and sphere emitter both operate on a separate region (you can stil stack several emitters in the same region of course).<br />
<br />
Each one has it's own color palette, sphere emitter has damping, but random emitter doesn't.<br />
<br />
Random emitter has one extra collider.<br />
<br />
Gravity, and the 2 colliders are linked to the particle system, so they apply to all regions.<br />
<br />
As much as it is a simple example, I'm pretty sure it's easy to see the potential and the flexibility it provides, and the great thing is that I did not have to change a single line of code in my effector/behaviour/colliders shader code (life is good at times).<br />
<br />
Here we are for part 2, for the next one I'll explain another cool feature (codename: Selectors)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-32558873283578013702015-06-05T17:48:00.000+01:002015-06-05T17:54:08.762+01:00Particle revamp (Part 1)<div dir="ltr" style="text-align: left;" trbidi="on">
I did not post for a little while, been attending several events in the mean time:<br />
<ul>
<li>Kinecthack London: Worked on network Kinect stream and real time point cloud alignment</li>
<li>Revision : Did my first production in a demoparty (ranked 8th in demo category)</li>
<li>Node15: Workshops and some quick sneaky DX12 presentation (Note: I'm not part of Early Access Program, I just figured the API myself and managed to get some render system up and running fighting with drivers, so I'm not on NDA ;)</li>
</ul>
<br />
<br />
Ok all those events were great fun, I should explain some technical parts about it, will do at some point, but for now let's go into some other technical parts.<br />
<br />
<br />
I wanted to revamp my particle system for a while, at some point I was thinking maybe a scratch rewrite would be fine since it's not an insane code base, but as usual my sensible way of doing comes back and I decided to just improve and refactor, which is always a better decision ;)<br />
<br />
<br />
So I got a lot of nice features already, tons of emitters (Position, Distance Field, Texture, Mesh, Kinect2, Point clouds...), some nice interaction parts, including advanced effectors like Sph,(accelerated with spatial grids), plenty of various force fields, and collider system (mostly distance field based, after all, a plane collider is just a distance field check with a specific function).<br />
<br />
<br />
Many effectors can also be controlled via "micro curves" (which is basically a 1d texture rendered from a track in my timeline, and driven by particle age.<br />
<br />
<br />
All the simulation part is entirely manager in my GPU (compute shader), and is pretty fast so I did not feel that part needed a major rewrite (but will have improvements, that's for next post).<br />
<br />
<br />
Particle counter is basically a ring buffer, and is currently managed in CPU, which is not a big deal for effectors, but a real problem for emitters, and since now most of my machines are fully dx11.1 enabled (eg: I got access to UAV at every stage feature), this becomes quite a blocker (as it opens a lot of possibilities that I'll explain later).<br />
<br />
<br />
So I decided to revamp (here understand : improve, not rewrite) this part, but first let's explain the problem.<br />
<br />
<br />
So we have a small structure that maintains the emission counters, like:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="15" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li>[<span style="color: #4ec9b0;">StructLayout</span>(<span style="color: #b8d7a3;">LayoutKind</span><span style="color: #b4b4b4;">.</span>Sequential)]</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">public</span> <span style="color: #569cd6;">struct</span> <span style="color: #4ec9b0;">EmitData</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> EmitCount;</li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> MaxParticles;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> EmitOffset;</li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> ThisFrameCount;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> ThisFrameStartOffset;</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #4ec9b0;">Vector3</span> dummy;</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
<br />
As you see it's just an evil mutable struct (it's only used to copy to constant buffer, don't worry ;)<br />
<br />
Now emitter just implements a simple interface:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="56" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">public</span> <span style="color: #569cd6;">interface</span> <span style="color: #b8d7a3;">IParticleEmitterObject</span> : <span style="color: #b8d7a3;">IParticleEffectObject</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">int</span> Emit(<span style="color: #4ec9b0;">RenderContext</span> context, <span style="color: #4ec9b0;">ParticleSystem</span> particles);</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<br />
As you see, emitters returns how many particles they did emit, then the particle system, after each emitter has been processed, updates the counters structures no next emitter starts in the right location.<br />
<br />
This works really well for simple emitters (32 particles randomly placed), but now I also have emitters that take data from GPU.<br />
<br />
So let's take another example, emit from texture.<br />
This is done in the following steps:<br />
<br />
<ul style="text-align: left;">
<li>Create a buffer (pos+color), with an Append flag</li>
<li>Dispatch a compute shader that will go read each pixel</li>
<li>If pixel satisfies a condition (luminance for example, but can be anything else), append the pixel position + color in the Append buffer. </li>
<li>Copy buffer counter.</li>
<li>Dispatch N particles (where N is in CPU), get a random pixel that did satisfy the condition and push it to the particles buffers.</li>
</ul>
<div>
Now as you can clearly see that creates a problem, the amount of particles to emit is set in CPU, but we have no idea how many pixels did satisfy the condition. So we can have 3 edgy (and one can be nasty) cases (consider our emit count is 32)</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>We can have 20000 pixels that pass the test in frame 1, and emit 32 particles from that, int the next frame, I can emit 32 particles from a 200 pixel buffer. This means we have poor coverage control, I'd like to emit more particles if more pixels pass the test.</li>
<li>Less than 32 pixels passed the test (like 10), so some element get emitted several times.</li>
<li>Worst case of all, no pixels at all pass the test, so result can be... unpredictable.</li>
</ul>
<div>
<br /></div>
</div>
<div>
So to handle those cases, we have several options:</div>
<div>
<ul style="text-align: left;">
<li>In the compute shader emitter, if thread ID is > amount of elements that pass the test, push a "degenerate particle" (like position = float.maxvalue). This is of course ugly, needs to be repeated in every shader that take a gpu counter, but at least it works (even tho it could provide problems at simulation level).</li>
<li>Get the counter back in CPU: This is simple (just copy the counter back in a small staging buffer and read it back into cpu, then choose what you do), but it creates a stall as we need to flush and process the command buffer, and wait for it to be fully executed before to get back our 4 precious bytes. So again, not ideal.</li>
<li>Do it properly :) Move the counter data in GPU, and code to maintain that data to compute shader, and profit :)</li>
</ul>
<div>
So first thing, since counter data is in a constant buffer, let's not change all the shaders and the logic, so we use a small structured buffer which contains an exact copy of the data (so we process in structured buffer, and then use CopyResource to copy from StructuredBuffer to Constant Buffer</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="6" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #57a64a;">//Matches the cbuffer layout, so we can use copyresource</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">struct</span> sParticleEmitInfo</li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> emitCount<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">uint</span> maxParticles<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> emitOffset<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">uint</span> thisFrameCount<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> thisFrameStartOffset<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float3</span> dummy<span style="color: #b4b4b4;">;</span> <span style="color: #57a64a;">//to match cbuffer padding</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">StructuredBuffer</span><span style="color: #b4b4b4;"><</span>sParticleEmitInfo<span style="color: #b4b4b4;">></span> ParticleEmitBuffer <span style="color: #b4b4b4;">:</span> PARTICLEEMITBUFFER<span style="color: #b4b4b4;">;</span></li>
<li><span style="color: #569cd6;">RWStructuredBuffer</span><span style="color: #b4b4b4;"><</span>sParticleEmitInfo<span style="color: #b4b4b4;">></span> RWParticleEmitBuffer <span style="color: #b4b4b4;">:</span> RWPARTICLEEMITBUFFER<span style="color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
</div>
<div>
<br /></div>
Now we need to modify our emitter, so amount of particles emitted can be either provided as int (like before), or using a location in our graphics card.<br />
<br />
So for this we model a union type, I would gladly prefer that in f# but for now don't want to move all my codebase to it :)<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 400px; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 4em; padding: 0;">
<li><span style="color: #569cd6;">public</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #4ec9b0;">StaticResult</span> staticResult;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">private</span> <span style="color: #4ec9b0;">DidNotRunResult</span> didNotRunResult;</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #4ec9b0;">UnorderedAccessViewResult</span> uavResult;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">private</span> <span style="color: #4ec9b0;">BufferResult</span> bufferResult;</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #b8d7a3;">ResultType</span> resultType;</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">private</span> ParticleEmitterResult()</li>
<li style="background: #0c0c0c;"> {</li>
<li> </li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">static</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span> DidNotRun()</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #4ec9b0;">ParticleEmitterResult</span> result <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span>();</li>
<li> result<span style="color: #b4b4b4;">.</span>didNotRunResult <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">DidNotRunResult</span>();</li>
<li style="background: #0c0c0c;"> result<span style="color: #b4b4b4;">.</span>resultType <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>DidNotRun;</li>
<li> <span style="color: #569cd6;">return</span> result;</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">static</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span> Static(<span style="color: #569cd6;">uint</span> elementCount)</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #4ec9b0;">ParticleEmitterResult</span> result <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span>();</li>
<li> result<span style="color: #b4b4b4;">.</span>staticResult <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">StaticResult</span>(elementCount);</li>
<li style="background: #0c0c0c;"> result<span style="color: #b4b4b4;">.</span>resultType <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Static;</li>
<li> <span style="color: #569cd6;">return</span> result;</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">static</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span> UnorderedView(<span style="color: #4ec9b0;">UnorderedAccessView</span> view)</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">if</span> (view <span style="color: #b4b4b4;">==</span> <span style="color: #569cd6;">null</span>)</li>
<li> <span style="color: #569cd6;">throw</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ArgumentNullException</span>(<span style="color: #d69d85;">"view"</span>);</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #4ec9b0;">ParticleEmitterResult</span> result <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span>();</li>
<li style="background: #0c0c0c;"> result<span style="color: #b4b4b4;">.</span>uavResult <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">UnorderedAccessViewResult</span>(view);</li>
<li> result<span style="color: #b4b4b4;">.</span>resultType <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Uav;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">return</span> result;</li>
<li> }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">static</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span> Buffer(SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span> buffer, <span style="color: #569cd6;">int</span> offset)</li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">if</span> (buffer <span style="color: #b4b4b4;">==</span> <span style="color: #569cd6;">null</span>)</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">throw</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ArgumentNullException</span>(<span style="color: #d69d85;">"buffer"</span>);</li>
<li> <span style="color: #569cd6;">if</span> (offset <span style="color: #b4b4b4;"><</span> <span style="color: #b5cea8;">0</span>)</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">throw</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ArgumentOutOfRangeException</span>(<span style="color: #d69d85;">"offset"</span>, <span style="color: #d69d85;">"offset must be greater than 0"</span>);</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #4ec9b0;">ParticleEmitterResult</span> result <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">ParticleEmitterResult</span>();</li>
<li> result<span style="color: #b4b4b4;">.</span>bufferResult <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BufferResult</span>(buffer, offset);</li>
<li style="background: #0c0c0c;"> result<span style="color: #b4b4b4;">.</span>resultType <span style="color: #b4b4b4;">=</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Buffer;</li>
<li> <span style="color: #569cd6;">return</span> result;</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">internal</span> <span style="color: #569cd6;">void</span> Handle(<span style="color: #4ec9b0;">RenderContext</span> context, <span style="color: #b8d7a3;">IParticleEmitterResultHandler</span> handler)</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">switch</span>(<span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>resultType)</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">case</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>DidNotRun:</li>
<li> handler<span style="color: #b4b4b4;">.</span>HandleDidNotRun(context);</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">break</span>;</li>
<li> <span style="color: #569cd6;">case</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Static:</li>
<li style="background: #0c0c0c;"> handler<span style="color: #b4b4b4;">.</span>HandleStaticResult(context, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>staticResult<span style="color: #b4b4b4;">.</span>ElementCount);</li>
<li> <span style="color: #569cd6;">break</span>;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">case</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Uav:</li>
<li> handler<span style="color: #b4b4b4;">.</span>HandleUavResult(context, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>uavResult<span style="color: #b4b4b4;">.</span>UnorderedView);</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">break</span>;</li>
<li> <span style="color: #569cd6;">case</span> <span style="color: #b8d7a3;">ResultType</span><span style="color: #b4b4b4;">.</span>Buffer:</li>
<li style="background: #0c0c0c;"> handler<span style="color: #b4b4b4;">.</span>HandleBuffer(context, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>bufferResult<span style="color: #b4b4b4;">.</span>Buffer, <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>bufferResult<span style="color: #b4b4b4;">.</span>Offset);</li>
<li> <span style="color: #569cd6;">break</span>;</li>
<li style="background: #0c0c0c;"> }</li>
<li> }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">enum</span> <span style="color: #b8d7a3;">ResultType</span> { DidNotRun, Static, Uav, Buffer }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">sealed</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">DidNotRunResult</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> </li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">sealed</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">StaticResult</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">private</span> <span style="color: #569cd6;">readonly</span> <span style="color: #569cd6;">uint</span> elementCount;</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">uint</span> ElementCount</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">get</span> { <span style="color: #569cd6;">return</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>elementCount; }</li>
<li> }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> StaticResult(<span style="color: #569cd6;">uint</span> elementCount)</li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>elementCount <span style="color: #b4b4b4;">=</span> elementCount;</li>
<li style="background: #0c0c0c;"> }</li>
<li> }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">sealed</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">UnorderedAccessViewResult</span></li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #569cd6;">readonly</span> <span style="color: #4ec9b0;">UnorderedAccessView</span> view;</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> <span style="color: #4ec9b0;">UnorderedAccessView</span> UnorderedView</li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">get</span> { <span style="color: #569cd6;">return</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>view; }</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> UnorderedAccessViewResult(<span style="color: #4ec9b0;">UnorderedAccessView</span> view)</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>view <span style="color: #b4b4b4;">=</span> view;</li>
<li> }</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">sealed</span> <span style="color: #569cd6;">class</span> <span style="color: #4ec9b0;">BufferResult</span></li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">private</span> <span style="color: #569cd6;">readonly</span> SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span> buffer;</li>
<li> <span style="color: #569cd6;">private</span> <span style="color: #569cd6;">readonly</span> <span style="color: #569cd6;">int</span> offset;</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span> Buffer</li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">get</span> { <span style="color: #569cd6;">return</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>buffer; }</li>
<li style="background: #0c0c0c;"> }</li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">public</span> <span style="color: #569cd6;">int</span> Offset</li>
<li> {</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">get</span> { <span style="color: #569cd6;">return</span> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>offset; }</li>
<li> }</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">public</span> BufferResult(SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span> buffer, <span style="color: #569cd6;">int</span> offset)</li>
<li style="background: #0c0c0c;"> {</li>
<li> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>buffer <span style="color: #b4b4b4;">=</span> buffer;</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">this</span><span style="color: #b4b4b4;">.</span>offset <span style="color: #b4b4b4;">=</span> offset;</li>
<li> }</li>
<li style="background: #0c0c0c;"> }</li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
This is a bit cumbersome, but well it's pretty safe to use.<br />
As a side note in f# this would look like this:<br />
<br />
<div style="border-image: none; border: 1px solid rgb(0, 0, 128); color: black; font-family: Consolas, "Courier New", Courier, Monospace; font-size: 10pt; text-align: left;">
<div style="background: rgb(0, 0, 128); color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="3" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">open</span> SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11</li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">open</span> System</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">type</span> ParticleSystemArgs(maxElements<span style="color: #b4b4b4;">:</span>int) <span style="color: #b4b4b4;">=</span></li>
<li> <span style="color: #569cd6;">member</span> x<span style="color: #b4b4b4;">.</span>maxElements <span style="color: #b4b4b4;">=</span> maxElements</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">type</span> StaticEmitResult(elementCount<span style="color: #b4b4b4;">:</span>int) <span style="color: #b4b4b4;">=</span> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">member</span> x<span style="color: #b4b4b4;">.</span>elementCount <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">if</span> elementCount <span style="color: #b4b4b4;"><</span> <span style="color: #b5cea8;">0</span> <span style="color: #569cd6;">then</span> raise(ArgumentOutOfRangeException(<span style="color: #d69d85;">"elementCount"</span>,<span style="color: #d69d85;">"Muse be greater or equalthan 0"</span>)) <span style="color: #569cd6;">else</span> elementCount</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">type</span> EmitUnorderedViewResult(view<span style="color: #b4b4b4;">:</span>UnorderedAccessView) <span style="color: #b4b4b4;">=</span></li>
<li> <span style="color: #569cd6;">member</span> x<span style="color: #b4b4b4;">.</span>view <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">if</span> view <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">null</span> <span style="color: #569cd6;">then</span> raise(ArgumentNullException(<span style="color: #d69d85;">"view"</span>)) <span style="color: #569cd6;">else</span> view</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">type</span> EmitBufferResult(buffer<span style="color: #b4b4b4;">:</span>Buffer,offset<span style="color: #b4b4b4;">:</span>int) <span style="color: #b4b4b4;">=</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">member</span> x<span style="color: #b4b4b4;">.</span>buffer <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">if</span> buffer <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">null</span> <span style="color: #569cd6;">then</span> raise(ArgumentNullException(<span style="color: #d69d85;">"buffer"</span>)) <span style="color: #569cd6;">else</span> buffer</li>
<li> <span style="color: #569cd6;">member</span> x<span style="color: #b4b4b4;">.</span>offset <span style="color: #b4b4b4;">=</span> <span style="color: #569cd6;">if</span> offset <span style="color: #b4b4b4;"><</span> <span style="color: #b5cea8;">0</span> <span style="color: #569cd6;">then</span> raise(ArgumentOutOfRangeException(<span style="color: #d69d85;">"offset"</span>,<span style="color: #d69d85;">"Offset should be greater or equal than 0"</span>)) <span style="color: #569cd6;">else</span> offset</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">type</span> ParticleEmitResult <span style="color: #b4b4b4;">=</span></li>
<li style="background: #0c0c0c;"> | DidNotEmit <span style="color: #569cd6;">of</span> unit</li>
<li> | StaticResult <span style="color: #569cd6;">of</span> StaticEmitResult</li>
<li style="background: #0c0c0c;"> | UavResult <span style="color: #569cd6;">of</span> EmitUnorderedViewResult</li>
<li> | BufferResult <span style="color: #569cd6;">of</span> EmitBufferResult</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">type</span> IParticleEmitter <span style="color: #b4b4b4;">=</span></li>
<li style="background: #0c0c0c;"> <span style="color: #57a64a;">// abstract method</span></li>
<li> <span style="color: #569cd6;">abstract</span> <span style="color: #569cd6;">member</span> Emit<span style="color: #b4b4b4;">:</span> ParticleSystemArgs <span style="color: #569cd6;">-></span> ParticleEmitResult</li>
<li style="background: #0c0c0c;"> </li>
<li><span style="color: #569cd6;">type</span> IParticleEmitHandler <span style="color: #b4b4b4;">=</span> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">abstract</span> <span style="color: #569cd6;">member</span> HandleNoEmit <span style="color: #b4b4b4;">:</span> unit <span style="color: #569cd6;">-></span> unit</li>
<li> <span style="color: #569cd6;">abstract</span> <span style="color: #569cd6;">member</span> HandleStatic <span style="color: #b4b4b4;">:</span> int <span style="color: #569cd6;">-></span> unit</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">abstract</span> <span style="color: #569cd6;">member</span> HandleUav <span style="color: #b4b4b4;">:</span> UnorderedAccessView <span style="color: #569cd6;">-></span> unit</li>
<li> <span style="color: #569cd6;">abstract</span> <span style="color: #569cd6;">member</span> HandleBuffer <span style="color: #b4b4b4;">:</span> EmitBufferResult <span style="color: #569cd6;">-></span> unit</li>
<li style="background: #0c0c0c;"> </li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">module</span> ParticleFunctions <span style="color: #b4b4b4;">=</span> </li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">let</span> ApplyHandler (x<span style="color: #b4b4b4;">:</span>ParticleEmitResult, handler<span style="color: #b4b4b4;">:</span> IParticleEmitHandler)<span style="color: #b4b4b4;">=</span> </li>
<li> <span style="color: #569cd6;">match</span> x <span style="color: #569cd6;">with</span></li>
<li style="background: #0c0c0c;"> | DidNotEmit d <span style="color: #569cd6;">-></span> handler<span style="color: #b4b4b4;">.</span>HandleNoEmit()</li>
<li> | StaticResult sr <span style="color: #569cd6;">-></span> handler<span style="color: #b4b4b4;">.</span>HandleStatic(sr<span style="color: #b4b4b4;">.</span>elementCount)</li>
<li style="background: #0c0c0c;"> | UavResult ur <span style="color: #569cd6;">-></span> handler<span style="color: #b4b4b4;">.</span>HandleUav(ur<span style="color: #b4b4b4;">.</span>view)</li>
<li> | BufferResult br <span style="color: #569cd6;">-></span> handler<span style="color: #b4b4b4;">.</span>HandleBuffer(br)</li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">let</span> DoEmit(emitter<span style="color: #b4b4b4;">:</span>IParticleEmitter,args<span style="color: #b4b4b4;">:</span>ParticleSystemArgs, handler <span style="color: #b4b4b4;">:</span> IParticleEmitHandler) <span style="color: #b4b4b4;">=</span></li>
<li style="background: #0c0c0c;"> ApplyHandler(emitter<span style="color: #b4b4b4;">.</span>Emit(args), handler)</li>
</ol>
</div>
</div>
</div>
</div>
Much more concise and the pattern matching is much safer in there, but whatever :)<br />
<br />
<div style="border-image: none; border: 1px solid rgb(0, 0, 128); color: black; font-family: Consolas, "Courier New", Courier, Monospace; font-size: 10pt;">
<div style="background: rgb(0, 0, 128); color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="56" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">public</span> <span style="color: #569cd6;">interface</span> <span style="color: #b8d7a3;">IParticleEmitterObject</span> : <span style="color: #b8d7a3;">IParticleEffectObject</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #4ec9b0;">ParticleEmitterResult</span> Emit(<span style="color: #4ec9b0;">RenderContext</span> context, <span style="color: #4ec9b0;">ParticleSystem</span> particles);</li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
</div>
<div style="border-image: none; border: 1px solid rgb(0, 0, 128); color: black; font-family: Consolas, "Courier New", Courier, Monospace; font-size: 10pt;">
<br />
<br />
Pretty simple, now we can return different data types that can contain data.<br />
<br />
And now we have another interface to handle result, as :<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">public</span> <span style="color: #569cd6;">interface</span> <span style="color: #b8d7a3;">IParticleEmitterResultHandler</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">void</span> HandleDidNotRun(<span style="color: #4ec9b0;">RenderContext</span> context);</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">void</span> HandleStaticResult(<span style="color: #4ec9b0;">RenderContext</span> context, <span style="color: #569cd6;">uint</span> elementCount);</li>
<li> <span style="color: #569cd6;">void</span> HandleUavResult(<span style="color: #4ec9b0;">RenderContext</span> context, <span style="color: #4ec9b0;">UnorderedAccessView</span> uav);</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">void</span> HandleBuffer(<span style="color: #4ec9b0;">RenderContext</span> context, SharpDX<span style="color: #b4b4b4;">.</span>Direct3D11<span style="color: #b4b4b4;">.</span><span style="color: #4ec9b0;">Buffer</span> buffer, <span style="color: #569cd6;">int</span> offset);</li>
<li>}</li>
</ol>
</div>
</div>
<br />
<br />
As you can see, there's 4 cases, let's first explain those:<br />
<br />
<ul style="text-align: left;">
<li>Did not run: Emitter did not run at all, I decided to have it as a case instead of returning 0 (so you can also explain why it did not run.</li>
<li>Static : This is the same case as our previous cases</li>
<li>UnorderedView : Counter is located in UAV, which is the case we we use Emit/Counter buffers to push particles. So for example if we want to emit every pixel that did pass the test in our previous case, we do an indirect dispatch and return the view (which contains the counter)</li>
<li>Buffer : This is in a GPU buffer (we also need to provide location in that case). This is very useful for coverage based emitters (for example, we could say, emit 50% of the elements that passed the test every frame, in that case we need to process the counter in a small compute shader to generate a custom dispatch call).</li>
</ul>
<div>
So from there, we can easily update our structured buffer above (using compute shader, but actually kept the readback version for debug purposes)</div>
<div>
<br /></div>
<div>
Now the only small difference is when processing effectors, we don't know the particle count anymore, so instead of using Dispatch we use DispatchIndirect (which is trivial to implement), and use Indirect buffers for drawing as well so, DrawIndirect to draw as sprite, and DrawIndexedInstancedIndirect to render particles as geometry.</div>
<div>
<br /></div>
<div>
So here we go, from there we have a fully fledged counter system in our graphics card, which also mean, for any type of emitters where we want to push every element that pass the test, we can now do it in a single pass (no more need for intermediate buffer, use a CounterBuffer or use InterlockedAdd).</div>
<div>
<br /></div>
<div>
And now since got access to UAV at every stage, it's possible to load balance using tessellation/domain shader</div>
<div>
<br /></div>
<div>
Here is an example of an hybrid particle emitter (which doesn't draw anything on screen but just push adaptive amount of particles depending on triangle size)</div>
<div>
<br /></div>
<div>
Declaration:<br />
<br /></div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="20" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #569cd6;">cbuffer</span> cbemitParams <span style="color: #b4b4b4;">:</span> <span style="color: #569cd6;">register</span><span style="color: #b4b4b4;">(</span>b0<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">float</span> MinSize <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0.1f</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> MaxSize <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">20.0f</span><span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float</span> MinimumTessel <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">1.0f</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> MaximumTessel <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">12.0f</span><span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float</span> VelocityScale <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">1.0f</span><span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">struct</span> vsInput</li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float3</span> p <span style="color: #b4b4b4;">:</span> POSITION<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float3</span> n <span style="color: #b4b4b4;">:</span> NORMAL<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">struct</span> hsConstOutput</li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> edges<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">3</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">:</span> SV_TessFactor<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float</span> inside<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">:</span> SV_InsideTessFactor<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}<span style="color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Our hardcore vertex and hull shaders:<br />
<br />
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="41" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li>vsInput VS<span style="color: #b4b4b4;">(</span>vsInput input<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> input<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}</li>
<li> </li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>domain<span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"tri"</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #b4b4b4;">[</span>partitioning<span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"fractional_even"</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>outputtopology<span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"triangle_cw"</span><span style="color: #b4b4b4;">)]</span></li>
<li><span style="color: #b4b4b4;">[</span>outputcontrolpoints<span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">3</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #b4b4b4;">[</span>patchconstantfunc<span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"HSConst"</span><span style="color: #b4b4b4;">)]</span></li>
<li>vsInput HS<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">InputPatch</span><span style="color: #b4b4b4;"><</span>vsInput<span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">3</span><span style="color: #b4b4b4;">></span> input<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">uint</span> id <span style="color: #b4b4b4;">:</span> SV_OutputControlPointID<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> <span style="color: #569cd6;">return</span> input<span style="color: #b4b4b4;">[</span>id<span style="color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Now the hull constant function, which defines tesselation factor based on triangle size:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="56" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li>hsConstOutput HSConst<span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">InputPatch</span><span style="color: #b4b4b4;"><</span>vsInput<span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">3</span><span style="color: #b4b4b4;">></span> patch<span style="color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;">{</li>
<li> hsConstOutput output<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">float3</span> p1 <span style="color: #b4b4b4;">=</span> patch<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">].</span>p<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float3</span> p2 <span style="color: #b4b4b4;">=</span> patch<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">].</span>p<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float3</span> p3 <span style="color: #b4b4b4;">=</span> patch<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">2</span><span style="color: #b4b4b4;">].</span>p<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">float</span> v <span style="color: #b4b4b4;">=</span> length<span style="color: #b4b4b4;">(</span>cross<span style="color: #b4b4b4;">(</span>p2<span style="color: #b4b4b4;">-</span>p1<span style="color: #b4b4b4;">,</span>p3<span style="color: #b4b4b4;">-</span>p1<span style="color: #b4b4b4;">));</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">float</span> r <span style="color: #b4b4b4;">=</span> MaxSize <span style="color: #b4b4b4;">-</span> MinSize<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float</span> n <span style="color: #b4b4b4;">=</span> <span style="color: #b4b4b4;">(</span>v <span style="color: #b4b4b4;">-</span> MinSize<span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">/</span> r<span style="color: #b4b4b4;">;</span></li>
<li> <span style="color: #569cd6;">float</span> f <span style="color: #b4b4b4;">=</span> MinimumTessel <span style="color: #b4b4b4;">+</span> n <span style="color: #b4b4b4;">*</span> <span style="color: #b4b4b4;">(</span>MaximumTessel <span style="color: #b4b4b4;">-</span> MinimumTessel<span style="color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> f <span style="color: #b4b4b4;">=</span> clamp<span style="color: #b4b4b4;">(</span>f<span style="color: #b4b4b4;">,</span>MinimumTessel<span style="color: #b4b4b4;">,</span>MaximumTessel<span style="color: #b4b4b4;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> output<span style="color: #b4b4b4;">.</span>edges<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> f<span style="color: #b4b4b4;">;</span></li>
<li> output<span style="color: #b4b4b4;">.</span>edges<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> f<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> output<span style="color: #b4b4b4;">.</span>edges<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">2</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> f<span style="color: #b4b4b4;">;</span></li>
<li> output<span style="color: #b4b4b4;">.</span>inside<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span>f<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="color: #569cd6;">return</span> output<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;">}</li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
And the domain shader, which performs the emission:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: Consolas, 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #0c0c0c; color: gainsboro; max-height: 300px; overflow: auto;">
<ol start="60" style="background: #000000; margin: 0 0 0 3em; padding: 0;">
<li><span style="color: #b4b4b4;">[</span>domain<span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"tri"</span><span style="color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="color: #569cd6;">void</span> DS<span style="color: #b4b4b4;">(</span>hsConstOutput input<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">OutputPatch</span><span style="color: #b4b4b4;"><</span>vsInput<span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">3</span><span style="color: #b4b4b4;">></span> op<span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float3</span> dl <span style="color: #b4b4b4;">:</span> SV_DomainLocation<span style="color: #b4b4b4;">)</span></li>
<li>{</li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> vid <span style="color: #b4b4b4;">=</span> RWPositionBuffer<span style="color: #b4b4b4;">.</span>IncrementCounter<span style="color: #b4b4b4;">();</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float3</span> p <span style="color: #b4b4b4;">=</span> uv<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">].</span>p</li>
<li> <span style="color: #b4b4b4;">+</span> uv<span style="color: #b4b4b4;">.</span>y <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">].</span>p</li>
<li style="background: #0c0c0c;"> <span style="color: #b4b4b4;">+</span> uv<span style="color: #b4b4b4;">.</span>z <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">2</span><span style="color: #b4b4b4;">].</span>p<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">float3</span> n <span style="color: #b4b4b4;">=</span> uv<span style="color: #b4b4b4;">.</span>x <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">].</span>n</li>
<li> <span style="color: #b4b4b4;">+</span> uv<span style="color: #b4b4b4;">.</span>y <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">].</span>n</li>
<li style="background: #0c0c0c;"> <span style="color: #b4b4b4;">+</span> uv<span style="color: #b4b4b4;">.</span>z <span style="color: #b4b4b4;">*</span> op<span style="color: #b4b4b4;">[</span><span style="color: #b5cea8;">2</span><span style="color: #b4b4b4;">].</span>n<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> n <span style="color: #b4b4b4;">=</span> normalize<span style="color: #b4b4b4;">(</span>n<span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">*</span> VelocityScale<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="color: #569cd6;">uint</span> particleid <span style="color: #b4b4b4;">=</span> <span style="color: #b4b4b4;">(</span>vid <span style="color: #b4b4b4;">+</span> EmitOffset<span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">%</span> MaxParticles<span style="color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> RWPositionBuffer<span style="color: #b4b4b4;">[</span>particleid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> p<span style="color: #b4b4b4;">;</span></li>
<li> RWInitialPositionBuffer<span style="color: #b4b4b4;">[</span>particleid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> p<span style="color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> RWVelocityBuffer<span style="color: #b4b4b4;">[</span>particleid<span style="color: #b4b4b4;">]</span> <span style="color: #b4b4b4;">=</span> n<span style="color: #b4b4b4;">;</span></li>
<li>}</li>
</ol>
</div>
</div>
<br />
As you see we perform increment counter on Particle position buffer (flag is set to 0 before to run the shader).<br />
<br />
Then we just return the position buffer UAV as a result, which contains the total amount of particles that got emitted.<br />
<br />
Make sure to disable pixelshader and geometry shader, set a dummy viewport (otherwise it will not run), and disable depth state, and profit :)<br />
<br />
Next part, demoing various emitters, and explain some other new features that this did open.<br />
<br />
<br />
<br />
<br /></div>
</div>
</div>
</div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-38514016568293759622015-02-20T15:52:00.000+00:002015-02-20T15:52:03.399+00:00Profiling Direct2d (and hybrid ui rendering)<div dir="ltr" style="text-align: left;" trbidi="on">
For a while I really wanted to know how much my User interface rendering costs me in pure reality.<br />
I can consider my ui pretty smooth, but smoother is better than smooth ;)<br />
<br />
So to debug Direct2d, you can use the Visual Studio Graphics debugger, but since I have several windows/panels, It's quite hard to get a screenshot.<br />
<br />
Also I noticed that sometimes a snapshot doesn't include all the elements.<br />
<br />
Technically I know that Direct2d uses a DirectX11 (with feature level 10) device, so if I can get this device pointer, I can easily run queries between those BeginDraw/EndDraw calls.<br />
<br />
But it looks like it's not possible....<br />
<br />
However...<br />
<br />
It is now possible to provide our own DirectX11 device to a Direct2d context. I looked at that feature earlier on and thought it would be really complicated to update, but this was so simple that I feel embarrassed that I didn't do it before ;)<br />
<br />
So reasoning is simple, instead of creating a HwmdRenderTarget, we create a SwapChain using our DirectX11 device instead.<br />
<br />
Then we can create a Direct2d Render Context from this:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 200px; overflow: auto;">
<ol start="58" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> context2d </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DeviceContext</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">swapChain</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Texture</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">QueryInterface</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">SharpDX</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">DXGI</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">Surface</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">());</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #57a64a;">//Call release on texture since queryinterface does an addref</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Release(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">swapChain</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Texture</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">NativePointer);</span></li>
</ol>
</div>
</div>
<br />
<br />
Yes, this is that easy.<br />
<br />
Context is create from SwapChain, so it will use the device which own that one, instead of creating a new one.<br />
<br />
Also since our context implements Direct2d RenderTarget, there was no code update for the rest of the ui rendering, life is good at times ;)<br />
<br />
There's only one difference now, calling EndDraw does not trigger a Present call on the swapchain (technically I could use a standard render target instead of a SwapChain), so you have to call Present on your swapchain manually (not a big deal really ;)<br />
<br />
<br />
So now I have device context working that way, I can just create a Pipeline Statistics and a TimeStamp query.<br />
<br />
I'm pretty interested in primitive count and render time obiously.<br />
<br />
<h2 style="text-align: left;">
1/Primitive cost</h2>
<div>
So first let's have a look at each geometry I use and check the cost at IA Stage. </div>
<div>
Since I draw a border, I check the cost for the "Fill[Primitive]", and for the "Draw[Primitive] which builds me outline.</div>
<div>
<br /></div>
<div>
One I first use a lot is RoundedRectangle (with a 1 pixel corner).</div>
<div>
<br /></div>
<div>
<div>
FillRoundedRectangle (1 pix corner) : 96</div>
<div>
DrawRoundedRectancle: 264</div>
</div>
<div>
<br /></div>
<div>
So a single round rectangle is more than 350 primitives per element, that hurts (a lot)</div>
<div>
<br /></div>
<div>
Let replace those by standard Rectangle (as a side note since I have the grid snap, the visual difference was actually what I could call: "None")</div>
<div>
<br /></div>
<div>
FillRectangle : 6</div>
<div>
<br /></div>
<div>
This was pretty expected, 2 triangles</div>
<div>
<br /></div>
<div>
DrawRectangle : 190</div>
<div>
<br /></div>
<div>
This was much less expected, and feels rather high.</div>
<div>
<br /></div>
<div>
Still, replacing Round Rectangle by Rectangle pretty much half you poly count (and gave a pretty high boost to my rendering of course)</div>
<div>
<br /></div>
<div>
Now let's go for Ellipse (Which I use for pins/keyframes in timeliner):</div>
<div>
<div>
<br /></div>
<div>
FillEllipse : 204</div>
<div>
DrawEllipse : 204</div>
</div>
<div>
<br /></div>
<div>
This is quite a staggering cost, I often have more than 1000 keyframes in my timeliner nowadays (Ok I cull keyframe rendering already), so my worst case scenarios (fully unzoomed ui and panel with all visible) is a whooping 408000 primitives!</div>
<div>
<br /></div>
<div>
In case of a patch, I can replace pin from Ellipse to Rectangle as well (I still learned to prefer ellipse which is visually much more pleasing, but then I can also add a render mode param (to shoose low/high quality).</div>
<div>
<br /></div>
<div>
In case of Timeline, can't really use quad, so I need a solution (see below)</div>
<div>
<br /></div>
<div>
Next we have Lines/Beziers</div>
<div>
<br /></div>
<div>
Line (whatever vertical/size...) : 46</div>
<div>
Bezier : from 312 -> 620</div>
<div>
Dashed Bezier : same as above</div>
<div>
<br /></div>
<div>
So links are also rather expensive, switch to choose link style is definitely a nice thing to add.</div>
<div>
<br /></div>
<div>
And obviously, finally : </div>
<div>
<br /></div>
<div>
Text : 6 </div>
<div>
<br /></div>
<div>
I'll go back into this later, but pretty much text is 6 primitives (and likely a sprite sheet texture bound as well).</div>
<h2>
2/Draw ordering and Buffers</h2>
<div>
This is one thing which I actually looked more while using the graphics debugger, but this also gives you very valuable information.</div>
<div>
<br /></div>
<div>
For any solid color brush, direct2d fills the geometry content into a buffer, and either when it gets a context change (see below) or buffer is full, It copies the buffer and do a draw. </div>
<div>
<br /></div>
<div>
So it does a pretty cool job at limiting draw calls, but does not use so much of GPU instancing, except for Text rendering.</div>
<div>
<br /></div>
<div>
So let's take a standard Node draw routine, and well see what's bad in there (pseudo code)</div>
<div>
<br /></div>
<div>
for each node</div>
<div>
fill rectangle</div>
<div>
draw outline</div>
<div>
draw title (text)</div>
<div>
draw pins (another loop)</div>
<div>
end for</div>
<div>
<br /></div>
<div>
This translates this way in Direct2d (let's say we have 2 nodes, and I'll remove pins for clarity)</div>
<div>
<br /></div>
<div>
context->Draw(pcount, offset); //This is rectangle + first outline</div>
<div>
context->DrawInstanced(6,1,0,0,0); //Text</div>
<div>
<div>
context->Draw(pcount, offset); //This is rectangle + first outline</div>
<div>
context->DrawInstanced(6,1,0,0,0); //Text</div>
</div>
<div>
<br /></div>
<div>
So each node need 2 draw calls. </div>
<div>
Obvious issue is that text rendering requires a different set of shaders, so Direct2d has to swap and can't batch efficiently anymore.</div>
<div>
<br /></div>
<div>
So let's reorganize out drawing this way:</div>
<div>
<br /></div>
<div>
<div>
for each node</div>
<div>
fill rectangle</div>
<div>
draw outline</div>
<div>
end for</div>
</div>
<div>
<br /></div>
<div>
for each node</div>
<div>
draw title</div>
<div>
end for</div>
<div>
<br /></div>
<div>
so now we are instead building 2 loops, first we render all the rectangles, then we render all the text.</div>
<div>
<br /></div>
<div>
And then magically :</div>
<div>
context->DrawInstanced(6,n,0,0,0); //Node count</div>
<div>
<br /></div>
<div>
So now all our text is batched in a single draw, and rectangle is also reduced (depending on node count, but pretty often it reduces to a couple of calls maximum).</div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
3/Hybrid rendering</h2>
<div>
So now by replacing some elements, I already managed to get quite a significant gain, </div>
<div>
<br /></div>
<div>
Here is roundrect to rect cost on a reasonably large patch (please note that cpu/gpu times are not additive, since they work in tandem)</div>
<div>
<br /></div>
<div>
RoundRect + Ellipse</div>
<div>
<div>
CPU : 6.5ms</div>
<div>
GPU : 4ms</div>
</div>
<div>
<br /></div>
<div>
Rectangles</div>
<div>
<div>
CPU : 3ms</div>
<div>
GPU : 0.5ms</div>
</div>
<div>
<br /></div>
<div>
This is a pretty huge boost (specially considering we have the same quality).</div>
<div>
<br /></div>
<div>
Now I mentioned that swapping Ellipse for Rectangle was not an option for timeline, so I need a solution.</div>
<div>
<br /></div>
<div>
The obvious first choice is to use a small circle texture, but that does not fit really well with antialias (quite a big loss of quality).</div>
<div>
<br /></div>
<div>
So I need another solution....</div>
<div>
<br /></div>
<div>
And...</div>
<div>
<br /></div>
<div>
Do you remember? I am now drawing on a DirectX11 Swapchain, and I got access to it.</div>
<div>
<br /></div>
<div>
So let's move hybrid</div>
<div>
<br /></div>
<div>
Here is a 1000 + keyframe rendering profile (full redraw every frame, all keyframes visible)</div>
<div>
<div>
CPU : 14ms</div>
<div>
GPU : 9ms</div>
<div>
Primitives : 388k</div>
</div>
<div>
<br /></div>
<div>
We can clearly see that hurts our graphics card quite a lot, since Direct2d doesn't instance in the GPU side, we have 388000 primitives uploaded on our GPU.</div>
<div>
<br /></div>
<div>
Rendering process as follow (pseudo code again)</div>
<div>
<br /></div>
<div>
for each track</div>
<div>
render header </div>
<div>
for each keyframe</div>
<div>
if keyframe in timeline time range</div>
<div>
calculate position</div>
<div>
draw keyframe</div>
<div>
end if</div>
<div>
end for</div>
<div>
end for</div>
<div>
render other bits (rulers...)</div>
<div>
<br /></div>
<div>
So now let's give DirectX11 a bit of work, we create a simple instancing shader (rebuilds size and get color from a small buffer)</div>
<div>
<br /></div>
<div>
We create 2 structured buffers (1 for screen space position, 1 for color index)</div>
<div>
<br /></div>
<div>
and change the rendering as follow</div>
<div>
<br /></div>
<div>
reset keyframe counter</div>
<div>
for each track </div>
<div>
render header</div>
<div>
for each keyframe</div>
<div>
if keyframe in timeline time range</div>
<div>
add position/colorid into the cpu array</div>
<div>
increment keyframe counter</div>
<div>
end if</div>
<div>
end for</div>
<div>
end for </div>
<div>
if keyframe counter > 0</div>
<div>
end draw (give hand from d2d to d3d)</div>
<div>
copy position/colorid to buffers</div>
<div>
draw instanced circles (outline) -> only need to upload position buffer + single draw => huge win)</div>
<div>
draw instanced circles (background) -> reuse the same buffer but scale down the circle in VS</div>
<div>
begin draw (we give back direct2d drawing rights)</div>
<div>
end if</div>
<div>
render other bits</div>
<div>
<br /></div>
<div>
Now using instanced circles here we are</div>
<div>
<div>
CPU : 3ms</div>
<div>
GPU : 2.4ms</div>
<div>
Primitives : 51k</div>
</div>
<div>
<br /></div>
<div>
That's 5 times faster on cpu workload, and 4 times faster on GPU, not bad ;)</div>
<div>
Also we divided our primitive count by more than 6, without a loos of quality!</div>
<div>
<br /></div>
<div>
Let's try other techniques (Note: here we lose antialias in that case)</div>
<div>
Instanced Rectangles-> clip/discard in pixel shader</div>
<div>
<div>
CPU : 3ms</div>
<div>
GPU : 2.0ms</div>
<div>
Primitives : 13k</div>
</div>
<div>
<br /></div>
<div>
No initial geometry (build both Rectangles in GS, clip in PS)</div>
<div>
<div>
CPU : 2.9ms</div>
<div>
GPU : 1.7ms</div>
<div>
Primitives : 11k</div>
</div>
<div>
<br /></div>
<div>
In case you accept to lose AA settings, that can be another reasonable gain (thinking lower end machines)</div>
<div>
<br /></div>
<div>
So be able to use DirectX11 alongside Direct2d is a pretty massive win :)</div>
<div>
<br /></div>
<h2 style="text-align: left;">
4/Next stage</h2>
<div>
Obviously realizing how much gain we can get out of hybrid rendering, it would be a shame to stop here, users love smooth UI, so let's strive to give them this :)</div>
<div>
<br /></div>
<div>
Also having access to device makes it much easier for some other features (like draw some texture inside the d2d viewport).</div>
<div>
<br /></div>
<div>
Also as a side note, yes idea is to render user interface every frame (no partial redraw for now). </div>
<div>
Maybe partial can feel more efficient, but only once you nailed the full draw (since a zoom/pan = redraw, I don't want a half a second drop when I do this action ;)</div>
<div>
<br /></div>
<div>
New results/post soon</div>
<div>
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-76315366281897459792015-02-14T15:05:00.002+00:002015-02-14T15:05:29.621+00:00Timeliner (again)<div dir="ltr" style="text-align: left;" trbidi="on">
I didn't post in my blog for quite a while, been rather busy on projects, January was rather packed.<br />
<br />
I used vvvv for one and FlareTic for the other.<br />
<br />
At the end of each project, I could see how important a proper Timeliner is and how this changes your workflow (really I mean it, and coming from me who used to hate timelines, it must mean something...)<br />
<br />
I already added the basic remaining features in december (copy paste, undo/redo stack, organize tracks/groups, zoom+ pan, navigation, snap to rulers...), which is the MINIMUM expected.<br />
<br />
Once the basic is done, time to start fancy features (always do basic then fancy, not the other way round...)<br />
<br />
First is keyframe group, you select a bunch of keyframes and can move them as a single unit (while also allowing to move keyframe itself).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK7f4s9NSLdfe0fqIV7FVK980gaDM5rVluqhtrnNOcY0QOSbAOAwykXWRE9XSR060NG8PuxiYizgJ-Iq9039elfMEiKe8nLjbnoLZbetTaYO-Hsxsvl1UITVnDQUP2X75QWbM7dfLlYDac/s1600/tg2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK7f4s9NSLdfe0fqIV7FVK980gaDM5rVluqhtrnNOcY0QOSbAOAwykXWRE9XSR060NG8PuxiYizgJ-Iq9039elfMEiKe8nLjbnoLZbetTaYO-Hsxsvl1UITVnDQUP2X75QWbM7dfLlYDac/s1600/tg2.png" height="113" width="320" /></a></div>
<br />
You can see keyframes with small alpha, ctrl + click allows you to move the whole group instead of the track itself.<br />
<br />
This is really handy when you need to quickly organize your key frame after some requirement change.<br />
<br />
Next you can notice purple/blue keyframes, what are those?<br />
<br />
This is a simple thing called aliases. So those keyframes reference a parent one.<br />
<br />
This is really useful when you copy a bulk of keyframes, but need the same value (almost). Alias host an offset to the parent value, so changing the parent also change the alias, while you can keep a bit of variation using offsets.<br />
<br />
<br />
So all of this really changed my way of working, but now, let's think forward...non linear playback.<br />
<br />
First I already have a playback optimizer (using tree based interval data structure).<br />
<br />
So now let's allow to play those clips somewhere else.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg93ZJVVqomFjZDP5aBkmumZl0Y0j2icQ485GNFQ-yee7TcQ2lBv1y6Q6T8WPehsIa_tmFzIsHYoVRaPh5z2nrM06r293dST0s0D5rStaSCU73kap84B8O-Ko1L9m7yoxfo_raHY_HXuQGq/s1600/tlnl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg93ZJVVqomFjZDP5aBkmumZl0Y0j2icQ485GNFQ-yee7TcQ2lBv1y6Q6T8WPehsIa_tmFzIsHYoVRaPh5z2nrM06r293dST0s0D5rStaSCU73kap84B8O-Ko1L9m7yoxfo_raHY_HXuQGq/s1600/tlnl.png" height="172" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Ok screen shot doesn't show much cool stuff, but simple concept is, I can now have a track as a node, and a custom time pin input, so I have the ease of design (via editor), but can also play a track (eventually in different places with different times).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I got 2 versions of track playback, one with time input, one with a signal that asks: start play (which I use with kinect gesture recognizer for example).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
That's a pretty handy new feature, but let's not stop in there, let's go... forward (things are never good enough ;)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
One common issue I have, most of my data in my tool is stored in GPU (particle system, generated geometry...)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Many times I need some form of control over it (let's say for example compute particle size from age). I often use quick formulas for that, but then thinking : this timeline editor is so easy to use, why not having this track used for this form of control instead of my ghetto formulas?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Track data fits really well into a 1d texture, so here we go, create a node that renders the whole track into texture (with controllable precision), sampler with smooth it out a little if really needed.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdI3ZXfSHgHi3cIKlOzk8sv-LzJtHLvqPe4hicHn5xSIPiauc1SrP_3DnZu43aZeQBueurm9JWxVIjmUde5q5EneQGM24fgXGS3dtxnFFyIrnhC4kyT65UJR7zcY_QXrjhzZhqno3bqj0t/s1600/gtl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdI3ZXfSHgHi3cIKlOzk8sv-LzJtHLvqPe4hicHn5xSIPiauc1SrP_3DnZu43aZeQBueurm9JWxVIjmUde5q5EneQGM24fgXGS3dtxnFFyIrnhC4kyT65UJR7zcY_QXrjhzZhqno3bqj0t/s1600/gtl.png" height="169" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here we go, create new particle behaviour that take 1d texture as control, and here we go, half million particles with age/size controlled via timeliner, life is beautiful as times ;)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As a side note, playback control using 1d texture/sampler is also so seamless that it becomes embarrassingly easy :</div>
<div class="separator" style="clear: both; text-align: left;">
* One off playback : clamp sampler</div>
<div class="separator" style="clear: both; text-align: left;">
* Loop : wrap</div>
<div class="separator" style="clear: both; text-align: left;">
* Ping pong : mirror</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next stage (going forward again), Multi render into Texture1DArray (so can use several tracks for diversity).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As a side note my node collection also did a pretty hefty climb, but let's keep this for later posts :)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-54882353274082167622014-11-23T17:48:00.000+00:002014-11-23T17:48:25.755+00:00Shader Linker (Part 2)<div dir="ltr" style="text-align: left;" trbidi="on">
Lately I had some time again to work in FlareTic.<br />
<br />
I added some new nice pixel material functions, here are a couple of screenshots:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUih-Npf6Wu0hpPCyjXbfhDELtQMPX7g7ieg3gqJ1LaVR3b7quBKixDE-3SfZNSYBQMr01EIoinPiyNopNlwGrxNDLWx5FW6OhaJHZol6itqNIY5aMY9PNqMmxgNUEPWNBqIg9RBXnb960/s1600/mat002.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUih-Npf6Wu0hpPCyjXbfhDELtQMPX7g7ieg3gqJ1LaVR3b7quBKixDE-3SfZNSYBQMr01EIoinPiyNopNlwGrxNDLWx5FW6OhaJHZol6itqNIY5aMY9PNqMmxgNUEPWNBqIg9RBXnb960/s1600/mat002.jpg" height="181" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmMMj0109nY_0J5oYtbJm90RIWJpxHi-irgRnfmYta9uJh-DC_DmopNR1HdTNzXC_hWB9irJJqdGJwBB0JPgIfQeGEmLO9h7_XtG9jqks52TDzkGAr98_Muhmbl4hBqGJiI3wGntt4WViF/s1600/mat009.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmMMj0109nY_0J5oYtbJm90RIWJpxHi-irgRnfmYta9uJh-DC_DmopNR1HdTNzXC_hWB9irJJqdGJwBB0JPgIfQeGEmLO9h7_XtG9jqks52TDzkGAr98_Muhmbl4hBqGJiI3wGntt4WViF/s1600/mat009.jpg" height="180" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now a lot of my procedural materials share a lot in common, they are mostly either wave/noise functions, which are then combined.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In the example above I use 4 noise functions (2 for roughness, 2 for reflectivity), which are then combined either as additive/multiply.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now being able to combine those functions in an easier way would be rather handy. And hey, I already have a function linker patch to generate pixel shaders.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Even tho I have the base that is totally required (hybrid node/code linker), it still has some flaws.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
First, you need a lot of swizzle operators. This adds a lot of pollution in the patch, to just process something like "set float to vector4".</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
But luckily, I already mentionned I had implicit converters.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So I created a simple version of them, which add extra instruction to linker, so it can call passvaluewithswizzle instead of passvalue.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiETAegCaXPMzjyZfCdyRMc7G5FxMqOVD5tuZ8PeCxtAXGT_L88nl-ErtsZfBZaZVZ6upGzNct5myGygRCwugDwB7b0FKJCCb8vqgIwDbvcaZx8fG2yBt4k6JOzolGoDG20XvbC_ijd5wsp/s1600/shadercomp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiETAegCaXPMzjyZfCdyRMc7G5FxMqOVD5tuZ8PeCxtAXGT_L88nl-ErtsZfBZaZVZ6upGzNct5myGygRCwugDwB7b0FKJCCb8vqgIwDbvcaZx8fG2yBt4k6JOzolGoDG20XvbC_ijd5wsp/s1600/shadercomp.png" height="174" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If we look at the screenshot above, now instead of having a xxxx node to convert float to float4 we can see converter just added itself implicitely, reducing patch node pollution.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now if we want to perform conversion the opposite way (for example, float4 to float), we run into an issue : which component to take?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
But since I can add configuration to links (yes in FlareTic links can also have parameters that you can modify via inspector), this is suddenly trivial, I just add a swizzle parameter so we can change which component we want. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In that case it had a little twist, since when this parameter changes, I need to ask the linker to build me a new pixelshader, but that's rather trivial.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9wk2hbSs5KVmC-SMevvW-LvR5XBK5kzKmqSaMOHYrQK-3ulxASJwr7tyqOdNxr0skuytOjAb6szWiRFN695WjQOKvJp45V4y6b9eIgFLS_IyPz5Y9y0EnS4i4GCbZ-sLegXR1XBuGWUo_/s1600/inspect2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9wk2hbSs5KVmC-SMevvW-LvR5XBK5kzKmqSaMOHYrQK-3ulxASJwr7tyqOdNxr0skuytOjAb6szWiRFN695WjQOKvJp45V4y6b9eIgFLS_IyPz5Y9y0EnS4i4GCbZ-sLegXR1XBuGWUo_/s1600/inspect2.png" height="180" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can see in screenshot above, selected link has a swizzle parameter (those links are yellow in the patch, since they imply a loss of data, and it makes it easier for the user to see they can modifiy link behaviour).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next there's the most serious issue for usability. </div>
<div class="separator" style="clear: both; text-align: left;">
To be able to create a pixelshader, the graph must be complete, if an input pin does not have a connection link process will fail.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So I could easily provide a default, but let's think better, if an input pin has no connection, it would be much nicer to have the value in inspector and be able to change it real time.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So instead, I build a hidden RawBuffer, and a few reader functions.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
When I parse the graph, if a pin is connected i call passvalue, if not, I ask the hiddenbuffer for a data slot, hiddenbuffer also returns me reader node, which will grab data from buffer.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Before to run the pixelshader, I grab the data from the inspector and copy to buffer, so it's easy to tweak input parameters if they are not connected.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF6Wv2zzirrgxSYqVz_eXeIqYcmB4X7g7VoQXeTYUMViyT5ibtBf72fV73y4N_yGs2wOVHs-vWbjQTtGR-GgEsO5N8V5XUbp7qJ0snmzlsyx0SYG1v4iXCWy40U-alcC2yCblC9LH7a6pj/s1600/inspect.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF6Wv2zzirrgxSYqVz_eXeIqYcmB4X7g7VoQXeTYUMViyT5ibtBf72fV73y4N_yGs2wOVHs-vWbjQTtGR-GgEsO5N8V5XUbp7qJ0snmzlsyx0SYG1v4iXCWy40U-alcC2yCblC9LH7a6pj/s1600/inspect.png" height="180" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can see that the multiply node shows me value editor for non connected pin. Modifying value does not need to relink shader, it's just copied in buffer before the call.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now once all of this is done, I just needed to create a Input/Output template for my deffered materials, and make sure I sort the calls properly. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And here we go, hybrid code/patch material editor, promised I'll do some nicer screenshots next time ;)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNAwkIzfE9otMg6IOzOoMzFEeinL5dfLfjmCxfn9l1maCEgY-bmYMhfuSzIxBv5WK1s98jNaP2An9KE3iBcpiqDceWKqJQjw5iRbpO9Q52Yn_q_ArGoj5Ejv_Q9PmNOSwRJHOFoFq0Uuvs/s1600/sc3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNAwkIzfE9otMg6IOzOoMzFEeinL5dfLfjmCxfn9l1maCEgY-bmYMhfuSzIxBv5WK1s98jNaP2An9KE3iBcpiqDceWKqJQjw5iRbpO9Q52Yn_q_ArGoj5Ejv_Q9PmNOSwRJHOFoFq0Uuvs/s1600/sc3.png" height="179" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLVWX0G32Mgb4zjRwigY2bj0feczlHUfTemFEEcTlDh4HFh4GGG_BL6aVQCPsuVTEH-TNciM0nQeViHrdKua4kLLqN9YUJe4IYhGaTGZUXEqS5MlHVUX5PU9mC9bI06_nLkmiyawzK4-2k/s1600/sc4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLVWX0G32Mgb4zjRwigY2bj0feczlHUfTemFEEcTlDh4HFh4GGG_BL6aVQCPsuVTEH-TNciM0nQeViHrdKua4kLLqN9YUJe4IYhGaTGZUXEqS5MlHVUX5PU9mC9bI06_nLkmiyawzK4-2k/s1600/sc4.png" height="180" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now for next feature set (still work in progress):</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>Function grouping</li>
<li>More aggressive packing for buffer data.</li>
<li>Custom cbuffer integration</li>
</ul>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-16843717665179296422014-10-28T14:43:00.001+00:002014-10-28T14:43:19.580+00:00Hap Attack (Part 2)<div dir="ltr" style="text-align: left;" trbidi="on">
In previous post I explained a bit how to decode Hap files.<br />
<br />
I explained a bit how the QuickTime format works, so let's show a bit of code.<br />
<br />
First we need to access a leaf node to extract information, for this let's build a small interface:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ILeafAtomReader</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Read(</span><span style="background: #1e1e1e; color: #4ec9b0;">FileStream</span><span style="background: #1e1e1e; color: gainsboro;"> ds);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now let's show an example implementation:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ChunkOffsetReader</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ILeafAtomReader</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> chunkOffsetTable </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Table</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">chunkOffsetTable; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Read(</span><span style="background: #1e1e1e; color: #4ec9b0;">FileStream</span><span style="background: #1e1e1e; color: gainsboro;"> ds)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #57a64a;">//Bypass header</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Seek(</span><span style="background: #1e1e1e; color: #b5cea8;">4</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">SeekOrigin</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Current);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> entrycount </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReadSize();</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">for</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> i </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">; i </span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;"> entrycount; i</span><span style="background: #1e1e1e; color: #b4b4b4;">++</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> size </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReadSize();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">chunkOffsetTable</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(size);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
This is reasonably simple, we go parse the data we require.<br />
<br />
Now there is a little problem, some parsers will read the whole atom, some parsers might only read the data they want, so our file position pointer might not be at the end of the atom.<br />
<br />
To circumvent that, let's add a little adapter:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="14" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">LeafAtomReaderAdapter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ILeafAtomReader</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ILeafAtomReader</span><span style="background: #1e1e1e; color: gainsboro;"> reader;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> LeafAtomReaderAdapter(</span><span style="background: #1e1e1e; color: #b8d7a3;">ILeafAtomReader</span><span style="background: #1e1e1e; color: gainsboro;"> reader)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (reader </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentNullException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"reader"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">reader </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> reader;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Read(</span><span style="background: #1e1e1e; color: #4ec9b0;">FileStream</span><span style="background: #1e1e1e; color: gainsboro;"> ds)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> currentpos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">reader</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Read(ds);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Seek(currentpos, </span><span style="background: #1e1e1e; color: #b8d7a3;">SeekOrigin</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Begin);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
This takes another atom reader, but before to let it read, it stores the file position pointer, and restores it once the other reader is done.<br />
<br />
Since Atom order is not guaranteed, we also need to tell which containers we are interested in:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="17" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;">[] containers </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;">[]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #d69d85;">"moov"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #d69d85;">"trak"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #d69d85;">"mdia"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #d69d85;">"minf"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #d69d85;">"stbl"</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">};</span></li>
</ol>
</div>
</div>
<br />
<br />
Then once we find the right media, sample table (the one which contains hap), we need to lookup a bit of extra information, so we need to store moov and trak atom offset (so we can then read tkhd to get video size info, and mvhd to get time units).<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="54" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (containers</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Contains(fcc</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString()))</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (fcc</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString() </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"trak"</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">currenttrakoffset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (fcc</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString() </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"moov"</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">currentmoovoffset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #57a64a;">//Keep parent position, since we'll want to get this to read sample table</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Parse(ds, ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
Once we found a track with hap, we can jump back to the file position and go read headers.<br />
<br />
So now we can finally play hap files.<br />
Only issue, without ssd, this is drive intensive, and we generally have a lot of memory, so let's allow to load the whole video data in ram.<br />
<br />
This is done differently in QT and Avi.<br />
<br />
In QT I already built the lookup table, so I can just load a copy of the file in memory, and lookup from there:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="15" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">unsafe</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DataStream</span><span style="background: #1e1e1e; color: gainsboro;"> ReadFile(</span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> path, </span><span style="background: #1e1e1e; color: #4ec9b0;">CancellationToken</span><span style="background: #1e1e1e; color: gainsboro;"> token, </span><span style="background: #1e1e1e; color: #b8d7a3;">IProgress</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> progress, </span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> chunkSize </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1024</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> fs </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">File</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">OpenRead(path);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AllocHGlobal((</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;">)fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> pointerOffset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">byte</span><span style="background: #1e1e1e; color: gainsboro;">[] chunk </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">byte</span><span style="background: #1e1e1e; color: gainsboro;">[chunkSize];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> remaining </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Convert</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToInt32(fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> read </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">while</span><span style="background: #1e1e1e; color: gainsboro;"> (remaining </span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> toread </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Math</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Min(remaining, chunkSize);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Read(chunk, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">, toread);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Copy(chunk, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">, pointerOffset, toread);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">pointerOffset </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> toread;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">read </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> toread;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">)read </span><span style="background: #1e1e1e; color: #b4b4b4;">/</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">)fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">progress</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Report(p);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">remaining </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Convert</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToInt32(fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Position);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (token</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IsCancellationRequested)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Close();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FreeHGlobal(dataPointer);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OperationCanceledException</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> ds </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DataStream</span><span style="background: #1e1e1e; color: gainsboro;">(dataPointer, fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length, </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">false</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">fs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Close();</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> ds;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
This is just a simple file reader, that grabs blocks and report progress, so it can be sent as a background task.<br />
<br />
For Avi I got no lookup table, but some api to get frameindex -> data (from disk). So I create a memory block large enough to contain the whole video (file size works perfectly for that purpose ;)<br />
<br />
Then In background I go request frames and build a prefix sum:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="54" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">unsafe</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">AviOffsetTable</span><span style="background: #1e1e1e; color: gainsboro;"> BuildTable(</span><span style="background: #1e1e1e; color: #4ec9b0;">hapFileVFW</span><span style="background: #1e1e1e; color: gainsboro;"> fileinfo, </span><span style="background: #1e1e1e; color: #4ec9b0;">CancellationToken</span><span style="background: #1e1e1e; color: gainsboro;"> token, </span><span style="background: #1e1e1e; color: #b8d7a3;">IProgress</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> progress)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">long</span><span style="background: #1e1e1e; color: gainsboro;"> fileLength </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">FileInfo</span><span style="background: #1e1e1e; color: gainsboro;">(fileinfo</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Path)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Length;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> frameCount </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> fileinfo</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FrameCount;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AllocHGlobal((</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;">)fileLength);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> offsetPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">OffsetTable</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> offsetTable </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">OffsetTable</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> currentOffset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">for</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> i </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">; i </span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;"> frameCount; i</span><span style="background: #1e1e1e; color: #b4b4b4;">++</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">fileinfo</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">WriteFrame(i, offsetPointer, </span><span style="background: #1e1e1e; color: #569cd6;">out</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">OffsetTable</span><span style="background: #1e1e1e; color: gainsboro;"> t </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OffsetTable</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Length </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Offset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> currentOffset</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">offsetTable</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(t);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">offsetPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">currentOffset </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> prog </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">)i </span><span style="background: #1e1e1e; color: #b4b4b4;">/</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">)frameCount;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">progress</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Report(prog);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (token</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IsCancellationRequested)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FreeHGlobal(dataPointer);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OperationCanceledException</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">progress</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Report(</span><span style="background: #1e1e1e; color: #b5cea8;">1.0</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">AviOffsetTable</span><span style="background: #1e1e1e; color: gainsboro;">(offsetTable, dataPointer);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
This is simple too, we just ask the avi wrapper to write into our pointer, get number of bytes written and move pointer by that offset for next frame. At the same time we build our offset table.<br />
<br />
Once we have our data loaded in memory everything is much simpler :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="143" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> ReadFrame(</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> frameIndex, </span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> buffer)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">memoryLoader </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">memoryLoader</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Complete)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> tbl </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">memoryLoader</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">DataStream;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">IntPtr</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> tbl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">DataPointer;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> poslength </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> tbl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Table[frameIndex];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">dataPointer </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;">)poslength</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Offset;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> dataPointer;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">else</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> readSamples </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIStreamRead(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">VideoStream, frameIndex, </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">, buffer, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">frameSize</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Width </span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">frameSize</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Height</span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: #b5cea8;">6</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> readBytes, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> readSamples);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> buffer;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
in first case we just return a pointer from our lookup table (no memory copy required), in the second case we read from disk.<br />
<br />
Preloading content into memory gives a huge performance gain (and memory is rather cheap, easy to have 64 gigs in a single machine, so preload can be a definite good option).<br />
<br />
So after that comes all the usual cleanup, manage videos element count and make sure we don't have memory leaks / crashes.<br />
<br />
Now I have a really nicely working player, why limit our imagination?<br />
<br />
First, I wanted to test some 8k encoding, so I exported a few frames from 4v and tried to use virtualdub for encode in hap. Press Save->Out of memory.<br />
<br />
So instead, let's just encode directly from vvvv ;)<br />
<br />
Writing encoder was easy, you set avi headers with you video size/framerate/compression, then you only need to get texture from gpu, convert in whichever dxt/bc format you want, compress with snappy if required, write frame.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb5xhSeJvslOvP2tvbgvK3wIHP_O7e0TZSXwD1zFtp9X56exEiPA5lVDg-Oj4wFoXXPjCGzL7FXcDh_GkIFx4GAhxHcrqGbP2lguqjuNbgn_doq2T6ypjSz3sIu_tZ5xjPA2kYs10vFZt3/s1600/testaviwrite_2014.10.27-15.09.32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb5xhSeJvslOvP2tvbgvK3wIHP_O7e0TZSXwD1zFtp9X56exEiPA5lVDg-Oj4wFoXXPjCGzL7FXcDh_GkIFx4GAhxHcrqGbP2lguqjuNbgn_doq2T6ypjSz3sIu_tZ5xjPA2kYs10vFZt3/s1600/testaviwrite_2014.10.27-15.09.32.png" height="178" width="320" /></a></div>
<br />
One thing well done!<br />
<br />
Next, since we run on dx11 hardware, we have access to new block compression formats:<br />
<br />
<ul style="text-align: left;">
<li>BC6: three channels half floating point (hdr playback, mmmmmhhhh)</li>
<li>BC7: 4 channels, better quality than BC3/DXT5, but encoding is really slow</li>
</ul>
<div>
So let's add a few more FourCC, and add option in encoder/decoder:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKMiEFj5K1dlRoGWsFL9aOpNXV13lEPTSOZJ5FZ0G3gJIlbbLaFiKrtJmXuSJPe4MYr6iBUwwfa2WsMDSkhrDASTuYgCjXo3Y9-7FwFEeExS_YuIedh5ITyi4e5YFv8lQGgm1HFaBv4VdU/s1600/testWriteHdr_2014.10.27-15.32.48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKMiEFj5K1dlRoGWsFL9aOpNXV13lEPTSOZJ5FZ0G3gJIlbbLaFiKrtJmXuSJPe4MYr6iBUwwfa2WsMDSkhrDASTuYgCjXo3Y9-7FwFEeExS_YuIedh5ITyi4e5YFv8lQGgm1HFaBv4VdU/s1600/testWriteHdr_2014.10.27-15.32.48.png" height="178" width="320" /></a></div>
<div>
<br /></div>
<div>
Now we have new hap Formats:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="9" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">enum</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">hapFormat</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGB_DXT1_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAB</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGB_DXT1_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBB</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGBA_DXT5_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAE</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGBA_DXT5_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBE</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">YCoCg_DXT5_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAF</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">YCoCg_DXT5_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBF</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGB_BC6S_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xA3</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGB_BC6S_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xB3</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGB_BC6U_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xA4</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGB_BC6U_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xB4</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGBA_BC7_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xA7</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGBA_BC7_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xB7</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
Please note that those formats are also available out of the box in OpenGL (btpc compression).<br />
So any software that use GL3.1 + can take advantage of it (and really softwares should already have moved to a GL4+ core profile, so there are NO excuses ;)<br />
<br />
<br />
Finally, people always tend to think of videos as just a sequence of images.<br />
<br />
Although there are some cases where other formats are more suitable (panoramic/dome projection).<br />
<br />
In that case cubemaps are much more suited for this.<br />
<br />
Oh and DXT/BC formats support cubemap compression.<br />
<br />
So let's just write cubemap data as a frame, which was 0 lines of code in my case, since my writer already supports cubemap export.<br />
<br />
Then there's only a little twist, in the avi stream info, don't forget to multiply data required by 6 (yes we now have 6 textures in one frame)<br />
<br />
in AVISTREAMINFO :<br />
public Int32 dwSuggestedBufferSize;<br />
<br />
Is the field where we initiate buffers.<br />
<br />
Then decoding frames works exactly like standard textures (Cubemaps are Texture2D too, so loading is done exactly the same way).<br />
<br />
There's of course a little twist, in case of CubeTexture we need to set different parameters on ShaderResourceView creation:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="130" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (videoTexture</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Description</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">OptionFlags</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">HasFlag(</span><span style="background: #1e1e1e; color: #b8d7a3;">ResourceOptionFlags</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">TextureCube))</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;"> videoView </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;">(device</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Device, videoTexture);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">else</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceViewDescription</span><span style="background: #1e1e1e; color: gainsboro;"> srvd </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceViewDescription</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">ArraySize </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">6</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">FirstArraySlice </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Dimension </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ShaderResourceViewDimension</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">TextureCube,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Format </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> videoTexture</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Description</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Format,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">MipLevels </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> videoTexture</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Description</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MipLevels,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">MostDetailedMip </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;"> videoView </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;">(device</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Device, videoTexture,srvd);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
That's more or less it, cube texture encoding/playback with Hap:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievfM0BXoqOCslipOBiUrAhRgKtUhNFSGOgyayJBI6exfaDwGsRbKMfmdhptY9nxU-F__KbwOEq40AdCJ9CW6VpEXSQjtr_xgN75qpYoKMqefJcuJ3c22i_T8nGc6qQTmf7hVPCXXI9UeR/s1600/hapCube_2014.10.28-14.33.13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievfM0BXoqOCslipOBiUrAhRgKtUhNFSGOgyayJBI6exfaDwGsRbKMfmdhptY9nxU-F__KbwOEq40AdCJ9CW6VpEXSQjtr_xgN75qpYoKMqefJcuJ3c22i_T8nGc6qQTmf7hVPCXXI9UeR/s1600/hapCube_2014.10.28-14.33.13.png" height="290" width="320" /></a></div>
<br />
<br />
Some days well spent!!<br />
<br />
<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-27918550540975492502014-10-25T17:16:00.000+01:002014-10-25T17:16:10.798+01:00Hap attack (and Quicktime fun)<div dir="ltr" style="text-align: left;" trbidi="on">
A little while ago I got asked to add Hap support in vvvv.<br />
<br />
This is a rather simple format, idea is that you get a BC1/BC3 frame (with small snappy compression), so you can do fast GPU upload.<br />
<br />
It's more or less the scheme used by many "media servers", one difference is that all is packed in a single file instead of a bunch of dds files.<br />
<br />
It's a pretty useful format since frame load is very fast, and can even be done within the frame, so you can have perfect synchronisation between videos on a single (or multiple) machines.<br />
<br />
So the first step is to simply decode a frame, as a test rig I just used a media foundation source reader, which hapilly gives me a sample (aka: a frame), in compressed form.<br />
<br />
Once you have this, everything is reasonably straightforward:<br />
<br />
First 4 bytes are [length] (3 bytes) + Flag (1 byte)<br />
<br />
Flag gives you compression + format like this (c#):<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="9" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">enum</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">hapFormat</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGB_DXT1_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAB</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGB_DXT1_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBB</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">RGBA_DXT5_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAE</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">RGBA_DXT5_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBE</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">YCoCg_DXT5_None </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xAF</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">YCoCg_DXT5_Snappy </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0xBF</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Once you have this, you need to call Snappy to decompress (if relevant):<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="143" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> uncomp </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b8d7a3;">SnappyStatus</span><span style="background: #1e1e1e; color: gainsboro;"> st </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SnappyCodec</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetUncompressedLength(bptrData, frameLength, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> uncomp);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">st </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SnappyCodec</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Uncompress(bptrData, frameLength, (</span><span style="background: #1e1e1e; color: #569cd6;">byte</span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;">)snappyTempData, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> uncomp);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">initialData </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> snappyTempData;</span></li>
</ol>
</div>
</div>
<br />
<br />
I just used an existing P/Invoke wrapper, no need to waster time reinventing the wheel:<br />
<br />
http://snappy4net.codeplex.com/<br />
<br />
Now you have your frame ready, you just have to upload to your GPU :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="153" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Texture2DDescription</span><span style="background: #1e1e1e; color: gainsboro;"> textureDesc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Texture2DDescription</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">ArraySize </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">BindFlags </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">BindFlags</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ShaderResource,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">CpuAccessFlags </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">CpuAccessFlags</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">None,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Format </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> format</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetTextureFormat(),</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Height </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">frameSize</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Height,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Width </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">frameSize</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Width,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">MipLevels </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">OptionFlags </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ResourceOptionFlags</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">None,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">SampleDescription </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> SharpDX</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">DXGI</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">SampleDescription</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">),</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Usage </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ResourceUsage</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Immutable</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DataRectangle</span><span style="background: #1e1e1e; color: gainsboro;"> dataRectangle </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DataRectangle</span><span style="background: #1e1e1e; color: gainsboro;">(initialData, format</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetPitch(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">frameSize</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Width));</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Texture2D</span><span style="background: #1e1e1e; color: gainsboro;"> videoTexture </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Texture2D</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device, textureDesc, dataRectangle);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;"> videoView </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ShaderResourceView</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device, videoTexture);</span></li>
</ol>
</div>
</div>
<br />
format.GetTextureFormat() takes care of properly converting the hap format to the relevant BC texture format.<br />
<br />
That was about it to decode a frame, hardcore work ;)<br />
<br />
Now as usual this part is only the tip of the iceberg, you have to think how to handle playback.<br />
<br />
My initial thought was to continue using Media Foundation source reader, so I write a little player and check decode time, around 1.5ms per full hd frame (on a laptop with no SSD).<br />
<br />
So all is pretty promising, really fast decode access, but then you reach the point where you want to loop your video, (which involves calling SetCurrentPosition on your source reader).<br />
<br />
Surprisingly, this is extremely slow, grabbing a frame after a seek suddenly takes 60ms (which is far too much obviouly). That completely removes random play (seek every frame) as well.<br />
<br />
So back to the good old windows AVI api, which just parses file and allows you to load a random frame in memory.<br />
<br />
First we load the file:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="58" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIFileInit();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">fileHandle </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> r </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIFileOpen(</span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> fileHandle, </span><span style="background: #1e1e1e; color: #d69d85;">@"E:\repositories\cartfile\other\EncodingTest\sample-1080p30-Hap.avi"</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">OF_READWRITE, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIFileGetStream(fileHandle, </span><span style="background: #1e1e1e; color: #569cd6;">out</span><span style="background: #1e1e1e; color: gainsboro;"> videoStram, </span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">streamtypeVIDEO, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">AVISTREAMINFO</span><span style="background: #1e1e1e; color: gainsboro;"> streamInfo </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">AVISTREAMINFO</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIStreamInfo(videoStram, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> streamInfo, </span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SizeOf(streamInfo));</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">BITMAPINFO</span><span style="background: #1e1e1e; color: gainsboro;"> bi </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">BITMAPINFO</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> biSize </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Marshal</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SizeOf(bi);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIStreamReadFormat(videoStram, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> bi, </span><span style="background: #1e1e1e; color: #569cd6;">ref</span><span style="background: #1e1e1e; color: gainsboro;"> biSize);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">SharpDX</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Multimedia</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">FourCC</span><span style="background: #1e1e1e; color: gainsboro;"> fcc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> SharpDX</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Multimedia</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: #4ec9b0;">FourCC</span><span style="background: #1e1e1e; color: gainsboro;">(bi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">bmiHeader</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">biCompression);</span></li>
</ol>
</div>
</div>
<br />
Please note that we get the Hap FourCC in the bitmap compression header (so we of course add a check to verify our AVI is encoded using Hap.<br />
<br />
Now to get a frame, we simply call:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="123" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Avi</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AVIStreamRead(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">videoStram, frameIndex, </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">aviTempData, </span><span style="background: #1e1e1e; color: #b5cea8;">1920</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1080</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
</ol>
</div>
</div>
<br />
<br />
With our frame Index. Since Hap uses one keyframe per frame, this is extremely fast.<br />
Once done we upload to GPU as previous.<br />
<br />
Now bit of code to integrate into vvvv, just wrap all that lot into some plugins:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMUTnOJXJyxBx5iyr77xc-YouY5XF2FOmN3wiIe-t3qolPKiNXgls_a7_JlKgiSizHMV5ilZEnlNTn6DrAkXLSwlqHK4sQLKj0Lf6GngYZ5ZD8_TWYHmY_37x05Kiiq8dUndalflMW8yaO/s1600/hapTest_2014.10.25-15.39.11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMUTnOJXJyxBx5iyr77xc-YouY5XF2FOmN3wiIe-t3qolPKiNXgls_a7_JlKgiSizHMV5ilZEnlNTn6DrAkXLSwlqHK4sQLKj0Lf6GngYZ5ZD8_TWYHmY_37x05Kiiq8dUndalflMW8yaO/s1600/hapTest_2014.10.25-15.39.11.png" height="320" width="301" /></a></div>
<br />
<br />
That's pretty much it. Please note that upload is so fast that I didn't bothered yet to do any buffering. I quite like the concept of "ask for this frame and get it" :)<br />
<br />
Now one thing is that hap can have 2 containers. Avi (from the directshow codec), or MOV (from the quicktime codec).<br />
<br />
Of course most hap files from people using this thing called Mac will encode using the second codec. It's actually easy to change container, but well, it would be much better to read quicktime files directly.<br />
<br />
That causes an initial problem, you need Quicktime installed on Windows (which sucks), and that implies to use the QuickTime SDK for windows (which has been abandoned more than 5 years ago). So that also mean forget 64 bits support.<br />
<br />
As a side note, I can limit my use case, I only want to read Hap, if a video is from another codec my player just will not accept it.<br />
<br />
So let's see if we can't just parse that mov file and just extract raw data like we do using AVI.<br />
<br />
Here only difference, I did not found any wrapper (like vfw.h does for AVI), so time to go read specifications and open Hexadecimal editor ;)<br />
<br />
For people interested, I will leave you to read the whole specs :<br />
https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFPreface/qtffPreface.html#//apple_ref/doc/uid/TP40000939-CH202-TPXREF101<br />
<br />
But let's summarize,<br />
<br />
QuickTime files use the concept of Atom (which more or less just a Node in a tree structure).<br />
Each Atom has a length, a code (fourcc) and can either contain other atoms or data, this is structured this way:<br />
<br />
[Length 4 Bytes][FourCC 4 Bytes][Data = Length - 8 Bytes]<br />
<br />
Yes length parameter includes itself and FourCC.<br />
<br />
Please note there is nothing in the file format to know automatically is an Atom is a Leaf (data) or a Container (contains other Atoms), so you have to go read the documentation and find by yourself.<br />
<br />
First atom is called : File Type compatibility (contains a header to check is it's a valid quicktime file, plus few version info.<br />
<br />
Next we have "wide", which is a special one to allow to add a flag for large files.<br />
<br />
Then we have "mdat" , which contains all the sample data (where we want to read from). But of course for now we don't know how data is organized.<br />
<br />
So we need to go to the next one (called "moov"). Which contains all the information we need. There's a really high amount of options, but roughly from there we retrieve frame per second, and track list ("trak" atom).<br />
<br />
We can already go into the track header ("tkhd" atom) to retrieve track length / size.<br />
<br />
Then our work is not finished, we need to check if our file is Hap, this is contained in the "stsd" atom (Sample Description).<br />
<br />
Once we are in the sample table, the most important data is at the reach of our hand (how to find position/length of a frame).<br />
<br />
First, data is organized in chunks. A chunk contains one or more samples (so for example you can load the whole chunk from file instead of one at a time).<br />
<br />
So we need to enumerate file offset for each chunks, which is contained into the "stco" Atom (Chunk Offset Atom).<br />
<br />
Data is simply a prefix table, which contains file offset for each chunk. Please note the offset is absolute to the file, which makes it much easier since once we get that data we don't need to check for child Atom anymore.<br />
<br />
Here is the data for a test mov file (powered by Hex Editor and Windows calculator ;)<br />
<br />
stco (chunkoffsets)<br />
Chunk 1 Offset : 48<br />
Chunk 2 Offset : 1015901<br />
Chunk 3 Offset : 2030918<br />
Chunk 4 Offset : 3045373<br />
Chunk 5 Offset : 4058366<br />
Chunk 6 Offset : 4348429<br />
<br />
Pretty simple, since all is absolute search is also much faster.q<br />
<br />
Now, we need to know each Sample (or frame) size.<br />
<br />
All frames size are contained in a single Atom ("stsz"), so we go thought them and get frame length:<br />
<br />
stsz (sample size table)<br />
Sample 1 : 144974<br />
Sample 2 : 145333<br />
Sample 3 : 145210<br />
Sample 4 : 145344<br />
Sample 5 : 145065<br />
Sample 6 : 144811<br />
<br />
Now we still don't know how samples relate to chunks (the last missing piece of the puzzle).<br />
<br />
Now we need to read data in "stsc" atom (Sample to Chunk), which is a prefix table.<br />
<br />
In my sample mov, this is described this way:<br />
<br />
stsc (sample to chunk)<br />
First/Sample Per Chunk/ Descriptor<br />
1 / 7 / 1<br />
5 / 2 / 1<br />
6 / 1 / 1<br />
<br />
As you can see this is compressed (7+2+1 = 10), and my file has 31 frames.<br />
<br />
So this simply expands, as from 1 to 5 (the first 4 chunks), we have 7 samples.<br />
<br />
Which is correct, since 7*4+2+1 = 31<br />
<br />
<br />
So that's about it, with all that data we are ready to roll, we first build a prefix sum for chunk offsets:<br />
0 - 7 - 14 - 21- 28 - 30<br />
<br />
From this it's pretty easy to retrieve in which chunk our frame is contained.<br />
<br />
Once we know chunk + position in chunk, we need to iterate using each sample length until we reach our position.<br />
<br />
So third frame location is :<br />
<br />
First Chunk = 48 + 144974 + 145333<br />
<br />
Of course we can precompute all this (per chunk or per sample), so we end up having 2 arrays:<br />
frameindex->location<br />
frameindex->size<br />
<br />
Then we just load our frame from file into memory, and rinse and repeat the Hap upload.<br />
<br />
So here we go, Hap decoder (small SharpDX standalone sample) , which reads Hap MOV file without any need for QuickTime installed.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSuiC8Li_i-aUi8vbVKr1Y9U0_pY3L6EWTGO9Msq1hdBaC6XsPlFMsTWakQlFvuXti6e9BRQfUM95O_74Vgo9aoqUkDLyCjdvdH2QxBJdWSR_A6UdSltOCiWa2mIi-YZGlrxECj7gtkqxe/s1600/hopmo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSuiC8Li_i-aUi8vbVKr1Y9U0_pY3L6EWTGO9Msq1hdBaC6XsPlFMsTWakQlFvuXti6e9BRQfUM95O_74Vgo9aoqUkDLyCjdvdH2QxBJdWSR_A6UdSltOCiWa2mIi-YZGlrxECj7gtkqxe/s1600/hopmo.png" height="252" width="320" /></a></div>
<br />
<br />
<br />
Fun times<br />
<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-20382406289783588312014-08-10T15:08:00.001+01:002014-08-10T15:08:38.336+01:00Implicit Converters<div dir="ltr" style="text-align: left;" trbidi="on">
I already spoke a bit about converting types.<br />
<br />
Since in FlareTic all the "dataflow patch types" use some form of generic holder for pins, link is done simply as:<br />
<br />
Check if input type is assignable from output type, if yes allow link.<br />
Now this creates some issues as for example float is not assignable to bool.<br />
<br />
So I don't want to create AsBool (Float) , AsFloat(Bool) and so on for all types, that makes a patch bloated for nothing, I need another solution.<br />
<br />
Enters converters<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="33" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverterFactory</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> CanConvert(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> from, </span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> to);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: gainsboro;"> CreateConverter();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> Convert(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> from);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> Warning { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> WarnMessage { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
The first interface allows to check if we can convert types, and when we connect creates the converter that does the job.<br />
<br />
Now when we check for connection, we have a list of factories, so if we find a converter, we can link :)<br />
<br />
For raw .NET primitive types, you have to build by yourself, so to speed this up, few generic builders:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">FuncConverter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> convertFunc;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> warning;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> message;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> FuncConverter(</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> func, </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> warning, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> message)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">convertFunc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> func;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">warning </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> warning;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">message </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> message;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> Convert(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> from)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">convertFunc((TFrom)from);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> Warning</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">warning; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> WarnMessage</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">message; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And the factory :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="40" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">abstract</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">FuncConverterFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverterFactory</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> convertFunc;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> warn;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> msg;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> FuncConverterFactory(</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> func, </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> warning </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">false</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> message </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">convertFunc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> func;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">warn </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> warning;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">msg </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> message;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> CanConvert(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> from, </span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> to)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> from </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TFrom) </span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> to </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TTo);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: gainsboro;"> CreateConverter()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">FuncConverter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TFrom, TTo</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">convertFunc, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">warn, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">msg);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
Next bit of boilerplate, could have done several ways, but you only do it once ;)<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="64" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">IntToFloatConverter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #4ec9b0;">FuncConverterFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> IntToFloatConverter() : </span><span style="background: #1e1e1e; color: #569cd6;">base</span><span style="background: #1e1e1e; color: gainsboro;">(i </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> i) { }</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">FloatToIntConverter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #4ec9b0;">FuncConverterFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> FloatToIntConverter() : </span><span style="background: #1e1e1e; color: #569cd6;">base</span><span style="background: #1e1e1e; color: gainsboro;">(f </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;">)f, </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #d69d85;">"Conversion from float to int is explicit, some data can be lost"</span><span style="background: #1e1e1e; color: gainsboro;"> ) { }</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
You can notice that explicit casting also induce a message, so we can warn user in some cases.<br />
<br />
Now for all other types, we go reflect implicit/explicit table for other types:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="131" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ImplicitReflectionConverterFactory</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverterFactory</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> CanConvert(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> from, </span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> to)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> f </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> from</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetMethods()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">m </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"op_Implicit"</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReturnType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> to</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Count() </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">]</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ParameterType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> from)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FirstOrDefault() </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (f) { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">f </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> to</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetMethods()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">m </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"op_Implicit"</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReturnType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> to</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Count() </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">]</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ParameterType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> from)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FirstOrDefault() </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> f;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: gainsboro;"> CreateConverter()</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ImplicitReflectionConverter</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now let's go a bit forward, why not also being able to auto convert opencv image to dx11 texture, that's why you use a converter factory, since now converter will also hold a resource, so we need one instance per link.<br />
<br />
Converter code is just boilerplate, create texture for the same format as opencv image, and copy content in gpu when possible.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw5k2evvE-V-GPwXrQMY3l1BXqd65Te3VcNWVEr32JA8rzcRAbEZjIWxijdkpqEHHvuNmC6K6idE8UDJgXPX3lta4gLxnu8ZC8f6rSa7cdpDcbu6IFU0jLWmtZWonqY1yCS1v8zn05t1Ji/s1600/implicit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw5k2evvE-V-GPwXrQMY3l1BXqd65Te3VcNWVEr32JA8rzcRAbEZjIWxijdkpqEHHvuNmC6K6idE8UDJgXPX3lta4gLxnu8ZC8f6rSa7cdpDcbu6IFU0jLWmtZWonqY1yCS1v8zn05t1Ji/s1600/implicit.png" height="171" width="320" /></a></div>
<br />
Here we go, of course user interface must reflect that we are using a converter, so blue mean converter, yellow means converter with warning.<br />
<br />
Now opencv image can be directly linked to any node that wants a texture, and you can notice sharpdx types can be auto translated (Color4 has a Vector3 explicit operator, so it's automatically scanned by the reflector).<br />
<br />
I love clean patches ;)<br />
<br />
Now one common issue, we might want some form of control over the conversion, for example, float to string, we'd like to specify a format. So let's push the concept forward and make our link configurable via inspector.<br />
<br />
Easy then, let's add a small additional interface:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="46" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IConfigurableTypeConverter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IParameter</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Parameters { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And here we go:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="13" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">StringFormatConverter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IConfigurableTypeConverter</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">StringParameter</span><span style="background: #1e1e1e; color: gainsboro;"> format;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> StringFormatConverter()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">format </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">StringParameter</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">StringParameterConverter</span><span style="background: #1e1e1e; color: gainsboro;">());</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">format</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Value </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"f"</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">format</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"Format"</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> Convert(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> from)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{ </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">String</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Format(</span><span style="background: #1e1e1e; color: #d69d85;">"{0:"</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> format</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Value </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"}"</span><span style="background: #1e1e1e; color: gainsboro;">, from);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> Warning</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">false</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> WarnMessage</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IParameter</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Parameters</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">yield</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">format;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now when we select a link in the editor, if it implements this interface we can manage properties, as per the screenshot:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVpRTzedxdukbW6cS9N2V2pvyt0_zCWDPDckEDRtZ7eV9Uc1oDrk6a-DjBhz7wSppH8Bv7S1bK-Ek-OniiQaqW170qNEJkpbjbShBA4Zq34kyzrXBj1PecyluBN14lut3lUtWE2tRrdwBx/s1600/linkattrib.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVpRTzedxdukbW6cS9N2V2pvyt0_zCWDPDckEDRtZ7eV9Uc1oDrk6a-DjBhz7wSppH8Bv7S1bK-Ek-OniiQaqW170qNEJkpbjbShBA4Zq34kyzrXBj1PecyluBN14lut3lUtWE2tRrdwBx/s1600/linkattrib.png" height="99" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So far it's great, using the reflection from c# helped to speed up the process a lot.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
On next stage, we have the obvious question/problem, what happens if we have multiple converters that allow similar types?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here we have several choices:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>Take the first one</li>
<li>Show a selector when we complete link</li>
<li>Have the selector in the inspector instead</li>
</ul>
<div>
I haven't made a choice, but take first one + selector is the most sensible option for now.</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-60191998715478368722014-08-03T16:36:00.002+01:002014-08-03T16:37:06.474+01:00Timeliner - Part 2<div dir="ltr" style="text-align: left;" trbidi="on">
So after playing with doing dx11 track rendering, I was speaking with some friends, and they shown me some screenshots of after effects timeline (I knew a bit how it was looking like but my memory was rusty).<br />
<br />
What I actually like in the is the minimalism, you don't really display curves, which is pretty cool, and then all timelines are consistent, it makes it much easier to use several data types (and in my tool i got a lot).<br />
<br />
That would also integrate pretty well with my tool, since I can easily push a parameter to the timeline, track count will grow rather steadily.<br />
<br />
So I start to work on the design, since I got a Direct2d renderer I might as well reuse is (it's far from perfect, but it's nice enough and I can add improvements on the way, why rewrite something from scratch again anyway).<br />
<br />
I decided to take group into account right away, and just draw circles instead of rotated quads (was lazy to build path, and anyway circle look nice).<br />
<br />
Instead of directly integrating I just generate a small dataset so I can have a feel,<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiKSBc4dbr0SfM2rPQU__n4at26TvKTkmgKtcv4fXoUn_IPRqMPvwy8uJtVYhyy34jrJn0zt_dcoCDRxeBY2rOKxoRVX5VxphYYEeAskvbiu34Uai1UDir2kXQTzDSSgzHrjT-H2vvrz5O/s1600/tm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiKSBc4dbr0SfM2rPQU__n4at26TvKTkmgKtcv4fXoUn_IPRqMPvwy8uJtVYhyy34jrJn0zt_dcoCDRxeBY2rOKxoRVX5VxphYYEeAskvbiu34Uai1UDir2kXQTzDSSgzHrjT-H2vvrz5O/s1600/tm.png" height="45" width="320" /></a></div>
<br />
First iteration is nice, now you of course need a header and a time ruler, plus play/stop/loop buttons.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVMI51kNFON2UDQxOljne9k0-SeHAjx-n3ImkF1IogDf_NEWMNdfx90oAEmgMgEp8_dVwZoPSSAYZI9dVPWMakUC19Cez8gRbkgqqR5xHVInbUfWfmgU1sw4h6vshbV7lx1AV6ze6kt2lh/s1600/tm3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVMI51kNFON2UDQxOljne9k0-SeHAjx-n3ImkF1IogDf_NEWMNdfx90oAEmgMgEp8_dVwZoPSSAYZI9dVPWMakUC19Cez8gRbkgqqR5xHVInbUfWfmgU1sw4h6vshbV7lx1AV6ze6kt2lh/s1600/tm3.png" height="61" width="320" /></a></div>
<br />
Next you need to show information about a keyframe, so I built a small tooltip:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWgn5SCh6N_IjX51zG4LiFL3hyO-NtT23_Ch7uN7VNAmUnxSZhakjeKT6UxvAdfRJq_bZ4Oqv58wCC10qAndsAdl-CqslXtSJGPeKpB7R-DPwFBYpQvMryqcWnTCT0LIRYP9K97vB1gLa4/s1600/tm4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWgn5SCh6N_IjX51zG4LiFL3hyO-NtT23_Ch7uN7VNAmUnxSZhakjeKT6UxvAdfRJq_bZ4Oqv58wCC10qAndsAdl-CqslXtSJGPeKpB7R-DPwFBYpQvMryqcWnTCT0LIRYP9K97vB1gLa4/s1600/tm4.png" height="50" width="320" /></a></div>
<br />
Now I wrote track evaluators, to start to attach tracks to parameters, add a register (so if a parameter datatype is not registered I simply can't create a track from it.<br />
<br />
Since speaking about evaluation, I looked at 3 techniques:<br />
<br />
<ul style="text-align: left;">
<li>Check in linear way: You have a list of keyframe sorted by time, and search from the beginning. This is obviously the easiest, but the further you are in your timeline the slower it gets. If you don't have many tracks/keyframes it's ok, but it can become inefficient rather fast. This is how it's done in 4v timeline so far.</li>
<li>Linear playback optimization: Since you consider that most time you will just play, you store current key frame, and on each time step check if you passed the next. This is how it's done in Duration. This is totally great for pure linear playback, but you need to fall back to the linear version for seeking. If you start to add timeline automation you can have some issues.</li>
<li>Tree based structures : You use whatever form of binary tree optimization, so you get faster look up. It costs a bit more on adding/removing keyframe, but you get a decent gain on playback (which is generally desired in case of real time rendering). In my case I use interval tree, which is a technique I used first on databases 10 years ago, and used it to optimize some skinning animations a while back too. It's easy to implement, and you get a balance between linear playback/seek, which fits pretty well my use case. I could also easily fallback to previous technique if I need automation, or even better do a mix of both (use tree as soon as you need a seek, then move back to linear optimized version once you got your keyframe again).</li>
</ul>
<br />
<br />
Next, I'm not interested to build groups myself, so they simply are generated per patch, which makes my life much easier, and it's much clearer to see what parameter belongs where:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivEsLKVtPu7KOpGt9KdSxgaiRdw1w7UZvJ55v1nnbeL3TQcQnvAABdMTOMUeIZ2NyILsIoWYSBDDwYH5nORZMwYLD215NXaXzsXLAvhfDcT6fgRriVaUTh6R0IO35dE2HmYYdBt_Yw_BKR/s1600/tm5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivEsLKVtPu7KOpGt9KdSxgaiRdw1w7UZvJ55v1nnbeL3TQcQnvAABdMTOMUeIZ2NyILsIoWYSBDDwYH5nORZMwYLD215NXaXzsXLAvhfDcT6fgRriVaUTh6R0IO35dE2HmYYdBt_Yw_BKR/s1600/tm5.png" height="173" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next you do all the usual part, standard editor features, probably forgot same that are done, but well as a user you know what's required ;)</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>Load/Save to file (json)</li>
<li>Make collapsing work</li>
<li>Move key-frames</li>
<li>Move global timer</li>
<li>Add a node to retrieve timer from timeline</li>
<li>Add more datatypes (for now there's bool/float/int/vector2/vector3/quaternion/string)</li>
</ul>
<div>
To integrate in my tool it's also pretty simple, press shortcut on a parameter to create a track, then another shortcut to push value from it at current time, simplicity at it's best.</div>
<div>
<br /></div>
<div>
After one thing , you also want to edit values, so I found that showing editor windows was cumbersome (but needed for some types, so still in the plan).</div>
<div>
<br /></div>
<div>
So for some simple types I added a small shortcut handler, so if a keyframe is selected you can do quick keyboard control (like arrows for value, space switches a bool on/off).</div>
<div>
<br /></div>
<div>
Still some features missing of course (multi select is next but easy as hell, small editor widgets), but even in that state it's already pretty usable, which I find great considering I did not even work more than 2 days on it, really it's impossible to do a timeliner wrong ;)</div>
<div>
<br /></div>
<div>
I specially love how nicely it integrates, push parameter, add key-frames, workflow feels pretty seamless it's great.</div>
<div>
<br /></div>
<div>
Here is a sample of the whole layout in action (visual suck but it's to show the timeline after all)</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4xux3pdIRcZ1fCtkcUdfGvZWXtfbCxwz8hCT23yt-SQnCWV1VKLC6vCVVG5OqYWf2wF2EisNuqDTHlcT-xZWzX6rF_-Sce-9BueL3sazBZVkNE42BkcTZG8yZcURvzjSEzUfMvcS-ez5/s1600/tm7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4xux3pdIRcZ1fCtkcUdfGvZWXtfbCxwz8hCT23yt-SQnCWV1VKLC6vCVVG5OqYWf2wF2EisNuqDTHlcT-xZWzX6rF_-Sce-9BueL3sazBZVkNE42BkcTZG8yZcURvzjSEzUfMvcS-ez5/s1600/tm7.png" height="180" width="320" /></a></div>
<div>
<br /></div>
<br />
New milestone reached ;)<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-3749320090733595512014-07-31T20:27:00.003+01:002014-08-01T12:04:10.756+01:00Timeline<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
One obvious very useful feature for most graphics and audio toolset is some form of timeline.<br />
<br />
In 4v you have the native one, which with a little effort could become ok (add undo, move keyframes with keyboard, export/import, and better color editor), but in it's current state is at best irritating. It's not as bad as the hlsl code completion in 4v but that's another story ;)<br />
<br />
Then you have more standalone ones, vezer looks pretty cool but mac only, so not for me.<br />
<br />
You also have duration, which is likely the best but has 2 major flaws, missing scroll and groups. Also opengl rendering would not fit as easily to integrate in my tool.<br />
<br />
Then you have this brand new Posh svg, new 4v timeliner, presented as usual as the next big thing which will make your grandmother dance rock and roll again, and so and so.<br />
<br />
So first pre alpha release tests were let's call it.... disappointing. Only one track type, no interpolation, and an amount of ui bugs that it could just eat a piece of wood like piranhas would eat my bum.<br />
Next first "public" release is well... appalling, I personally hardly see the point of releasing something in that state, except to show off your incompetence at building user interface.<br />
<br />
So first thing you do when you build a timeliner, you prepare a decent track setup, there is NO point showing 5 key frames and one track. So I start to prepare 8 tracks, 40 key frames each (which is really a small setup), and then everything goes laggy, I get 40 % cpu usage (where the hell does that go), selecting and moving several frames just blow up everything, you can't even recover and have to restart the software, usability at it's best.<br />
<br />
So well I start to report those issues, and happily suggest that some DirectX11/OpenGL rendering for that type of things would likely fit and scale much nicer, but only reply I get is "yes I know it's slow but I don't care Dx is not as interesting as svg". So I try to explain that well if your ui doesn't scale, you might look for something else, but I get the usual "I don't give a fuck type of attitude which pisses me off so much". We suggested that actually some of the changes could easily make it through the old one (some undo + key) , I get the same I don't give a fuck.<br />
<br />
So well I don't really understand the point (and as a user slightly pissed off that you have to pay 500 euros a license to get that type of answer). And I feel really horrified that this took several month to produce, I'm getting really worried about user interface in the next vvvv50, since in current version since there's no will to improve the old version, then it gets decided to produce a brand new ui framework which is as shit, so I got more or less no faith that we will ever have a decently smooth user interface in previous or next gen vvvv.<br />
<br />
But let's stop whining and go to the more fun part ;)<br />
<br />
So I'm still without a timeliner, since now I got 2 10% baked unusable pieces of junk, and some others which are nice but I can't integrate them.<br />
<br />
So since I also mentioned dx11 would be a good candidate, I decided to spend an afternoon doing track renderers. Also that would really prove a point that modern rendering wins against this browser jazz. I also decided to only focus on the rendering for now, since well it's not too hard to hittest and drag a point after all ;)<br />
<br />
Main focus is also to of course have some fast rendering, I want a smooth user interface ;)<br />
<br />
I just push my tracks into buffers and then render them. I decided to start with color, which is really simple.<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="7" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> ColorKeyFrame</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> color</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> time</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> trackid</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> KeyFrameLink</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> left</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> right</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">ColorKeyFrame</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> ColorKeyFrameBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: #569cd6;">StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">KeyFrameLink</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> ColorLinkBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> TrackOffsetBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #57a64a;">//x = top, y = height</span></li>
</ol>
</div>
</div>
</div>
<br />
Render a bulk of instanced quads, grab color on the left keyframe, color on the right keyframe, position with a map function.<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="44" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">psInput VS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">vsInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">psInput output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">KeyFrameLink cl </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ColorLinkBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ii</span><span style="background: #1e1e1e; color: #b4b4b4;">]; </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">ColorKeyFrame left </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ColorKeyFrameBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">cl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">left</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">ColorKeyFrame right </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ColorKeyFrameBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">cl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">right</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> tid </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ii</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">tid </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> tid </span><span style="background: #1e1e1e; color: #b4b4b4;">/</span><span style="background: #1e1e1e; color: gainsboro;"> cpPerTrack</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> pos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> offset </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> TrackOffsetBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">tid</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> map</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">left</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">time</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">right</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">time</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">*=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">2.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">-=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y </span><span style="background: #1e1e1e; color: #b4b4b4;">+=</span><span style="background: #1e1e1e; color: gainsboro;"> offset</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y </span><span style="background: #1e1e1e; color: #b4b4b4;">*=</span><span style="background: #1e1e1e; color: gainsboro;"> offset</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">pos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> mul</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">),</span><span style="background: #1e1e1e; color: gainsboro;">tRange</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">colstart </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> left</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">color</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">colend </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> right</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">color</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Send to the (hardcore) pixel shader:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="78" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> PS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">psInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_Target</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span><span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> lerp</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">colstart</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">colend</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
That was so hard ;)<br />
<br />
Now let's go for value, positioning keyframe point, well one small Segment instance, just so simple that there's nothing to say about it, now let's build the connections, and let's add the fact that I want more curves (aka tweens):<br />
<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="7" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> ValueKeyFrame</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> value</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> time</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> trackid</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> interpolation</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> KeyFrameLink</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> left</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> right</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<br />
<br />
Of course usual buffers are there too, we send a PatchListWithOneControlPoint batch for each connection (we don't need 2, that's beautiful).<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="43" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> linkData</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> left </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> CPOINT0</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> right </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> CPOINT1</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<br />
Now we only need to pass trough keyframe IDs till we reach the domain shader:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="144" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">domain</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #d69d85;">"isoline"</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">psInput DS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">hsConstantOutput input</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">OutputPatch</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">linkData</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> op</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> uv </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_DomainLocation</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">psInput output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> t </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> uv</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">ValueKeyFrame kl </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ValueKeyFrameBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">op</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">left</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">ValueKeyFrame kr </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ValueKeyFrameBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">op</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">right</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> start </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ComputePosition</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">op</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">left</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> end </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> ComputePosition</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">op</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">right</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> x </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> lerp</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">start</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">end</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">t</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> y </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> lerp</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">start</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">end</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">lerpFunc</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">t</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">kl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">interpolation</span><span style="background: #1e1e1e; color: #b4b4b4;">));</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> pos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">pos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> mul</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">pos</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">0.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">),</span><span style="background: #1e1e1e; color: gainsboro;"> tRange</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
lerpFunc selects interpolation function, which are all the basic tween modes.<br />
<br />
Now well, bang track is simple instanced quad or line, nothing to speak about.<br />
<br />
Then let's add wave track, I thought it would be a bit complicated, but that was so easy it's even embarrassing. So first get your favorite audio API (I used Bass). Load a music file, read all the samples as float and feed to a big fat structured buffer (float or float2). I chose float since at least i push any type of multi channel later.<br />
<br />
Render a quad, then here is the insane pixel shader:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="38" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> PS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">psInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_Target</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span><span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> cnt</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> stride</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">WaveDataBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetDimensions</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">cnt</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">stride</span><span style="background: #1e1e1e; color: #b4b4b4;">); </span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> off </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> cnt</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> xpos </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;"> off</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> sampleleft </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> WaveDataBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">xpos</span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: #b5cea8;">2</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> sampleright </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> WaveDataBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">xpos</span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: #b5cea8;">2</span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> y </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">; </span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">y </span><span style="background: #1e1e1e; color: #b4b4b4;">*=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">2.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">y </span><span style="background: #1e1e1e; color: #b4b4b4;">-=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">abs</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">sampleleft</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> abs</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">))</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0.1f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
That was hardcore, I could do a bit of oversampling for sure, but it already looks pretty ok.<br />
<br />
So here we go, then you add a small ruler.<br />
<br />
And now pushing some 4000 keyframes:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVeHS37NQ67AEnH-o2st0HpZU-YO8r7EjVtu-C5VsEadmyy-8LLtw6XkDaWV4YQtZ8uZnnHIPZ-cWCendy8zu2fCEKbOUsX7MjoIkGz2Xja_NRpOyTe4iKnoqlUXJ7tfPhySU6B7e0W9T3/s1600/t3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVeHS37NQ67AEnH-o2st0HpZU-YO8r7EjVtu-C5VsEadmyy-8LLtw6XkDaWV4YQtZ8uZnnHIPZ-cWCendy8zu2fCEKbOUsX7MjoIkGz2Xja_NRpOyTe4iKnoqlUXJ7tfPhySU6B7e0W9T3/s1600/t3.png" height="180" width="320" /></a></div>
<br />
Unzoomed view:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwnTFIuRGBwWBxhloi3sNTk5lVjotyAwXEbKz4yP1NLLtnQki_oE2BH_MoSXPsey2PbeoZff1vk-U9Iijxu2IQnuF4OViMqEbZPce2c_jLmxINRhcZqCxmD3TTwIWpqDrnGKLBmMdCAs7J/s1600/t.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwnTFIuRGBwWBxhloi3sNTk5lVjotyAwXEbKz4yP1NLLtnQki_oE2BH_MoSXPsey2PbeoZff1vk-U9Iijxu2IQnuF4OViMqEbZPce2c_jLmxINRhcZqCxmD3TTwIWpqDrnGKLBmMdCAs7J/s1600/t.png" height="180" width="320" /></a></div>
<br />
And let's push the ui a little bit, since I said I wanted it to scale, 14K keyframes:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6ipfqTETlY-NXkzCchjaInVF52jODyJADZNSvUlfULt09rCjOBUG6nP-Nm0Vns7MHdW4c-JfPEOlTpgLo8_aXGJmE8BksWxW4-GmYD9YyEiw-NHWAgfPaJiv8s8zc93hkQZHl5KwaOd-/s1600/_Timeliner-Renderer_2014.07.31-21.15.22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6ipfqTETlY-NXkzCchjaInVF52jODyJADZNSvUlfULt09rCjOBUG6nP-Nm0Vns7MHdW4c-JfPEOlTpgLo8_aXGJmE8BksWxW4-GmYD9YyEiw-NHWAgfPaJiv8s8zc93hkQZHl5KwaOd-/s1600/_Timeliner-Renderer_2014.07.31-21.15.22.png" height="149" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
3 hours well spent, I now got a pretty decent scalable timeline renderer, which is a pretty huge step forward (80 fps rendering every frame, no caching is rather good so far).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
To conclude, hlsl > all :)</div>
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-74158851345705105142014-07-16T02:07:00.001+01:002014-07-16T02:07:55.940+01:00OpenCV, Compute and immutability<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
I know some of my friends use rather regularly the very nice OpenCV contribution from Elliot Woods.<br />
<br />
Most times people use the Camera/Projector calibration tool. This works pretty well (could do with some ui improvemements), but most times I wanted to look at it I always end up with the same problem, you need to download the whole Image pack.<br />
<br />
This is a great pack of course, but in that scenario, downloading a 500 megs bulk of dlls (which can also depend of version) is let's call "not ideal". Ok in our times with super fast internet you would think it's ok, but well, my hard drive doesn't like it (so I don't either). All that to call a single opencv function!<br />
<br />
So just wrote a small P/Invoke dll (and use static library linking instead of dynamic), one 20 lines of dynamic plugin to call the function and here we go, 1 megabyte dll which doesn't need any other external. I like minimalism ;)<br />
<br />
I remember I wanted to do this for a while, and considering the amount of (no) time it took I fell very embarrassed )<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihWPApdRB6ubpBkt4rJuKpOFuFiEqPggl3mSv-Mt765h7nHTmctsWC3JawND9gUgkPjrcUAfzUYK5Eq7uA1980Ia3IApuCJadQzwDfeFgcsCPKqAXEAa8VTzYaO_w9CsIrOfqUDwJ6oy32/s1600/oc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihWPApdRB6ubpBkt4rJuKpOFuFiEqPggl3mSv-Mt765h7nHTmctsWC3JawND9gUgkPjrcUAfzUYK5Eq7uA1980Ia3IApuCJadQzwDfeFgcsCPKqAXEAa8VTzYaO_w9CsIrOfqUDwJ6oy32/s1600/oc.png" height="170" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now after this there's a (few) things I wanted to add/change in that tool.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
First the point selection is nice in some cases, but not so nice in others. Basically current technique renders object space coordinates in a texture, then you just sample that texture.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If you have a model crammed with small polygons it's fine enough, but what I would simply like to do in general is just get closest vertex from a triangle raycast. Since I don't want to blow up 100k rays in cpu, and 3d model is already in GPU (as obviously we want to render it), let's do a little bit of compute shader ;)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So first let's load the model into a big fat buffer (to avoid subsets annoyance, simple prefix sum on indices), then we have the following data structures:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> PositionBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> POSITIONBUFFER</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> IndexBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> INDEXBUFFER</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">AppendStructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> AppendVertexHitBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> APPENDVERTEXHITBUFFER</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> raypos </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> RAYPOSITION</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> raydir </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> RAYDIRECTION</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> FaceCount </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> FACECOUNT</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> eps </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> EPSILON </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0.000001f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<br />
Pretty simple, mouse position is converted back to ray, and we use append buffer to get potential candidates (since we might hit several triangles).<br />
<br />
Now here is our ray shader (I omit the ray formula, which is the same as in http://www.geometrictools.com/ )<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="31" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">numthreads</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">64</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> CS_RayTriangle</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: gainsboro;"> dtid </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_DispatchThreadID</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">>=</span><span style="background: #1e1e1e; color: gainsboro;"> FaceCount</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> {</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: gainsboro;"> face </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> IndexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p1 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> PositionBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">face</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p2 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> PositionBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">face</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">y</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p3 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> PositionBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">face</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">z</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> diff </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> raypos </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> p1</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> e1 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> p2 </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> p1</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> e2 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> p3 </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> p1</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> n </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> normalize</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">cross</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">e1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">e2</span><span style="background: #1e1e1e; color: #b4b4b4;">));</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> DdN </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> dot</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">raydir</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">n</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> fsign</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> hit </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #57a64a;">//Do you rayhit</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">hit</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">AppendVertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Append</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">p1</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">AppendVertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Append</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">p2</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">AppendVertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Append</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">p3</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now when we hit a triangle, we append 3 vertices as "candidates", we now need to find the one closest to us. We could readback filtered data (using CopyResourceRegion), and finish computation on CPU, but that's not fun, so let's continue ;)<br />
<br />
First to think option is to sort the data, but that's expensive, we only want the closest element.<br />
<br />
So first let's process all elements and write the closest distance into a single buffer:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="72" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">numthreads</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">64</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> CS_MinDistance</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: gainsboro;"> dtid </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_DispatchThreadID</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">>=</span><span style="background: #1e1e1e; color: gainsboro;"> VertexHitCountBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Load</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">))</span><span style="background: #1e1e1e; color: gainsboro;"> {</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> VertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> d </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> distance</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">raypos</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">p</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> dummy</span><span style="background: #1e1e1e; color: #b4b4b4;">; </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">InterlockedMin</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">RWMinDistanceBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">],</span><span style="background: #1e1e1e; color: gainsboro;">asuint</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">d</span><span style="background: #1e1e1e; color: #b4b4b4;">),</span><span style="background: #1e1e1e; color: gainsboro;">dummy</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now we need to filter closest element:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="84" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">numthreads</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">64</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> CS_StoreIndex</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: gainsboro;"> dtid </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_DispatchThreadID</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x </span><span style="background: #1e1e1e; color: #b4b4b4;">>=</span><span style="background: #1e1e1e; color: gainsboro;"> VertexHitCountBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Load</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">))</span><span style="background: #1e1e1e; color: gainsboro;"> {</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> VertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">dtid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> d </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> distance</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">raypos</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">p</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> ud </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> asuint</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">d</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> mind </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> MinDistanceBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">]; </span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">InterlockedCompareStore</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">RWMinElementBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">],</span><span style="background: #1e1e1e; color: gainsboro;"> mind</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;">ud</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Please note that we don't store position directly since interlocked operations are only allowed on int/uint type. Also we don't handle case if we have more than one candidate, this is easy to replace Store by append (but anyway at some point we need to decide which point we select).<br />
<br />
And just get position:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="97" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">numthreads</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> CS_ExtractPosition</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">uint3</span><span style="background: #1e1e1e; color: gainsboro;"> dtid </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_DispatchThreadID</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> idx </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> RWMinElementBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">RWPositionBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">]</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> VertexHitBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">idx</span><span style="background: #1e1e1e; color: #b4b4b4;">];</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Copy those 12 bytes back in your CPU and you have your closest vertex.<br />
<br />
One part of the morning well spent )<br />
<br />
Now one feature which is always useful for a good editor (since at the end we edit points), if of course some form of undo/redo.<br />
<br />
You have three main ways to implement undo:<br />
<br />
<ul style="text-align: left;">
<li>For each action, use one function to update your model and one function to revert it. THis can be really cumbersome and error prone.</li>
<li>Serialize the state, and on undo create a new (or part modified) state from serialized data</li>
<li>Use immutable state</li>
</ul>
<div>
I have much growing interest into using more immutable in general, this is safer and i like the concept around it (ok it doesn't map well everywhere and can consume memory), but in that case (something like 10 points and couple projectors data), this sounds like a good use case.</div>
<div>
<br /></div>
<div>
So here is a calibration point:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CalibrationPoint(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">screenPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">objectPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> ScreenPosition</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">screenPosition; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> ObjectPosition</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">objectPosition; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
You can see that once we create our point, we can't change properties anymore.<br />
<br />
No to update properties, instead of setting data directly, we return a new point. There's a little way to help memory, if property is the same we return the same instance:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="31" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;"> SetScreenPosition(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">screenPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">?</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;">(screenPosition, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">objectPosition);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;"> SetObjectPosition(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">objectPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">?</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">screenPosition, objectPosition);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;"> Set(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">objectPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">screenPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition </span><span style="background: #1e1e1e; color: #b4b4b4;">?</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;">(screenPosition, objectPosition);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now do the same for Projector and calibration data:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> name;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> points;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> Projector(</span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> name, </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> points)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (name </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentNullException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"name"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (points </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentNullException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"points"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> name;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">points </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> points;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> Name</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">name; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Points</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">points; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
</div>
<br />
Some of the functions to modify (create new) state:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="44" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> AddPoint(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screenPosition, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> objectPosition)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> point </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;">(screenPosition, objectPosition);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">name, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">points</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Concat(</span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;">[] { point }));</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> RemovePoint(</span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;"> point)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">name, </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">points</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(p </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> point));</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Calibration class:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> projectors;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationSettings</span><span style="background: #1e1e1e; color: gainsboro;"> settings;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> Calibration(</span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationSettings</span><span style="background: #1e1e1e; color: gainsboro;"> settings, </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> projectors)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (settings </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentNullException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"settings"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (projectors </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentNullException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"projectors"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">settings </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">projectors </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> projectors;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And to update projector data:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="41" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> UpdateProjector(</span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> oldProjector, </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> newProjector)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (oldProjector </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> newProjector)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">else</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> projs </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">projectors</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToList();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> idx </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> projs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IndexOf(oldProjector);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (idx </span><span style="background: #1e1e1e; color: #b4b4b4;">>=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">projs[idx] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> newProjector;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">settings, projs);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">else</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">throw</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ArgumentException</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"oldProjector"</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #d69d85;">"This projector is not part of this calibration data"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
I could do argument check first of course, and you can use some "Builder classes" to maintain those updates, but you get the point.<br />
<br />
Now someone would say, this is a lot of work for simple classes....<br />
<br />
But now once you are done with this (not so bad) boilerplate, here is out undo stack:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationUndoStack</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Stack</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> undoStack;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CalibrationUndoStack(</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> initial)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Stack</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Push(initial);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Apply(</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> commandFunc)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> newState </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> commandFunc(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Current);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">if</span><span style="background: #1e1e1e; color: gainsboro;"> (newState </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Current)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Push(newState);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> Current</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Peek(); }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> Undo()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CanUndo </span><span style="background: #1e1e1e; color: #b4b4b4;">?</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Pop() : </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Peek();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> CanUndo</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">undoStack</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Count </span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
As you can see, since we always return a new state, we pass a lambda to the stack, and if object has been modified (eg: function returns a new state), then we push our new state. That's how easy that is.<br />
<br />
To implement update commands becomes as trivial as :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="13" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> AddProjector(</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> c, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> name)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> c</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AddProjector(name);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> RenameProjector(</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> state, </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> projector, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> newname)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> projector</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SetName(newname);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> state</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(projector, p);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> AddPoint(</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> state, </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> projector, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screen, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> obj)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> projector</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AddPoint(screen, obj);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> state</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(projector, p);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> SetScreenPoint(</span><span style="background: #1e1e1e; color: #4ec9b0;">Calibration</span><span style="background: #1e1e1e; color: gainsboro;"> state, </span><span style="background: #1e1e1e; color: #4ec9b0;">Projector</span><span style="background: #1e1e1e; color: gainsboro;"> projector, </span><span style="background: #1e1e1e; color: #4ec9b0;">CalibrationPoint</span><span style="background: #1e1e1e; color: gainsboro;"> point, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> screen)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> newPoint </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> point</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SetScreenPosition(screen);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> newProjector </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> projector</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdatePoint(point, newPoint);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> state</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(projector, newProjector);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
</div>
<br />
And as you notice, this looks pretty verbose, here is how to do the same in f# (I love type inference, amongst may other things)<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="6" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">module</span><span style="background: #1e1e1e; color: gainsboro;"> CalibrationCommandsFS </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> addprojector (c</span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;">Calibration,n) </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> c</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AddProjector(n);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> renameprojector(c</span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;">Calibration,p, n) </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> c</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(p,p</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SetName(n))</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> addpoint(c</span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;">Calibration,p,s,o) </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> c</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(p,p</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AddPoint(s,o))</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> setscreenpoint(c</span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;">Calibration,proj,pt,s) </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> c</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdateProjector(proj,proj</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">UpdatePoint(pt,pt</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">SetScreenPosition(s)))</span></li>
</ol>
</div>
</div>
<br />
And to operate on calibration:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="17" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> x </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> CalibrationUndoStack()</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> s </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> CalibrationSettings(Matrix</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Identity)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> empty </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> []</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">let</span><span style="background: #1e1e1e; color: gainsboro;"> c </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> Calibration(s, [])</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;">x</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Apply(</span><span style="background: #1e1e1e; color: #569cd6;">fun</span><span style="background: #1e1e1e; color: gainsboro;"> c </span><span style="background: #1e1e1e; color: #569cd6;">-></span><span style="background: #1e1e1e; color: gainsboro;"> addprojector(c,</span><span style="background: #1e1e1e; color: #d69d85;">"hello"</span><span style="background: #1e1e1e; color: gainsboro;">))</span></li>
</ol>
</div>
</div>
</div>
<br />
That's it for now, but likely more f# soon ;)</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-39660726621687890082014-07-11T10:32:00.003+01:002014-07-11T20:59:33.454+01:00Shader Linker<div dir="ltr" style="text-align: left;" trbidi="on">
I already posted about shader linking graph previously, so I thought I would give a bit more details about it.<br />
<br />
Now that DirectX11.2 is implemented in SharpDX, it was much easier to integrate, removed some small c++ library hack in the meantime.<br />
<br />
Now as much as I still don't think shader patching fits every use case, I have to admit there's a few times where it proves really useful.<br />
<br />
First scenario is actually not using the linker, but the function reflector. You build a library of functions, and so some form of signature matching, for example:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> GravityStrength </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">0.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">,-</span><span style="background: #1e1e1e; color: #b5cea8;">1.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: #b5cea8;">0.0f</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: #569cd6;">export</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> Gravity</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> p</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> v</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> GravityStrength</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now the library reflector will scan all functions, and if signature matches (in this example, particle force field needs pos/vel tuple), it will automatically create a node. Attaching this node to a generic force field node will take the base code, include the function header and compile a new shader.<br />
<br />
This is something I did a lot already (using function headers to inject code in an incomplete shader and include then compile), so you can build a function library while having a single main function, but function reflection brings it to the next level, since I can now have fast collection of nodes in few line of code.<br />
<br />
I use it for a lot of cases (geometry displacers, materials, particles interaction...) and it's great.<br />
<br />
For geometry displacers, for example (it's overly simplified compared to the real version), I have several displace techniques (tetrahedron, tube, face), each need a displacement value from a position.<br />
<br />
So as soon as I have a new displacement technique, it can be integrated with all displacer functions, which gives a great amount of flexibility (and removes a lot of boilerplate code).<br />
<br />
Now I have some cases where I need some more complex functions, and where using the linker really shine:<br />
<br />
<ul style="text-align: left;">
<li>Pixel shader for screen space textures. I use this a lot for masks</li>
<li>Deffered Pixel materials : Use noise/sine functions for color/rough/reflectivity can be done in handlers, but I often need more complex functions.</li>
<li>Distance field builders</li>
</ul>
<div>
Here is an example for pixel mask builder:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglLEE4En4Pr6z9fjIDcBVJqIrnxCUM8HPbSaWzHPhZs9FdM3-OmYo93zQC4CVRmB5bXXp_a_6Y2NbFHEI9_YJiG9FtTbDbxqwgeMKIbhJF7n1OTz2xmrFB5NTkyOhjr0YjSdTpdy4oM111/s1600/spn2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglLEE4En4Pr6z9fjIDcBVJqIrnxCUM8HPbSaWzHPhZs9FdM3-OmYo93zQC4CVRmB5bXXp_a_6Y2NbFHEI9_YJiG9FtTbDbxqwgeMKIbhJF7n1OTz2xmrFB5NTkyOhjr0YjSdTpdy4oM111/s1600/spn2.png" height="174" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu4LCY1nuOC4iytVIQOstyEv43Rt1LIRGUnCiC0K0sHa8gOL1BJPyIdHE8dtdbla0-jXaBTofzyiv7tRWEjy6X2MCCqUYkPRCuqtmqUn50ytRAZ5k6HaEzz70RY_PSTUxbxw3DEUxIYe_w/s1600/spn3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu4LCY1nuOC4iytVIQOstyEv43Rt1LIRGUnCiC0K0sHa8gOL1BJPyIdHE8dtdbla0-jXaBTofzyiv7tRWEjy6X2MCCqUYkPRCuqtmqUn50ytRAZ5k6HaEzz70RY_PSTUxbxw3DEUxIYe_w/s1600/spn3.png" height="173" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Great thing about all this, I have a nice collection of pre built functions (noise, sine displaces...) since I don't want to patch that, and I can easily combine them to create variations. If I need a new function, I can also create a custom one using code and it will reflect parameters and create me a node. Having mixed support for patch/code is such a great feature.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now one thing I also would like to build quite easily is Distance Field.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I already have distance field builder, which is made using compute shader, and uses an include script to build function. This works really well, but having it as patch could also be interesting.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So first thing, you build your small function collection (primitive distance function, bend/twist operators, union/substract/intersect...). And you have all your nodes ready. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now this runs into an issue, the shader linker only builds either Vertex or Pixel shader.</div>
<div class="separator" style="clear: both; text-align: left;">
I could use the "GenerateHLSL" function, and include that in my code, but then you lose the advantage of using linker over compiler = speed. Link speed is REALLY fast compared to compile speed.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So let's rewrite that routine, since writing to volume is also really easy to implement in standard pipeline too.</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>Create a single RenderTarget for your Volume</li>
<li>Send a draw call with N full screen Quad instances (or triangle, your choice), where N = volume Depth</li>
<li>In vertex Shader, multiply instance ID by inverse Slice count, and pass object space position plus this depth to geometry shader (as well as instance id itself)</li>
<li>In geometry shader, assign Instance id to SV_RenderTargetArrayIndex so each quad instance is drawn in single slice.</li>
<li>Compute your distance function in Pixel Shader :)</li>
</ul>
<div>
Here is definition:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="1" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> vsInput</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> POSITION</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float2</span><span style="background: #1e1e1e; color: gainsboro;"> uv </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> TEXCOORD0</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> ii </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_InstanceID</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> gsInput</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> POSITION</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> xyz </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SDFPOS</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> ii </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SLICEINDEX</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> gsOutput</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_Position</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> xyz </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SDFPOS</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">uint</span><span style="background: #1e1e1e; color: gainsboro;"> rt </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_RenderTargetArrayIndex</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">struct</span><span style="background: #1e1e1e; color: gainsboro;"> psInput</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float4</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_Position</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: gainsboro;"> xyz </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SDFPOS</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> SliceCount </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">128</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
Vertex Shader:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="34" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">gsInput VS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">vsInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">gsInput output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">p</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">xyz </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">float3</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">uv</span><span style="background: #1e1e1e; color: #b4b4b4;">,</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ii </span><span style="background: #1e1e1e; color: #b4b4b4;">/</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;">SliceCount</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0.5f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ii </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ii</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Geometry Shader:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="44" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">maxvertexcount</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #b5cea8;">3</span><span style="background: #1e1e1e; color: #b4b4b4;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> GS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">triangle</span><span style="background: #1e1e1e; color: gainsboro;"> gsInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: #b5cea8;">3</span><span style="background: #1e1e1e; color: #b4b4b4;">],</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">inout</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">TriangleStream</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">gsOutput</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> gsout</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span><span style="background: #1e1e1e; color: gainsboro;"> </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">gsOutput output</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">for</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> i </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> i </span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">3</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span><span style="background: #1e1e1e; color: gainsboro;"> i</span><span style="background: #1e1e1e; color: #b4b4b4;">++)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">i</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">p</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">xyz </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">i</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">xyz</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">rt </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> input</span><span style="background: #1e1e1e; color: #b4b4b4;">[</span><span style="background: #1e1e1e; color: gainsboro;">i</span><span style="background: #1e1e1e; color: #b4b4b4;">].</span><span style="background: #1e1e1e; color: gainsboro;">ii</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">gsout</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Append</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: gainsboro;">gsout</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RestartStrip</span><span style="background: #1e1e1e; color: #b4b4b4;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And a dummy pixel shader (that builds a sphere):<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="58" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> PS</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">psInput input</span><span style="background: #1e1e1e; color: #b4b4b4;">)</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">:</span><span style="background: #1e1e1e; color: gainsboro;"> SV_Target</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> length</span><span style="background: #1e1e1e; color: #b4b4b4;">(</span><span style="background: #1e1e1e; color: gainsboro;">input</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">xyz</span><span style="background: #1e1e1e; color: #b4b4b4;">)-</span><span style="background: #1e1e1e; color: #b5cea8;">0.25f</span><span style="background: #1e1e1e; color: #b4b4b4;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br />
Now we can just bypass this dummy pixel shader and use a patch version of it, as in those screenshots:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi08Q7b_I2s8xetdVX9lajIwl2QQFT02osHqQo3ulrTptZzQtnJwWydUga-DBHsD-zZd6KHCf28JNlsJJsRVVpUE_MqGnBWZhjm_ZBWE32rRuilVjD8oOO1KPaePvh7tDAfT5a6Rih_VibT/s1600/mcblob2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi08Q7b_I2s8xetdVX9lajIwl2QQFT02osHqQo3ulrTptZzQtnJwWydUga-DBHsD-zZd6KHCf28JNlsJJsRVVpUE_MqGnBWZhjm_ZBWE32rRuilVjD8oOO1KPaePvh7tDAfT5a6Rih_VibT/s1600/mcblob2.png" height="171" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuLvA5HnE9_cbqGvVFqUdk2mO2celZV4sIIu4v4RH7ZSuXr1UYaTlvmjRbNQpxYLlH-L6hjPMjOq5L_WZZcbWLgfXmvd1mICULZC8VXuwn1_IdBC3CJsn6blyiv6U2hk7uyLUpW7OEnBa7/s1600/mcblob.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuLvA5HnE9_cbqGvVFqUdk2mO2celZV4sIIu4v4RH7ZSuXr1UYaTlvmjRbNQpxYLlH-L6hjPMjOq5L_WZZcbWLgfXmvd1mICULZC8VXuwn1_IdBC3CJsn6blyiv6U2hk7uyLUpW7OEnBa7/s1600/mcblob.png" height="171" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here we go, distance field patcher :)</div>
<br />
And a version with some nodes built from code editor, hybrid is the future ;)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6aITEKnJl3BrXbGqTLRUvXsbm6LLpJDQqlrS5EQkBQ65tcyTr5fvNX3qmf4ITwlKBNJovlV555SbzRkcndXqlylpubDdNoIjetvuIcSrVBRn9ZJKR87oEYoiLIn4EKhjZfI59iEOwvY2I/s1600/pixel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6aITEKnJl3BrXbGqTLRUvXsbm6LLpJDQqlrS5EQkBQ65tcyTr5fvNX3qmf4ITwlKBNJovlV555SbzRkcndXqlylpubDdNoIjetvuIcSrVBRn9ZJKR87oEYoiLIn4EKhjZfI59iEOwvY2I/s1600/pixel.png" height="180" width="320" /></a></div>
<br /></div>
</div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-41458931435902634012014-05-31T19:57:00.000+01:002014-05-31T19:57:17.814+01:00Reflecting Types<div dir="ltr" style="text-align: left;" trbidi="on">
Lately I've been posting about using IL generation to connect elements.<br />
<br />
I know I was about to post series about Scene Graph, but since I like to do things in an non ordered fashion (and at the end of the day, it's my blog ;) , I'll go a bit deeper into objects.<br />
<br />
In most graph oriented architecture, we have to create nodes, and connectors, so we have to build inputs/outputs...<br />
<br />
We have several ways to do it:<br />
<br />
<ul style="text-align: left;">
<li>Big factory: You have calls like CreateIntParameter, CreateValueInput, or generic version like CreateInput<T> ...</li>
<li>Injection : You use decorators in order to inject some implementation. (So doing ISpread<int> internally generates a IntInputPin or something like that).</li>
</ul>
<div>
Going deeper, why do we even need pins? Let's take the following example:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="32" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> Hello { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> Integer { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> ReadOnly { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"ReadOnly"</span><span style="background: #1e1e1e; color: gainsboro;">; } }</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> Double { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> DoubleOutput { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
This is pretty easy to reflect properties, since we know about get/set, we can create a "virtual pin" automatically, so why even wrap the property?<br />
<br />
In most systems we would work it like that:<br />
<br />
<ul style="text-align: left;">
<li>Wrap hello as input and Output Pin. </li>
<li>Wrap ReadOnly as Output pin.</li>
<li>Create a link that wraps InputPin<double> and OutputPin<double></li>
</ul>
<br />
So let's do this in a simpler way, let's say we want to connect Hello (output) to Prop2 "DoubleOutput"<br />
<br />
First we need a Func to access Property:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="274" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #4ec9b0;">Delegate</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateDelegate(</span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">), instance, property</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetGetMethod());</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And a way to set property:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="279" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> BuildSetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #4ec9b0;">Delegate</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateDelegate(</span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">), instance, property</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetSetMethod());</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now we have to connect both, eg: read from source and write to destination:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="284" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> source, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> getter, </span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> dest, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> setter)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> getFunc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(source, getter);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> setAction </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildSetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(dest, setter);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> () </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> setAction(getFunc());</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
That was that easy, now we can simply have:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="315" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Hello </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">20.0</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Integer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">20</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span><span style="background: #1e1e1e; color: gainsboro;"> p2 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> connect </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(p, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"Hello"</span><span style="background: #1e1e1e; color: gainsboro;">), p2, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"Double"</span><span style="background: #1e1e1e; color: gainsboro;">));</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">connect();</span></li>
</ol>
</div>
</div>
<br />
All done, out connector is ready ;)<br />
<br />
If we need conversion, this is as easy, we can use a small interface:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="19" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource,TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">TDest Convert(TSource source);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DoubleToStringConverter</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> Convert(</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> source)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> source</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString() </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">" from converter"</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Then our connector can either use this small interface, or we can just set a lambda is case we can't be bother ed adding one file + namespaces + new class, get rid of object oriented verbosity basically ;)<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="291" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource, TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> source, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> getter, </span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> dest, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> setter, </span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource,TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> converter)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> getFunc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(source, getter);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> setAction </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildSetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(dest, setter);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> () </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> setAction(converter(getFunc()));</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource, TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> source, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> getter, </span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> dest, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> setter, </span><span style="background: #1e1e1e; color: #b8d7a3;">ITypeConverter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource, TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> converter)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> getFunc </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSource</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(source, getter);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> setAction </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> BuildSetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TDest</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(dest, setter);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> () </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> setAction(converter</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Convert(getFunc()));</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
In action:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="327" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> connectConverter </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(p, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"Hello"</span><span style="background: #1e1e1e; color: gainsboro;">), p2, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"DoubleOutput"</span><span style="background: #1e1e1e; color: gainsboro;">), (d) </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> d</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString() </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">" Hello"</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;">connectConverter();</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> connectInterface </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> Connect</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(p, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"Hello"</span><span style="background: #1e1e1e; color: gainsboro;">), p2, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Prop2</span><span style="background: #1e1e1e; color: gainsboro;">)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperty(</span><span style="background: #1e1e1e; color: #d69d85;">"DoubleOutput"</span><span style="background: #1e1e1e; color: gainsboro;">), </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DoubleToStringConverter</span><span style="background: #1e1e1e; color: gainsboro;">());</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;">connectInterface();</span></li>
</ol>
</div>
</div>
<br />
Now we can actually simply reflect type, create IO on rules, but operate directly on properties.<br />
Direct access costs us a few virtual calls, but since we haven't got a layer on top, this is even more minimized.<br />
<br />
<br />
Once we have this, let's looks at it further, let's show how to display our element, with custom formatted string per type, in this example I just log to console, bu this is easily extendable to user interface, writing, serialization...<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="108" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> PropertyType { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayObject(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">interface</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Display();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
First we do some simple defaults:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="203" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">BasicDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> display;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> BasicDisplay(</span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> display)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">display </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> display;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Display()</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">display();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">abstract</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">TypedDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> PropertyType</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(T); }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">abstract</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayObject(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Then two stupid int and double implementations:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="228" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DoubleDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #4ec9b0;">TypedDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">override</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayObject(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> getter </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Program</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(instance, property);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> action </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> () </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Console</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">WriteLine(property</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">" Double: "</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> getter()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString());</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">BasicDisplay</span><span style="background: #1e1e1e; color: gainsboro;">(action);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">IntDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #4ec9b0;">TypedDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">override</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayObject(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance, </span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;"> property)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> getter </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Program</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">BuildGetter</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(instance, property);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: gainsboro;"> action </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> () </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Console</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">WriteLine(property</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"Int: "</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">+</span><span style="background: #1e1e1e; color: gainsboro;"> getter()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString());</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">BasicDisplay</span><span style="background: #1e1e1e; color: gainsboro;">(action);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now we need to know if a property is capable of display of not:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="155" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyRegistry</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> factories;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayPropertyRegistry(</span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> factories)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">factories </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> factories;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayPropertyRegistry(</span><span style="background: #1e1e1e; color: #569cd6;">params</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;">[] factories)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">factories </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> factories;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> SearchCandidate(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> type)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> factories</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(f </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> f</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PropertyType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> type);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> CanDisplay(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> type)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> SearchCandidate(type)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FirstOrDefault() </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;"> GetFactory(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> type)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> SearchCandidate(type)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">First();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
<br />
Add filtering support:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="119" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyFilter</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyRegistry</span><span style="background: #1e1e1e; color: gainsboro;"> registry;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayPropertyFilter(</span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyRegistry</span><span style="background: #1e1e1e; color: gainsboro;"> registry)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">registry </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> registry;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Tuple</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> ReflectType(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> type)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> props </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> type</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetProperties()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(p </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> p</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetGetMethod() </span><span style="background: #1e1e1e; color: #b4b4b4;">!=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> registry</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CanDisplay(p</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PropertyType));</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> props</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Select(p </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Tuple</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">PropertyInfo</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplayFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(p, registry</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetFactory(p</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PropertyType)));</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
From here we know from a given type, every property that we can display, and how to create them. We only used object type so far, so now we need to add instance in the mix:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="136" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayObjectFactory</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyFilter</span><span style="background: #1e1e1e; color: gainsboro;"> filter;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> DisplayObjectFactory(</span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyFilter</span><span style="background: #1e1e1e; color: gainsboro;"> filter)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">filter </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> filter;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ObjectDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> GetDisplay(</span><span style="background: #1e1e1e; color: #569cd6;">object</span><span style="background: #1e1e1e; color: gainsboro;"> instance)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> factories </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> filter</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReflectType(instance</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetType());</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> elements </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> factories</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Select(f </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> f</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Item2</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">DisplayObject(instance, f</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Item1));</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ObjectDisplay</span><span style="background: #1e1e1e; color: gainsboro;">(elements);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
And the final object that displays our information:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="185" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ObjectDisplay</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">readonly</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> displayElements;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> ObjectDisplay(</span><span style="background: #1e1e1e; color: #b8d7a3;">IEnumerable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> displayElements)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">displayElements </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> displayElements;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Display()</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">foreach</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #b8d7a3;">IPropertyDisplay</span><span style="background: #1e1e1e; color: gainsboro;"> display </span><span style="background: #1e1e1e; color: #569cd6;">in</span><span style="background: #1e1e1e; color: gainsboro;"> displayElements)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">display</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Display();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Our final code, that gets an instance and displays any supported data:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="307" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyRegistry</span><span style="background: #1e1e1e; color: gainsboro;"> registry </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyRegistry</span><span style="background: #1e1e1e; color: gainsboro;">(</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DoubleDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;">(),</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">IntDisplayFactory</span><span style="background: #1e1e1e; color: gainsboro;">());</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyFilter</span><span style="background: #1e1e1e; color: gainsboro;"> filter </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayPropertyFilter</span><span style="background: #1e1e1e; color: gainsboro;">(registry);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayObjectFactory</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DisplayObjectFactory</span><span style="background: #1e1e1e; color: gainsboro;">(filter);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;"> p </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Prop</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Hello </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">20.0</span><span style="background: #1e1e1e; color: gainsboro;">,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Integer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">20</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> display </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetDisplay(p);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">display</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Display();</span></li>
</ol>
</div>
</div>
<br />
You can easily think that's a lot of classes and a lot of code to just display properties of a class (we could just iterate through property list and do some "tostring"<br />
<br />
But...<br />
<br />
<ul style="text-align: left;">
<li>This is more extensible, and if you need to access your properties a lot, you get a pretty big gain over reflection.</li>
<li>You can register any type, replace as you wish, so you avoid the dreaded massive switch.</li>
<li>By having more classes, and less work per class, you have much more invariants, pretty much every class is ready to go once constructed, no temporal coupling (only edge case is CanDisplay/GetFactory which could create a related exception).</li>
<li>You are not limited to just a "tostring", create a controller, network serializer, add a proxy for automatic property change dispatch, possibilities are endless ;)</li>
</ul>
<div>
Here we are for now, promised I'll get back into Scene Graph next post (or maybe not ;)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-21562905768549213022014-05-28T12:53:00.000+01:002014-05-28T12:53:29.314+01:00(Reasonably) Modern SceneGraph (Introduction)<div dir="ltr" style="text-align: left;" trbidi="on">
I decided to go a bit deeper into how FlareTic internals are handled, and decided that next posts will be some series about SceneGraph.<br />
<br />
Since my tool is not designed to be a game engine, but for procedural graphics, I have some different requirements/limitations that need a different thinking.<br />
<br />
So let's see what we will cover, and what we need for a reasonably modern rendering system. Most code will be in c#, but you'll likely see a bit of F# appearing too ;)<br />
<h2 style="text-align: left;">
1/Asset management</h2>
This is a no brainer, asset managers are necessary everywhere, whereas it is from textures/models.<br />
<br />
Main required features are:<br />
<br />
<ul style="text-align: left;">
<li>Background loading: You don't want to block your rendering while you load this fat 3d distance field.</li>
<li>Converters : You will likely want to convert your data into some internal representation. For example, prepare a 3d model in a way that you can directly upload to gpu, or take a bulk of textures and convert to texture array.</li>
<li>Generators : Most times we also need more procedural assets, so a simple generator function is also eligible as an asset (random buffers is something I widely use).</li>
<li>Child asset : For example, from a 3d model asset, you want a distance field representation.</li>
<li>Metadata : 2D Texture, 3D Texture don't make any sense on it's own, so we also need to indicate what data is contained in the texture (distance field/potential field/velocity/normal map/height map....)</li>
<li>Drag drop handler so when you drop on the patch it creates appropriate node.</li>
<li>Hierarchy : so if you have a texture folder (namespace), you can prefetch all resources in that folder for fast switching.</li>
</ul>
<h2 style="text-align: left;">
2/Render Elements</h2>
<div>
At some point in our scene, we need some resources which are not part of our asset system (some shaders, some buffers....)</div>
<div>
<br /></div>
<div>
Here are all render elements in FlareTic</div>
<div>
<ul style="text-align: left;">
<li>Fully immutable: Those resources are loaded once per node, and will never change. (Shaders are a very good example for it).</li>
<li>Low update frequency : Those are the ones that don't change very often (actually mostly at design time). So they are built as immutable in GPU, and dumped/recreated when required by the user. Very common example will be standard primitives. Since resource is immutable in GPU, it can be uploaded async without a problem.</li>
<li>Dynamic Resources (CPU) : Those are resources which change pretty often, like any camera textures. In FlareTic they are built as dynamic, and uploaded to gpu using MapSubResource. They require a rendercontext, so note that they do not fit async loading model very well. As a side note, please Microsoft and beloved DirectX team, can we just async upload content in an existing resource one day, without the need for a render context? Seems (hope) DirectX12 is getting this way.</li>
<li>Dynamic Resources (GPU) : This is increasingly important (or I could call it fundamental) in FlareTic. A lot of resources are updated once per frame, either via Stream Output,Compute Shaders (for example, geometry via modifiers, particle systems,splines...). They also require Render Context, but no upload, so they are quite easier to schedule.</li>
<li>Renderables : Once we have our particle system ready, we might want to render it on the screen as well ;) Renderables can be rendered several times per frame (shadow map/depth pre pass...)</li>
<li>Post processors : Who can survive without it ;) Or course you want to also provide a forward path and a deferred path. </li>
</ul>
</div>
<h2 style="text-align: left;">
3/Stages</h2>
<div>
From the time we start our application to the time our scene is rendered on the screen, we of course have several stages.</div>
<div>
<br /></div>
<h3 style="text-align: left;">
A/Load/Unload</h3>
<div>
This is when we load a scene graph patch, and this is more tricky than many people think.</div>
<div>
We of course want to be able to load/dump a scene graph patch in async way.</div>
<div>
So let's see the load process</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Create all nodes: We first create all nodes, there is no mix of node/link load, and json files format reflects this pretty well (no messed xml). One place for all nodes, one place for all links (life can be so simple sometimes ;) </li>
<li>Assign parameters : We parameter values for nodes, please note in (most) cases, this is immediate, bt in some cases they can be retained (see below)</li>
<li>Connect nodes : Since our nodes already told on loading what thy expect, we can safely connect them together. Since some connections can also create a compile task, this is also important to keep in background.</li>
<li>Apply retained parameters : As mentioned, a compile task can be created at link time (feels a bit reverse here ;) So some shader parameters are created at this stage. Once this happens, retained parameters are finally flushed to the node. On a side note, since dx11.2, this is now deprecated feature (since I can directly reflect a function instead).</li>
</ul>
<div>
So now what we really want is modify that to make it more flexible:</div>
</div>
<div>
<ul style="text-align: left;">
<li>Load behaviour: We want to load patch without any resource this can easily be done in a thread and is pretty fast. Loading only the object graph doesn't consume much memory either, so it's rather simple to have a lot of scene graphs ready to show off their coolness.</li>
<li>Load resources : We indicate to this scene that we want it ready to show off, so it should get dressed. Same, we want this async (and ideally with a little progress bar as an eye candy ;)</li>
</ul>
<h3 style="text-align: left;">
B/Render</h3>
</div>
<div>
I'll keep rendering as one stage, but obviously this is divided is several sub stages:</div>
<div>
<ul style="text-align: left;">
<li>Update low frequency resources : Those are trivial to do async, some concurrency control is still useful</li>
<li>Update per frame resources : those do not depend on graph in general so they can also be pushed, but in this case in serial (render context).</li>
<li>Update GPU resource : Particles, Geometry modifiers.... All the bits that needs to be made look good after</li>
<li>Render : Make look good</li>
<li>Apply post processing : Make look better </li>
</ul>
</div>
<h3 style="text-align: left;">
C/Fine tuned priority</h3>
<div>
Nodes in FlareTic scene graphs have no centralized priority system (like a pull based dataflow for example).</div>
<div>
<br /></div>
<div>
As opposite, a node has full decision power on how to process it's own children. </div>
<div>
<br /></div>
<div>
This gives some pretty nice advantages:</div>
<div>
<ul style="text-align: left;">
<li>Since a node can decide, we have full flexibility and can make complex decisions trivially.</li>
<li>Easy to cut a part of the graph, just don't call child ;)</li>
<li>Easy for user to just connect things and they work, instead of having a mess because you connected something in the wrong order.</li>
</ul>
</div>
<div>
Of course there is also some drawbacks:</div>
<div>
<ul style="text-align: left;">
<li>A lot of work is dealt by the node. This can of course be offset using abstract classes, but still quite some work.</li>
<li>It's harder to have a more global control (logging/error handling is very easy when you have centralized traversal)</li>
<li>No global control also makes it harder to process parts in parallel, which is something that increasingly needs to be taken into account.</li>
</ul>
</div>
<div>
So we need the best of both worlds in some ways, dataflow doesn't give the flexibility we need, but we still want this global control.</div>
<div>
<br /></div>
<div>
Luckily, as we will see this can the solved rather elegantly.</div>
<div>
<br /></div>
<div>
Of course there's a lot of other features (that are already there, like Shader caching, Dynamic compilation, Handlers, Resource pools...) that are part of a scene graph, but they are not so much "core features", so they might be discussed in separate posts at some point.</div>
<div>
<br /></div>
<br />
That's it for now, quite a large program to come, stay tuned.</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-15959511631385479872014-04-17T14:06:00.000+01:002014-04-17T14:06:56.006+01:00Geometry and Functions<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
After finishing my projects, I finally have time to work on some way long overdue features.<br />
<br />
I'm doing a lot of work on my user interface revamp, and also doing a lot of code cleanup since now Windows Phone gives us access (also long overdue) to all nice features like P/Invoke, Direct2d....<br />
<br />
This means after a bit of tweaking on SharpDX code base, windows phone is now AnyCpu, which is really great, having x86, x64, ARM and lot of targets to maintain is not pleasing at all.<br />
<br />
Also I decided to move on and remove the old DirectX11/DirectX11.1 targets on my toolbox. No more Windows 7 support, I prefer to focus on having a better build for Desktop / RT / Phone instead.<br />
<br />
Now after all this I thought it was time to work on another (well overdue as well) feature.<br />
<br />
I've always been interested into processing geometry in compute shaders instead of using StreamOut.<br />
<br />
This gives some pretty useful advantages:<br />
<br />
<ul style="text-align: left;">
<li>Write in place : RWStructuredBuffer rocks, no need for ping/pong</li>
<li>Writing Indexed geometry using Geometry Shader is doable, but rather painful.</li>
<li>Much easier to do more advanced post processing</li>
<li>Access to indirect Draw, which means it's much easier to instance generated geometry, StreamOut does not give us access to internal counter, except using a query, eg: not ideal.</li>
</ul>
<div>
Here are my structures:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="16" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> positionbuffer;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> normalsbuffer;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> uvbuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> appendindexbuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11InstancedIndexedDrawer</span><span style="background: #1e1e1e; color: gainsboro;"> drawer;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DispatchIndirectBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> vertexIndirectDispatch;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DispatchIndirectBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> indexIndirectDispacth;</span></li>
</ol>
</div>
</div>
</div>
<div>
<br />
Pretty simple, with two things to note:<br />
<ul style="text-align: left;">
<li>Position buffer is created with the counter flag</li>
<li>Index Buffer is created with the append flag</li>
</ul>
</div>
<div>
Now there are a few bits to consider:</div>
<div>
<ul style="text-align: left;">
<li>Structured Buffer is not bindable as Vertex Buffer: This is more or less a non issue in my case, since most of my shaders already fetch data from StructuredBuffers using SV_VertexID</li>
<li>StructuredBuffer is not bindable as Index Buffer. This is more annoying, since you need to bind it to the pipeline, no way to fetch. This is quite easy to sort still, as you can just create a standard index buffer (which allow raw view and give it UAV access), then just use a compute shader to copy indices.</li>
</ul>
<div>
So with this setup we are more or less set, you can process per vertex using VertexIndirectDispatcher, process per face using IndexIndirectDispatcher, and since you have access to counter/append, you can also easily emit/remove Geometry.</div>
</div>
<div>
<br /></div>
<div>
Now one main issue with this setup, you need to feed your buffers with some initial geometry. </div>
<div>
You have a very simple way to do this in DirectX11.1 , but the feature is only supported on ATI.</div>
<div>
<br /></div>
<div>
So instead, let's replace my old monolithic geometry builders by something more flexible</div>
<div>
<br /></div>
<div>
For now my geometry builders look like this:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="17" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;"> QuadNormals(</span><span style="background: #1e1e1e; color: #4ec9b0;">Quad</span><span style="background: #1e1e1e; color: gainsboro;"> settings)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;"> geom </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;">(device);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Tag </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PrimitiveType </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PrimitiveType;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> vertices </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> indices </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #57a64a;">//Build your array</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">VertexBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11VertexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable(device, vertices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IndexBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable(device, indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InputLayout </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Layout;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">VertexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InputLayout </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InputLayout;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Topology </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">PrimitiveTopology</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">TriangleList;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">HasBoundingBox </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> geom;</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
This has a bit too many things to do:<br />
<br />
<ul style="text-align: left;">
<li>Read settings</li>
<li>Build Vertices/Indices list</li>
<li>Create Geometry resource</li>
</ul>
<br />
The big problem is that all is in one function, so let's improve and decouple this a little bit<br />
<br />
First geometry builders do some pretty simple things, append vertices and append faces, so let's change the construction code like this.<br />
<br />
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IGeometryBuilder</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Segment</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;"> GetPrimitiveInfo(</span><span style="background: #1e1e1e; color: #4ec9b0;">Segment</span><span style="background: #1e1e1e; color: gainsboro;"> settings)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> phase </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Phase;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> cycles </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Cycles;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> inner </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InnerRadius;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> res </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Resolution;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> flat </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> settings</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Flat;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> vcount </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> res </span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">2</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> icount </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> (res </span><span style="background: #1e1e1e; color: #b4b4b4;">-</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">) </span><span style="background: #1e1e1e; color: #b4b4b4;">*</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">6</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;">(vcount, icount);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> Construct(</span><span style="background: #1e1e1e; color: #4ec9b0;">Segment</span><span style="background: #1e1e1e; color: gainsboro;"> settings, </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> appendVertex, </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Int3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> appendIndex)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
Now we have one builder class responsible to build geometry, but it has no idea of which data structure we use anymore, which is great, since now it's very easy to:<br />
<br />
<ul style="text-align: left;">
<li>Use different data back end (DataStream, List...)</li>
<li>Pack data the way we want</li>
<li>Completely bypass something (if resolution parameter does not change for example, we can set appendIndex function to null, so we completely ignore building faces).</li>
</ul>
<div>
<br /></div>
<div>
Here is a simple example to append data into lists:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="10" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> vertices </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> indices </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Vertices { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">vertices; } }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">List</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> Indices { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">indices; } }</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> AppendVertex(</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> position, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> normal, </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector2</span><span style="background: #1e1e1e; color: gainsboro;"> uv)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: gainsboro;"> v </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: gainsboro;">()</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Position </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector4</span><span style="background: #1e1e1e; color: gainsboro;">(position</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">X, position</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Y, position</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Z, </span><span style="background: #1e1e1e; color: #b5cea8;">1.0f</span><span style="background: #1e1e1e; color: gainsboro;">),</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Normals </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> normal,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">TexCoords </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> uv</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">};</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">vertices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(v);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> AppendIndex(</span><span style="background: #1e1e1e; color: #4ec9b0;">Int3</span><span style="background: #1e1e1e; color: gainsboro;"> index)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(index</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">X);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(index</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Y);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Add(index</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Z);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> TransformVertices(</span><span style="background: #1e1e1e; color: #4ec9b0;">Func</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> transformFunction)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">for</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #569cd6;">int</span><span style="background: #1e1e1e; color: gainsboro;"> i </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">; i </span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">vertices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Count; i</span><span style="background: #1e1e1e; color: #b4b4b4;">++</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: gainsboro;"> v </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> vertices[i];</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">vertices[i] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> transformFunction(v);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
<br />
Now to construct our geometry, we can simply do:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="14" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">partial</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitivesManager</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;"> Cylinder(</span><span style="background: #1e1e1e; color: #4ec9b0;">Cylinder</span><span style="background: #1e1e1e; color: gainsboro;"> settings)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">CylinderBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CylinderBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> appender </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;"> info </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetPrimitiveInfo(settings);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Construct(settings, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendVertex, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendIndex);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> FromAppender(settings, appender, info);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;"> FromAppender(</span><span style="background: #1e1e1e; color: #4ec9b0;">AbstractPrimitiveDescriptor</span><span style="background: #1e1e1e; color: gainsboro;"> descriptor, </span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> appender, </span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;"> info)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;"> geom </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexedGeometry</span><span style="background: #1e1e1e; color: gainsboro;">(device);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Tag </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> descriptor;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PrimitiveType </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> descriptor</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PrimitiveType;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">VertexBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11VertexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable(device, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Vertices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IndexBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11IndexBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable(device, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InputLayout </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pos4Norm3Tex2Vertex</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Layout;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Topology </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">PrimitiveTopology</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">TriangleList;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">HasBoundingBox </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> info</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">IsBoundingBoxKnown;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">geom</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">BoundingBox </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> info</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">BoundingBox;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> geom;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
What is great by passing functions instead of interfaces, it's much easier to composite actions, for example, we can easily compute bounding box while we create our List.<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="18" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> appender </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;"> info </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetPrimitiveInfo(settings);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> max </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MinValue, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MinValue, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MinValue);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;"> min </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MaxValue, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MaxValue, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MaxValue);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Construct(settings, (v, n, u) </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{ appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendVertex(v, n, u); min </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Min(min, v); max </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Max(max, v); }, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendIndex);</span></li>
</ol>
</div>
</div>
<br />
We can also attach several Appenders, like:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="42" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> appender </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">MultiListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> multilist </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">MultiListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Construct(settings, (v, n, u) </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{ </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendVertex(v, n, u);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">multilist</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendVertex(v, n, u);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">,appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendIndex);</span></li>
</ol>
</div>
</div>
</div>
</div>
</div>
<br />
And you noticed we can optimize by only filling one index buffer ;)<br />
<br />
To build StructuredBuffers instead of geometry, here we are:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="39" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">MultiListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;"> appender </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">MultiListGeometryAppender</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Construct(settings, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendVertex, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AppendIndex);</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> intialposition </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(device, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Positions</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> initialindices </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateImmutable</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Int3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(device, appender</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Indices</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToArray());</span></li>
</ol>
</div>
</div>
<br />
Also, we can write to a dynamic buffer directly:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; max-height: 300px; overflow: auto;">
<ol start="39" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> builder </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">SegmentBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">PrimitiveInfo</span><span style="background: #1e1e1e; color: gainsboro;"> info </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetPrimitiveInfo(settings);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: gainsboro;"> dynamicposition </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateDynamic</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">Vector3</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(device, info</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">VerticesCount);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DataStream</span><span style="background: #1e1e1e; color: gainsboro;"> ds </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> dynamicposition</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">MapForWrite(context);</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">builder</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Construct(settings, (p,n,u) </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> ds</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Write(p) , </span><span style="background: #1e1e1e; color: #569cd6;">null</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">dynamicposition</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Unmap(context);</span></li>
</ol>
</div>
</div>
<br />
<br />
Here we are, next post I'll show a few examples of what we can now do with compute geometry (and some new idea for particle system ;)</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-85619359400117416212014-03-06T21:36:00.003+00:002014-03-06T21:36:36.538+00:00IL, connecting people...<div dir="ltr" style="text-align: left;" trbidi="on">
After a quite good amount of work on the User interface (more post to follow on this part), I decided to go back into the inner tech of things, and try to find some different approaches.<br />
<br />
One important thing when you are a user and you use graphical programming, you need to connect elements. With class (reference types), this is rather straightforward, you use Type.IsAssignableFrom and you're more or less done.<br />
<br />
Now let's have a bit more interest into value types.<br />
<br />
In that case the above (of course) doesn't work. let's make a very simple Pin model:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="13" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">InputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> T data;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> T Data</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">data; }</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">internal</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">set</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{ </span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">data </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">value</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">T</span><span style="background: #1e1e1e; color: #b4b4b4;">></span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> T Data { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
As you see, nothing fancy.<br />
<br />
Now let's say we have those :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="50" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> input </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">InputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> output </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
</ol>
</div>
</div>
<br />
They of course can't natively connect (Type.IsAssignable) with not work. But in c#:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="54" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: gainsboro;"> f </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">150.0f</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: gainsboro;"> d </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> f;</span></li>
</ol>
</div>
</div>
<br />
This is perfectly valid, so there must be a way.<br />
<br />
So how to handle connections in that case?<br />
We have a few cases that we can thing of:<br />
<br />
<ul style="text-align: left;">
<li>This is a native type</li>
<li>The type already implements either implicit or explicit</li>
<li>We want to do it ourselves and provide our own.</li>
</ul>
<div>
I'll start by option 2 (will explain the reason below).</div>
<div>
<br /></div>
<div>
By reflection, to check if a type is assignable to another one, this is what we do instead:</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="14" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">MethodInfo</span><span style="background: #1e1e1e; color: gainsboro;"> FindMethod(</span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> t)</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> t</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetMethods()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Where(</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">m </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Name </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"op_Implicit"</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ReturnType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TTarget)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Count() </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #b4b4b4;">&&</span><span style="background: #1e1e1e; color: gainsboro;"> m</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetParameters()[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">]</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ParameterType </span><span style="background: #1e1e1e; color: #b4b4b4;">==</span><span style="background: #1e1e1e; color: gainsboro;"> t)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FirstOrDefault();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
If we have a MethodInfo, we are able to invoke this and convert our type.<br />
<br />
So after we can easily build a small IL Generator that builds either a Func or a small class wrapping instances. In each case this is simple:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="50" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSourceType, TDestType</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> CreateAction()</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;">[] helloArgs </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> { </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TSourceType), </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TDestType) };</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">DynamicMethod</span><span style="background: #1e1e1e; color: gainsboro;"> hello </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DynamicMethod</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Guid</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">NewGuid()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ToString(), </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;">), helloArgs, </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(TSourceType)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Module);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ILGenerator</span><span style="background: #1e1e1e; color: gainsboro;"> il </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> hello</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">GetILGenerator();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">il</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Emit(</span><span style="background: #1e1e1e; color: #4ec9b0;">OpCodes</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Ldarg_1);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">il</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Emit(</span><span style="background: #1e1e1e; color: #4ec9b0;">OpCodes</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Ldarg_0);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">EmitGetter(il);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">emit(il);</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">EmitSetter(il);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">il</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Emit(</span><span style="background: #1e1e1e; color: #4ec9b0;">OpCodes</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Ret);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Type</span><span style="background: #1e1e1e; color: gainsboro;"> t </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">typeof</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSourceType, TDestType</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSourceType, TDestType</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> res </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> (</span><span style="background: #1e1e1e; color: #4ec9b0;">Action</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: gainsboro;">TSourceType, TDestType</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">)hello</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateDelegate(t);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> res;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
EmitGetter and Setter just take care of automatic property/field to choose a CallVirt/LdFld operator.<br />
<br />
Now from that you can simply do :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="50" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> input </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">InputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> output </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">output</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Data </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">154.0f</span><span style="background: #1e1e1e; color: gainsboro;">;</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> dbl </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DoubleNativeTypeConverter</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> gen </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> dbl</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateGenerator</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">OutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">InputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;">(</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">Select</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">OutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">float</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(tp </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> tp</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Data), </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">Select</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">InputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #569cd6;">double</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(t </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> t</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Data)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> act </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> gen</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateAction();</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;">act(output, input);</span></li>
</ol>
</div>
</div>
<br />
<br />
The BIG difference, you can do all this at runtime, with reflection. No need to build two million converters.<br />
<br />
Of course an acute reader would notice, I have : DoubleNativeTypeConverter<br />
<br />
Yes basic primitive types (as of double, int, float...) don't expose this to reflection, so in that case you have to implement this manually (doing this for 20 types instead of thousands is a trade off I happily take, and in those cases you can simply use the Conv_(Type) opcode and just build a list of supported types, not a biggie.<br />
<br />
Please note that in this case I emit a Func (eg: a dynamic method), which in some cases is not always what you want (If your converter needs to hold resources for example, you'd need to generate a class with IDisposable, wich would just have an "update function'". You could also simply register this class an write it by hand. In neither case it's an issue.<br />
<br />
Possibilities are a bit endless, more on that in the next post (which might be a little while due to my project workload)...<br />
<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-11174310272162662642014-02-11T23:08:00.000+00:002014-02-11T23:08:19.973+00:00Direction and UI design<div dir="ltr" style="text-align: left;" trbidi="on">
Since I didn't posted for quite a bit in my blog, I thought maybe it's time for another post, since I've been pretty busy on many fronts.<div>
<br /></div>
<div>
First thing, I'm (finally) almost done with this China project, and this was a right pain (for a pretty nice result have to admit). There was a one last bug and I hope the last update will finally tick if off. The result of this update will certainly bring another blog post, but since I don't know yet I'll shut up in the mean time ;)</div>
<div>
<br /></div>
<div>
On other parts, I'm working a lot on reworking my demo tool user interface. I don't want to rewrite from scratch, since I believe it's a bad idea in many cases, but want to shift a bit and try something new.</div>
<div>
<br /></div>
<div>
Main thing, is, at the end of the day, people use a software, so the ui design/functionalities comes as a first. As system programmers, we often will write a kick ass runtime, but forget the utter basics of useability (a basic usability function might come very late in the pipeline because we found this new super fast code generation technique and focused there instead of any ui part).</div>
<div>
<br /></div>
<div>
This is of course even more apparent when you work with small teams (I mean, under 20 people). In my case and my tool I'm one developer, which also have to do projects for a living, so I can't even dedicate 10% of my full time on this.</div>
<div>
<br /></div>
<div>
So instead, I started to think of it in reverse, eg: this is what I need for my tool:</div>
<div>
<ul style="text-align: left;">
<li>Patch interface</li>
<li>Code editor</li>
<li>Dock panel (since I want to organize my layout)</li>
<li>Node lister</li>
<li>Informative elements (logger/project explorer/compilation error report...)</li>
</ul>
<div>
So now the concept is to build the main User Interface without any runtime in there.</div>
<div>
<br /></div>
<div>
By then you might argue that building a shell without any features is at best useless, and by trying it now, I would disagree:</div>
<div>
<ul style="text-align: left;">
<li>By using a ui without being distracted by any fancy looking visual you create, you start to really focus on ui. For example, you will immediately notice you'd like a dock, better undo function, that your ui is not smooth (no reference to 4v here ;) .</li>
<li>Since I know how to implement decently good graphics (still need to improve on that area for sure as well ;), The way I implement a particle system (as example) does not matter at this stage. And actually by thinking of this particle system I will see how the user interface can support the feature. Already having this particle system hinders that fact.</li>
<li>You WILL modify your user interface to correlate with your runtime (and modify you runtime too, softwares are constantly modified as a fact), but at least by working on UI first, you'll make sure that a rather decent amount of usability features are present and you software is not a bulk of unusable functions.</li>
<li>People want to use a software, so working on mockup also allows me to show a proper designer/ui specialist the concepts, and get insights (and programmers should never have the last word on ui design, another fact). What is convenient is what the user finds convenient, not your opinion as a programmer. Having well designed mockups also allows me to send a template find to a friend which will help building a nice menu order, shortcut list. While I delegate that, I suddenly have much more available time to build the core runtime.</li>
</ul>
<div>
So now when you build UI, you're overbloated with APIs, and it's hard to make a choice.</div>
</div>
<div>
<br /></div>
<div>
Since I don't plan to port my tool to whatever Android/Mac... (and anyway, as above, if you don't have a team of 20+ programmers or open source your program, don't even remotely think about multiplatform), I have the following choices (which can of course being mixed up, but single API streamlines things a tad).</div>
<div>
<br /></div>
<div>
<ul style="text-align: left;">
<li>Windows forms: The old good one, integrates super easily with Direct3D, simple to learn, can be extreme clunky and an absolute pain to do theming. Code editors/Dockers already available, good graph component for now I rolled my own (in D2D)</li>
<li>Direct2d : Great for building graph and other custom widgets,very good text/strokes rendering, quite fast in general, but complex layouts with d2d on it's own will be for sure cumbersome (not speaking of building a code editor with syntax coloring and other nitfy features).</li>
<li>Wpf: Most balanced of all, text can be blurry at times still, but good at shapes, code editor+docker also available, Direct3d integration reasonably easy, but such an overdesigned api that it's really daunting (for writing 2 crappy forms it's more or less ok, but decent builders become much more cumbersome). Theming is not too hard but also badly streamlined. </li>
<li>Direct3d : Same as Direct2d, but you have to do all yourself ;) You could really start to build proper gpu UI, and start to rethink data structures but it's a hell of work. If you'd need intermediate texture integration in your canvas, that will rock performances compared to anything else tho.</li>
</ul>
<div>
So here we go for now, some more info soon ))</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
<div>
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-34531464399357625432014-01-12T15:22:00.002+00:002014-01-12T15:22:45.258+00:00On plugin architecture<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
I was looking a bit a decoupling my code in a better way, for the moment Dx11 nodes follow the current way:<br />
<br />
<ul style="text-align: left;">
<li>Implement IPluginEvaluate</li>
<li>Implement either ResourceProvider or ResourceContextProvider</li>
</ul>
<div>
Then when you Implement ResourceProvider you use : SetDevice(RenderDevice device)</div>
<div>
<br /></div>
<div>
In some way this forces you to register a SetDevice method (so you don't forget to grab device), but this is not ideal in many points.</div>
<div>
<br /></div>
<div>
One thing I don't like with this, you have too much cooking and so much work is wasted on initialization order. Let's take a very basic example:<br />
<br /></div>
<div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #b8d7a3;">IDxDeviceListener</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IDxResourceContextProvider</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Input</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer In"</span><span style="background: #1e1e1e; color: gainsboro;">, DefaultValue </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FInBuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Output</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> SetDevice(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br /></div>
<div>
Please note that I omitted the update/evaluate for clarity.<br />
<br />
So what happens is First object constructor is called (here a default constrcutor since none is specified),<br />
then Buffer In and Buffer Out are injected into the node, to finish, once node is ready, SetDevice is called to the node.<br />
<br />
Now if I add a constructor, we here have the same:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #b8d7a3;">IDxDeviceListener</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IDxResourceContextProvider</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Input</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer In"</span><span style="background: #1e1e1e; color: gainsboro;">, DefaultValue </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FInBuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Output</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost</span><span style="background: #1e1e1e; color: gainsboro;"> host;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">ImportingConstructor</span><span style="background: #1e1e1e; color: gainsboro;">()]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CopyCounterNode(</span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost</span><span style="background: #1e1e1e; color: gainsboro;"> host)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">host </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> host;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">void</span><span style="background: #1e1e1e; color: gainsboro;"> SetDevice(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
</div>
</div>
<br />
Please note that first here there's 2 things which are pretty bad:<br />
<br />
<ul style="text-align: left;">
<li>I need to use ImportingConstructor otherwise MEF ignores injection (and plugin creation will fail). This is just really bad. That means I need to add an attribute on every single class of my model. Which, by propagating, would mean I'd need to use MEF even in my standalone library! Even worse, you also need to use attribute in every subclass, since they are not propagated.</li>
<li>Using attributes for input/output sounds a good idea, saves some time, but that's reasonably true for simple nodes, where you use inheritance, that creates issue. If I mark my pins as private, I get compiler warning (rightly so), you can use pragma to disable, but then you need to do that on all nodes, really intrusive as well.</li>
</ul>
<div>
Now one cool thing, I can export my DX11 Services, and have them injected, so instead I can do :</div>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IDxResourceContextProvider</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Input</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer In"</span><span style="background: #1e1e1e; color: gainsboro;">, DefaultValue </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b5cea8;">1</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FInBuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">Output</span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,IsSingle</span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer;</span></li>
<li> </li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost</span><span style="background: #1e1e1e; color: gainsboro;"> host;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">ImportingConstructor</span><span style="background: #1e1e1e; color: gainsboro;">()]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CopyCounterNode(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device, </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost</span><span style="background: #1e1e1e; color: gainsboro;"> host)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">host </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> host;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
But this will of course miserably fail.<br />
The simple reason is that FOutBuffer is injected after the constructor. You can't get a proper working object.<br />
<br />
2 Solutions for this:<br />
<br />
<ul style="text-align: left;">
<li>Implement IPartImportsSatisfiedNotification , and move the buffer initialization into this. Hurray,one more interface, one more remote method to implement, more intrusion.</li>
<li>Create pins by hand in constructor, via IIOFactory. Example below:</li>
</ul>
<div>
<br /></div>
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IDxResourceContextProvider</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IPartImportsSatisfiedNotification</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FInBuffer;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">ImportingConstructor</span><span style="background: #1e1e1e; color: gainsboro;">()]</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CopyCounterNode(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device, </span><span style="background: #1e1e1e; color: #b8d7a3;">IIOFactory</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory)</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">device </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FInBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceInputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer In"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceOutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<div>
<br /></div>
<div>
This feels a little bit more verbose, but now you have something correct (eg : when your object is instanciated it is ready to use, no more dodgy ordering. Initialization is in one place, and you can easily add some extensions methods/static methods to IOFactory to reduce overhead.<br />
<br />
Another great advantage, you can create some nicer extensions like :<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="45" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">static</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Layer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> CreateDX11LayerOut(</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">IIOFactory</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device,</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDelegate</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginIO</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderSettings</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;"> rendermethod,</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">string</span><span style="background: #1e1e1e; color: gainsboro;"> name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"Layer Out"</span><span style="background: #1e1e1e; color: gainsboro;">, </span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">bool</span><span style="background: #1e1e1e; color: gainsboro;"> subscribe </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">)</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> attr </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">OutputAttribute</span><span style="background: #1e1e1e; color: gainsboro;">(name) { IsSingle </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;"> };</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">var</span><span style="background: #1e1e1e; color: gainsboro;"> pin </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceOutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Layer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(name, subscribe);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">pin[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Layer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">pin[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">][device] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Layer</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">pin[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">][device]</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Render </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> rendermethod;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">return</span><span style="background: #1e1e1e; color: gainsboro;"> pin;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
<br />
Now if you call CreateDX11LayerOut, you even took care of the naming by providing a default, which is much easier to mess up with attributes (random typo, no idea of naming...)<br />
<br />
Last issue then, this ImportingConstructor is annoying, specially it needs to be everywhere.<br />
<br />
So I tried to check If I could get rid of MEF (partly), and build a small plugin interface with a far better container, eg : Autofac<br />
<br />
One thing I like is all initialization code is centralized (and not scattered randomly like in MEF so you don't know what exported/imported anymore).<br />
<br />
Building container is rather simple:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="96" style="background: #000000; margin: 0 0 0 3em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #4ec9b0;">ContainerBuilder</span><span style="background: #1e1e1e; color: gainsboro;"> cb </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">ContainerBuilder</span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterInstance</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IHDEHost</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(hdehost)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterInstance</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">INodeInfoFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(ni)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterInstance</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">IORegistry</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(ioreg)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IIORegistry</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterInstance</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">ILogger</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(logger)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterInstance(</span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RenderDevice)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DxDevice</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned();</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">container </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Build();</span></li>
</ol>
</div>
</div>
<br />
Please note that I didn't added all services here, but you also have a lot of nitfy features, and using AutoFac I can now technically even use composition on my core runtime, which was not possible with MEF (except adding attributes everywhere).<br />
<br />
More fun, I can import all vvvv services in one go using their Integration library.<br />
<br />
Now to register a plugin:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="40" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">container </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> parent</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">BeginLifetimeScope</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">(</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">(cb) </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Register(c </span><span style="background: #1e1e1e; color: #b4b4b4;">=></span><span style="background: #1e1e1e; color: gainsboro;"> pluginHost)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginHost2</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">INode</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IInternalPluginHost</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">ExternallyOwned();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterType</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">AutoFacIOFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">AutoFacIOFactory</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IIOFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InstancePerLifetimeScope();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">cb</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">RegisterType(pluginType)</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">As</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">()</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">InstancePerLifetimeScope();</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> </li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">iofactory </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> container</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Resolve</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">AutoFacIOFactory</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">PluginBase </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> container</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Resolve</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">autoevaluate </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> nodeInfo</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">AutoEvaluate;</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">OnCreated(</span><span style="background: #1e1e1e; color: #4ec9b0;">EventArgs</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Empty);</span></li>
</ol>
</div>
</div>
<br /></div>
</div>
<div>
Also really simple, and can be even more simplified, but I wanted to do a quick try.<br />
<br />
Best of all now, I have proper inheritance support, keeping what I want private/protected and so on:<br />
<br />
<div style="border: #000080 1px solid; color: black; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;">
<div style="background: #000080; color: white; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">
Code Snippet</div>
<div style="background: #ddd; overflow: auto;">
<ol start="11" style="background: #000000; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #b8d7a3;">IPluginEvaluate</span><span style="background: #1e1e1e; color: gainsboro;">, </span><span style="background: #1e1e1e; color: #b8d7a3;">IDxResourceContextProvider</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">Pin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FInBuffer;</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">protected</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> Device { </span><span style="background: #1e1e1e; color: #569cd6;">get</span><span style="background: #1e1e1e; color: gainsboro;">; </span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">set</span><span style="background: #1e1e1e; color: gainsboro;">; }</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CopyCounterNode(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device, </span><span style="background: #1e1e1e; color: #b8d7a3;">IIOFactory</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">Device </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> device;</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FInBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceInputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11StructuredBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer In"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceOutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li> </li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">[</span><span style="background: #1e1e1e; color: #4ec9b0;">PluginInfo</span><span style="background: #1e1e1e; color: gainsboro;">(Name </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"CopyCounter2"</span><span style="background: #1e1e1e; color: gainsboro;">, Category </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"DX11.Buffer"</span><span style="background: #1e1e1e; color: gainsboro;">, Version </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">""</span><span style="background: #1e1e1e; color: gainsboro;">, Author </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #d69d85;">"vux"</span><span style="background: #1e1e1e; color: gainsboro;">)]</span></li>
<li><span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">class</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode2</span><span style="background: #1e1e1e; color: gainsboro;"> : </span><span style="background: #1e1e1e; color: #4ec9b0;">CopyCounterNode</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">private</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #b8d7a3;">ISpread</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">>></span><span style="background: #1e1e1e; color: gainsboro;"> FOutBuffer2;</span></li>
<li style="background: #0c0c0c;"> </li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">public</span><span style="background: #1e1e1e; color: gainsboro;"> CopyCounterNode2(</span><span style="background: #1e1e1e; color: #4ec9b0;">RenderDevice</span><span style="background: #1e1e1e; color: gainsboro;"> device, </span><span style="background: #1e1e1e; color: #b8d7a3;">IIOFactory</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory) : </span><span style="background: #1e1e1e; color: #569cd6;">base</span><span style="background: #1e1e1e; color: gainsboro;">(device,iofactory)</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;">{</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer2 </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> iofactory</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">CreateResourceOutputPin</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">(</span><span style="background: #1e1e1e; color: #d69d85;">"Buffer Out"</span><span style="background: #1e1e1e; color: gainsboro;">,</span><span style="background: #1e1e1e; color: #569cd6;">true</span><span style="background: #1e1e1e; color: gainsboro;">);</span></li>
<li style="background: #0c0c0c;"> <span style="background: #1e1e1e; color: gainsboro;"></span><span style="background: #1e1e1e; color: #569cd6;">this</span><span style="background: #1e1e1e; color: #b4b4b4;">.</span><span style="background: #1e1e1e; color: gainsboro;">FOutBuffer2[</span><span style="background: #1e1e1e; color: #b5cea8;">0</span><span style="background: #1e1e1e; color: gainsboro;">] </span><span style="background: #1e1e1e; color: #b4b4b4;">=</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #569cd6;">new</span><span style="background: #1e1e1e; color: gainsboro;"> </span><span style="background: #1e1e1e; color: #4ec9b0;">DX11Resource</span><span style="background: #1e1e1e; color: #b4b4b4;"><</span><span style="background: #1e1e1e; color: #4ec9b0;">DX11RawBuffer</span><span style="background: #1e1e1e; color: #b4b4b4;">></span><span style="background: #1e1e1e; color: gainsboro;">();</span></li>
<li> <span style="background: #1e1e1e; color: gainsboro;">}</span></li>
<li style="background: #0c0c0c;"><span style="background: #1e1e1e; color: gainsboro;">}</span></li>
</ol>
</div>
</div>
</div>
<br />
No more references to MEF, inheritance is streamlined. Also now you can see that device can't be written by then child class, and no more compiler warning.<br />
<br />
Technically class is now perfectly isolated, and node don't know about autofac or using a container. The IOC manages it for you, you can replace it by another one if you want, or make you own barebone version.<br />
<br />
Now you also have proper initialization at the place it should be : the constructor.<br />
<br />
And as usual one very funny thing, this is MUCH less code than the .NET factory for the same features ;)<br />
<div>
<br /></div>
</div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0tag:blogger.com,1999:blog-9189716717329233051.post-44834479927917385942014-01-11T19:15:00.001+00:002014-01-11T19:15:50.620+00:00Happy new year, News, and thoughts<div dir="ltr" style="text-align: left;" trbidi="on">
First Happy new year!<br />
<br />
2013 was pretty great (first DX11 release, Node13, lots of interesting projects, birth of a new tool ;)<br />
<br />
Hope 2014 will follow, and to be honest, it's starting quite in many interesting ways.<br />
<br />
First thing I'm reasonably happy on adoption for DirectX11, still some parts are missing, but most times people going into it don't go back (which is a good sign).<br />
<br />
There's still some nodes missing, but well I'm kinda more or less on my own writing it (thanks to the few people who contributed nodes), on top of various projects, so it's a lot of time (gladly I use it for projects, so at least I can add some bug fixes/Few more nodes, but nodes are generally so specific they not really much point pushing to core).<br />
<br />
If a few wannabe c# programmers decide to pop in and help add some of the missing nodes (Text Geometry/XFile writer/Player...), please feel free to ping me, I'll happily help with basics of coding a Dx11 node (it's much easier than writing a DX9 one believe me ;)<br />
<br />
Also of course thanks to people who started to post dx11 contributions, I believe that helps adoption, and at least I can spend more efforts on the runtime instead.<br />
<br />
On the same way I'd love few people to write help patches and more examples, it also takes time, I rather enjoy to explain routines, but same thing = time.<br />
<br />
So now 2014 started on a quite fast paced mode (I spent bit of time between xmas and new year too), let's see what's going on:<br />
<br />
<ul style="text-align: left;">
<li>Port to core runtime to SharpDX is pretty much complete, nicer, faster, simpler. That means support to latest versions, and support up to Win7 is there.</li>
<li>Texture was bit of an issue, but thanks to directxtex.codeplex.com , few exports and P/Invoke, now have a portable Texture reader/writer, with tga support on the way, and BC7 encoder, if you survive the "very" slow export, in order to enjoy the very fast import ;)</li>
<li>Most of old nodes are also done (i'd say 80% of the nodes are ported)</li>
<li>Many type of nodes are now templated (using T4 templates), so most geometry/layer and others, are just reflected and node is generated from that, makes refactoring a hell of a lot easier).</li>
<li>Shader nodes have been reasonably revamped.</li>
<li>Lot of new interesting/experimental features on the way too ;)</li>
<li>Many high level nodes, so non shader experts can start to use their gpu in a reasonable way :)</li>
</ul>
<div>
Now of course there's still work to do, Pin system (once greg will have sorted the convolution issue), will also get some revamp, Resource management is getting along more improvements, and still some more questions about some other bits (see below).</div>
<div>
<br /></div>
<div>
Please note that most work as been done to make API simpler. API now uses less code, is faster, and I find using it is also less code. Writing a node with new API is really simple, there's much less cooking around.</div>
<div>
<br /></div>
<div>
First session of rolling out (pre alpha early bird to not use for production you've been warned) small release is incoming, so will be able to see how things are getting along.</div>
<div>
<br /></div>
<div>
There is still some bits I'd like to work on, in no particular order:</div>
<div>
<ul style="text-align: left;">
<li>Code editor: Time to really start to think as fx files as projects, and just not a window with unusable code completion. </li>
<li>Improve elements decoupling: Some more core, vvvv being so tied to MEF it's gonna be fun, but there's some big rationale behind it, which deserves a post on it's own.</li>
<li>Get rid of property injection : So i can really get proper inheritance control , and nodes could even be reused.</li>
<li>More high level nodes: No comment, everyone likes high level nodes</li>
<li>New transforms : The funny thing is actuallyafter some thoughts, moving transforms to a new type opens a hell of a lot of new doors, more on that later, that deserves another post.</li>
<li>Continue to simplify: It doesn't mean lot of small files with 2 lines of code each (no offense to java people, which actually can't since their header is already filled with imports ;) Simpler is better, I don't need the most amazing configurable runtime, I need a lightweight, easy to use and fast runtime!</li>
<li>Some more top secret things are also on the way ;)</li>
</ul>
<div>
As usual, thanks for reading and happy new year again !</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<br />
<br />
<br /></div>
Mr Vuxhttp://www.blogger.com/profile/14723452478445867649noreply@blogger.com0