{"id":57,"date":"2012-06-15T13:08:09","date_gmt":"2012-06-15T06:08:09","guid":{"rendered":"http:\/\/lhkbob.com\/blog\/?p=57"},"modified":"2012-06-16T14:51:02","modified_gmt":"2012-06-16T07:51:02","slug":"vector-caching-in-ferox-with-entreri","status":"publish","type":"post","link":"https:\/\/lhkbob.com\/blog\/vector-caching-in-ferox-with-entreri\/","title":{"rendered":"Vector caching in Ferox with Entreri"},"content":{"rendered":"<p>The ferox-scene API uses the Entreri component framework to define a number of components that can be combined to describe entities within a scene. \u00a0Many properties of these components are vector or matrix types, such as direction, position, transform, color, etc. \u00a0I needed a solution that had the following features:<\/p>\n<ol>\n<li>Packed the data internally into a primitive array<\/li>\n<li>Exposed the data as a Vector3 or Matrix3<\/li>\n<li>Did not require the allocation of a result object to access the data<\/li>\n<\/ol>\n<p>To solve problem #1, I implemented custom Properties that wrap a DoubleProperty but provide getters and setters using the appropriate math types. \u00a0At the Property level, they getters require a result type but I was on the right path to solving #2 and #3.<\/p>\n<p>The math Properties were implemented very similarly and fit this general pattern:<\/p>\n<pre class=\"brush:java\">@Factory(FooProperty.Factory.class)\r\npublic class FooProperty implements Property {\r\n   private final DoubleProperty realData; \r\n\r\n   public Foo get(int index, Foo result) { } \r\n\r\n   public void set(int index, Foo value) { } \r\n\r\n   @Attribute\r\n   public static @interface DefaultFoo {\r\n      \/\/ attributes for default Foo's\r\n   }\r\n\r\n   \/\/ Factory implementation to create FooProperties\r\n   public static class Factory implements PropertyFactory&lt;FooProperty&gt; { }\r\n}<\/pre>\n<p>Here is an example of how a Vector3 could be stored as a property:<\/p>\n<pre class=\"brush:java\">@Factory(Vector3Property.Factory.class);\r\npublic class Vector3Property {\r\n   \/\/ 3 elements for x, y, z\r\n   private final DoubleProperty values = new DoubleProperty(3); \r\n\r\n   public void get(int index, Vector3 v) {\r\n      \/\/ sets the state of v to match the indexed data\r\n      v.set(values.getIndexedData(), index * 3);\r\n   }\r\n\r\n   public void set(int index, Vector3 v) {\r\n      \/\/ gets the state of v into the indexed data\r\n      v.get(values.getIndexedData(), index * 3);\r\n   }\r\n\r\n   @Attribute\r\n   public static @interface DefaultVector3 {\r\n      double x();\r\n      double y();\r\n      double z();\r\n   }\r\n\r\n   public static class Factory implements PropertyFactory&lt;Vector3Property&gt; {\r\n      \/\/ implementation checks for DefaultVector3 attribute for\r\n      \/\/ initial value assignment\r\n   }\r\n}<\/pre>\n<p>This provides a convenient wrapper around a DoubleProperty and provides us with an annotation to set the default value of each vector to separate x, y, and z values. However, it does not help with reduced instantiation because it requires an input Vector3 to get or set values in the property.<\/p>\n<p>By using the protected onSet(int)\u00a0method in ComponentData implementations, we can add an unmanaged Vector3 field to a component type that is cached, and is kept in-sync with the property with the set listener method.<\/p>\n<pre class=\"brush:java\">public class MyComponent extends ComponentData&lt;MyComponent&gt; {\r\n   @DefaultVector3(x=1.0, y=0.0, z=1.0);\r\n   private Vector3Property vector;\r\n\r\n   @Unmanaged\r\n   private final Vector3 cache = new Vector3();\r\n\r\n   \/\/ Use @Const to tell programmers not to mutate data.\r\n   \/\/ Alternatively expose a read-only interface.\r\n   public @Const Vector3 getVector3() {\r\n      return cache;\r\n   }\r\n\r\n   public void setVector3(Vector3 v) {\r\n      cache.set(v);\r\n      vector.set(getIndex(), v);\r\n   }\r\n\r\n   @Override\r\n   protected void onSet(int index) {\r\n      vector.get(index, v);\r\n   }\r\n}<\/pre>\n<p>With all of this together, you can create many Component&lt;MyComponent&gt; and the vectors will be automatically packed into a hidden double array. \u00a0This provides good cache locality. \u00a0Using the wrapper Vector3Property and the onSet() event listener in MyComponent, the final exposed interface is a convenient Vector3 instance. \u00a0Even with all of this, only a single instance of Vector3 is required for each instance of MyComponent.<\/p>\n<p>Because ComponentData instances are used as fly-weight objects over the identifying Components, this makes iterating over all MyComponent&#8217;s require minimal object creation overhead.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The ferox-scene API uses the Entreri component framework to define a number of components that can be combined to describe entities within a scene. \u00a0Many&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[5],"tags":[10,11],"_links":{"self":[{"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/posts\/57"}],"collection":[{"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":10,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/posts\/57\/revisions"}],"predecessor-version":[{"id":69,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/posts\/57\/revisions\/69"}],"wp:attachment":[{"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/media?parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/categories?post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lhkbob.com\/blog\/wp-json\/wp\/v2\/tags?post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}