<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://book.abe.free.fr/blog/?feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>abe.blog() - Tag - flash</title>
  <link>http://book.abe.free.fr/blog/?</link>
  <atom:link href="http://book.abe.free.fr/blog/?feed/tag/flash/rss2" rel="self" type="application/rss+xml"/>
  <description>abe.blog.put ( graphics )
abe.blog.put ( code )
return true</description>
  <language>en</language>
  <pubDate>Tue, 21 May 2013 09:44:10 +0200</pubDate>
  <copyright>All rights reserved - Cédric Néhémie 2005</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Ludum Dare 20 - Rainbow Riding HoodZ</title>
    <link>http://book.abe.free.fr/blog/?post/2011/05/03/Ludum-Dare-20-Rainbow-Riding-HoodZ</link>
    <guid isPermaLink="false">urn:md5:7cca9276b0d7bc4331a5f1925bdde4cf</guid>
    <pubDate>Tue, 03 May 2011 12:37:00 +0200</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>flash</category><category>game</category><category>ld48</category><category>ludumdare</category>    
    <description>    &lt;p&gt;Pfiouu, weekend de fou furieux, 72 heures pour concevoir et réaliser un jeu avec mes compère &lt;a href=&quot;http://www.hkoncept.net/&quot; hreflang=&quot;fr&quot;&gt;Mr_Hk_&lt;/a&gt; et &lt;a href=&quot;http://www.serasounddesign.com/&quot; hreflang=&quot;fr&quot;&gt;Aries&lt;/a&gt;, on peut parler d'un sacré challenge.&lt;/p&gt;


&lt;p&gt;Un grand merci à &lt;a href=&quot;http://www.motion-twin.com/&quot; hreflang=&quot;fr&quot;&gt;Motion Twin&lt;/a&gt; pour nous avoir hébergé le temps de la manifestation, ainsi qu'a &lt;a href=&quot;http://www.ludumdare.com/compo/category/ld-20/?author_name=valandre&quot; hreflang=&quot;en&quot;&gt;Valandre&lt;/a&gt; et &lt;a href=&quot;http://www.ludumdare.com/compo/category/ld-20/?author_name=deepnight&quot; hreflang=&quot;en&quot;&gt;Deepnight&lt;/a&gt; qui nous ont accompagné pendant ce week end.&lt;/p&gt;


&lt;h3&gt;&lt;a href=&quot;http://dl.dropbox.com/u/5708588/raindow_riding_hood/bin/Rainbow_riding_hood.html&quot;&gt;PLAY THE GAME&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=4185&quot;&gt;&lt;img src=&quot;http://www.ludumdare.com/compo/wp-content/compo2/45257/4185-shot0.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=4185&quot;&gt;&lt;img src=&quot;http://www.ludumdare.com/compo/wp-content/compo2/45257/4185-shot1.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=4185&quot;&gt;&lt;img src=&quot;http://www.ludumdare.com/compo/wp-content/compo2/45257/4185-shot2.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=4185&quot;&gt;&lt;img src=&quot;http://www.ludumdare.com/compo/wp-content/compo2/45257/4185-shot3.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=4185&quot;&gt;&lt;img src=&quot;http://www.ludumdare.com/compo/wp-content/compo2/45257/4185-shot4.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Voila :).&lt;/p&gt;


&lt;p&gt;À bientôt.&lt;/p&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2011/05/03/Ludum-Dare-20-Rainbow-Riding-HoodZ#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2011/05/03/Ludum-Dare-20-Rainbow-Riding-HoodZ#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/185</wfw:commentRss>
      </item>
    
  <item>
    <title>GPP : Preprocessing and FDT</title>
    <link>http://book.abe.free.fr/blog/?post/2009/05/16/GPP-Preprocessing-and-FDT</link>
    <guid isPermaLink="false">urn:md5:4008abc02a958a66442023068ed141f5</guid>
    <pubDate>Fri, 22 May 2009 22:15:00 +0200</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>flash</category><category>preprocessing</category>    
    <description>&lt;p&gt;A quick note about some research I've done on preprocessing and its usage in combination with FDT. It'll demonstrate how to configure &lt;a href=&quot;http://en.nothingisreal.com/wiki/GPP&quot; hreflang=&quot;fr&quot; title=&quot;Generic Pre Pocessor&quot;&gt;GPP&lt;/a&gt; to make it compliant with FDT.&lt;/p&gt;    &lt;p&gt;I'm not going to detail why using preprocessor or what you can do with it, but how to work with it in an environment which doesn't recognize it.&lt;/p&gt;


&lt;h4&gt;First problem&lt;/h4&gt;


&lt;p&gt;Using a preprocessor assume that you insert specific instructions in your files. If you use a &lt;code&gt;cpp&lt;/code&gt; style preprocessor the syntax of the macro definition are well known by FDT so writing :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define FOO this is foo&lt;/pre&gt;


&lt;p&gt;will not be considered as an error. But referring to &lt;code&gt;FOO&lt;/code&gt; in your code wil result in FDT showing an error because FOO haven't be declared (in fact it was declared, but FDT don't know that it was, it's not actionscript).&lt;/p&gt;


&lt;p&gt;It's really an important point, because when you have dozens of errors due to the preprocessing stuff you greatly reduce the relevancy of the FDT's live error highlighting feature. And it also could sometimes break autocompletion.&lt;/p&gt;


&lt;p&gt;To solve that issue, you need a way to insert preprocessing instructions without breaking the parser. The solution have to work in any context we should use preprocessors such as :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;FOO
var foo : Number = FOO;
trace( FOO );&lt;/pre&gt;


&lt;p&gt;It's at that time I came to look at &lt;a href=&quot;http://en.nothingisreal.com/wiki/GPP&quot; hreflang=&quot;fr&quot; title=&quot;Generic Pre Pocessor&quot;&gt;GPP&lt;/a&gt; which allow to create your own preprocessing instructions syntax and provide default modes compliant with cpp syntax (which I'll use as base for my experiment).&lt;/p&gt;


&lt;p&gt;To install GPP on Debian based linux distro open a shell and execute :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;sudo apt-get install gpp&lt;/pre&gt;


&lt;p&gt;I've first tryed to work with syntax such as &lt;code&gt;&amp;quot;FOO&amp;quot;&lt;/code&gt;, &lt;code&gt;/FOO/&lt;/code&gt; or &lt;code&gt;&amp;lt;FOO/&amp;gt;&lt;/code&gt; to trick the parser, but it should remain the type problem and I couldn't use it in all context.&lt;/p&gt;


&lt;p&gt;I finally came to the following syntax :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;[].FOO&lt;/pre&gt;


&lt;p&gt;FDT will interpret this as an access to a dynamic property of an anonymous array. As FDT can't know the type of the property it will consider it as of type &lt;code&gt;*&lt;/code&gt;, and don't show any error when used in a typed context.&lt;/p&gt;


&lt;p&gt;The GPP's option to setup the user-defined macro call syntax is &lt;code&gt;-U&lt;/code&gt;, in that case the command line look like :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;gpp   -U &amp;quot;[].&amp;quot; &amp;quot;\W&amp;quot; &amp;quot;(&amp;quot; &amp;quot;,&amp;quot; &amp;quot;)&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;#&amp;quot; &amp;quot;\&amp;quot; \ 
  	-O &amp;quot;GPPTest.as&amp;quot; \
  	&amp;quot;GPPTest.as&amp;quot;&lt;/pre&gt;


&lt;h4&gt;Second problem&lt;/h4&gt;


&lt;p&gt;You probably want, at some point, create macro with arguments. Take a look at the example below :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;// define a macro with arguments
#define CONCAT|#1#2

// call that macro, FDT will show error cause hello
//and world are not declared 
[].CONCAT(hello, world)
// produce : hello world&lt;/pre&gt;


&lt;p&gt;That macro will take the two arguments and will concatenate them. But neither &lt;code&gt;hello&lt;/code&gt; nor &lt;code&gt;world&lt;/code&gt; are declared members, and you probably don't want to define them as string such as the example below :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;[].CONCAT(&amp;quot;hello&amp;quot;, &amp;quot;world&amp;quot;)
// produce : &amp;quot;hello&amp;quot; &amp;quot;world&amp;quot;&lt;/pre&gt;


&lt;p&gt;So, to workaround this issue I simply wrap all the macro arguments into a single quote string such as below :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;[].CONCAT('hello, world')
// produce : hello world&lt;/pre&gt;


&lt;p&gt;In fact, the macro arguments start sequence is defined with &lt;code&gt;('&lt;/code&gt; and the macro arguments end sequence is defined with &lt;code&gt;')&lt;/code&gt;, in that way FDT will not complain any more about undeclared member's call. It also prevent from misinterpretation when you're passing invalid actionscript construct into a macro (example below).&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define VERSION #1 &amp;quot;Version : 1.0&amp;quot; #2

[].VERSION('trace( , )');
// produce : trace( &amp;quot;Version : 1.0&amp;quot; )&lt;/pre&gt;


&lt;p&gt;The new command line, at this step, look like :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;gpp   -U &amp;quot;[].&amp;quot; &amp;quot;\W&amp;quot; &amp;quot;('&amp;quot; &amp;quot;,&amp;quot; &amp;quot;')&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;#&amp;quot; &amp;quot;\&amp;quot; \ 
  	-O &amp;quot;GPPTest.as&amp;quot; \
  	&amp;quot;GPPTest.as&amp;quot;&lt;/pre&gt;


&lt;p&gt;However there's some limitations with this workaround :&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; - If you want to pass a string as argument (with the quotes) you can only use the double quotes, and as the GPP's cpp mode define strings with both &lt;code&gt;&amp;quot;&lt;/code&gt; and &lt;code&gt;'&lt;/code&gt; you'll need to remove the second string definition using the &lt;code&gt;-s&lt;/code&gt; option, or you can redefine all the comments and strings option like that (I've encountered some issues using the &lt;code&gt;-s&lt;/code&gt; options because of the default mode, so I prefer redefine all that stuff by myself) :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;gpp   -U &amp;quot;[].&amp;quot; &amp;quot;\W&amp;quot; &amp;quot;('&amp;quot; &amp;quot;,&amp;quot; &amp;quot;')&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;#&amp;quot; &amp;quot;\&amp;quot; \ 
  	+c &amp;quot;/*&amp;quot; &amp;quot;*/&amp;quot; \ 
 	+c &amp;quot;//&amp;quot; &amp;quot;\n&amp;quot; \
  	+s &amp;quot;\&amp;quot;&amp;quot; &amp;quot;\&amp;quot;&amp;quot; &amp;quot;\\&amp;quot; \
  	-O &amp;quot;GPPTest.as&amp;quot; \
  	&amp;quot;GPPTest.as&amp;quot;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; - GPP offer to create macro with named arguments. In order to create such macro you need to use user defined macro call as the name of the new macro, such as&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define FOO(x,y) this is x, and the this is y.&lt;/pre&gt;


&lt;p&gt;But it seems that GPP doesn't like quotes in that context. In that case, there's a little trick to do before defining these kind of macros. Just use the &lt;code&gt;#mode&lt;/code&gt; macro to change locally the way the macro are called, like that :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;// push a new mode in the modes' stack
#mode push
// change the macro call syntax for the pushed mode
#mode user &amp;quot;&amp;quot; &amp;quot;&amp;quot; &amp;quot;(&amp;quot; &amp;quot;\W,\W&amp;quot; &amp;quot;)&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;#&amp;quot; &amp;quot;\\&amp;quot;;
// define the macro using the new mode syntax
#define FOO(x,y) this is x, and the this is y.
// remove the mode
#mode pop&lt;/pre&gt;


&lt;h4&gt;Third problem&lt;/h4&gt;


&lt;p&gt;Another case which may cause trouble to FDT is the case of multi-line macro definition such as :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define FOO I want to insert a new line \
in the macro&lt;/pre&gt;


&lt;p&gt;GPP's cpp mode define a macro definition as starting with &lt;code&gt;#&lt;/code&gt; and finishing with &lt;code&gt;\n&lt;/code&gt;. So you have to escape the new line character to create a multi-line declaration.
When FDT find a &lt;code&gt;#&lt;/code&gt; character it simply ignore the rest of the line, but it don't understand that escaping the new line char means that the macro definition continue on the next line, so, if the next line don't start with a &lt;code&gt;#&lt;/code&gt; char it'll parse it as normal code, which probably result in errors.&lt;/p&gt;


&lt;p&gt;For that issue I found that XML can be used outside of the class definition, I modified the built-in macro syntax to match that syntax :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;&amp;lt;#define:FOO I want to insert a new line 
in the macro/&amp;gt;&lt;/pre&gt;


&lt;p&gt;The GPP's option to setup meta-macro definition syntax is &lt;code&gt;-M&lt;/code&gt;. To produce that syntax, the option will look like that :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;-M &amp;quot;&amp;lt;#&amp;quot; &amp;quot;/&amp;gt;&amp;quot; &amp;quot;:&amp;quot; &amp;quot;\B&amp;quot; &amp;quot;/&amp;gt;&amp;quot; &amp;quot;&amp;lt;&amp;quot; &amp;quot;/&amp;gt;&amp;quot;&lt;/pre&gt;


&lt;p&gt;However it'll produce many parsing error while starting to nest  macros definition. Take the following example :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define ASIS(x) x
#define SILENT(x) ASIS()
#define ASSERTS(msg) SILENT(
	#ifndef DEBUG
	#define TEMP(x) trace( x + ' at #file
:#line
' )
	#else
	#define TEMP(x)
	#endif
) TEMP(msg)&lt;/pre&gt;


&lt;p&gt;It create a simple macro called ASSERTS witch render a trace call with the file and line appended to the macro argument. The issue here is that we cannot use the XML like syntax because it suppose to nest macros. But as the macro definition is supposed to be ended with a &lt;code&gt;\n&lt;/code&gt; char, it produces many errors in FDT because some lines starts with invalid chars. You can workaround this by using another termination char for the macro definition, such as &lt;code&gt;;&lt;/code&gt; for example.&lt;/p&gt;


&lt;p&gt;With these settings, the previous example look like :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;#define ASIS(x) x;
#define SILENT(x) ASIS();
#define ASSERTS(msg) SILENT(
	#ifndef DEBUG;
	#define TEMP(x) trace( x + ' at #file;:#line;' ); 
	#else;
	#define TEMP(x); 
	#endif; ) TEMP(msg);&lt;/pre&gt;


&lt;p&gt;The fact that the single quote string is not defined allow GPP to parse macro in the string, without having to escape the quote (which result in big mess in the FDT parsing).
And as you can see, you can now inline the part that may produce errors in FDT. And the command line now look like :&lt;/p&gt;

&lt;pre class=&quot;brush: plain&quot;&gt;gpp +n \
-U &amp;quot;[].&amp;quot; &amp;quot;\W&amp;quot; &amp;quot;('&amp;quot; &amp;quot;,&amp;quot; &amp;quot;')&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; &amp;quot;#&amp;quot; &amp;quot;\\&amp;quot; \
	-M &amp;quot;#&amp;quot; &amp;quot;\n&amp;quot; &amp;quot;\B&amp;quot; &amp;quot;\B&amp;quot; &amp;quot;;&amp;quot; &amp;quot;(&amp;quot; &amp;quot;)&amp;quot; \
  	+c &amp;quot;/*&amp;quot; &amp;quot;*/&amp;quot; \
 	+c &amp;quot;//&amp;quot; &amp;quot;\n&amp;quot; \
  	+s &amp;quot;\&amp;quot;&amp;quot; &amp;quot;\&amp;quot;&amp;quot; &amp;quot;\\&amp;quot; \
  	-O &amp;quot;GPPTest.as&amp;quot; \
  	&amp;quot;../src/GPPTest.as&amp;quot;&lt;/pre&gt;


&lt;h4&gt;Conclusion&lt;/h4&gt;


&lt;p&gt;All these tricks works well for the common usage of a preprocessor, but for some advanced GPP's features such as &lt;code&gt;defeval&lt;/code&gt; macro there's still a lot of issues coming from the syntax changes. I'll continue to search how I can fix the issues with &lt;code&gt;defeval&lt;/code&gt;, but I'm not sure there's a way to fix it. So stay tuned :).&lt;/p&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/05/16/GPP-Preprocessing-and-FDT#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/05/16/GPP-Preprocessing-and-FDT#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/169</wfw:commentRss>
      </item>
    
  <item>
    <title>Using PixelBender on Linux with Wine and PBDT</title>
    <link>http://book.abe.free.fr/blog/?post/2009/04/25/Using-PixelBender-on-Linux</link>
    <guid isPermaLink="false">urn:md5:c03089b7088197b77fad2b45f2c02f70</guid>
    <pubDate>Sat, 25 Apr 2009 19:52:00 +0200</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>flash</category><category>linux</category><category>pixel bender</category><category>wine</category>    
    <description>&lt;p&gt;&lt;a href=&quot;http://blog.joa-ebert.com/&quot; hreflang=&quot;en&quot;&gt;Joa Erbert&lt;/a&gt; just release the &lt;a href=&quot;http://blog.joa-ebert.com/2009/04/24/pbdt-release/&quot; hreflang=&quot;en&quot;&gt;PDBT&lt;/a&gt; plugin for &lt;a href=&quot;http://www.eclipse.org/&quot; hreflang=&quot;en&quot;&gt;Eclipse&lt;/a&gt;, and as I was waiting for it since &lt;a href=&quot;http://blog.joa-ebert.com/2009/02/27/pixelbender-development-tool/&quot; hreflang=&quot;en&quot;&gt;its first announcement&lt;/a&gt; I'm happy to propose you a little step by step on how to setup &lt;a href=&quot;http://www.winehq.org/&quot; hreflang=&quot;en&quot;&gt;Wine&lt;/a&gt; properly and use the PDBT plugin with the Pixel Bender Toolkit.&lt;/p&gt;    &lt;h4&gt;Wine and Winetricks&lt;/h4&gt;


&lt;p&gt;Download and install Wine with apt :&lt;/p&gt;
&lt;pre&gt;
sudo apt-get install wine
&lt;/pre&gt;


&lt;p&gt;Get the &lt;a href=&quot;http://wiki.winehq.org/winetricks&quot; hreflang=&quot;en&quot;&gt;winetricks&lt;/a&gt; command file :&lt;/p&gt;
&lt;pre&gt;
wget http://www.kegel.com/wine/winetricks
&lt;/pre&gt;


&lt;p&gt;Then execute these commands, it will greatly simplify the use of winetricks :&lt;/p&gt;
&lt;pre&gt;
chmod +x winetricks
sudo mv winetricks /usr/bin
&lt;/pre&gt;


&lt;h4&gt;Installing Pixel Bender&lt;/h4&gt;

&lt;p&gt;In my humble opinion, trying to install Pixel Bender directly in wine is way too hard and long (as for all the CS3|CS4 stuff), many error occurs and trying to fix all issues is probably not possible. The simpler is to install it on Windows, and then copying the whole &lt;code&gt;Pixel Bender Toolkit&lt;/code&gt; folder into wine (~/.wine/dosdevices/c:/Program\ Files).&lt;/p&gt;


&lt;p&gt;Once the copy done, you can try to run the &lt;code&gt;pbutil.exe&lt;/code&gt; with :&lt;/p&gt;
&lt;pre&gt;
wine ~/.wine/dosdevices/c:/Program\ Files/Pixel\ Bender\ Toolkit/pbutil.exe
&lt;/pre&gt;


&lt;p&gt;If you have any errors such :&lt;/p&gt;
&lt;pre&gt;
fixme:actctx:parse_depend_manifests Could not find dependent assembly L&amp;quot;Microsoft.VC80.CRT&amp;quot;
fixme:actctx:parse_depend_manifests Could not find dependent assembly L&amp;quot;Microsoft.VC80.CRT&amp;quot;
err:module:import_dll Library MSVCP80.dll (which is needed by L&amp;quot;Z:\\media\\disk\\Dev\\tools\\archives\\Pixel Bender Toolkit\\aif_core.dll&amp;quot;) not found
err:module:import_dll Library MSVCR80.dll (which is needed by L&amp;quot;Z:\\media\\disk\\Dev\\tools\\archives\\Pixel Bender Toolkit\\aif_core.dll&amp;quot;) not found
err:module:import_dll Library aif_core.dll (which is needed by L&amp;quot;Z:\\media\\disk\\Dev\\tools\\archives\\Pixel Bender Toolkit\\pbutil.exe&amp;quot;) not found
fixme:actctx:parse_depend_manifests Could not find dependent assembly L&amp;quot;Microsoft.VC80.CRT&amp;quot;
...
&lt;/pre&gt;


&lt;p&gt;That there is some missing dlls, that's where we need to use &lt;code&gt;winetricks&lt;/code&gt;. Report to the &lt;a href=&quot;http://wiki.winehq.org/winetricks&quot; hreflang=&quot;en&quot;&gt;Winetricks page&lt;/a&gt; to find which lib to load to get all the missing dlls.&lt;/p&gt;


&lt;p&gt;In my case (the log above), I needed to execute :&lt;/p&gt;
&lt;pre&gt;
winetricks vcrun2005sp1 vcrun2005
&lt;/pre&gt;

&lt;p&gt;Which installs the MS Visual C++ 2005 libraries (mfc80,msvcp80,msvcr80) into wine.&lt;/p&gt;


&lt;p&gt;When you get :&lt;/p&gt;
&lt;pre&gt;
APPLICATION ERROR: not enough command line arguments! Program usage: pbutil inputFileName outputFileName
&lt;/pre&gt;

&lt;p&gt;It works !!&lt;/p&gt;


&lt;h4&gt;PDBT&lt;/h4&gt;


&lt;p&gt;Once You've install the PDBT plugin into the proper Eclipse install, you need to make sure that PDBT will call &lt;code&gt;pbutil.exe&lt;/code&gt; with Wine. The operation is really simple, create a file named &lt;code&gt;pbutil&lt;/code&gt; in the Pixel Bender Util directory in Wine, make it executable, and write :&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh
wine &amp;quot;$0.exe $@&amp;quot;
&lt;/pre&gt;


&lt;p&gt;That's all, now PDBT will compile &lt;code&gt;.pbj&lt;/code&gt; file each time you save your &lt;code&gt;.pbk&lt;/code&gt; files :).&lt;/p&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/04/25/Using-PixelBender-on-Linux#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/04/25/Using-PixelBender-on-Linux#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/166</wfw:commentRss>
      </item>
    
  <item>
    <title>La bonne blague de Flash</title>
    <link>http://book.abe.free.fr/blog/?post/2009/04/16/La-bonne-blague-de-Flash</link>
    <guid isPermaLink="false">urn:md5:6dcbcac6d20c3ea25686ce42fa022f58</guid>
    <pubDate>Thu, 16 Apr 2009 12:44:00 +0200</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>flash</category><category>jsfl</category><category>script</category>    
    <description>&lt;p&gt;La bonne blague, c'est que si vous importez une image dans la bibliothèque de Flash, que vous placez ce bitmap au sein d'un clip, que vous cochez la case &lt;em&gt;Exporter pour ActionScript&lt;/em&gt;, alors l'image n'est plus une image mais un objet Shape une fois le fichier compilé. Impossible donc d'accéder aux propriétés du bitmap. Si vous souhaitez par exemple activer ou désactiver le lissage, ou le pixel snapping à l'exécution, et ben vous pouvez pas !&lt;/p&gt;    &lt;p&gt;L'explication ? &lt;a href=&quot;http://www.actionscript.org/forums/showthread.php3?t=178142&quot; hreflang=&quot;en&quot;&gt;J'en ai trouvé une ici&lt;/a&gt;, par le toujours très pertinent &lt;a href=&quot;http://www.senocular.com/&quot; hreflang=&quot;en&quot;&gt;Senocular&lt;/a&gt; :&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;Flash consolidates child objects on the timeline by merging all vector shapes and bitmaps in a timeline (that occupy the same frame span). To make this work for bitmaps, they are converted to vector shapes with bitmap fills. But in doing this, many vectors and bitmaps can go from dozens of different objects and children and become just one. Since none of these objects can be dynamically manipulated at runtime (i.e. you cannot associate instance names with them) this consolidation is suitable and efficient.&lt;/p&gt;
&lt;p&gt;
If you want the bitmapData, you'll have to draw the screen with whats there now, or better yet, get the bitmap from the library.&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;&lt;br /&gt;
En résumé, pour éviter que chaque image d'une animation soit encombré de dizaines d'objets, Flash converti tout les bitmaps en formes vectorielles, et utilise un remplissage bitmap pour afficher l'image. L'idée peut paraître séduisante, si ce n'est qu'elle limite grandement l'usage d'images à partir de bibliothèques créées dans Flash.&lt;/p&gt;


&lt;p&gt;On a alors deux solutions possible.
&lt;br /&gt;
Soit on n'a pas besoin d'accéder aux propriétés du bitmap à l'exécution (aussi bien au niveau du BitmapData que de l'objet Bitmap devant le contenir) et auquel cas on peut laisser Flash faire ses optimisations, mais si un lissage est nécessaire sur les images c'est à la personne constituant la bibliothèque de cocher l'option adéquate pour chaque image.
&lt;br /&gt;
L'autre solution, c'est d'exporter pour ActionScript l'image et non pas le clip la contenant, le résultat, c'est que l'image est instanciable en tant que BitmapData.
Le seul souci pour moi, c'est que le constructeur de la classe BitmapData impose de définir les dimensions de l'image, ce qui me pose quelques problèmes car je préfère pouvoir instancier les ressources graphiques à la volée et sans avoir à préciser des arguments (ainsi je peux plus ou moins tout inter-changé à l'exécution).
&lt;br /&gt;
On en reviens donc à la première solution, c'est-à-dire que le graphiste en charge de la bibliothèque dans Flash doit régler correctement les options de chaque image. Hors, l'option &amp;quot;Autoriser le lissage&amp;quot; est toujours décoché par défaut. Du coup, j'ai développé un petit script JSFL pour autoriser le lissage sur tout les bitmaps d'une bibliothèque. Script que voici :&lt;/p&gt;

&lt;pre class=&quot;brush: js&quot;&gt;﻿var lib = fl.getDocumentDOM().library;
// on force la sélection de tout les éléments afin de pouvoir
// traiter la totalité de la bibliothèque d'un coup
lib.selectAll();

var a = lib.items;
for( var i in a )
{
	var asset = a[i];

	if( asset.itemType == &amp;quot;bitmap&amp;quot; )
		asset.allowSmoothing = true;
}&lt;/pre&gt;


&lt;p&gt;Voila, en espérant que ça soit utile à d'autres.&lt;/p&gt;


&lt;p&gt;PS : C'est typiquement le genre de détails qui ne me fait pas du tout regretter mon passage sous Linux et mon abandon de Flash dans mon travail quotidien. Je trouve l'usage des metatag [Embed] beaucoup plus souple que de passer par Flash pour la constitution de bibliothèque.&lt;/p&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/04/16/La-bonne-blague-de-Flash#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/04/16/La-bonne-blague-de-Flash#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/165</wfw:commentRss>
      </item>
    
  <item>
    <title>Teasing</title>
    <link>http://book.abe.free.fr/blog/?post/2009/02/20/Teasing</link>
    <guid isPermaLink="false">urn:md5:e6dd4c72e4f19c976919e73ec2fda290</guid>
    <pubDate>Fri, 20 Feb 2009 12:06:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>aesia</category><category>experiment</category><category>flash</category>    
    <description>&lt;p&gt;A bit of teasing about some works I've done the past months for &lt;a href=&quot;http://aesia.fr&quot; hreflang=&quot;fr&quot;&gt;Aesia&lt;/a&gt;. For the moment the code is far to be clean enough for a public release.
&lt;br /&gt;
You can see in the Log windows the string used to fill the custom text field.&lt;/p&gt;    &lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/AdvancedTextFieldTest.swf&quot; width=&quot;500&quot; height=&quot;700&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/AdvancedTextFieldTest.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/02/20/Teasing#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/02/20/Teasing#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/154</wfw:commentRss>
      </item>
    
  <item>
    <title>Camera &amp; Layers - Part 3 - Rotation</title>
    <link>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-Layers-Part-3-Rotation</link>
    <guid isPermaLink="false">urn:md5:d7ba742d6bbd285b51e67b5a12735aa5</guid>
    <pubDate>Thu, 12 Feb 2009 20:16:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>camera</category><category>flash</category><category>game</category>    
    <description>&lt;p&gt;The third part of the camera &amp;amp; layers series. Now we are going to make the world rotating according to the camera.&lt;/p&gt;    &lt;h4&gt;Rotation&lt;/h4&gt;


&lt;p&gt;That's the most difficult part of the creation of the &lt;code&gt;Camera&lt;/code&gt;, and to achieve that we must use some matrix computations. By the way, the camera rotation can't be used directly with bitmap based renderer (because of the &lt;code&gt;BitmapData.copyPixel&lt;/code&gt; limitations).&lt;/p&gt;


&lt;p&gt;The change in the &lt;code&gt;Camera&lt;/code&gt; class are really small. The only significant changes are the add of getters to access the original (unmodified) width and height and a protected property which will store the camera rotation. Rotation is an angle in radians, in that way there's no need to convert the rotation value each time we will need to operate a transformation onto an object.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;protected var _rotation : Number;&lt;/pre&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function get originalWidth () : Number { return _originalWidth; }
public function get originalHeight () : Number { return _originalHeight; }&lt;/pre&gt;


&lt;p&gt;I also modify the &lt;code&gt;Camera&lt;/code&gt; constructor like this :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function Camera ( screen : Rectangle = null, zoom : Number = 1, rotation : Number = 0, silent : Boolean = false )
{
	_rotation = rotation;
	this.screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
	this.zoom = zoom;
	silentMode = silent;
}&lt;/pre&gt;


&lt;p&gt;I affect the rotation before setting screen and zoom for the reason that rotation don't affect directly the other camera properties. It's a bit weird, because if the rotation is different than 0, the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; properties of the screen will not be accurate. But as the &lt;code&gt;Rectangle&lt;/code&gt; class don't handle rotation, we should use a &lt;code&gt;Polygon&lt;/code&gt; instead, but it should be a heavy change and it doesn't fit well with the performance purpose that games requires.&lt;/p&gt;


&lt;p&gt;I also add accesors for the rotation :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function get rotation () : Number { return _rotation; }
public function set rotation ( n : Number ) : void
{
	_rotation = n;
	fireSilentCameraChange();
}&lt;/pre&gt;


&lt;p&gt;In the same way, I modify the &lt;code&gt;CameraEvent&lt;/code&gt; to add an accessor to the camera rotation :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function get rotation () : Number { return camera.rotation; }&lt;/pre&gt;


&lt;p&gt;Ok, now the big part. To handle the rotation in the layer, we have to change the whole transformation routine. Instead of affecting each value independently we will use a &lt;code&gt;Matrix&lt;/code&gt; object.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function cameraChanged ( e : CameraEvent ) : void
{   	
	// first we store some usefull data for computation
	var m : Matrix = transform.matrix;
	var sc : Point = e.camera.center;
	var csx : Number = e.camera.screen.x;
	var csy : Number = e.camera.screen.y;

	// reset the matrix
	m.identity();

	// translate the matrix corresponding to the scroll and parallax part
	m.translate( -csx * parallax, -csy * parallax );
	
	//  we scale and rotate the matrix according to the center of the camera
	scaleAndRotateAroundExternalPoint( m, 
							sc.x - csx, 
							sc.y - csy,
							-e.rotation, 
							e.zoom,
						  	e.zoom );
	
	// then we translate the camera to return back the transformation center to the stage center
	// it's because of that translation that we need to access the camera's original width and height
	m.translate( csx - sc.x + ( e.camera.originalWidth / 2 ),
			 csy - sc.y + ( e.camera.originalHeight / 2 ) );

	// affect the matrix to this layer
	transform.matrix = m;
}
// that implementation is based on the work of Robert Penner for the fl.motion package in Flash.
public function scaleAndRotateAroundExternalPoint(m:Matrix, x:Number, y:Number, angleRadians:Number, scalex : Number, scaley : Number ):void
{
	m.tx -= x;
	m.ty -= y;
	m.rotate( angleRadians );
	m.scale( scalex, scaley );
	m.tx += x;
	m.ty += y;
}&lt;/pre&gt;


&lt;p&gt;The last change is operated in the demo class to animate the camera rotation&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;camera.rotation = n / 8;&lt;/pre&gt;

&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/CameraTut4.swf&quot; width=&quot;550&quot; height=&quot;200&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/CameraTut4.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;



&lt;h4&gt;Last words&lt;/h4&gt;

&lt;p&gt;As you have probably notice, with the rotation the &lt;code&gt;Rectangle&lt;/code&gt; figuring the screen is no longer a reliable source to know the real screen part. That's due to the fact that the &lt;code&gt;Rectangle&lt;/code&gt; class don't handle rotation natively. As a consequence, the &lt;code&gt;getLocalCameraScreen&lt;/code&gt; is somewhat useless for all case where &lt;code&gt;rotation != 0&lt;/code&gt;. One way to solve these cases is to use a &lt;code&gt;Polygon&lt;/code&gt; object instead of &lt;code&gt;Rectangle&lt;/code&gt; but that require much more matrix computation, each vertex of the polygon have to be rotated each time the camera rotation change. It's will be a bit heavier than without rotation, and if you don't need rotation you should prefer the lighter implementation presented before. In most games there's no need for rotation, that's why I always have an implementation that fit with the context.&lt;/p&gt;


&lt;p&gt;I hope that these posts have been useful for you. And if I get some time in the next months, I'll try to complete them with some funny usages of cameras.&lt;/p&gt;


&lt;h4&gt;Complete code&lt;/h4&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	[Event ( name=&amp;quot;cameraChange&amp;quot;, type=&amp;quot;CameraEvent&amp;quot; )]
	public class Camera extends EventDispatcher
	{
		public var silentMode : Boolean;
		
		protected var _screen : Rectangle;
		protected var _zoom : Number;
		protected var _rotation : Number;
		
		protected var _originalWidth : Number;
		protected var _originalHeight : Number;
		
		public function Camera ( screen : Rectangle = null, zoom : Number = 1, rotation : Number = 0, silent : Boolean = false )
		{
			_rotation = rotation;
			this.screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
			this.zoom = zoom;
			silentMode = silent;
		}
		
		/*---------------------------------------------------------------------
		 * ACCESSORS
		 *--------------------------------------------------------------------*/
		
		public function get x () : Number { return _screen.x; }  
		public function set x ( n : Number ) : void
		{ 
			_screen.x = n;
			fireSilentCameraChange ();
		}
		public function get y () : Number { return _screen.y; }  
		public function set y ( n : Number ) : void
		{ 
			_screen.y = n;
			fireSilentCameraChange ();
		}      
		public function get width () : Number { return _screen.width; }  
		public function set width ( n : Number ) : void
		{ 
			_screen.width = n;
			fireSilentCameraChange ();
		}
		public function get height () : Number { return _screen.height; }  
		public function set height ( n : Number ) : void
		{ 
			_screen.height = n;
			fireSilentCameraChange ();
		} 
		
		public function get originalWidth () : Number { return _originalWidth; }
		public function get originalHeight () : Number { return _originalHeight; }
		
		public function get rotation () : Number { return _rotation; }
		public function set rotation ( n : Number ) : void
		{
			_rotation = n;
			fireSilentCameraChange();
		}
		   
		public function get center () : Point	
		{ 
			return new Point( _screen.x + _screen.width / 2, 
							  _screen.y + _screen.height / 2 ); 
		}
		public function set center ( p : Point ) : void
		{
			_screen.x = p.x - ( _screen.width / 2 );
			_screen.y = p.y - ( _screen.height / 2 );
			fireSilentCameraChange ();
		}
		public function get centerX () : Number { return center.x; }  
		public function set centerX ( n : Number ) : void
		{ 
			center = new Point( n, center.y );
			fireSilentCameraChange ();
		}
		public function get centerY () : Number { return center.y; }  
		public function set centerY ( n : Number ) : void
		{ 
			center = new Point( center.x, n );
			fireSilentCameraChange ();
		}    
		public function get screen () : Rectangle { return _screen.clone(); }
		public function set screen ( screen : Rectangle ) : void
		{
			_screen = screen;
			_originalWidth = screen.width;
			_originalHeight = screen.height;
			fireSilentCameraChange ();
		}
		public function get zoom () : Number { return _zoom; }
		public function set zoom ( n : Number ) : void
		{
		    _zoom = n;
		
		    // save the actual screen center
		    var c : Point = center;
		        
		    _screen.width = _originalWidth / _zoom;
		    _screen.height = _originalHeight / _zoom;
		
		    center = c;
		}
		
		/*---------------------------------------------------------------------
		 * PUBLIC MISC
		 *--------------------------------------------------------------------*/
		public function centerDisplayObject ( display : DisplayObject ) : void
		{
			var r : Rectangle = display.getBounds( display.parent );
			var x : Number = r.x + r.width / 2;
			var y : Number = r.y + r.height / 2;
			
			center = new Point( x, y );
		}	
		public function addCameraChangeListener ( closure : Function ) : void
		{
			addEventListener( CameraEvent.CAMERA_CHANGE, closure );
		}
		public function removeCameraChangeListener ( closure : Function ) : void
		{
			removeEventListener( CameraEvent.CAMERA_CHANGE, closure );
		} 
		public function fireCameraChange () : void
		{
			if( hasEventListener( CameraEvent.CAMERA_CHANGE ) )
		    	dispatchEvent( new CameraEvent( CameraEvent.CAMERA_CHANGE, this ) ); 
		}
		
		/*---------------------------------------------------------------------
		 * PROTECTED MEMBERS
		 *--------------------------------------------------------------------*/
		
		protected function fireSilentCameraChange () : void
		{
			if( !silentMode )
				fireCameraChange();
		}
	}
}&lt;/pre&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package 
{
	import flash.display.Sprite;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class CameraLayer extends Sprite
	{
	    public var parallax : Number;
	  
	    public function CameraLayer ( parallax : Number = 1 )
	    {
	         this.parallax = parallax;
	    }
	     
		public function cameraChanged ( e : CameraEvent ) : void
		{
			// first we store some usefull data for computation
			var m : Matrix = transform.matrix;
			var sc : Point = e.camera.center;
			var csx : Number = e.camera.screen.x;
			var csy : Number = e.camera.screen.y;
			
			// reset the matrix
			m.identity();
			
			// translate the matrix corresponding to the scroll and parallax part
			m.translate( -csx * parallax, -csy * parallax );
			
			//  we scale and rotate the matrix according to the center of the camera
			scaleAndRotateAroundExternalPoint( m, 
											 sc.x - csx, 
											 sc.y - csy,
											  -e.rotation, 
											   e.zoom,
									  		   e.zoom );
			
			// then we translate the camera to return back the transformation center to the stage center
			// it's because of that translation that we need to access the camera's original width and height
			m.translate( csx - sc.x + ( e.camera.originalWidth / 2 ),
						 csy - sc.y + ( e.camera.originalHeight / 2 ) );
			
			// affect the matrix to this layer
			transform.matrix = m;
		}
		// that implementation is based on the work of Robert Penner for the fl.motion package in Flash.
		public function scaleAndRotateAroundExternalPoint(m:Matrix, x:Number, y:Number, angleRadians:Number, scalex : Number, scaley : Number ):void
		{
			m.tx -= x;
			m.ty -= y;
			m.rotate( angleRadians );
			m.scale( scalex, scaley );
			m.tx += x;
			m.ty += y;
		}
	    
		public function getLocalCameraScreen ( c : Camera ) : Rectangle
		{
			return new Rectangle( c.x * parallax,
								  c.y * parallax, 
								  c.width, 
								  c.height);
		}
	}
}&lt;/pre&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package
{
	public class CameraEvent extends Event
	{
		static public const CAMERA_CHANGE : String = &amp;quot;cameraChange&amp;quot;;
		
		public var camera : Camera;
	
		public function CameraEvent ( type : String, 
								camera : Camera, 
								bubbles : Boolean = false, 
								cancelable : Boolean = false )
		{
			super( type, bubbles, cancelable );
			this.camera = camera;
		}
		public function get screen () : Rectangle { return camera.screen; }
		public function get zoom () : Number { return camera.zoom; }
		public function get rotation () : Number { return camera.rotation; }
	}
}&lt;/pre&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-Layers-Part-3-Rotation#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-Layers-Part-3-Rotation#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/152</wfw:commentRss>
      </item>
    
  <item>
    <title>Camera &amp; Layers - Part 2 - Zoom</title>
    <link>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-and-Layers-Part-2-Zoom</link>
    <guid isPermaLink="false">urn:md5:2bc96212086b583a611bd252b8866eff</guid>
    <pubDate>Mon, 02 Feb 2009 20:45:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>camera</category><category>flash</category><category>game</category>    
    <description>&lt;p&gt;The second post in the camera &amp;amp; layers series. In this post we will look at implementing the zoom in the previously created &lt;code&gt;Camera&lt;/code&gt; and &lt;code&gt;CameraLayer&lt;/code&gt; classes.&lt;/p&gt;    &lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2&gt;Zoom&lt;/h2&gt;


&lt;p&gt;As I previously say, the &lt;code&gt;screen&lt;/code&gt; rectangle in &lt;code&gt;Camera&lt;/code&gt; represent the part of the stage that should be on the screen. So, to implements zoom in our camera, we should consider these two assumptions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The size of the rectangle must grow or reduce according to the zoom factor.&lt;/li&gt;
&lt;li&gt;The zoom will be performed on the middle of the screen. So the screen rectangle position will change according.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all, we need to change our &lt;code&gt;Camera&lt;/code&gt; class to implements zoom. As the &lt;code&gt;Rectangle&lt;/code&gt; instance, figuring the screen, have to be resized we have to store the original width and height of the camera each time a new screen rectangle is defined for the camera. So we add some protected properties in the class body.&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;protected var _zoom : Number;
protected var _minZoom : Number;
protected var _maxZoom : Number;

protected var _originalWidth : Number;
protected var _originalHeight : Number;&lt;/pre&gt;


&lt;p&gt;Then, in the &lt;code&gt;screen&lt;/code&gt; setter, the width and height of the rectangle are stored.&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;public function set screen ( r : Rectangle ) : void
{
    _screen = r;
    _originalWidth = r.width;
    _originalHeight = r.height;
    fireSilentCameraChange ();
}&lt;/pre&gt;


&lt;p&gt;We need accessors for the zoom stuff :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;public function get zoom () : Number { return _zoom; }
public function set zoom ( n : Number ) : void
{
    // restrict the zoom value into the boundary
    _zoom = Math.max( _minZoom, Math.min( _maxZoom, n ) );

    // save the actual screen center
    var c : Point = center;
        
    _screen.width = _originalWidth / _zoom;
    _screen.height = _originalHeight / _zoom;
    
    // relocate and fire event
    center = c;
}
public function get minZoom () : Number { return _minZoom; }
public function set minZoom ( n : Number ) : void
{
    _minZoom = n;
    // force to check boundary and update
    zoom = zoom;
}
public function get maxZoom () : Number { return _maxZoom; }
public function set maxZoom ( n : Number ) : void
{
    _maxZoom = n;
    // force to check boundary and update
    zoom = zoom;
}&lt;/pre&gt;


&lt;p&gt;And to initialize the new stuff, I add some arguments to the &lt;code&gt;Camera&lt;/code&gt; constructor, call the &lt;code&gt;screen&lt;/code&gt; and &lt;code&gt;zoom&lt;/code&gt; setters (by calling &lt;code&gt;this.screen&lt;/code&gt; we also initialize the original dimension for the screen).&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;public function Camera ( screen : Rectangle = null, 
								zoom : Number = 1, 
								minZoom : Number = 0.1, 
								maxZoom : Number = 2, 
								silent : Boolean = false )
{
	this._minZoom = minZoom;
	this._maxZoom = maxZoom;
	this.screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
	this.zoom = zoom;
	silentMode = silent;
}&lt;/pre&gt;


&lt;p&gt;In the &lt;code&gt;CameraEvent&lt;/code&gt; class we add a getter for the zoom :&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;public function get zoom () : Number { return camera.zoom; }&lt;/pre&gt;


&lt;p&gt;In the &lt;code&gt;CameraLayer&lt;/code&gt; class we modify the &lt;code&gt;cameraChange&lt;/code&gt; function :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;public function cameraChange ( e : CameraEvent ) : void
{
     // use the parallax and camera zoom to multiply the screen coords
    x = -e.screen.x * e.zoom * parallax;
    y = -e.screen.y * e.zoom * parallax;
    // scale is equal to zoom
    scaleY = scaleX = e.zoom;
}&lt;/pre&gt;


&lt;p&gt;And last but not least, in the &lt;code&gt;enterFrame&lt;/code&gt; function of our sample demo, add :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;// make the zoom vary between 0.5 and 1.5
camera.zoom = 1 + Math.sin( n/4 )*.5;&lt;/pre&gt;


&lt;p&gt;As the on screen size of the layers will change due to the zoom change, I adapt th &lt;code&gt;fillLayer&lt;/code&gt; function to always dots all over the screen :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;s.x = Math.random() * 2200;
s.y = -100 + Math.random() * 400;&lt;/pre&gt;


&lt;p&gt;Instead of :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;s.x = Math.random() * 1100;
s.y = Math.random() * 200;&lt;/pre&gt;


&lt;p&gt;Run the demo and look :&lt;/p&gt;

&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/CameraTut3.swf&quot; width=&quot;550&quot; height=&quot;200&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/CameraTut3.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;



&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


&lt;h3&gt;Special cases&lt;/h3&gt;

&lt;h4&gt;Zoom &amp;amp; Parallax at the same time&lt;/h4&gt;

&lt;p&gt;Combining zoom and parallax together don't produce a perspective effect, there's no focal or no depth value at all. Of course, you can obtain it by implementing these features in your camera.&lt;/p&gt;


&lt;h4&gt;Zoom &amp;amp; BitBlit-based renderer&lt;/h4&gt;

&lt;p&gt;As &lt;code&gt;BitmapData.copyPixel&lt;/code&gt; don't support scale or rotation, You can't use zoom directly. There's, as far as I know, two solutions to this issue :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You use the &lt;code&gt;BitmapData.draw&lt;/code&gt; method instead, and create a &lt;code&gt;Matrix&lt;/code&gt; instance to provide to the function. It's important to notice that using the &lt;code&gt;draw&lt;/code&gt; method don't offer as much performance as using &lt;code&gt;copyPixel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You create the &lt;code&gt;Bitmap&lt;/code&gt;, onto which your renderer will draw, bigger than the screen size. Then you can use the &lt;code&gt;zoom&lt;/code&gt; factor to resize that bitmap, and at the same time, you change the size of the redrawn part of that bitmap in your renderer. The size of the &lt;code&gt;BitmapData&lt;/code&gt;, in that case, should be &lt;code&gt;width / minZoom&lt;/code&gt; and &lt;code&gt;height / minZoom&lt;/code&gt; (according to &lt;code&gt;BitmapData&lt;/code&gt; size limitations).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Complete &lt;code&gt;Camera&lt;/code&gt; class&lt;/h5&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;package
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	[Event ( name=&amp;quot;cameraChange&amp;quot;, type=&amp;quot;flash.events.Event&amp;quot; )]
	public class Camera extends EventDispatcher
	{
	    public var silentMode : Boolean;
		
		protected var _screen : Rectangle;
		protected var _zoom : Number;
		protected var _minZoom : Number;
		protected var _maxZoom : Number;
		
		protected var _originalWidth : Number;
		protected var _originalHeight : Number;
		
		public function Camera ( screen : Rectangle = null,
										zoom : Number = 1, 
										minZoom : Number = 0.1, 
										maxZoom : Number = 2, 
										silent : Boolean = false )
		{
			this._minZoom = minZoom;
			this._maxZoom = maxZoom;
			this.screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
			this.zoom = zoom;
			silentMode = silent;
		}
		
		/*---------------------------------------------------------------------
		 * ACCESSORS
		 *--------------------------------------------------------------------*/
		
		public function get x () : Number { return _screen.x; }  
		public function set x ( n : Number ) : void
		{ 
			_screen.x = n;
			fireSilentCameraChange ();
		}
		public function get y () : Number { return _screen.y; }  
		public function set y ( n : Number ) : void
		{ 
			_screen.y = n;
			fireSilentCameraChange ();
		}      
		public function get width () : Number { return _screen.width; }  
		public function set width ( n : Number ) : void
		{ 
			_screen.width = n;
			fireSilentCameraChange ();
		}
		public function get height () : Number { return _screen.height; }  
		public function set height ( n : Number ) : void
		{ 
			_screen.height = n;
			fireSilentCameraChange ();
		}    
		public function get center () : Point	
		{ 
			return new Point( _screen.x + _screen.width / 2, 
							  _screen.y + _screen.height / 2 ); 
		}
		public function set center ( p : Point ) : void
		{
			_screen.x = p.x - ( _screen.width / 2 );
			_screen.y = p.y - ( _screen.height / 2 );
			fireSilentCameraChange ();
		}
		public function get centerX () : Number { return center.x; }  
		public function set centerX ( n : Number ) : void
		{ 
			center = new Point( n, center.y );
			fireSilentCameraChange ();
		}
		public function get centerY () : Number { return center.y; }  
		public function set centerY ( n : Number ) : void
		{ 
			center = new Point( center.x, n );
			fireSilentCameraChange ();
		}    
		public function get screen () : Rectangle { return _screen.clone(); }
		public function set screen ( screen : Rectangle ) : void
		{
			_screen = screen;
			_originalWidth = screen.width;
			_originalHeight = screen.height;
			fireSilentCameraChange ();
		}
		public function get zoom () : Number { return _zoom; }
		public function set zoom ( n : Number ) : void
		{
			// restrict the zoom value into the boundary
			_zoom = Math.max( _minZoom, Math.min( _maxZoom, n ) );
		
			// save the actual screen center
			var c : Point = center;
		        
			_screen.width = _originalWidth / _zoom;
			_screen.height = _originalHeight / _zoom;
		
			// relocate and fire event
			center = c;
		}
		public function get minZoom () : Number { return _minZoom; }
		public function set minZoom ( n : Number ) : void
		{
			_minZoom = n;
			// force to check boundary and update
			zoom = zoom;
		}
		public function get maxZoom () : Number { return _maxZoom; }
		public function set maxZoom ( n : Number ) : void
		{
			_maxZoom = n;
			// force to check boundary and update
			zoom = zoom;
		}
		
		/*---------------------------------------------------------------------
		 * PUBLIC MISC
		 *--------------------------------------------------------------------*/
		public function centerDisplayObject ( display : DisplayObject ) : void
		{
			var r : Rectangle = display.getBounds( display.parent );
			var x : Number = r.x + r.width / 2;
			var y : Number = r.y + r.height / 2;
			
			center = new Point( x, y );
		}	
		public function addCameraChangeListener ( closure : Function ) : void
		{
			addEventListener( CameraEvent.CAMERA_CHANGE, closure );
		}
		public function removeCameraChangeListener ( closure : Function ) : void
		{
			removeEventListener( CameraEvent.CAMERA_CHANGE, closure );
		} 
		public function fireCameraChange () : void
		{
			if( hasEventListener( CameraEvent.CAMERA_CHANGE ) )
				dispatchEvent( new CameraEvent( CameraEvent.CAMERA_CHANGE, this ) ); 
		}
		
		/*---------------------------------------------------------------------
		 * PROTECTED MEMBERS
		 *--------------------------------------------------------------------*/
		
		protected function fireSilentCameraChange () : void
		{
			if( !silentMode )
				fireCameraChange();
		}
	}

}&lt;/pre&gt;


&lt;h5&gt;Complete &lt;code&gt;CameraEvent&lt;/code&gt; class&lt;/h5&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;package
{
	import flash.events.Event;
	import flash.geom.Rectangle;

	public class CameraEvent extends Event
	{
		static public const CAMERA_CHANGE : String = &amp;quot;cameraChange&amp;quot;;
		
		public var camera : Camera;
	
		public function CameraEvent ( type : String, 
									  camera : Camera, 
									  bubbles : Boolean = false, 
									  cancelable : Boolean = false )
		{
			super( type, bubbles, cancelable );
			this.camera = camera;
		}
		public function get screen () : Rectangle { return camera.screen; }
		public function get zoom () : Number { return camera.zoom; }
	}
}&lt;/pre&gt;


&lt;h5&gt;Complete &lt;code&gt;CameraLayer&lt;/code&gt; class&lt;/h5&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;package
{
	import flash.display.Sprite;
	import flash.geom.Rectangle;

	public class CameraLayer extends Sprite
	{
		public var parallax : Number;
	  
		public function CameraLayer ( parallax : Number = 1 )
		{
			this.parallax = parallax;
		}
	     
		public function cameraChange ( e : CameraEvent ) : void
		{
			// use the parallax to multiply the screen coords
			x = -e.screen.x * e.zoom * parallax;
			y = -e.screen.y * e.zoom * parallax;
			// scale is equal to zoom
			scaleY = scaleX = e.zoom;
		}
	    
		public function getLocalCameraScreen ( c : Camera ) : Rectangle
		{
			return new Rectangle( c.x * parallax,
								  c.y * parallax, 
								  c.width, 
								  c.height);
		}
	}
}&lt;/pre&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-and-Layers-Part-2-Zoom#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/01/27/Camera-and-Layers-Part-2-Zoom#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/151</wfw:commentRss>
      </item>
    
  <item>
    <title>Camera &amp; Layers - Part 1 - Scrolling and Parallax</title>
    <link>http://book.abe.free.fr/blog/?post/2009/01/25/Camera-and-Layers-Part-1-Scroll-and-Parallax</link>
    <guid isPermaLink="false">urn:md5:6591e031263ce8e44ebb292d0c68179a</guid>
    <pubDate>Fri, 30 Jan 2009 19:51:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>camera</category><category>flash</category><category>game</category>    
    <description>&lt;p&gt;There's the first post of a series about some concepts I learn during the last six years, since I started to learn programming.&lt;/p&gt;


&lt;p&gt;As I don't really know how to introduce it, I will do it briefly. The first topic of that series will be about camera and layers. These objects are one of those I use everyday, in almost every game project.&lt;/p&gt;    &lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;
Many game types require, in their engine, features such scrolling, parallax and objects buffering. These features are, in many games, an important part of the engine, such as in tile based game, shoot them up, platform games, etc...&lt;/p&gt;


&lt;p&gt;In the first engine I wrote, I built these features independently, without thinking about how I can manage all that stuff in a simple and unique way, stupid isn't it ? Resulting that these engines was really hard to maintain (that's rather obvious...). Scrolling was achieved by moving the main stage &lt;code&gt;MovieClip&lt;/code&gt; accordingly to the moves of the first player character. Then, when it comes to add some parallax layer in the background I have to keep a reference to the first player character in each of these layers. And concerning objects buffering, pfff... It was really a mess... I prefer not to talk about it ^^'. Of course all the code I wrote for a game was too dependent of the game elements, so I rewrote that part in each new game.&lt;/p&gt;


&lt;p&gt;It's at that time I started to think about a way to handle all that stuff with a single object : a &lt;code&gt;Camera&lt;/code&gt;. Those who are familiar with 3D world always manipulate cameras, but in the 2D world that's not a widely adopted practice. And it's not a game specific tool, a camera is really usefull when creating application. For exemple, with that camera, creating an application with a main canvas, with common controls like pan, zoom or canvas rotation (such as those we can see in software such &lt;a href=&quot;http://apps.corel.com/painterx&quot; hreflang=&quot;en&quot;&gt;Painter&lt;/a&gt; or &lt;a href=&quot;http://www.artrage.com/&quot; hreflang=&quot;en&quot;&gt;ArtRage&lt;/a&gt;), is pretty fast. So I think everybody should benefit of using that kind of stuff.&lt;/p&gt;


&lt;h3&gt;Camera Basis&lt;/h3&gt;


&lt;p&gt;Basically, a camera can be represented as a &lt;code&gt;Rectangle&lt;/code&gt; object. That rectangle figure the screen, or, more precisely, the part of the stage that should be on the screen. Of course, our camera must notify all layers (or any other kind of camera listeners) attached to it to change their state when camera state have changed. So the &lt;code&gt;Camera&lt;/code&gt; class will extends &lt;code&gt;EventDispatcher&lt;/code&gt;. I don't want to have an object with too much dependencies with the render, that's why the camera system will be event-based.&lt;/p&gt;


&lt;p&gt;I will not talk at this time of all the methods the &lt;code&gt;Camera&lt;/code&gt; class should implements, so I start with a really poor implementation of the &lt;code&gt;Camera&lt;/code&gt; class. You can find a more usable version at the end of this page.&lt;/p&gt;

&lt;pre class=&quot;brush: as3&quot;&gt;package 
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Rectangle;

    [Event ( name=&amp;quot;cameraChange&amp;quot;, type=&amp;quot;flash.events.Event&amp;quot; )]
    public class Camera extends EventDispatcher
    {
        // screen is public for the moment, faster to write and to test
        public var screen : Rectangle;

        public function Camera ( screen : Rectangle = null )
        {
            this.screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
        }
        public function fireCameraChange () : void
        {
            dispatchEvent( new Event ( &amp;quot;cameraChange&amp;quot; ) ); 
        }
    }
}&lt;/pre&gt;


&lt;p&gt;Ok, now we have the base for our &lt;code&gt;Camera&lt;/code&gt; class, I'll return on that later in order to make it more user-friendly. For the moment, let's talk about layers.&lt;/p&gt;


&lt;p&gt;A layer, in this context, is just a &lt;code&gt;DisplayObject&lt;/code&gt; which move according to the camera it listen to. A layer always move in the inverse direction of the camera, so, when camera screen is at coordinates &lt;code&gt;x=500&lt;/code&gt; and &lt;code&gt;y=500&lt;/code&gt;, the layer coordinates will be &lt;code&gt;x=-500&lt;/code&gt; and &lt;code&gt;y=-500&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package 
{
    import flash.events.Event;
    
    public class CameraLayer extends Sprite
    {
        public function CameraLayer ()
        {}
         
        public function cameraChanged ( e : Event ) : void
        {
             var camera : Camera = e.target as Camera;

             x = -camera.screen.x;
             y = -camera.screen.y;
        }
    }
}&lt;/pre&gt;


&lt;p&gt;It's as simple as that :). Now you can fill the layer with whatever object you want, and after having register the layer to the &lt;code&gt;cameraChange&lt;/code&gt; event of the camera, the layer will move accordingly to the camera moves.&lt;/p&gt;


&lt;p&gt;Below a sample code of demo :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;		

	[SWF(width=&amp;quot;550&amp;quot;, height=&amp;quot;200&amp;quot;)]
	public class CameraTut1 extends Sprite 
	{
		private var camera : Camera;
		private var layer : CameraLayer;	

		public function CameraTut1 ()
		{
			camera = new Camera( new Rectangle( 0, 0, 550, 200 ) );
			layer = new CameraLayer();
			
			camera.addEventListener( &amp;quot;cameraChange&amp;quot; , layer.cameraChanged );
			
			fillLayer();
			addChild( layer );
			
			addEventListener( Event.ENTER_FRAME, enterFrame );
		}
		// used to move the cam
		private var n:Number = 0;
		private function enterFrame ( e : Event ) : void
		{
			// move the camera and make it loop back to origin
			camera.screen.x = 225 + Math.sin( n ) * 225;
			camera.fireCameraChange();
			
			n += 0.05;
		}
		private function fillLayer () : void
		{
			var l : Number = 100;
			
			while (l--)
			{
				var s : Shape = new Shape();
				s.graphics.beginFill(0);
				s.graphics.drawCircle(0, 0, 5 + Math.random() * 5);
				s.graphics.endFill();
				
				s.x = Math.random() * 1100;
				s.y = Math.random() * 200;
				
				layer.addChild( s );
			}
		}
	}
}&lt;/pre&gt;


&lt;p&gt;And the result (the swf was compiled with the latest &lt;a href=&quot;http://www.adobe.com/products/flex/flexdownloads/index.html&quot; hreflang=&quot;en&quot;&gt;Flex SDK&lt;/a&gt;, and targeted to &lt;a href=&quot;http://get.adobe.com/fr/flashplayer/&quot; hreflang=&quot;fr&quot;&gt;Flash Player 10&lt;/a&gt;) :&lt;/p&gt;

&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/CameraTut1.swf&quot; width=&quot;550&quot; height=&quot;200&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/CameraTut1.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;



&lt;p&gt;As you can see, the scroll works :).&lt;/p&gt;


&lt;h3&gt;Parallax&lt;/h3&gt;


&lt;p&gt;Parallax&lt;sup&gt;[&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2009/01/25/#pnote-150-1&quot; id=&quot;rev-pnote-150-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; is pretty simple to implements. We just need to add a property to the &lt;code&gt;CameraLayer&lt;/code&gt; class and use it as a factor on camera screen coordinates.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package 
{
    import flash.events.Event;
    
    public class CameraLayer extends Sprite
    {
        public var parallax : Number;
      
        public function CameraLayer ( parallax : Number = 1 )
        {
             this.parallax = parallax
        }
         
        public function cameraChanged ( e : Event ) : void
        {
             var camera : Camera = e.target as Camera;

             // use the parallax to multiply the screen coords
             x = -camera.screen.x * parallax;
             y = -camera.screen.y * parallax;
        }
    }
}&lt;/pre&gt;


&lt;p&gt;And now, let's create a new layer in our demo :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;	

	[SWF(width=&amp;quot;550&amp;quot;, height=&amp;quot;200&amp;quot;)]
	public class CameraTut2 extends Sprite 
	{
		private var camera : Camera;
		private var layer1 : CameraLayer;	
		private var layer2 : CameraLayer;	

		public function CameraTut2 ()
		{
			camera = new Camera( new Rectangle( 0, 0, 550, 200 ) );
			layer1 = new CameraLayer(.5);
			layer2 = new CameraLayer();
			
			camera.addEventListener( &amp;quot;cameraChange&amp;quot; , layer1.cameraChanged );
			camera.addEventListener( &amp;quot;cameraChange&amp;quot; , layer2.cameraChanged );
			
			fillLayer( layer1 );
			fillLayer( layer2 );
			
			layer1.alpha = .3;
						
			addChild( layer1 );
			addChild( layer2 );
			
			addEventListener( Event.ENTER_FRAME, enterFrame );
		}
		// used to move the cam
		private var n:Number = 0;
		private function enterFrame ( e : Event ) : void
		{
			// move the camera and make it loop back to origin
			camera.screen.x = 225 + Math.sin( n ) * 225;
			camera.fireCameraChange();
			
			n += 0.05;
		}
		private function fillLayer ( layer : CameraLayer ) : void
		{
			var l : Number = 100;
			
			while (l--)
			{
				var s : Shape = new Shape();
				s.graphics.beginFill(0);
				s.graphics.drawCircle(0, 0, 5 + Math.random() * 5);
				s.graphics.endFill();
				
				s.x = Math.random() * 1100;
				s.y = Math.random() * 200;
				
				layer.addChild( s );
			}
		}
	}
}&lt;/pre&gt;


&lt;p&gt;As you can see, the &lt;code&gt;layer1&lt;/code&gt; object is moving two times slower than the &lt;code&gt;layer2&lt;/code&gt; :&lt;/p&gt;

&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/CameraTut1.2.swf&quot; width=&quot;550&quot; height=&quot;200&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/CameraTut1.2.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;



&lt;h3&gt;A bit of refactoring&lt;/h3&gt;


&lt;p&gt;It's to clean up things and improve the usability of the &lt;code&gt;Camera&lt;/code&gt; class.&lt;/p&gt;


&lt;p&gt;The first things I'll do is to create a custom event class, named &lt;code&gt;CameraEvent&lt;/code&gt;, which store the camera's events names and provide some shortcuts to camera's properties.
I create the event first in that way I can made all the &lt;code&gt;Camera&lt;/code&gt; and &lt;code&gt;CameraLayer&lt;/code&gt; refactoring in a single step.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package
{
	public class CameraEvent extends Event
	{
		static public const CAMERA_CHANGE : String = &amp;quot;cameraChange&amp;quot;;
		
		public var camera : Camera;
	
		public function CameraEvent ( type : String, 
									  camera : Camera, 
									  bubbles : Boolean = false, 
									  cancelable : Boolean = false )
		{
			super( type, bubbles, cancelable );
			this.camera = camera;
		}
		public function get screen () : Rectangle { return camera.screen; }
	}
}&lt;/pre&gt;


&lt;p&gt;Now let's start &lt;code&gt;Camera&lt;/code&gt; refactoring. Below the list of changes operated :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dispatch a &lt;code&gt;CameraEvent&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Created some accessors on the &lt;code&gt;Camera&lt;/code&gt; class to access screen's properties.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;addCameraChangeListener&lt;/code&gt; and&lt;code&gt;removeCameraChangeListener&lt;/code&gt; functions which register or unregister the passed-in closure for listening to the &lt;code&gt;CameraEvent.CAMERA_CHANGE&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;centerDisplayObject&lt;/code&gt; method which center the camera on the passed-in &lt;code&gt;DisplayObject&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also created an handy &lt;code&gt;silentMode&lt;/code&gt; for the camera. The silent mode disable the dispatch of the &lt;code&gt;cameraChange&lt;/code&gt; event when modifying a property. Then, in a game routine, you can perform a lot of camera operations before dispatching a unique event to update the whole scene. The check for the silent mode is done in the &lt;code&gt;fireSilentCameraChange&lt;/code&gt; method. All setters use that method instead of &lt;code&gt;fireCameraChange&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	[Event ( name=&amp;quot;cameraChange&amp;quot;, type=&amp;quot;CameraEvent&amp;quot; )]
	public class Camera extends EventDispatcher
	{
		public var silentMode : Boolean;
		
		protected var _screen : Rectangle;
		
		public function Camera ( screen : Rectangle = null, silent : Boolean = false )
		{
			this._screen = screen ? screen : new Rectangle ( 0, 0, 550, 400 );
			silentMode = silent;
		}
		
		/*---------------------------------------------------------------------
		 * ACCESSORS
		 *--------------------------------------------------------------------*/
		
		public function get x () : Number { return _screen.x; }  
		public function set x ( n : Number ) : void
		{ 
			_screen.x = n;
			fireSilentCameraChange ();
		}
		public function get y () : Number { return _screen.y; }  
		public function set y ( n : Number ) : void
		{ 
			_screen.y = n;
			fireSilentCameraChange ();
		}      
		public function get width () : Number { return _screen.width; }  
		public function set width ( n : Number ) : void
		{ 
			_screen.width = n;
			fireSilentCameraChange ();
		}
		public function get height () : Number { return _screen.height; }  
		public function set height ( n : Number ) : void
		{ 
			_screen.height = n;
			fireSilentCameraChange ();
		}    
		public function get center () : Point	
		{ 
			return new Point( _screen.x + _screen.width / 2, 
						  _screen.y + _screen.height / 2 ); 
		}
		public function set center ( p : Point ) : void
		{
			_screen.x = p.x - ( _screen.width / 2 );
			_screen.y = p.y - ( _screen.height / 2 );
			fireSilentCameraChange ();
		}
		public function get centerX () : Number { return center.x; }  
		public function set centerX ( n : Number ) : void
		{ 
			center = new Point( n, center.y );
			fireSilentCameraChange ();
		}
		public function get centerY () : Number { return center.y; }  
		public function set centerY ( n : Number ) : void
		{ 
			center = new Point( center.x, n );
			fireSilentCameraChange ();
		}
		public function get screen () : Rectangle { return _screen.clone(); }
		public function set screen ( screen : Rectangle ) : void
		{
			_screen = screen;
			fireSilentCameraChange ();
		}
		
		/*---------------------------------------------------------------------
		 * PUBLIC MISC
		 *--------------------------------------------------------------------*/
		
		public function centerDisplayObject ( display : DisplayObject ) : void
		{
			var r : Rectangle = display.getBounds( display.parent );
			var x : Number = r.x + r.width / 2;
			var y : Number = r.y + r.height / 2;
			
			center = new Point( x, y );
		}
		public function addCameraChangeListener ( closure : Function ) : void
		{
			addEventListener( CameraEvent.CAMERA_CHANGE, closure );
		} 
		public function removeCameraChangeListener ( closure : Function ) : void
		{
			removeEventListener( CameraEvent.CAMERA_CHANGE, closure );
		}
		public function fireCameraChange () : void
		{
			if( hasEventListener( CameraEvent.CAMERA_CHANGE ) )
				dispatchEvent( new CameraEvent( CameraEvent.CAMERA_CHANGE, this ) ); 
		}
		
		/*---------------------------------------------------------------------
		 * PROTECTED MEMBERS
		 *--------------------------------------------------------------------*/
		
		protected function fireSilentCameraChange () : void
		{
			if( !silentMode )
				fireCameraChange();
		}
	}
}&lt;/pre&gt;


&lt;p&gt;And now, it's the &lt;code&gt;CameraLayer&lt;/code&gt; turn. There's just two changes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;cameraChange&lt;/code&gt; method take a &lt;code&gt;CameraEvent&lt;/code&gt; instance as argument. The layer placement is done using the event shortcuts.&lt;/li&gt;
&lt;li&gt;I added a &lt;code&gt;getLocalCameraScreen&lt;/code&gt; method which return a &lt;code&gt;Rectangle&lt;/code&gt; instance corresponding to the camera screen in the layer coordinates system.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;brush: as&quot;&gt;package
{
	import flash.geom.Rectangle;

	public class CameraLayer extends Sprite
	{
		public var parallax : Number;
		  
		public function CameraLayer ( parallax : Number = 1 )
		{
			this.parallax = parallax;
		}
		     
		public function cameraChanged ( e : CameraEvent ) : void
		{
			// use the parallax to multiply the screen coords
			x = -e.screen.x * parallax;
			y = -e.screen.y * parallax;
		}
		
		public function getLocalCameraScreen ( c : Camera ) : Rectangle
		{
			return new Rectangle( c.x * parallax,
							 c.y * parallax, 
							 c.width, 
							 c.height);
		}
	}
}&lt;/pre&gt;


&lt;p&gt;As conclusion, below the last version of the demo code.&lt;/p&gt;


&lt;p&gt;Drag the stage to move the camera.&lt;/p&gt;

&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://book.abe.free.fr/blog/public/CameraTut2.swf&quot; width=&quot;550&quot; height=&quot;200&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://book.abe.free.fr/blog/public/CameraTut2.swf&quot; /&gt;
It seems that you haven't a Flash Player installed, go [here|http://get.adobe.com/fr/flashplayer/|fr] to get the latest version.
&lt;/object&gt;



&lt;p&gt;And the code of the demo :&lt;/p&gt;

&lt;pre class=&quot;brush: as&quot;&gt;package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;	

	[SWF(width=&amp;quot;550&amp;quot;, height=&amp;quot;200&amp;quot;)]
	public class CameraTut2 extends Sprite 
	{
		private var camera : Camera;
		private var layer1 : CameraLayer;

		private var layer2 : CameraLayer;	

		public function CameraTut2 ()
		{
			camera = new Camera( new Rectangle( 0, 0, 550, 200 ) );
			layer1 = new CameraLayer(.5);

			layer2 = new CameraLayer();
			
			camera.addEventListener( &amp;quot;cameraChange&amp;quot; , layer1.cameraChanged );

			camera.addEventListener( &amp;quot;cameraChange&amp;quot; , layer2.cameraChanged );
			layer1.alpha = .3;
			
			fillLayer( layer1 );
			fillLayer( layer2 );
						
			addChild( layer1 );

			addChild( layer2 );
			
			addEventListener( Event.ENTER_FRAME, enterFrame );

			stage.addEventListener( MouseEvent.MOUSE_DOWN, mouseDown );

			stage.addEventListener( MouseEvent.MOUSE_UP, mouseUp );

		}

		// used to move the cam
		private var lastXMouse : Number;

		private var lastYMouse : Number;
		private var down : Boolean;

		public function mouseDown ( e : MouseEvent ) : void
		{
			lastXMouse = mouseX;

			lastYMouse = mouseY;
			down = true;

		}

		public function mouseUp ( e : MouseEvent ) : void
		{
			down = false;
		}
		private function enterFrame ( e : Event ) : void
		{
			if( down )
			{
				// move the camera and make it loop back to origin
				camera.centerX -= mouseX - lastXMouse;

				camera.centerY -= mouseY - lastYMouse;
				camera.fireCameraChange();
				
				lastXMouse = mouseX;
				lastYMouse = mouseY;
			}
		}
		private function fillLayer ( layer : CameraLayer ) : void
		{
			var l : Number = 100;
			
			while (l--)
			{
				var s : Shape = new Shape();
				s.graphics.beginFill(0);
				s.graphics.drawCircle(0, 0, 5 + Math.random() * 5);
				s.graphics.endFill();
				
				s.x = Math.random() * 1100;
				s.y = Math.random() * 200;
				
				layer.addChild( s );
			}
		}
	}
}&lt;/pre&gt;


&lt;p&gt;That's all for today, the next parts will talk about adding zoom and then rotation to the camera. Next parts will come soon :).&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2009/01/25/#rev-pnote-150-1&quot; id=&quot;pnote-150-1&quot;&gt;1&lt;/a&gt;] If you don't know what parallax is, just take a look &lt;a href=&quot;http://en.wikipedia.org/wiki/Parallax&quot; hreflang=&quot;en&quot;&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2009/01/25/Camera-and-Layers-Part-1-Scroll-and-Parallax#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2009/01/25/Camera-and-Layers-Part-1-Scroll-and-Parallax#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/150</wfw:commentRss>
      </item>
    
  <item>
    <title>Templates FDT3 pour LowRA</title>
    <link>http://book.abe.free.fr/blog/?post/2008/02/11/Template-FDT3-pour-LowRA</link>
    <guid isPermaLink="false">urn:md5:1cf23e934f3d8b7e72f903f383de590f</guid>
    <pubDate>Mon, 11 Feb 2008 14:05:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>flash</category><category>lowra</category>    
    <description>&lt;p&gt;Pour ceux qui utilise FDT3 voici un petit fichier avec des templates pour Lowra.&lt;/p&gt;


&lt;p&gt;Le fichier est donc disponible dans les pièces jointes du billet.&lt;/p&gt;    &lt;p&gt;Au programme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commande&lt;/li&gt;
&lt;li&gt;Commande Asynchrone&lt;/li&gt;
&lt;li&gt;Classe de debug&lt;/li&gt;
&lt;li&gt;Model&lt;/li&gt;
&lt;li&gt;Vue&lt;/li&gt;
&lt;li&gt;Vue avec DisplayObjectContainer&lt;/li&gt;
&lt;li&gt;Plugin&lt;/li&gt;
&lt;li&gt;Liste d'évènements&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2008/02/11/Template-FDT3-pour-LowRA#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2008/02/11/Template-FDT3-pour-LowRA#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/135</wfw:commentRss>
      </item>
    
  <item>
    <title>La face cachée d'ASDoc</title>
    <link>http://book.abe.free.fr/blog/?post/2008/02/09/La-face-cachee-dASDoc</link>
    <guid isPermaLink="false">urn:md5:14cc17266c41e9755a271bb54def7782</guid>
    <pubDate>Sat, 09 Feb 2008 20:26:00 +0100</pubDate>
    <dc:creator>Cédric</dc:creator>
        <category>Coding</category>
        <category>as3</category><category>asdoc</category><category>flash</category>    
    <description>&lt;p&gt;Encore un billet très technique, en attendant de nouvelles images prochainement.&lt;/p&gt;


&lt;p&gt;Suite à de nombreuses questions concernant &lt;a href=&quot;http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&amp;amp;file=asdoc_127_1.html&quot; hreflang=&quot;en&quot; title=&quot;ASDoc sur la LiveDocs&quot;&gt;ASDoc&lt;/a&gt;, et sur comment résoudre les nombreux problèmes qui se pose lors de son utilisation, je vais tenter de débroussailler un peu la bête.&lt;/p&gt;


&lt;p&gt;Pour rappel, ASDoc est un outil fournit par Adobe, et qui permet de générer la documentation d'une &lt;acronym title=&quot;Application Programming Interface&quot;&gt;API&lt;/acronym&gt; à partir de son code source.&lt;/p&gt;    &lt;h3&gt;Sommaire&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#intro&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#exclude&quot;&gt;Exclure les dépendances de la documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#write&quot;&gt;Bien écrire la documentation dans son code&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#javadoc&quot;&gt;Différences avec l'outil JavaDoc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#param&quot;&gt;La balise @param&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#throws&quot;&gt;La balise @throws&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#issues&quot;&gt;Problèmes connus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://book.abe.free.fr/blog/?post/2008/02/09/#regexp&quot;&gt;Expressions Rationnelles utiles&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;


&lt;p&gt;&lt;a name=&quot;intro&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Introduction&lt;/h3&gt;


&lt;p&gt;L'arrivée d'un outil comme ASDoc dans le Flex SDK est une bonne nouvelle. ASDoc est un bon outil, il fournit la plupart des fonctionnalités que l'on attend de ce genre d'outil. Cependant, il n'est pas réellement soutenu par Adobe, ou plutôt Adobe n'a pas prévu de le faire évoluer ni de résoudre les problèmes déjà rapporté par les utilisateurs. En conséquence, en attendant une hypothétique ouverture des sources, il faut faire avec et trouver les moyens de contourner les problèmes rencontrés.&lt;/p&gt;


&lt;p&gt;&lt;a name=&quot;exclude&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Exclure les dépendances de la documentation&lt;/h3&gt;


&lt;p&gt;Le premier problème rencontré par la plupart des gens concerne la possibilité d'exclure les dépendances de la compilation. Plus concrètement, si je décide de générer la documentation de &lt;a href=&quot;http://code.google.com/p/kairos3&quot; hreflang=&quot;en&quot; title=&quot;Kairos AS3 sur Google Code&quot;&gt;Kairos&lt;/a&gt;, étant donné que de nombreux objets utilisent des classes ou des interfaces provenant de &lt;a href=&quot;http://code.google.com/p/lowra&quot; hreflang=&quot;en&quot; title=&quot;LowRA sur Google Code&quot;&gt;LowRA&lt;/a&gt;, toutes ces dépendances seront elles aussi documentées par ASDoc si je les défini avec l'argument &lt;strong&gt;-source-path&lt;/strong&gt;. Pour pouvoir exclure ces classes de la documentation, il faut utiliser la version pré-compilée de LowRA, et donc le fichier *.swc et l'argument &lt;strong&gt;-library-path&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;&lt;a name=&quot;write&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Bien écrire la documentation dans son code&lt;/h3&gt;


&lt;p&gt;Pour moi, la référence la plus importante pour bien rédiger de la documentation est l'article de Sun &lt;a href=&quot;http://java.sun.com/j2se/javadoc/writingdoccomments/&quot; hreflang=&quot;en&quot; title=&quot;How to write doc comments for the javadoc tool&quot;&gt;How to Write Doc Comments for the Javadoc Tool&lt;/a&gt;. Il contient à peu près tout ce qu'il faut pour écrire de la bonne documentation, il suffit de voir le résultat dans la documentation de l'API Java pour s'en rendre compte.&lt;/p&gt;


&lt;p&gt;&lt;a name=&quot;javadoc&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Différences avec l'outil JavaDoc&lt;/h4&gt;


&lt;p&gt;Même si ASDoc, comme de nombreux autres outils, s'inspire  des spécifications de Javadoc, il y a des différences entre les 2 outils assez importantes à connaître (outre celles liées aux fonctionnalités du langage) :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;strong&gt;&amp;lt;p&amp;gt;&lt;/strong&gt; doivent être systématiquement fermées dans ASDoc, alors que Javadoc se chargera de les fermer pour vous. Si vous ne respectez pas cette règle vous risquez d'avoir des surprises dans la mise en page de la documentation.&lt;/li&gt;
&lt;li&gt;Les balises &lt;strong&gt;{@code ...}&lt;/strong&gt; et &lt;strong&gt;{@link ...}&lt;/strong&gt; ne sont pas supporté par ASDoc, vous devrez donc utiliser respectivement les balises  &lt;strong&gt;&amp;lt;code&amp;gt;&lt;/strong&gt; et &lt;strong&gt;&amp;lt;a&amp;gt;&lt;/strong&gt; en remplacement.&lt;/li&gt;
&lt;li&gt;Les paramètres d'une fonction sont optionnels dans une balise &lt;strong&gt;@see&lt;/strong&gt; pointant vers une fonction.&lt;/li&gt;
&lt;li&gt;ASDoc ne supporte pas les fichiers de description de package, ni l'inclusion automatique d'exemples compilés dans la documentation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a name=&quot;param&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;La balise @param&lt;/h4&gt;


&lt;p&gt;La balise @param à un comportement un peu particulier dans sa gestion des espaces, il considère que la séquence entre le 1er espace et le 2ème espace est le nom de l'argument. Donc si l'on souhaite respecter les directives de Sun pour rendre les commentaires contenant la documentation plus lisibles, comme indenter tout les contenus de balises, il faut bien prendre garde aux espaces supplémentaires.&lt;/p&gt;

&lt;pre&gt;
/**
 * Un exemple de documentation
 *
 * @param 	param1	description param1
 * @param 	param2	description param2
 * @return	description du retour
 * @example	un exemple d'utilisation
 */
function foo ( param1 : String, param2 : Number = 0 ) ; Boolean;
&lt;/pre&gt;


&lt;p&gt;L'exemple précédent ne donnera pas une documentation propre, puisque les balises &lt;strong&gt;@param&lt;/strong&gt; sont suivi d'un espace puis d'une tabulation (sélectionnez le texte pour vous en rendre compte), le nom du paramètre sera donc ajouter au début de la description de celui-ci. Pour que le paramètre n'apparaisse pas dans la description il faut supprimer le 1er espace. Comme dans l'exemple ci-dessous :&lt;/p&gt;


&lt;pre&gt;
/**
 * Un exemple de documentation
 *
 * @param	param1	description param1
 * @param	param2	description param2
 * @return	description du retour
 * @example	un exemple d'utilisation
 */
function foo ( param1 : String, param2 : Number = 0 ) ; Boolean;
&lt;/pre&gt;


&lt;p&gt;Pour s'assurer qu'aucune balise &lt;strong&gt;@param&lt;/strong&gt; ne contient d'espaces inutiles, vous pouvez utiliser l'expression rationnelle suivante pour effectuer un remplacement (si votre IDE supporte les recherches avec des expressions rationelles)&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;@param[\s]+([^\s]+)&lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;@param	$1&lt;/pre&gt;


&lt;p&gt;Cette expression recherche toute les balises &lt;strong&gt;@param&lt;/strong&gt; suivi d'au minium un espace et les remplace par des balises &lt;strong&gt;@param&lt;/strong&gt; suivi d'une tabulation (ou d'un espace si vous préférez)&lt;/p&gt;


&lt;p&gt;&lt;a name=&quot;throws&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;La balise @throws&lt;/h4&gt;


&lt;p&gt;La balise &lt;strong&gt;@throws&lt;/strong&gt; est vraiment la plus capricieuse de toutes. Elle se présente sous cette forme :&lt;/p&gt;

&lt;pre&gt;@throws claspath.Error Description de l'erreur&lt;/pre&gt;


&lt;p&gt;Seulement il y a un petit hic, si la classe de l'erreur n'est pas directement déclarée dans le répertoire qui est documentée, par exemple si c'est une classe d'erreur fournit dans le core du SDK, ou dans une autre librarie dont votre code est dépendant. Non seulement il n'y aura pas de lien vers la classe de l'erreur, mais le nom de l'erreur sera complètement occulté. Comme pour la balise &lt;strong&gt;@param&lt;/strong&gt; ce sont les espaces qui conditionnent le traitement par ASDoc. Pour faire donc systématiquement apparaître le nom de l'erreur dans la documentation finale, il ne faudra pas compter avec la syntaxe normale de la balise. Comme dans l'exemple suivant :&lt;/p&gt;

&lt;pre&gt;
/**
 * Un exemple de documentation
 *
 * @param	param1	description param1
 * @param	param2	description param2
 * @return	description du retour
 * @throws	TypeError Le type de l'erreur ne sera pas visible
 * 		dans la documentation finale puisque TypeError existe
 * 		seulement dans les *.swc de Flex
 */
function foo ( param1 : String, param2 : Number = 0 ) ; Boolean;
&lt;/pre&gt;


&lt;p&gt;J'ai donc pris l'habitude de rédiger la documentation d'une exception ainsi (là encore sélectionnez le texte pour voir l'espace supplémentaire après la balise &lt;strong&gt;@throws&lt;/strong&gt;), et donc de ne plus utiliser la syntaxe normale de cette balise :&lt;/p&gt;

&lt;pre&gt;
/**
 * Un exemple de documentation
 *
 * @param	param1	description param1
 * @param	param2	description param2
 * @return	description du retour
 * @throws 	TypeError - Le type de l'erreur sera visible
 * 		dans la documentation finale mais au sein
 * 		de la description de l'erreur
 */
function foo ( param1 : String, param2 : Number = 0 ) ; Boolean;
&lt;/pre&gt;


&lt;p&gt;Là encore une petite expression rationnelle permet de s'assurer que toutes les balises &lt;strong&gt;@throws&lt;/strong&gt; sont correctement formées pour faire apparaître le type de l'erreur dans la documentation finale.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;@throws[\s]+([^\s]+)&lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;@throws 	&amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt; —&lt;/pre&gt;


&lt;p&gt;&lt;a name=&quot;issues&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Problèmes connus&lt;/h3&gt;


&lt;p&gt;Une petite liste de problèmes rencontrés avec l'outil ASDoc&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Il ne faut pas utiliser les balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt; dans une balise &lt;strong&gt;@see&lt;/strong&gt;, sinon cela provoquera un crash de ASDoc.&lt;/li&gt;
&lt;li&gt;Il ne faut pas utiliser de doubles quotes (&amp;quot;) dans une balise  &lt;strong&gt;@see&lt;/strong&gt;, sinon cela provoquera un crash de ASDoc.&lt;/li&gt;
&lt;li&gt;Les caractères spéciaux dans les options &lt;strong&gt;-footer&lt;/strong&gt;, &lt;strong&gt;-title&lt;/strong&gt;, &lt;strong&gt;-window-title&lt;/strong&gt;, &lt;strong&gt;-main-title&lt;/strong&gt; et &lt;strong&gt;-package&lt;/strong&gt; (en gros toutes les options permettant de rajouter du texte quelque part) doivent être écris sous leur forme HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;regexp&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Expressions Rationelles utiles&lt;/h3&gt;


&lt;p&gt;Une petites série d'expressions rationnelles bien utile pour convertir de la documentation d'un système vers un autre :&lt;/p&gt;


&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt; en AS2, qui définissent les exemples, par des balises &lt;strong&gt;&amp;lt;listing&amp;gt;&amp;lt;/listing&amp;gt;&lt;/strong&gt; qui sont les blocs d'exemples en AS3.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;&amp;lt;code&amp;gt;([^&amp;lt;]*)&amp;lt;/code&amp;gt;&lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;&amp;lt;listing&amp;gt;$1&amp;lt;/listing&amp;gt;&lt;/pre&gt;


&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;{@code ...}&lt;/strong&gt; qui ne sont pas supporté par ASDoc, remplacé par des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;\{@code ([a-zA-Z0-9.,:#()\s]*)\} &lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;&amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt;&lt;/pre&gt;


&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;&amp;lt;tt&amp;gt;&amp;lt;/tt&amp;gt;&lt;/strong&gt; par des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;&amp;lt;tt&amp;gt;([^&amp;lt;]*)&amp;lt;/tt&amp;gt;&lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;&amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt;&lt;/pre&gt;


&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;{@link ...}&lt;/strong&gt; qui ne sont pas supporté par ASDoc, remplacé par des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;
&lt;pre&gt;\{@link ([a-zA-Z0-9.,:#()\s]*)\} &lt;/pre&gt;

&lt;p&gt;Remplacer :&lt;/p&gt;
&lt;pre&gt;&amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt;&lt;/pre&gt;

&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt; par des tags &lt;strong&gt;{@code ...}&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;

&lt;pre&gt;&amp;lt;code&amp;gt;([^&amp;lt;]*)&amp;lt;/code&amp;gt;&lt;/pre&gt;


&lt;p&gt;Remplacer :&lt;/p&gt;

&lt;pre&gt;\{@code $1\}&lt;/pre&gt;


&lt;hr /&gt;


&lt;p&gt;Remplacement des balises &lt;strong&gt;&amp;lt;listing&amp;gt;&amp;lt;/listing&amp;gt;&lt;/strong&gt; par des balises &lt;strong&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;Rechercher :&lt;/p&gt;

&lt;pre&gt;&amp;lt;listing&amp;gt;([^&amp;lt;]*)&amp;lt;/listing&amp;gt;&lt;/pre&gt;


&lt;p&gt;Remplacer :&lt;/p&gt;

&lt;pre&gt;&amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt;&lt;/pre&gt;</description>
    
    
    
          <comments>http://book.abe.free.fr/blog/?post/2008/02/09/La-face-cachee-dASDoc#comment-form</comments>
      <wfw:comment>http://book.abe.free.fr/blog/?post/2008/02/09/La-face-cachee-dASDoc#comment-form</wfw:comment>
      <wfw:commentRss>http://book.abe.free.fr/blog/?feed/atom/comments/134</wfw:commentRss>
      </item>
    
</channel>
</rss>