{"id":635,"date":"2011-10-28T19:00:00","date_gmt":"2011-10-28T18:00:00","guid":{"rendered":"http:\/\/shadowcovenant.com\/blog\/2011\/10\/28\/surgeedimage-bank-editor\/"},"modified":"2011-10-28T19:00:00","modified_gmt":"2011-10-28T18:00:00","slug":"surgeedimage-bank-editor","status":"publish","type":"post","link":"http:\/\/shadowcovenant.com\/blog\/2011\/10\/28\/surgeedimage-bank-editor\/","title":{"rendered":"SurgeED&ndash;Image Bank Editor"},"content":{"rendered":"<p align=\"justify\">After a couple of weeks, I\u2019ve finished the Image Bank editor on the SurgeED tool\u2026 Took a bit longer than I was expecting, mainly because I had to add to the editor system the concept of child entities, with all the copy\/delete\/undo\/redo\/explorer issues associated with it\u2026<\/p>\n<p align=\"justify\">But first of all, what\u2019s an image bank (IB) and why do I use them?<\/p>\n<p align=\"justify\">Well, one of the main things you can do to increase performance in any engine (be it 2d or 3d) is to reduce the number of primitive drawing calls\u2026 I\u2019m not talking about actual primitives, but calls to the function that draws them\u2026 That requires a call to the low level system, and that call has a fixed setup time, no matter how many primitives you render in that call\u2026<\/p>\n<p align=\"justify\">So, it\u2019s better to create a single buffer with 1000 primitives (sprites in case of 2d) and draw that, than have 1000 buffers and draw them all\u2026 The performance increase is in several orders of magnitude\u2026 <\/p>\n<p align=\"justify\">This process is called \u201cbatching\u201d\u2026 <\/p>\n<p align=\"justify\">But to draw 1000 primitives in a single draw call, they have to share every render state (which includes all the like render properties, more importantly, the textures).<\/p>\n<p align=\"justify\">So, to draw 1000 primitives, they have to share the same texture, and this is done through creating an atlas, which is a single texture that has loads of images in it. Then, using UV mapping, we can index the separate images and use them in a single draw call to draw different objects\u2026 Below you can see an example of this:<\/p>\n<p align=\"justify\"><a href=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/BM_gui.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px\" title=\"BM_gui\" border=\"0\" alt=\"BM_gui\" src=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/BM_gui_thumb.jpg\" width=\"435\" height=\"439\" \/><\/a><\/p>\n<p align=\"justify\">This is accompanied by a file that describes where each of the individual images is:<\/p>\n<p><font size=\"1\" face=\"Courier New\">&lt;image_bank name=&quot;bm_gui_ib&quot; delete_textures=&quot;false&quot; normalized_coords=&quot;false&quot; read_textures=&quot;true&quot;&gt;     <br \/>&#160;&#160;&#160; &lt;source&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;layer type=&quot;diffuse&quot;&gt;bm_gui&lt;\/layer&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;images&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_arrow_s&quot; x=&quot;703&quot; y=&quot;0&quot; sx=&quot;32&quot; sy=&quot;95&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_arrow_u&quot; x=&quot;639&quot; y=&quot;0&quot; sx=&quot;32&quot; sy=&quot;95&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_btn&quot; x=&quot;191&quot; y=&quot;288&quot; sx=&quot;61&quot; sy=&quot;71&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_combine&quot; x=&quot;795&quot; y=&quot;152&quot; sx=&quot;184&quot; sy=&quot;85&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_exit_s&quot; x=&quot;639&quot; y=&quot;320&quot; sx=&quot;73&quot; sy=&quot;31&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_exit_u&quot; x=&quot;543&quot; y=&quot;320&quot; sx=&quot;73&quot; sy=&quot;31&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_s02&quot; x=&quot;319&quot; y=&quot;32&quot; sx=&quot;142&quot; sy=&quot;25&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_s03&quot; x=&quot;319&quot; y=&quot;57&quot; sx=&quot;142&quot; sy=&quot;23&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_s04&quot; x=&quot;319&quot; y=&quot;80&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_s05&quot; x=&quot;319&quot; y=&quot;104&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_s06&quot; x=&quot;319&quot; y=&quot;128&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u01&quot; x=&quot;0&quot; y=&quot;0&quot; sx=&quot;142&quot; sy=&quot;32&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u02&quot; x=&quot;0&quot; y=&quot;32&quot; sx=&quot;142&quot; sy=&quot;25&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u03&quot; x=&quot;0&quot; y=&quot;57&quot; sx=&quot;142&quot; sy=&quot;23&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u04&quot; x=&quot;0&quot; y=&quot;80&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u05&quot; x=&quot;0&quot; y=&quot;104&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u06&quot; x=&quot;0&quot; y=&quot;128&quot; sx=&quot;142&quot; sy=&quot;24&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;image name=&quot;b_inv_menu_u07&quot; x=&quot;0&quot; y=&quot;152&quot; sx=&quot;142&quot; sy=&quot;33&quot; hx=&quot;0&quot; hy=&quot;0&quot;\/&gt;      <br \/>&#8230;&#8230;&#8230;&#8230;&#8230;<\/font><\/p>\n<p align=\"justify\">The hotspot describes where is the \u201cgrip point\u201d of the image, which is helpful for rotations and just general positioning.<\/p>\n<p align=\"justify\">An image bank then gives \u201cnames\u201d to the images and says to the system where it can go get them (in terms of texture and positioning). A single image bank can use several textures:<\/p>\n<p><a href=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/afonso0400.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px\" title=\"afonso0400\" border=\"0\" alt=\"afonso0400\" src=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/afonso0400_thumb.jpg\" width=\"244\" height=\"244\" \/><\/a><a href=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/afonso0401.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px\" title=\"afonso0401\" border=\"0\" alt=\"afonso0401\" src=\"http:\/\/shadowcovenant.com\/blog\/wp-content\/uploads\/2011\/10\/afonso0401_thumb.jpg\" width=\"244\" height=\"244\" \/><\/a><\/p>\n<p>This helps with the organization of the image banks\u2026 <\/p>\n<p>One thing I added in the process of adding an editor for this (more on this later) was the ability of a single image have different layers (like diffuse, normal, etc). This will be helpful to define a decal system later, since I need both textures to create a really good decal, and I didn\u2019t want to create separate systems\u2026<\/p>\n<p>Basically an image can have multiple layers, the only restriction being that all the layers have to have the same size.<\/p>\n<p align=\"justify\">Up until now, the artists would create these Image Banks by hand, positioning images in a big image and creating a text file by hand, specifying where each element was. This was time consuming and very error-prone, and this was one of the motivations for the image bank editor.<\/p>\n<p align=\"justify\">The way the image bank editor works is very straightforward\u2026 You create an image bank component, and add pages to it\u2026 Each page can have different sizes and support different layers. Then you import images to a specific page (with all layers being a different source DDS image). Then you can move the images around, using the normal tools of the trade (snaps to grid, to other objects, padding support with visual warning where two images are overlapping, etc)\u2026<\/p>\n<p align=\"justify\">When the artist is satisfied with the image bank, he can \u201cGenerate\u201d it and the system will create the atlas and XML file, and it becomes available to all the editor system. The component can then be deleted (it can always be created again from the image bank), or left alone.<\/p>\n<p align=\"justify\">You can also add mountpoints on the images. On the sample above, you can see the character has a sword on his hand, but if we had a character that could yield a sword or an axe (for example), we could add a mountpoint to his hand and in the game run time, attach another object to a specific mountpoint.<\/p>\n<p align=\"justify\">I\u2019m very proud of the editor as a whole, and this component is very cool in action, since I believe it will cut down development time for 2d games a big deal (artists could lose up to 3 or 4 hours creating an atlas by hand, and add 2 more hours or so due to small errors, like a wrong position (easy to spot) or a wrong hotspot (harder to spot)).<\/p>\n<div style=\"padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px\" id=\"scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:4c32a745-e91e-4d23-b3a4-7ecae48f7f5c\" class=\"wlWriterEditableSmartContent\">\n<div><object width=\"640\" height=\"360\"><param name=\"movie\" value=\"http:\/\/www.youtube.com\/v\/-8eEoROnF0o?hl=en&amp;hd=1\"><\/param><embed src=\"http:\/\/www.youtube.com\/v\/-8eEoROnF0o?hl=en&amp;hd=1\" type=\"application\/x-shockwave-flash\" width=\"640\" height=\"360\"><\/embed><\/object><\/div>\n<\/div>\n<p>&#160;<\/p>\n<p>You can see the editor in action above\u2026 the frame rate is crap, think it is because of the on-the-fly encoding\u2026 This component doesn\u2019t perform as well as I\u2019d want, but it\u2019s easy to understand, considering that each image has to be drawn separately (in its own draw call), because we\u2019re trying to create the image bank that will solve that problem in game\u2026 <\/p>\n<p>Next stop in my travels in game development land will take me to rebuilding the fonts for Something Fishy, so I can start trying to port the game to tablets.<\/p>\n<div id=\"tweetbutton635\" class=\"tw_button\" style=\"\"><a href=\"http:\/\/twitter.com\/share?url=http%3A%2F%2Fshadowcovenant.com%2Fblog%2F2011%2F10%2F28%2Fsurgeedimage-bank-editor%2F&amp;text=SurgeED%26ndash%3BImage%20Bank%20Editor&amp;related=&amp;lang=en&amp;count=horizontal&amp;counturl=http%3A%2F%2Fshadowcovenant.com%2Fblog%2F2011%2F10%2F28%2Fsurgeedimage-bank-editor%2F\" class=\"twitter-share-button\"  style=\"width:55px;height:22px;background:transparent url('http:\/\/shadowcovenant.com\/blog\/wp-content\/plugins\/wp-tweet-button\/tweetn.png') no-repeat  0 0;text-align:left;text-indent:-9999px;display:block;\">Tweet<\/a><\/div>","protected":false},"excerpt":{"rendered":"<p>After a couple of weeks, I\u2019ve finished the Image Bank editor on the SurgeED tool\u2026 Took a bit longer than I was expecting, mainly because I had to add to the editor system the concept of child entities, with all the copy\/delete\/undo\/redo\/explorer issues associated with it\u2026 But first of all, what\u2019s an image bank (IB) [&hellip;]<\/p>\n<div id=\"tweetbutton635\" class=\"tw_button\" style=\"\"><a href=\"http:\/\/twitter.com\/share?url=http%3A%2F%2Fshadowcovenant.com%2Fblog%2F2011%2F10%2F28%2Fsurgeedimage-bank-editor%2F&amp;text=SurgeED%26ndash%3BImage%20Bank%20Editor&amp;related=&amp;lang=en&amp;count=horizontal&amp;counturl=http%3A%2F%2Fshadowcovenant.com%2Fblog%2F2011%2F10%2F28%2Fsurgeedimage-bank-editor%2F\" class=\"twitter-share-button\"  style=\"width:55px;height:22px;background:transparent url('http:\/\/shadowcovenant.com\/blog\/wp-content\/plugins\/wp-tweet-button\/tweetn.png') no-repeat  0 0;text-align:left;text-indent:-9999px;display:block;\">Tweet<\/a><\/div>","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23,6,59,58],"tags":[70,72,71],"class_list":["post-635","post","type-post","status-publish","format-standard","hentry","category-development","category-games","category-surgeed-2","category-tools","tag-batching","tag-image-bank","tag-performance"],"_links":{"self":[{"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/posts\/635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/comments?post=635"}],"version-history":[{"count":0,"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/posts\/635\/revisions"}],"wp:attachment":[{"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/media?parent=635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/categories?post=635"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/shadowcovenant.com\/blog\/wp-json\/wp\/v2\/tags?post=635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}