<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-10918543</atom:id><lastBuildDate>Tue, 05 Aug 2008 18:18:48 +0000</lastBuildDate><title>DMINATORs BLOG</title><description /><link>http://dminator.blogspot.com/</link><managingEditor>noreply@blogger.com (Dmitri Kuznetsov)</managingEditor><generator>Blogger</generator><openSearch:totalResults>164</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/DminatorsBlog" type="application/rss+xml" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-3049913735740987753</guid><pubDate>Tue, 05 Aug 2008 18:13:00 +0000</pubDate><atom:updated>2008-08-05T21:18:48.603+03:00</atom:updated><title>Another photo</title><description>&lt;p&gt;I haven't posted a photo update here for some time. So here it goes - a new photo taken atTallinn harbour in june.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.caedes.net/Zephir.cgi?lib=Caedes::Infopage&amp;amp;image=DMINATOR-1217956175.jpg"&gt;&lt;img src="http://content.foto.mail.ru/mail/kna_int/Birds/i-53.jpg" /&gt;&lt;/a&gt;</description><link>http://dminator.blogspot.com/2008/08/another-photo.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-7833016889963440343</guid><pubDate>Sat, 02 Aug 2008 20:19:00 +0000</pubDate><atom:updated>2008-08-03T00:20:24.837+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Lens</category><category domain="http://www.blogger.com/atom/ns#">Zoom</category><category domain="http://www.blogger.com/atom/ns#">Photo</category><category domain="http://www.blogger.com/atom/ns#">Macro</category><title>Need super macro lens ? Make them yourself !</title><description>&lt;p&gt;I am a big macro fan.&lt;/p&gt;&lt;p&gt;So when I see a bug or insect, I usually take a camera and shoot it. The problem is that my kit lens aren't good enough. So I needed something better.&lt;/p&gt;&lt;p&gt;Well I made a lens myself. A rather easy thing to do if you have some materials. The lens construction is very simple just one front element from an old soviet 'LOMO' camera and a tube.&lt;/p&gt;&lt;p&gt;Here is how it looks like:&lt;/p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214380908980804450"&gt;&lt;img src="http://lh6.ggpht.com/DMINATORpix/SF0zz0thG2I/AAAAAAAAAJw/_8AzC6gwYyE/s400/IMG_8052.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Here is a front lens element:&lt;/p&gt;&lt;p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214380825189043410"&gt;&lt;img src="http://lh5.ggpht.com/DMINATORpix/SF0zu8kATNI/AAAAAAAAAJg/wUflQHvQ2UA/s400/IMG_7717.JPG" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And a comparison with other lenses (from left to right: kit 18-55mm, my custom super macro, 70-200 f2.8 IS):&lt;/p&gt;&lt;p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214380799055203890"&gt;&lt;img src="http://lh4.ggpht.com/DMINATORpix/SF0ztbNNjjI/AAAAAAAAAJY/7WKvQ9U1Ojw/s400/IMG_7712.JPG" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I think the lens produces about 3-4 x magnification. It is pretty hard to use, because I have to hold it close to the camera, set exposure and aperture manually. Picture in a viewfinder is almost black so it is very hard to see anything. Still it is possible to make some interesting pictures:&lt;/p&gt;&lt;br /&gt;Bubbles in the glass:&lt;br /&gt;&lt;p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214381022302579986"&gt;&lt;img src="http://lh5.ggpht.com/DMINATORpix/SF0z6a3iLRI/AAAAAAAAAKY/Dsfu-LLtrxU/s400/IMG_8174.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Bristles of a toothbrush:&lt;/p&gt;&lt;p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214380761590080866"&gt;&lt;img src="http://lh3.ggpht.com/DMINATORpix/SF0zrPo1JWI/AAAAAAAAAJQ/3e9FGy_aB7g/s400/IMG_8014.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And here is a small part of some flower:&lt;/p&gt;&lt;p&gt;&lt;a href="http://picasaweb.google.com/DMINATORpix/Home_Made_Macro_Lens/photo#5214383078271701954"&gt;&lt;img src="http://lh3.ggpht.com/DMINATORpix/SF01yF8xU8I/AAAAAAAAAKk/CeRVCFajSIs/s400/IMG_8118.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;I also added a slideshow from the picasa album with other pictures:&lt;br /&gt;&lt;br /&gt;&lt;embed type="application/x-shockwave-flash" src="http://picasaweb.google.com/s/c/bin/slideshow.swf" width="288" height="192" flashvars="host=picasaweb.google.com&amp;amp;RGB=0x000000&amp;amp;feed=http%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2FDMINATORpix%2Falbumid%2F5214380572188237281%3Fkind%3Dphoto%26alt%3Drss" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;</description><link>http://dminator.blogspot.com/2008/08/need-super-macro-lens-make-them.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-8153174428771409294</guid><pubDate>Wed, 30 Jul 2008 22:22:00 +0000</pubDate><atom:updated>2008-07-31T02:37:09.894+03:00</atom:updated><title>Listbox yeay !</title><description>&lt;p&gt;Well. &lt;/p&gt;&lt;p&gt;I finally added the listbox to the GE2 GUI control list.&lt;/p&gt;&lt;p&gt;Initially I wanted to implement a container control that would allow scrolling of its child controls(contents). I took a pretty complicated task. As it turned out later, the idea had a major flow. The problem was that container control has a fixed size. Now when other controls are located inside it, their size changes depending on the distance between child and parent control bounds. But scrolling assumes that there are 2 areas: visible area and full size scrollable area. I couldn't figure out how to combine these two things together. &lt;/p&gt;&lt;p&gt;So my conclusion was that in order to implement scrolling properly each control should have different scrolling logic depending on the control functionality. And it is how the windows controls work, I think. Just look at the listbox or window scrollbars functionality.&lt;/p&gt;&lt;p&gt;Anyway the listbox is working, and as usual the final implementation was a fairly simple one, especially for the end user.&lt;/p&gt;&lt;p&gt;This is how it looks in the template file:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;overlay&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              name = "list_box_item"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              align = "left | top | right "&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;        &amp;lt;objects&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;               &amp;lt;text&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     name = "caption"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     text = "list_box_item"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                    dock = "fill"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;               &amp;lt;/text&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;        &amp;lt;/objects&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt; &amp;lt;/overlay&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt; &amp;lt;overlay&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         name = "list_box"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         minimumWidth = 0.1&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         minimumHeight = 0.1&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         width = 0.10&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         height = 0.20&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         &amp;lt;items&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     value="1111"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;/item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     value="2222"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;/item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                 &amp;lt;item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                      value="3333"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;/item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     value="4444"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                &amp;lt;/item&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;p&gt;           &amp;lt;/items&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;     &amp;lt;objects&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt; &lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;           &amp;lt;container&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                   name = "container"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                   dock = "fill"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                  padding.right = 0.05&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;            &amp;lt;/container&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;           &amp;lt;v_scroll_bar&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              name = "vscroll"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              height = 0.20&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              left   = 0.05&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;             dock = "right"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;             scissor = "parent"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;          &amp;lt;/v_scroll_bar&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;           //A background rectangle to show control bounds&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;          &amp;lt;background&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;               name = "background"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;               dock = "fill"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;/em&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;               &amp;lt;states&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                     normal  = "check_normal"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;                   disabled  = "check_disabled"&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;              &amp;lt;/states&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;         &amp;lt;/background&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;      &amp;lt;/objects&gt;&lt;em&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/em&gt; &amp;lt;/overlay&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;You can see the container and scrollbar here. The scrollbar is recognised when control is loaded and is linked to the container event system automatically. So when you scroll it, the container contents are scrolled also with it. &lt;/span&gt;&lt;overlay&gt;&lt;objects&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;The background serves only a visual purpose by showing white grid on top of the listbox to make it look more distinct from other controls.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;The other thing that listbox requires is the definition of how the listbox items would be displayed. This is where list_box_item overlay is used. It can be overloaded by specifing template = "list_box_item" clause manually inside the listbox overlay. User can also create their own class with advanced logic and show it instead of the default type.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;Listbox items itself can be added very easily:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#009900;"&gt;&lt;em&gt;  lbox1.items.InsertBack( "string1" );&lt;br /&gt;  lbox1.items.InsertBack( "string2" );&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;container&gt;&lt;v_scroll_bar&gt;&lt;background&gt;&lt;states&gt;&lt;overlay&gt;&lt;objects&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;And changed :&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#009900;"&gt;&lt;em&gt; lbox1.items[0] = "changed2";&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;Note that item_changed event is automatically triggered when any item gets changed via delegate. A tricky system but it works!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;There are many events that get triggered when different things happen to the listbox. The most important event occurs when user clicks on different item. Video shows a really good example how it actually works. From programmers perspective:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#33cc00;"&gt;&lt;em&gt; lbox1.OnSelectedIndexChanged = MemberFunction( &amp;amp;GUITest::listBoxSelectedIndexChanged );&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;The new value is obtained via arguemnts passed with delegate:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#009900;"&gt;&lt;em&gt; void listBoxSelectedIndexChanged(GUIBase* sender, GUISelectedIndexChangedEventArgs*  args)&lt;br /&gt; {&lt;br /&gt;         if( args != NULL )&lt;br /&gt;         {&lt;br /&gt;                 lblIndex.caption = args-&gt;newItemValue;&lt;br /&gt;         }&lt;br /&gt; }&lt;/em&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000000;"&gt;That is as easy as it can possible get. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Here is a video: (I have also added a new Youtube feature - annotations)&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;em&gt;&lt;container&gt;&lt;em&gt;&lt;v_scroll_bar&gt;&lt;em&gt;&lt;background&gt;&lt;em&gt;&lt;states&gt;&lt;overlay&gt;&lt;objects&gt;&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/objects&gt;&lt;/overlay&gt;&lt;/states&gt;&lt;/em&gt;&lt;/background&gt;&lt;/em&gt;&lt;/v_scroll_bar&gt;&lt;/em&gt;&lt;/container&gt;&lt;/em&gt;&lt;span style="color:#006600;"&gt;&lt;em&gt;&lt;container&gt;&lt;span style="color:#006600;"&gt;&lt;em&gt;&lt;v_scroll_bar&gt;&lt;span style="color:#006600;"&gt;&lt;em&gt;&lt;background&gt;&lt;span style="color:#006600;"&gt;&lt;em&gt;&lt;states&gt;&lt;overlay&gt;&lt;objects&gt;&lt;object width="425" height="344"&gt;&lt;embed src="http://www.youtube.com/v/Tnt1rryH2Yc&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/objects&gt;&lt;/overlay&gt;&lt;/states&gt;&lt;/em&gt;&lt;/span&gt;&lt;/background&gt;&lt;/em&gt;&lt;/span&gt;&lt;/v_scroll_bar&gt;&lt;/em&gt;&lt;/span&gt;&lt;/container&gt;&lt;/em&gt;&lt;/span&gt;</description><link>http://dminator.blogspot.com/2008/07/listbox-yeay.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-2793840042002492768</guid><pubDate>Fri, 25 Apr 2008 19:22:00 +0000</pubDate><atom:updated>2008-04-25T22:34:02.383+03:00</atom:updated><title>ADOgames forum opened!</title><description>Hi.&lt;br /&gt;&lt;br /&gt;ADOgames forum is now operational.&lt;br /&gt;&lt;br /&gt;We would try and keep the forum updated with information regarding our current projects. Forum is also permanent place for the discussion about Galactic Engine 2.&lt;br /&gt;&lt;br /&gt;Go ahead and visit us:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://forum.adogames.com/"&gt;&lt;img src="http://adogames.com/logos/forum-banner-440x120.gif" /&gt;&lt;/a&gt;</description><link>http://dminator.blogspot.com/2008/04/adogames-forum-opened.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-5773707834486594380</guid><pubDate>Tue, 22 Apr 2008 22:00:00 +0000</pubDate><atom:updated>2008-04-23T01:40:35.788+03:00</atom:updated><title>GE2 GUI Prototype 1.5 TrackBars</title><description>Hi.&lt;br /&gt;&lt;br /&gt;I would like to give another update regarding the new GUI I am working on.&lt;br /&gt;&lt;br /&gt;The latest changes that were made:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. Control position bounds:&lt;/strong&gt;&lt;br /&gt;Every control position now can be limited to certain bounds:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. DragBox grid snap:&lt;/strong&gt;&lt;br /&gt;It is possible to define how the drag control item position would be rounded when it is dragged.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. DragBox axis filter:&lt;/strong&gt;&lt;br /&gt;For DragBox the programmer can define in which direction the drag control would move. Either X , Y or both&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Using all these features it is possible to define TrackBar.&lt;br /&gt;&lt;br /&gt;The trackBar is a simple control that has a small control usually called "Thumb" or "Slider".&lt;br /&gt;Every windows user is familar with display control window with resolution trackbar:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In Galactic engine there are 2 trackbar controls: vertical and horizontal. Each control has a "thumb" which itself is a DragBox control. The DragBox was defined with position bounds so it wouldn't pass through the trackbar parent size rectangle. Also it has a specific axis defined so it would drag controls only in one direction. When dragging is occured the control finds new thumb position and recalculates current trackbar value based on relative percentage between minimum and maximum values.&lt;br /&gt;&lt;br /&gt;Trackbars can have also the maximum and minimum values set, so the thumb would only move within these limits.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is a video that demonstrates new trackbar in action:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/UDnBeVRYcz8&amp;hl=en"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;embed src="http://www.youtube.com/v/UDnBeVRYcz8&amp;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://forum.adogames.com/phpBB3/viewtopic.php?f=4&amp;t=9"&gt;For more information visit Galactic Engine 2 forum&lt;/a&gt;</description><link>http://dminator.blogspot.com/2008/04/ge2-gui-prototype-15-trackbars.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-4571006006464812482</guid><pubDate>Wed, 16 Apr 2008 18:01:00 +0000</pubDate><atom:updated>2008-04-16T21:11:33.547+03:00</atom:updated><title>Stack walker added</title><description>Another little update.&lt;br /&gt;&lt;br /&gt;I have added stack walker for the engine created by &lt;a href="http://blog.kalmbach-software.de/"&gt;Jochen Kalambach&lt;/a&gt;. It is helpful tool that shows how the functions were called. With a little utility dbghelp.dll it is possible.&lt;br /&gt;&lt;br /&gt;Here is a screenshot that shows error report:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/SAZBIpjSR6I/AAAAAAAAAGg/SzGs5FfeZFo/s1600-h/stack_trace.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/SAZBIpjSR6I/AAAAAAAAAGg/SzGs5FfeZFo/s400/stack_trace.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5189907237439686562" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;By default any error in debug mode produces stack trace automatically. In release mode however it needs to be manually specified through config file.</description><link>http://dminator.blogspot.com/2008/04/stack-walker-added.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-1957977469183187027</guid><pubDate>Fri, 11 Apr 2008 18:34:00 +0000</pubDate><atom:updated>2008-04-11T21:45:21.604+03:00</atom:updated><title>GUI progress - drag box fun</title><description>Another update.&lt;br /&gt;&lt;br /&gt;Finally I added scissor functionality. It should cut any controls that move out of parent container bounds. You can clearly see this in action.&lt;br /&gt;&lt;br /&gt;Another thing I wanted to show is drag box. It is possible to make drag box move almost any  control including window close button.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/g1T6jAD7Bm4&amp;hl=en"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;embed src="http://www.youtube.com/v/g1T6jAD7Bm4&amp;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;</description><link>http://dminator.blogspot.com/2008/04/gui-progress-drag-box-fun.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-5989549492120442305</guid><pubDate>Thu, 03 Apr 2008 17:10:00 +0000</pubDate><atom:updated>2008-04-03T20:17:41.493+03:00</atom:updated><title>GE2 GUI Prototype 1.3</title><description>Hi.&lt;br /&gt;&lt;br /&gt;Another little update regaring new GUI system.&lt;br /&gt;&lt;br /&gt;A few things that I managed to add:&lt;br /&gt;&lt;br /&gt;1. Custom cursors for any type of control (You can see that in a video, how cursor style changes on hover event)&lt;br /&gt;2. Focus - Control that was used recently recieves input from keyboard.&lt;br /&gt;3. Switching between controls with TAB key. Kinda basic function that everyone uses in windows but a little harder to implement than it may look.&lt;br /&gt;&lt;br /&gt;Here is another video that shows the recently added features:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/HIPm6Ea6Xuc&amp;hl=en"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;embed src="http://www.youtube.com/v/HIPm6Ea6Xuc&amp;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;</description><link>http://dminator.blogspot.com/2008/04/ge2-gui-prototype-13.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-1501080583885801922</guid><pubDate>Tue, 01 Apr 2008 21:26:00 +0000</pubDate><atom:updated>2008-04-02T00:34:58.055+03:00</atom:updated><title>SunAge new RTS</title><description>Here is an interesting project that guys were making for 11 years!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.vertex4.com/sunage/"&gt;SunAge&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The best part is that it is finally finished and it looks really awesome. Although I haven't tried it yet, I am looking forward to it in the future.&lt;br /&gt;&lt;br /&gt;Definetelly check the video teaser:&lt;br /&gt;&lt;br /&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" id="gtembed" width="480" height="392"&gt; &lt;param name="allowScriptAccess" value="sameDomain"&gt;  &lt;param name="allowFullScreen" value="true"&gt; &lt;param name="movie" value="http://www.gametrailers.com/remote_wrap.php?mid=27934"&gt; &lt;param name="quality" value="high"&gt; &lt;embed src="http://www.gametrailers.com/remote_wrap.php?mid=27934" swliveconnect="true" name="gtembed" align="middle" allowscriptaccess="sameDomain" allowfullscreen="true" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="480" height="392"&gt;&lt;/embed&gt; &lt;/object&gt;</description><link>http://dminator.blogspot.com/2008/04/sunage-new-rts.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-7342239701368018921</guid><pubDate>Sun, 30 Mar 2008 20:28:00 +0000</pubDate><atom:updated>2008-03-30T23:39:39.733+03:00</atom:updated><title>GE2 GUI progress 1.2</title><description>Hi.&lt;br /&gt;&lt;br /&gt;Another little update. Here are few things that I have recently added :&lt;br /&gt;&lt;br /&gt;1. CheckBox - Simple control with .checked property just set it to true or false.&lt;br /&gt;2. RoundBox - works completelly automatically. If one round box is checked then all the other check boxes within the same contianer would be unchecked.&lt;br /&gt;3. Enable/Disable states. Another proprety for every control. Works by setting .enabled to true or false.&lt;br /&gt;&lt;br /&gt;Here is a video that demonstrates all of this in action:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/GY1MJf4Da3o&amp;hl=en"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;embed src="http://www.youtube.com/v/GY1MJf4Da3o&amp;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;</description><link>http://dminator.blogspot.com/2008/03/ge2-gui-progress-12.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-3237140260645419510</guid><pubDate>Wed, 26 Mar 2008 20:43:00 +0000</pubDate><atom:updated>2008-03-26T22:52:11.765+02:00</atom:updated><title>GE2 GUI work in progress 1.1</title><description>Hi.&lt;br /&gt;&lt;br /&gt;Just wanted to show a little progress with the new GUI system. Check this video:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt; &lt;param name="movie" value="http://www.youtube.com/v/Y5lJjVVZfFE"&gt;  &lt;embed src="http://www.youtube.com/v/Y5lJjVVZfFE" type="application/x-shockwave-flash" width="425" height="350"&gt;&lt;/embed&gt;  &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;It shows basic GUI system in action. One of the key features displayed in this video are:&lt;br /&gt;&lt;br /&gt;1. Working event system. Mouse Click,Hover,Move&lt;br /&gt;2. Working controls : button , drag_box, resize_box&lt;br /&gt;3. Text Alignment - shows that any text in any control can be aligned either to one edge or stretched between different edges.&lt;br /&gt;4. Anchor and dock in action. Inspired by .NET and quite similar to it.&lt;br /&gt;5. Ability to manually override close_button on a window. Look how one window doesn't has close button.&lt;br /&gt;6. Minimum and maximum sizes for the control. When the control is resized these values are applied.&lt;br /&gt;&lt;br /&gt;A few things still needs a little work:&lt;br /&gt;&lt;br /&gt;1. Scissor - The problem is that some controls break away from their parent container edges.&lt;br /&gt;2. Add Enabled/Disabled states.&lt;br /&gt;2. Add other controls...</description><link>http://dminator.blogspot.com/2008/03/ge2-gui-work-in-progress-11.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-8762545307108642324</guid><pubDate>Mon, 24 Mar 2008 18:28:00 +0000</pubDate><atom:updated>2008-03-24T20:45:39.704+02:00</atom:updated><title>Galatic Engine 2 GUI development continues</title><description>I haven't updated the engine version for some time now. This is because I have been really busy with new GUI development. I don't want to go into details about the new features because some of them are still in testing. Anyway here is one little widget I made it with Flex Builder. It shows how long I have been developing new GUI.&lt;br /&gt;&lt;br /&gt;The reflection skin has been taken from &lt;a href="http://www.wietseveenstra.nl/blog/2007/05/29/reflection-manager-10/"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="500" height="400"&gt;&lt;br /&gt;&lt;param name="movie" value="somefilename.swf"&gt;&lt;br /&gt;&lt;embed src="http://files.myopera.com/DMINATOR/files/GUIProgressCounter.swf" width="500" height="400"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;I still can't believe it has taken it so long !</description><link>http://dminator.blogspot.com/2008/03/galatic-engine-2-gui-development.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-1124239684638515819</guid><pubDate>Thu, 20 Mar 2008 17:18:00 +0000</pubDate><atom:updated>2008-03-20T19:29:06.253+02:00</atom:updated><title>Wild Boar TV Online</title><description>Here is an awesome new  service that has taken Estonian homes and offices by storm:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ilm.ee/~uploader/loodus/?leht=art08engseatv"&gt;WildBoar TV!&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ilm.ee/~uploader/loodus/lkpildid/060204aa012_v.jpg"&gt;&lt;img src="http://www.ilm.ee/~uploader/loodus/lkpildid/060204aa012_v.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It was created by some enthusiast from nature calender. It is a live stream from a place in the woods used for feeding wild boars. Check this page for archives &lt;a href="http://www.ilm.ee/~uploader/loodus/?leht=art08engseatv"&gt;Here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Or you can see what is going on there live &lt;a href="mms://tv.eenet.ee/siga"&gt;here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://looduskalender.ee"&gt;&lt;span&gt;Picture  © looduskalender.ee 2006&lt;/span&gt;&lt;/a&gt;</description><link>http://dminator.blogspot.com/2008/03/wild-boar-tv-online.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-1621028859115072014</guid><pubDate>Mon, 17 Mar 2008 18:02:00 +0000</pubDate><atom:updated>2008-03-17T20:12:57.784+02:00</atom:updated><title>Dolar drops below 10 EEK</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/R960GbzyiDI/AAAAAAAAAGY/2nkmXefs7Us/s1600-h/USDvEEK.png"&gt;&lt;br /&gt;&lt;/a&gt;It is the first time ever that dollar has dropped as low as 10 EEK.&lt;br /&gt;&lt;br /&gt;EEK is Estonia's currency.&lt;br /&gt;&lt;br /&gt;Here is a little graph to show the tendency of changes:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/R960GbzyiDI/AAAAAAAAAGY/2nkmXefs7Us/s1600-h/USDvEEK.png"&gt;&lt;br /&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/R960GbzyiDI/AAAAAAAAAGY/2nkmXefs7Us/s400/USDvEEK.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5178774644159842354" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have been following the changes within US economy for sometime and it keeps getting more and more worser. The disturbing factor is that US Federal bank keeps making the same steps and they doesn't seem to be working.&lt;br /&gt;Another problem is that Oil prices are rising and well it impacts everyone in the world. I can only hope it would end soon.</description><link>http://dminator.blogspot.com/2008/03/dolar-drops-below-10-eek.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-2816613351236288605</guid><pubDate>Sun, 09 Mar 2008 21:02:00 +0000</pubDate><atom:updated>2008-03-09T23:20:31.110+02:00</atom:updated><title>Stage6 shutdown</title><description>Unfortunatelly the popular video service at &lt;a href="http://www.stage6.com/"&gt;stage6.divx.com&lt;/a&gt; was shutdown. Here is the official explanation from the site team:&lt;br /&gt;&lt;br /&gt;Stage6.com has been shut down. Thank you for supporting the service.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;We created Stage6 with the mission of empowering content creators and viewers to discover a new kind of video experience. Ultimately, the continued operation of Stage6 was a very expensive enterprise that required an enormous amount of attention and resources that we at DivX are not in a position to continue to provide. There are a lot of other details involved, but at the end of the day it's really as simple as that.&lt;br /&gt;&lt;br /&gt;The DivX experience will continue, of course. Every day new DivX Certified devices arrive on the market making it easy to move video beyond the PC. Products powered by DivX Connected, our new initiative that lets users stream video, photos, music and Internet services from the PC to the TV, are hitting retail outlets. We remain committed to empowering content creators to deliver high quality video to a wide audience, and we'll continue to offer services that will make it easy to find videos online in the DivX format.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;It's been a wild ride, and none of it would have been possible without the support of our users. Thank you for making Stage6 everything that it was.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;There is another service that has the same and even more features -&lt;a href="http://www.veoh.com/"&gt; veoh.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One of  the key features is the Pro version. It allows synchronization of videos with different video services. For example you upload a video and veoh does all the uploading for you for other services like google video or youtube.&lt;br /&gt;&lt;br /&gt;There is also a video browser program that can be downloaded for Mac or windows. It searches and plays back all the videos that can be found on google video or youtube.&lt;br /&gt;&lt;br /&gt;Here is blazetris with veoh:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed src="http://www.veoh.com/videodetails2.swf?permalinkId=v63555539BQ3Q2xx&amp;id=9702941&amp;player=videodetailsembedded&amp;videoAutoPlay=0" allowfullscreen="true" width="540" height="438" bgcolor="#000000" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;a href="http://www.veoh.com/"&gt;Online Videos by Veoh.com&lt;/a&gt;</description><link>http://dminator.blogspot.com/2008/03/stage6-shutdown.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-3448106882740982620</guid><pubDate>Mon, 19 Nov 2007 20:14:00 +0000</pubDate><atom:updated>2007-11-19T23:53:17.155+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Line</category><category domain="http://www.blogger.com/atom/ns#">square</category><category domain="http://www.blogger.com/atom/ns#">none</category><category domain="http://www.blogger.com/atom/ns#">round</category><category domain="http://www.blogger.com/atom/ns#">render</category><category domain="http://www.blogger.com/atom/ns#">OpenGL</category><category domain="http://www.blogger.com/atom/ns#">cap</category><title>Line cap calculation</title><description>To continue my previous post, I would like to explain a little more about how the line cap is calculated.&lt;br /&gt;&lt;br /&gt;Here is the order at which the line is rendered:&lt;br /&gt;&lt;br /&gt;1. Line Start Cap calculation&lt;br /&gt;2. Join vertex calculation n1&lt;br /&gt;3. ...&lt;br /&gt;4. Join vertex calculation n1 + joinNum&lt;br /&gt;5. Line End Cap calculation&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see the cap starts the line and ends it. Because I am using GL_QUAD_STRIP then it is important to properly connect all the vertices together, and espcially make their total number base power of 4, because each quad consists of 4 points.&lt;br /&gt;&lt;br /&gt;There are usually 3 different cap styles:&lt;br /&gt;&lt;br /&gt;1. None (the cap vertexes  are created at origin of the start/end point) [2 vertexes]&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/R0IAWAqOwBI/AAAAAAAAAFY/rTVDrPCyifU/s1600-h/Cap_none.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/R0IAWAqOwBI/AAAAAAAAAFY/rTVDrPCyifU/s400/Cap_none.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134666903290036242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. Square (the cap vertexes are created at the same origin but with an offset equal the the line width)[2 vertexes]&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/R0IAWQqOwCI/AAAAAAAAAFg/qa2a_aS2C0U/s1600-h/Cap_Square.PNG"&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/R0IAWQqOwCI/AAAAAAAAAFg/qa2a_aS2C0U/s400/Cap_Square.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134666907585003554" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. Round (the cap vertexes form half-arc at the origin of the start/end point)[2 + 2*iterations vertexes]&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/R0IAWgqOwDI/AAAAAAAAAFo/OC7Xhao2EmM/s1600-h/Cap_Round.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/R0IAWgqOwDI/AAAAAAAAAFo/OC7Xhao2EmM/s400/Cap_Round.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134666911879970866" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So The first thing that is required - the general cap function:&lt;br /&gt;&lt;br /&gt; &lt;span style="color:#009900;"&gt;//Calculates cap for the line&lt;br /&gt; void CalculateCap(  LineVertex v0,&lt;br /&gt;                                         LineVertex v1,&lt;br /&gt;                                         bool start ) //decides is this cap starts the line = true or ends = false&lt;br /&gt; {&lt;br /&gt;&lt;br /&gt;       float len = CalculateDistance( v0 , v1 );&lt;br /&gt;&lt;br /&gt;       float dx1 = (v1.posY - v0.posY) / len;&lt;br /&gt;           float dy1 = (v1.posX - v0.posX) / len;&lt;br /&gt;           float dx2 = 0;&lt;br /&gt;           float dy2 = 0;&lt;br /&gt;&lt;br /&gt;           dx1 *= _size;&lt;br /&gt;           dy1 *= _size;&lt;br /&gt;&lt;br /&gt;          if( _capStyle != CapStyle_Round)&lt;br /&gt;         {&lt;br /&gt;                       if( _capStyle == CapStyle_Square)&lt;br /&gt;                 {&lt;br /&gt;                          dx2 = dy1 ;&lt;br /&gt;                          dy2 = dx1 ;&lt;br /&gt;                 }&lt;br /&gt;&lt;br /&gt;          if( start )&lt;br /&gt;         {&lt;br /&gt;               AddVertex( v0.posX + dx1 - dx2, v0.posY - dy1 - dy2);&lt;br /&gt;               AddVertex( v0.posX - dx1 - dx2, v0.posY + dy1 - dy2);&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;        {&lt;br /&gt;              //end of path&lt;br /&gt;             AddVertex( v0.posX - dx1 - dx2, v0.posY + dy1 - dy2);&lt;br /&gt;             AddVertex( v0.posX + dx1 - dx2, v0.posY - dy1 - dy2);&lt;br /&gt;        }&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;      //Converts radian result of atan2 to Deg we need for comaring later&lt;br /&gt;          float subAngle = -(TRIG_RAD2DEG( atan2( dx1 , dy1 ) ) - 180);&lt;br /&gt;&lt;br /&gt;     //simple but does check the direction of the line edge&lt;br /&gt;      if( (subAngle &gt; 90 )&amp;amp;&amp;amp;( subAngle &lt;= 270 ) )         &lt;br /&gt;      {               &lt;br /&gt;             if( start )              &lt;br /&gt;            {                    &lt;br /&gt;                    CalculateRound(   v0 ,                                                       &lt;br /&gt;                                                   dx1, -dy1 ,                                                      &lt;br /&gt;                                                  -dx1, dy1 ,                                                      &lt;br /&gt;                                                   v0.posX + dx1 ,                                                      &lt;br /&gt;                                                   v0.posY - dy1 ,                                                      &lt;br /&gt;                                                   true );             &lt;br /&gt;           }            &lt;br /&gt;          else                   &lt;br /&gt;               {                           &lt;br /&gt;                   CalculateRound(  v0 ,                                                            &lt;br /&gt;                                                  dx1, -dy1 ,                                                          &lt;br /&gt;                                                 -dx1, dy1 ,                                                           &lt;br /&gt;                                                 v0.posX - dx1 ,                                                           &lt;br /&gt;                                                 v0.posY + dy1 ,                                                          &lt;br /&gt;                                                  true );                   &lt;br /&gt;               }       &lt;br /&gt;      }      &lt;br /&gt;     else           &lt;br /&gt;          {                  &lt;br /&gt;                    if( start )              &lt;br /&gt;                    {                       &lt;br /&gt;                                 CalculateRound( v0 ,                                                        &lt;br /&gt;                                                             -dx1, dy1 ,                                                          &lt;br /&gt;                                                              dx1, -dy1 ,                                                        &lt;br /&gt;                                                              v0.posX - dx1 ,                                                         &lt;br /&gt;                                                              v0.posY + dy1 ,                                                         &lt;br /&gt;                                                              false );             &lt;br /&gt;                     }             &lt;br /&gt;                     else                  &lt;br /&gt;                          {                                &lt;br /&gt;                                  CalculateRound( v0 ,                                                                &lt;br /&gt;                                                              -dx1, dy1 ,                                                                 &lt;br /&gt;                                                               dx1, -dy1 ,                                                                  &lt;br /&gt;                                                               v0.posX + dx1 ,                                                                  &lt;br /&gt;                                                              v0.posY - dy1 ,                                                                  &lt;br /&gt;                                                               false );                 &lt;br /&gt;                          }           &lt;br /&gt;             }              &lt;br /&gt;      }  &lt;br /&gt;}&lt;/span&gt;  &lt;br /&gt;&lt;br /&gt;This general function finds the result vertexes this way: &lt;br /&gt;&lt;br /&gt;1. Finds relative position of the initial vertexes. Exactly the same way as it was made with "None" line join. &lt;br /&gt;&lt;br /&gt;2.Now depending on the Cap style:      &lt;br /&gt;&lt;br /&gt;  None     - Just use these calculated vertexes and add them to the render buffer.     &lt;br /&gt;  Square  - Apply line width multiplier and add them to the render buffer.     &lt;br /&gt;   Round  - This is more complicated:      &lt;br /&gt;&lt;br /&gt;For round join the renderer needs to calculate arc: &lt;br /&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;void CalculateRound(    &lt;br /&gt;                                         LineVertex v0,           //center of the line join                                               &lt;br /&gt;                                         float dx1, float dy1,  //the start point                                               &lt;br /&gt;                                         float dx2, float dy2,  //the end point                                              &lt;br /&gt;                                         float middleX ,                                               &lt;br /&gt;                                         float middleY ,     //The middle point for creating correct GL_QUAD vertex                                    bool reverse)    //use reverse incase of inner join&lt;br /&gt; &lt;br /&gt;{              &lt;br /&gt;&lt;br /&gt;          float a1 = TRIG_RAD2DEG( atan2( dy1 , dx1 ));                   &lt;br /&gt;          float a2 = TRIG_RAD2DEG( atan2( dy2 , dx2 ));                   &lt;br /&gt;&lt;br /&gt;          float angleStep =  (a1 - a2) ;                //number of iterations              &lt;br /&gt;          angleStep = angleStep / (iterations + 1)  ;               //starting angle              &lt;br /&gt;          float cangle = 0;              &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;           if( reverse )            &lt;br /&gt;          {                   &lt;br /&gt;                     //INNER JOIN                   &lt;br /&gt;                     AddVertex( middleX , middleY );                  &lt;br /&gt;                     AddVertex( v0.posX - dx2 , v0.posY - dy2);                 &lt;br /&gt;&lt;br /&gt;                      a2 += 180;                 &lt;br /&gt;                      cangle =  a2 ;                       &lt;br /&gt;&lt;br /&gt;                    for(int i = 0; i &lt; iterations ; i++)               &lt;br /&gt;                   {                        &lt;br /&gt;                            cangle += angleStep;                               //Also put the middle point for the GL to correctly link other GL_QUAD later                       &lt;br /&gt;                          AddVertex( middleX , middleY );                           //find the rotated point                               AddVertex(                                         &lt;br /&gt;                                             _size * trig.Cos(cangle) + v0.posX ,                                              &lt;br /&gt;                                             _size * trig.Sin(cangle) + v0.posY );                   &lt;br /&gt;                   }               &lt;br /&gt;&lt;br /&gt;                         AddVertex( middleX , middleY );               &lt;br /&gt;                         AddVertex( v0.posX - dx1, v0.posY - dy1);         &lt;br /&gt;          }         &lt;br /&gt;          else        &lt;br /&gt;               {                 &lt;br /&gt;                       //OUTER JOIN                 &lt;br /&gt;                      AddVertex( v0.posX + dx1 , v0.posY + dy1);                 &lt;br /&gt;                      AddVertex( middleX , middleY );                 //change the direction of angle iteration               &lt;br /&gt;                      angleStep *= -1;               &lt;br /&gt;                      cangle =  a1 ;               &lt;br /&gt;&lt;br /&gt;                      for(int i = 0; i &lt; iterations ; i++)             &lt;br /&gt;                     {                      &lt;br /&gt;                            cangle += angleStep;                             //find the rotated point                    &lt;br /&gt;&lt;br /&gt;                            AddVertex(                                            &lt;br /&gt;                                              _size * trig.Cos(cangle) + v0.posX ,                                            &lt;br /&gt;                                             _size * trig.Sin(cangle) + v0.posY );                    //Also put the middle point for the GL to correctly link other GL_QUAD later                   &lt;br /&gt;&lt;br /&gt;                           AddVertex( middleX , middleY );                        &lt;br /&gt;                   }                   &lt;br /&gt;&lt;br /&gt;                            AddVertex( v0.posX + dx2, v0.posY + dy2);              &lt;br /&gt;                            AddVertex( middleX , middleY );             &lt;br /&gt;           }  &lt;br /&gt; }  &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The arc calculation is not that hard. For this we need to have the center point, the start and end point. The middleX and middleY are used as an additional point to connect quad with. &lt;br /&gt;&lt;br /&gt;We also need to find the start angle from where to start iteration and the end angle when to end.&lt;br /&gt;&lt;br /&gt;Each iterations adds additional 2 vertexes.  If you look closely for the iteration code, you would see that it generates minimum 4 vertexes.  The first 2 vertexes are actually at the same point, they start the cap, then there are iteration vertexes and at the end 2 more for opening the next 2 vertexes &lt;br /&gt;&lt;br /&gt;The order of drawing for 3 iterations is shown next. This is for the start cap with values:  &lt;br /&gt;&lt;br /&gt;CalculateRound( v0 ,                                       &lt;br /&gt;                              dx1, -dy1 ,                                       &lt;br /&gt;                              -dx1, dy1 ,                                       &lt;br /&gt;                              v0.posX + dx1 ,                                       &lt;br /&gt;                              v0.posY - dy1 ,                                       &lt;br /&gt;                              true );  &lt;br /&gt;&lt;br /&gt;Initial state:&lt;br /&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/R0IAWAqOwAI/AAAAAAAAAFQ/wKPznp5f1CU/s1600-h/initial_points.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/R0IAWAqOwAI/AAAAAAAAAFQ/wKPznp5f1CU/s400/initial_points.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134666903290036226" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1. First 2 vertexes and iteration 0&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/R0IBBAqOwEI/AAAAAAAAAFw/U7HL6PXUWxU/s1600-h/after_1.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/R0IBBAqOwEI/AAAAAAAAAFw/U7HL6PXUWxU/s400/after_1.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134667642024411202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. Iteration 1&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/R0IBBgqOwFI/AAAAAAAAAF4/OSbMZYM0wQ0/s1600-h/after_2.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/R0IBBgqOwFI/AAAAAAAAAF4/OSbMZYM0wQ0/s400/after_2.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134667650614345810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. Iteration 2&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/R0IBBgqOwGI/AAAAAAAAAGA/2Z9sY8jIUMs/s1600-h/after_3.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/R0IBBgqOwGI/AAAAAAAAAGA/2Z9sY8jIUMs/s400/after_3.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134667650614345826" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4. And now the end 2 vertexes are calculated&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/R0IBBwqOwHI/AAAAAAAAAGI/IR3ycaJ-9qg/s1600-h/after_end.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/R0IBBwqOwHI/AAAAAAAAAGI/IR3ycaJ-9qg/s400/after_end.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5134667654909313138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is probably all that is required for rendering line cap styles.</description><link>http://dminator.blogspot.com/2007/11/line-cap-calculation.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-292676623042861569</guid><pubDate>Wed, 07 Nov 2007 19:31:00 +0000</pubDate><atom:updated>2007-11-08T21:30:28.881+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Line</category><category domain="http://www.blogger.com/atom/ns#">rendering</category><category domain="http://www.blogger.com/atom/ns#">miter</category><category domain="http://www.blogger.com/atom/ns#">round</category><category domain="http://www.blogger.com/atom/ns#">join</category><category domain="http://www.blogger.com/atom/ns#">bevel</category><category domain="http://www.blogger.com/atom/ns#">GE2</category><title>Line rendering Join calculation</title><description>For the past few weeks, I have been working on the new line join rendering system.&lt;br /&gt;&lt;br /&gt;This was required for the GUI system, because right now it is using only the most basic method, with huge noticeable cracks between line. I was also always wondering how it would be possible to make this line rendering happen. I haven't found allot of sources. There is only one source I used mainly for this. It is &lt;a href="http://www.antigrain.com/"&gt;AntiGrain project&lt;/a&gt;. This is really awesome rendering library that features vast number of different shapes. I used the join rendering system from there:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.antigrain.com/__code/include/agg_math_stroke.h.html"&gt;Math Stroke.H&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.antigrain.com/__code/src/agg_vcgen_stroke.cpp.html"&gt;VCGen stroke.cpp&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.antigrain.com/__code/include/agg_vcgen_stroke.h.html"&gt;VCgen stroke.H&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.antigrain.com/__code/include/agg_math.h.html"&gt;Agg Math.h&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is GPL project so source code learning is a must.&lt;br /&gt;&lt;br /&gt;I haven't figured out exactly how the rendering in the AGG works, but I managed to get a few pointers and a few handy functions, that I am using in my own implementation right now.&lt;br /&gt;&lt;br /&gt;Ok, first let's take the simple path of lines that are connected with each other:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlMI/AAAAAAAAAEI/s7eVYX8XddY/s1600-h/line_render_idea.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlMI/AAAAAAAAAEI/s7eVYX8XddY/s400/line_render_idea.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550554792400066" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are 9 lines each connected with different angle. Let's imagine the line size is increased. How the line would look like.&lt;br /&gt;&lt;br /&gt;The current approach I am using right now, would produce something like that:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlNI/AAAAAAAAAEQ/gPTpNSvidy4/s1600-h/line_render_none.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlNI/AAAAAAAAAEQ/gPTpNSvidy4/s400/line_render_none.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550554792400082" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is what I call "None" join style, because the vertices aren't connected to each other.&lt;br /&gt;&lt;br /&gt;How it was calculated ?&lt;br /&gt;&lt;br /&gt;Well it is done in specific order:&lt;br /&gt;&lt;br /&gt;1. Line Start Cap calculation&lt;br /&gt;2. Join vertex calculation n1&lt;br /&gt;3. ...&lt;br /&gt;4. Join vertex calculation n1 + joinNum&lt;br /&gt;5. Line End Cap calculation&lt;br /&gt;&lt;br /&gt;There is also different cap styles, for now I would only use the default none. Which creates 2 vertices for the start and end cap.&lt;br /&gt;&lt;br /&gt;For this specific line example the vertices would be calculated in this order:&lt;br /&gt;1.  Cap (2) - none cap&lt;br /&gt;2.  A+B (4)&lt;br /&gt;3.  B+C (4)&lt;br /&gt;4.  C+D (4)&lt;br /&gt;5.  D+E (4)&lt;br /&gt;6.  E+F (4)&lt;br /&gt;7.  F+G (4)&lt;br /&gt;8.  G+H (4)&lt;br /&gt;9.  H+I (4)&lt;br /&gt;10. Cap (2) - none cap&lt;br /&gt;&lt;br /&gt;There is total of 36 vertices required.&lt;br /&gt;&lt;br /&gt;Here is how the code would look for this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;//calculate the data&lt;br /&gt; void Calculate()&lt;br /&gt; {&lt;br /&gt;       //fully clear the rendering array&lt;br /&gt;       _renderVertex.Cleanup();&lt;br /&gt;  &lt;br /&gt;       //START THE CAP&lt;br /&gt;&lt;br /&gt;      //atleast 2 points required&lt;br /&gt;      if( _vertexes.GetLength() &lt; 2 )&lt;br /&gt;     {&lt;br /&gt;          return;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;     //GENERATE START CAP&lt;br /&gt;     CalculateCap( _vertexes[0] , _vertexes[1] , true );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     for(int i = 1; i &lt; _vertexes.GetLength() - 1; i++)&lt;br /&gt;    {&lt;br /&gt;           //CALCULATE JOINS&lt;br /&gt;           CalculateJoin( _vertexes[ i - 1] ,&lt;br /&gt;                                         _vertexes[ i + 0] ,&lt;br /&gt;                                         _vertexes[ i + 1] );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  //GENERATE END CAP&lt;br /&gt;  CalculateCap( _vertexes[ _vertexes.GetLength() - 1] , _vertexes[ _vertexes.GetLength() - 2] , false );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Join calculation itself, only needs to do few things. Calculate the distance between points is the first thing to do:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;float len1 = CalculateDistance( v0 , v1 );&lt;br /&gt;  float len2 = CalculateDistance( v1 , v2 );&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now if we have the distance we can calculate the rotated angle, like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;float dx1 = _size * (v1.posY - v0.posY) / len1;&lt;br /&gt;       float dy1 = _size * (v1.posX - v0.posX) / len1;&lt;br /&gt;       float dx2 = _size * (v2.posY - v1.posY) / len2;&lt;br /&gt;       float dy2 = _size * (v2.posX - v1.posX) / len2;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note the _size here is the width of the line.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;After that we need to calculate only the line points relation. They are either inner or outer join:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlOI/AAAAAAAAAEY/JsWWyOCfJG4/s1600-h/join_mode.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlOI/AAAAAAAAAEY/JsWWyOCfJG4/s400/join_mode.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550559087367394" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This can be done by calculate something like cross product. I have taken this from AGG:&lt;br /&gt;&lt;br /&gt; float cp = CrossProduct2D( v0.posX, v0.posY, v1.posX, v1.posY, v2.posX, v2.posY );&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;float CrossProduct2D(&lt;br /&gt;                                             const float&amp;amp; ax, const float&amp;amp; ay, //1 LINE&lt;br /&gt;                                             const float&amp;amp; bx, const float&amp;amp; by, //2 LINE&lt;br /&gt;                                             const float&amp;amp; cx, const float&amp;amp; cy ) //3 LINE&lt;br /&gt;{&lt;br /&gt;   return (cx - bx) * (by - ay) - (cy - by) * (bx - ax);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And now we can calculate the vertices itself, depending on the join style:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;if(cp != 0 &amp;amp;&amp;amp; (cp &gt; 0) == (_size &gt; 0))&lt;br /&gt;       {&lt;br /&gt;&lt;br /&gt;     // INNER JOIN&lt;br /&gt;     //just 2 vertices for end&lt;br /&gt;     AddVertex( v1.posX + dx1, v1.posY - dy1); //1&lt;br /&gt;     AddVertex( v1.posX - dx1, v1.posY + dy1); //2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     //and 2 vertices for start of another line&lt;br /&gt;     AddVertex( v1.posX + dx2, v1.posY - dy2); //3&lt;br /&gt;     AddVertex( v1.posX - dx2, v1.posY + dy2); //4&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;     // OUTER JOIN&lt;br /&gt;     //just 2 vertices for the end of first line&lt;br /&gt;     AddVertex( v1.posX + dx1, v1.posY - dy1); //1&lt;br /&gt;     AddVertex( v1.posX - dx1, v1.posY + dy1); //2&lt;br /&gt;&lt;br /&gt;     //and 2 vertices for start of another line&lt;br /&gt;     AddVertex( v1.posX + dx2, v1.posY - dy2); //3&lt;br /&gt;     AddVertex( v1.posX - dx2, v1.posY + dy2); //4&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first 2 vertices close to the previous quad and the next 2 opens the new one.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlPI/AAAAAAAAAEg/1EQk4hs8LNs/s1600-h/join_start.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlPI/AAAAAAAAAEg/1EQk4hs8LNs/s400/join_start.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550559087367410" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlQI/AAAAAAAAAEo/oZF9QtxO3Vk/s1600-h/join_end.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RzNgjPiVlQI/AAAAAAAAAEo/oZF9QtxO3Vk/s400/join_end.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550559087367426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This would continue this way untill the end cap is reached, which closes the quad. It is important to properly close the quads. Atleast with my video drivers it caused some really dangerous issues, when the computer screen started to flicker or it crashed and restarted. So additional caution is required.&lt;br /&gt;&lt;br /&gt;And here is how it looks when it is done:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlNI/AAAAAAAAAEQ/gPTpNSvidy4/s1600-h/line_render_none.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RzNgi_iVlNI/AAAAAAAAAEQ/gPTpNSvidy4/s400/line_render_none.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5130550554792400082" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So far for the most simple way :). I think I would also explain later how the more advanced ways of rendering line joins can be done.</description><link>http://dminator.blogspot.com/2007/11/line-rendering-join-calculation.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-5154567240610446516</guid><pubDate>Fri, 21 Sep 2007 18:07:00 +0000</pubDate><atom:updated>2007-09-21T22:45:20.414+03:00</atom:updated><title>Game States in GE2</title><description>This time I would like to explain a little about the game state system used in Galactic Engine 2. It is working well right now, however wasn't been tested in fairly complicated states so it may contain some bugs.&lt;br /&gt;&lt;br /&gt;Game states are used by the game developer to write the logic for the engine to use.&lt;br /&gt;There can be many game states  however only one is active. The user can decide which state he&lt;br /&gt;wants to use and when. The game states system for the GE2 was inspired by the &lt;a href="http://www.ogre3d.org/wiki/index.php/Managing_Game_States_with_OGRE"&gt;OGRE implementation&lt;/a&gt; and has similar logic behind it.&lt;br /&gt;&lt;br /&gt;In the GE2 GameState is base abstract class. It receives the events from the engine or input system. The user can the decide what he wants to do with the received data.&lt;br /&gt;&lt;br /&gt;Here are some functions that base abstract GameState class has:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;void OnConstruct();&lt;br /&gt;void OnDeConstruct();&lt;br /&gt;&lt;br /&gt;//called when entering this state or leaving it&lt;br /&gt;void OnEntry();&lt;br /&gt;void OnExit();&lt;br /&gt;&lt;br /&gt;//draws opengl stuff&lt;br /&gt;void OnDraw();&lt;br /&gt;&lt;br /&gt;//updates game logic&lt;br /&gt;void OnUpdate();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//Keyboard&lt;br /&gt;void OnKeyDown ( const GE2_Key &amp;amp;key );&lt;br /&gt;void OnKeyUp ( const GE2_Key &amp;amp;key);&lt;br /&gt;&lt;br /&gt;//Mouse&lt;br /&gt;void OnMoseMove (float &amp;amp;x, float &amp;amp;y, float &amp;amp;deltax, float &amp;amp;deltay);&lt;br /&gt;void OnMoseDown (float &amp;amp;x, float &amp;amp;y, Uint8&amp;amp; mouseButton);&lt;br /&gt;void OnMoseUp (float &amp;amp;x, float &amp;amp;y, Uint8&amp;amp; mouseButton);&lt;br /&gt;&lt;br /&gt;void OnQuit();&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;When user wants to use GameState he needs to inherit the base GameState class&lt;br /&gt;and make his own, like this:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;class MyGameState : public GameState&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;and override the function that he wants to use. For example if I want to draw a simple OpenGL drawing. I need to do this:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="color:#009900;"&gt;&lt;i&gt;&lt;span&gt;void MyGameState::OnDraw()&lt;br /&gt;{&lt;br /&gt;   //Drawing Code here&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;and if I want to get a keyboard event then something like this:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color:#009900;"&gt;&lt;span&gt;&lt;i&gt;void MyGameState::OnKeyDown( const GE2_Key &amp;amp;key )&lt;br /&gt;{&lt;br /&gt;     if( key == input.keys.F1 )&lt;br /&gt;     {&lt;br /&gt;           //Change to Full Screen&lt;br /&gt;           video.SetFullScreen( !video.IsFullScreen() );&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Now when the game state is defined all is needed is to pass it to the engine. This&lt;br /&gt;is required for any application of GE2. For example:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color:#009900;"&gt;&lt;span&gt;&lt;i&gt;void gameStart()&lt;br /&gt;{&lt;br /&gt;     //create my own game state&lt;br /&gt;     MyGameState myState;&lt;br /&gt;&lt;br /&gt;     stateManager.Start( &amp;amp;myState );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main( int argc, char* argv[] )&lt;br /&gt;{&lt;br /&gt;    //initiate engine through this function&lt;br /&gt;    global.startEngine( gameStart );&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;The gameStart() is required as separate function so the engine can check for memory leaks after the gameState ends, and also catch any exception automatically.&lt;br /&gt;&lt;br /&gt;Another thing game states are used for is the switching between states. Unfortunately I haven't tried this feature thoroughly , so it may cause some problems later, but the logic behind is really similar with OGRE. To switch to another state the user needs to call:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color:#009900;"&gt;&lt;span&gt;&lt;i&gt;//pushes new state on the stack and activates it&lt;br /&gt;stateManager.PushState( &amp;amp;myState );&lt;br /&gt;&lt;br /&gt;//removes the last state from the stack and deactivates it&lt;br /&gt;MyGameState *myState = stateManager.PopStat();&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;When the state is put on the stack the first time then OnConstruct() is called when it is removed then OnDeConstruct() is used. These functions are called only once so it is safe here to initialise all the variables or destruct them.&lt;br /&gt;&lt;br /&gt;The OnEntry() and OnExit() are used when the states are switched between.&lt;br /&gt;&lt;br /&gt;That's probably all there is.</description><link>http://dminator.blogspot.com/2007/09/game-states-in-ge2.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-3506839475893669529</guid><pubDate>Mon, 03 Sep 2007 21:35:00 +0000</pubDate><atom:updated>2007-09-04T02:14:23.828+03:00</atom:updated><title>Gradient calculation explained</title><description>In my previous post I have described how the gradient helped to solve few issues when creating skins for the GUI system. This time I would like to explain how the gradient is calculated.&lt;br /&gt;&lt;br /&gt;Previous generation GUI system was really primitive when it comes to drawing shapes. The biggest problem was probably calculating the color gradients. Because the shapes were created by raw GL_POLYGON data, each point parameters should be specified. This means for each point I had to write its UV coordinates, color value and position. Calculating the color was one of the most problematical parts of this process.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let’s for example say I have a simple rectangle with 4 points.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RtyRsNbb-uI/AAAAAAAAADI/GPYYfp3B8V4/s1600-h/4_points_rectangle.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RtyRsNbb-uI/AAAAAAAAADI/GPYYfp3B8V4/s400/4_points_rectangle.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116266236312290" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now If I wanted to make a good looking gradient color,  I had to manually calculate each point. For such simple rectangle this is not hard.&lt;br /&gt;&lt;br /&gt;For example let's pick the gradient top color &lt;i&gt;&lt;span&gt;&lt;span style="color:#cc0000;"&gt;RED=RGBA{1.0,0.0,0.0,1.0}&lt;/span&gt;&lt;/span&gt;&lt;/i&gt; and bottom with 0.0 alpha &lt;i&gt;&lt;span&gt;&lt;span style="color:#ffcccc;"&gt;RED={1.0,0.0,0.0,0.0}&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can easily calculate the 4 points of the shape:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color:#cc0000;"&gt;&lt;span&gt;&lt;i&gt;Point1 = RGBA{1.0,0.0,0.0,1.0}&lt;br /&gt;&lt;br /&gt;Point2 = RGBA{1.0,0.0,0.0,1.0}&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color:#ffcccc;"&gt;&lt;span&gt;&lt;i&gt;Point3 = RGBA{1.0,0.0,0.0,0.0}&lt;br /&gt;&lt;br /&gt;Point4 = RGBA{1.0,0.0,0.0,0.0}&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;The result is something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RtyRstbb-yI/AAAAAAAAADo/-LmArVeneLk/s1600-h/4_points_rectangle_vertical.PNG"&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/RtyRstbb-yI/AAAAAAAAADo/-LmArVeneLk/s400/4_points_rectangle_vertical.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116274826246946" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Usually however more complex shapes are used to define appearance of the GUI widgets. Take a simple rectangle with an arc on one of the edges. This makes calculation difficult especially when some day you would like to change the vertical gradient color to horizontal or even to linear gradient with angular rotation. Calculating colors now is really the job you would want to do the least.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RtyS7tbb-zI/AAAAAAAAADw/G-M11kbkiAc/s1600-h/4_points_rectangle_vertical_arc.PNG"&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/RtyS7tbb-zI/AAAAAAAAADw/G-M11kbkiAc/s400/4_points_rectangle_vertical_arc.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106117632035912498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The new GUI system tries to solve this problem, by calculating the colors automatically. Because the drawing of shapes is abstracted (user is using lines, circles, rectangles not the GL_POLYGON points directly) it is possible for the GUI system to calculate the points.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The only thing that user needs to define is the initial 2 gradient colors (start, end) and gradient type or angular rotation. The GUI system would do everything else.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I would like to describe this in more detail, how the vertex colors are calculated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am using 2 basic points for this. These points hold the initial color values and also the position relative to each other. This makes it possible to create different gradient widths and heights.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-vI/AAAAAAAAADQ/IkpC4LnkZT8/s1600-h/4_points_rectangle_base_points.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-vI/AAAAAAAAADQ/IkpC4LnkZT8/s400/4_points_rectangle_base_points.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116270531279602" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The downside is that because we are dealing with vertex points we loose some color values, depending on the number of total vertexes. To  better illustrate this imagine the circular gradient that is applied to simple 4 vertex rectangle. Because there are only 4 points it is not possible to describe the transition between them the same way as per pixel calculated image. The only way to improve this is to increase vertex size on the sides and with the shape itself. Another way is to apply texture . In the new GUI system however I decided not to use spherical gradient calculation because of these issues.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So right now I have only 3 gradient types – vertical , horizontal and angular.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Vertical gradient type is one of the most simplest.&lt;br /&gt;&lt;br /&gt;Each shape is created from line. Each line has 2 points. Basically the function loops and calculates color for each point.&lt;br /&gt;&lt;br /&gt;Before starting to calculate, we need to get 2 base gradient points – the most top left and bottom right points of the shape.&lt;br /&gt;The position of these points is relative to the maximum size of the shape so I use the shape left,top,width,height values for this.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;span style="color:#009900;"&gt;//here are positions of the gradient points&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;i&gt;RenderVertex gradientPos1 = GetVertexPosition( left , top , width , height , gradientPoint1 );&lt;br /&gt;RenderVertex gradientPos2 = GetVertexPosition( left , top , width , height , gradientPoint2 );&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;As a result I get absolute position x,y on the screen of each point&lt;br /&gt;&lt;br /&gt;When I have these 2 points I can find the distance between them in absolute coordinates:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//total horizontal distance between gradient points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;distv =  (gradientPos2.Y - gradientPos1.Y) ;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//ignore the sign value just incase&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;distv = fabs( distv );&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/RtyS79bb-0I/AAAAAAAAAD4/UABfp-guhXo/s1600-h/4_points_rectangle_vertical_distv.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/RtyS79bb-0I/AAAAAAAAAD4/UABfp-guhXo/s400/4_points_rectangle_vertical_distv.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106117636330879810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And when I got this, I can calculate the relative distance between the first top left points and the current point I am calculating:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;&lt;i&gt;&lt;span&gt;//now find the position of the point between them&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&lt;i&gt; &lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;if( distv == 0.0f )&lt;br /&gt;{&lt;br /&gt; posv  = 0.0f;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt; posv = (guiPoint.Y - gradientPos1.Y ) / distv;&lt;br /&gt;}&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/RtyS79bb-1I/AAAAAAAAAEA/e5Exz6wUaPI/s1600-h/4_points_rectangle_vertical_posv.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/RtyS79bb-1I/AAAAAAAAAEA/e5Exz6wUaPI/s400/4_points_rectangle_vertical_posv.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106117636330879826" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now when I have this posv I can apply it and find the result color interpolation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//calculate the color value now with simple interpolation&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;result.R =  gradColor1.R * (1.0f - posv) + gradColor2.R * posv;&lt;br /&gt;result.G =  gradColor1.G * (1.0f - posv) + gradColor2.G * posv;&lt;br /&gt;result.B =  gradColor1.B * (1.0f - posv) + gradColor2.B * posv;&lt;br /&gt;result.A =  gradColor1.A * (1.0f - posv) + gradColor2.A * posv;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RtyRstbb-yI/AAAAAAAAADo/-LmArVeneLk/s1600-h/4_points_rectangle_vertical.PNG"&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/RtyRstbb-yI/AAAAAAAAADo/-LmArVeneLk/s400/4_points_rectangle_vertical.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116274826246946" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The same way it works with the horizontal gradient type. This time however instead of using Height we use Width of the shape, but the process itself is exactly the same.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-wI/AAAAAAAAADY/nfXGuWJx8l4/s1600-h/4_points_rectangle_horizontal.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-wI/AAAAAAAAADY/nfXGuWJx8l4/s400/4_points_rectangle_horizontal.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116270531279618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A more complicated is the angular gradient calculation. For this we need additional parameter – angle in degrees. The user specifies the angle within range 0...360.&lt;br /&gt;&lt;br /&gt;We start the same way when calculatin vertical or horizontal gradient, but calculate both distances:&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//Find horizontal position first&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//total horizontal distance between gradient points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;disth =  (gradientPos2.X - gradientPos1.X) ;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//ignore the sign value just incase&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;disth = fabs( disth );&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//now find the position of the point between gradient points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( disth == 0.0f )&lt;br /&gt;{&lt;br /&gt; posh  = 0.0f;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt; posh = (guiPoint.X - gradientPos1.X ) / disth;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//Now find vertical position&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//total vertical distance between gradient points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;distv =  (gradientPos2.Y - gradientPos1.Y) ;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//ignore the sign value just incase&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;distv = fabs( distv );&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//now find the position of the point between gradient points&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( distv == 0.0f )&lt;br /&gt;{&lt;br /&gt; posv  = 0.0f;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt; posv = (guiPoint.Y - gradientPos1.Y ) / distv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The only thing left to do, is to calculate the rotated distances:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//make the angle within requested range&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;fangle = fabs(angle);&lt;br /&gt;&lt;br /&gt;if( fangle &gt; 360.0f)&lt;br /&gt;{&lt;br /&gt; fangle = 0.0f;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//the gltriangle size is 2Pi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;fangle = angle * 2;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;// 0 .. 90&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( (fangle &gt;= 0)&amp;&amp;amp;(fangle &lt; 180)&lt;br /&gt;&lt;span style="color:#009900;"&gt;//now rotate the point&lt;/span&gt;  &lt;br /&gt;posRot = posh * trig.GLTriangle( fangle + 180 ) + posv * trig.GLTriangle( fangle );&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;// 90 .. 180&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( (fangle &gt;= 180)&amp;&amp;amp;(fangle &lt; 360)&lt;br /&gt;&lt;span style="color:#009900;"&gt;//now rotate the point&lt;/span&gt;&lt;br /&gt; posRot = (1.0f - posh) * trig.GLTriangle( fangle + 180 ) + posv * trig.GLTriangle( fangle );&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;// 180 .. 270&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( (fangle &gt;= 360)&amp;&amp;amp;(fangle &lt; 540)&lt;br /&gt;&lt;span style="color:#009900;"&gt;//now rotate the point&lt;/span&gt;&lt;br /&gt; posRot = (1.0f - posh) * trig.GLTriangle( fangle + 180 ) + (1.0f - posv) * trig.GLTriangle( fangle );&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;// 270 .. 0&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;if( (fangle &gt;= 540) )&lt;br /&gt;{&lt;br /&gt;&lt;span&gt;&lt;span style="color:#009900;"&gt;//now rotate the point&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; posRot = posh * trig.GLTriangle( fangle + 180 ) + (1.0f - posv) * trig.GLTriangle( fangle );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;The trig.GLTriangle is a precalculated table of cos and sin values. I also change the sign depending on what angle is currently selected.&lt;br /&gt;&lt;br /&gt;With the posRot value I can get the required color value:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;result.R =  gradColor1.R * (1.0f - posRot) + gradColor2.R * posRot;&lt;br /&gt;result.G =  gradColor1.G * (1.0f - posRot) + gradColor2.G * posRot;&lt;br /&gt;result.B =  gradColor1.B * (1.0f - posRot) + gradColor2.B * posRot;&lt;br /&gt;result.A =  gradColor1.A * (1.0f - posRot) + gradColor2.A * posRot;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;That's it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-xI/AAAAAAAAADg/GIuWXm9jcio/s1600-h/4_points_rectangle_linear.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RtyRsdbb-xI/AAAAAAAAADg/GIuWXm9jcio/s400/4_points_rectangle_linear.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5106116270531279634" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is only a small feature of the new GUI system, however it makes a big difference when creating GUI skins, because it takes significiant portion of the work from the designer.</description><link>http://dminator.blogspot.com/2007/09/gradient-calculation-explained.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-2588251015963281186</guid><pubDate>Mon, 20 Aug 2007 20:33:00 +0000</pubDate><atom:updated>2007-08-21T00:24:32.259+03:00</atom:updated><title>Color themes and gradient power.</title><description>Hey!&lt;br /&gt;&lt;br /&gt;This time I would like to talk how the shapes are getting drawn using the list of color themes.&lt;br /&gt;&lt;br /&gt;The new GUI system includes a color theme support. Generally you define a unique color for each element of the widget shape. All the unique colors are stored in one list. By making another list with the same color names but with different color values, it is possible to apply new color values  to the GUI widgets without making changes within the widget itself.&lt;br /&gt;&lt;br /&gt;I made a separate file which is part of the skin. By default it is called themes.cfg .&lt;br /&gt;It holds different themes and each of them can hold different color values. Like this:&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color:#006600;"&gt;&lt;span&gt;&lt;span&gt;&lt;i&gt;&amp;lt;theme&amp;gt;&lt;br /&gt;                 name = "default"&lt;br /&gt;             &amp;lt;colors&amp;gt;&lt;br /&gt;                      window_fill                          = RGBA{ 0.4 , 0.4 , 0.4 , 1.0 }&lt;br /&gt;                     button_fill                             = RGBA{ 0.5 , 0.5 , 0.5 , 1.0 }&lt;br /&gt;                     button_hover_start_fill    = RGBA{ 0.0 , 1.0 , 0.0 , 0.1 }&lt;br /&gt;                     button_hover_end_fill        = RGBA{ 0.0 , 1.0 , 0.0 , 0.0 }&lt;br /&gt;      &amp;lt;/colors&amp;gt;&lt;br /&gt;&amp;lt;/theme&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;theme&amp;gt;&lt;br /&gt;      name = "blue"&lt;br /&gt;       &amp;lt;colors&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;i&gt;&amp;gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;                      window_fill                        = RGBA{ 0.0 , 0.0 , 0.4 , 1.0 }&lt;br /&gt;                      button_fill                          = RGBA{ 0.2 , 0.2 , 0.5 , 1.0 }&lt;br /&gt;                      button_hover_start_fill  = RGBA{ 0.0 , 0.0 , 1.0 , 0.1 }&lt;br /&gt;                      button_hover_end_fill     = RGBA{ 0.0 , 0.0 , 1.0 , 0.0 }&lt;br /&gt;      &amp;lt;/colors&amp;gt;&lt;br /&gt;&amp;lt;/theme&amp;gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;It is really easy and straightforward to change these values or add another theme.&lt;br /&gt;&lt;br /&gt;The gradient effect is created using only 2 colors from the theme table.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RsoCmtbb-qI/AAAAAAAAACo/et8wg2-EndE/s1600-h/gui_circle.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RsoCmtbb-qI/AAAAAAAAACo/et8wg2-EndE/s400/gui_circle.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5100892392003467938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see on this picture there are 2 points. Generally they are  used for defining the gradient and texture coordinate values. They are referenced in the strokes.cfg file:&lt;br /&gt;&lt;i&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="color:#006600;"&gt;&lt;i&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span&gt;&amp;lt;frame&amp;gt;&lt;br /&gt;           gradient = "vertical"&lt;br /&gt;            &amp;lt;point&amp;gt;&lt;br /&gt;                   theme = "button_hover_start_fill"&lt;br /&gt;                   uv = UV{ 0.0 , 0.0 }&lt;br /&gt;            &amp;lt;/point&amp;gt;&lt;br /&gt;            &amp;lt;point&amp;gt;&lt;br /&gt;                   theme = "button_hover_end_fill"&lt;br /&gt;                   uv = UV{ 1.0 , 1.0 }&lt;br /&gt;            &amp;lt;/point&amp;gt;&lt;br /&gt;&amp;lt;/frame&amp;gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;i&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;As you can see the shape is defined here using vertical gradient type.&lt;br /&gt;The color values for each vertex are interpolated depending on the initial point color values and the vertex position relative to the point1 and point2.&lt;br /&gt;&lt;br /&gt;There are also other different gradient types that can be used for defining shape appearance:&lt;br /&gt;&lt;br /&gt;Solid - only point1 color is used:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RsoCm9bb-sI/AAAAAAAAAC4/NGLSa7B04Fw/s1600-h/gui_circle_solid.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RsoCm9bb-sI/AAAAAAAAAC4/NGLSa7B04Fw/s400/gui_circle_solid.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5100892396298435266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Horizontal:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RsoCmtbb-rI/AAAAAAAAACw/BaDVozqY06Y/s1600-h/gui_circle_horizontal.PNG"&gt;&lt;img src="http://bp1.blogger.com/_EgthN2gZ80s/RsoCmtbb-rI/AAAAAAAAACw/BaDVozqY06Y/s400/gui_circle_horizontal.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5100892392003467954" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Linear - this is where it is possible to define the gradient angle = 0..360 degrees:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RsoCm9bb-tI/AAAAAAAAADA/a7bPG9QExpY/s1600-h/gui_circle_linear.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RsoCm9bb-tI/AAAAAAAAADA/a7bPG9QExpY/s400/gui_circle_linear.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5100892396298435282" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is probably all there is to know about the gradient and colors in the new GUI system.</description><link>http://dminator.blogspot.com/2007/08/color-themes-and-gradient-power.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-5589827755850732166</guid><pubDate>Thu, 02 Aug 2007 21:04:00 +0000</pubDate><atom:updated>2007-08-03T01:34:54.211+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Line</category><category domain="http://www.blogger.com/atom/ns#">antialiasing</category><category domain="http://www.blogger.com/atom/ns#">AA</category><category domain="http://www.blogger.com/atom/ns#">OpenGL</category><category domain="http://www.blogger.com/atom/ns#">Vector</category><category domain="http://www.blogger.com/atom/ns#">GUI</category><title>Finally an update !</title><description>It has been a while since I have updated this blog. Well the primary reason is, that I was working on the new GUI system and at that time there wasn't anything that could be shown.&lt;br /&gt;&lt;br /&gt;But it is progressing and I can show a few early screenshots.&lt;br /&gt;&lt;br /&gt;The old GUI systems worked fairly well, but had a few flaws. I tried to avoid these problems and add more functionality this time.&lt;br /&gt;&lt;br /&gt;One of the major problem in the old GUI was the rendering system. The GUI skin was one big file. It included description of how to render each widget and for each different state. There were generally 4 states: normal , disabled , hover , clicked. Each state is drawn by GL_POLYGON and all the points should be specified directly with (Color,Texture coordinate,position on the 2d screen and anchor). &lt;br /&gt;&lt;br /&gt;The new GUI however tries to minimize the amount of data that needs to be written. This is achieved by creating one stroke object that would later be used to draw different parts of many widgets, but it only needs to be defined once.&lt;br /&gt;&lt;br /&gt;The widget shape is created from the list of these strokes. The stroke itself is made from many 2d primitive shapes like: line , rectangle , round rectangle , circle , ellipse , arc and bezier. The amount of the data that needs to be written to define a stroke is minimum.&lt;br /&gt;&lt;br /&gt;Here is an example of the stroke created from 2 bezier curves:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RrJOCA2bfVI/AAAAAAAAACI/LyIVR6AtgvI/s1600-h/vector_gui_both_AA.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_EgthN2gZ80s/RrJOCA2bfVI/AAAAAAAAACI/LyIVR6AtgvI/s400/vector_gui_both_AA.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5094219925004451154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Each bezier curve is defined by 4 points. The GUI also allows to change the quality of shapes.&lt;br /&gt;&lt;br /&gt;The previous shape was created from 16 iterations this is created from 8:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/RrJRaQ2bfWI/AAAAAAAAACQ/JwS67p1sVcs/s1600-h/vector_gui_quality_8.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_EgthN2gZ80s/RrJRaQ2bfWI/AAAAAAAAACQ/JwS67p1sVcs/s400/vector_gui_quality_8.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5094223640151162210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Each shape except line and rectangle can have different quality versions.&lt;br /&gt;&lt;br /&gt;One of the most important additions to the GUI rendering system is the material system. The GUI uses the same material system that is used in any other engine part.&lt;br /&gt;This makes it possible to create all sorts of animation effects. The texture coordinates , gradient and alpha values are generated automatically:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_EgthN2gZ80s/RrJSPg2bfXI/AAAAAAAAACY/vmEVVvo72E8/s1600-h/vector_gui_texture.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_EgthN2gZ80s/RrJSPg2bfXI/AAAAAAAAACY/vmEVVvo72E8/s400/vector_gui_texture.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5094224554979196274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One of the most annoying issues when making GUI systems, especially with OpenGL is the lack of good line drawing functionality. The standard line drawing implementation is really limited. Not only it doesn't guarantee some line widths to be available, but the width itself is related directly to pixel width. Which makes it looks different on different resolutions. The other problem is antialiasing of the line. It is widely supported by most graphic cards this day, however their implementation depends on the graphic card manufacturer driver version, and can produce different results.&lt;br /&gt;&lt;br /&gt;The line drawing system that I am using here is created by two 4 vertex quads. Original drawing with one 4 vertex quad produced really noticeable jagged lines. However by adding additional quad and using blending, made it look really well, without almost any performance impact. It would also work on any OpenGL implementation and on any resolution the same correct way:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RrJWzA2bfYI/AAAAAAAAACg/JlGM0j1SEdE/s1600-h/GUI_Antialias_comp.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_EgthN2gZ80s/RrJWzA2bfYI/AAAAAAAAACg/JlGM0j1SEdE/s400/GUI_Antialias_comp.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5094229562911063426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I would probably make some more posts soon, if I manage to get something new working :)</description><link>http://dminator.blogspot.com/2007/08/finally-update.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-7968553542958084399</guid><pubDate>Sun, 27 May 2007 22:40:00 +0000</pubDate><atom:updated>2007-05-28T01:57:36.539+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">freetype2 font dpi lib build dll</category><title>FreeType2 support added</title><description>The new improvement, that I have just finished is the FreeType2 library fonts.&lt;br /&gt;&lt;br /&gt;I can now say that figuring the API wasn't so easy. The hardest part for me was the metrics system. There are so many things like widths, advances , dpi and so on, so it took me quite some time to just get an overall picture. One of the best sources for figuring everything out was &lt;a href="http://videogameprogramming.blogspot.com/2007/04/fast-truetype-fonts-using-freetype.html"&gt;this post by Brian Lawson&lt;/a&gt; it is well written and easy enough to follow.&lt;br /&gt;&lt;br /&gt;The new fonts with freetype2 are really looking great, not only it produces much higher quality glyphs, but generally it takes less space then usual bitmap textures I used before. It is also possible to change font resolution on the fly or with config option.&lt;br /&gt;&lt;br /&gt;Here are some sample images at different DPI values:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_EgthN2gZ80s/RloJaK--BVI/AAAAAAAAABg/9CUGjXvPAr0/s1600-h/font_dpi_50_50.PNG"&gt;&lt;img src="http://bp2.blogger.com/_EgthN2gZ80s/RloJaK--BVI/AAAAAAAAABg/9CUGjXvPAr0/s320/font_dpi_50_50.PNG" alt="" id="BLOGGER_PHOTO_ID_5069374675788629330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_EgthN2gZ80s/RloJaa--BWI/AAAAAAAAABo/NsehXUsNqIM/s1600-h/font_dpi_100_100.PNG"&gt;&lt;img src="http://bp3.blogger.com/_EgthN2gZ80s/RloJaa--BWI/AAAAAAAAABo/NsehXUsNqIM/s320/font_dpi_100_100.PNG" alt="" id="BLOGGER_PHOTO_ID_5069374680083596642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_EgthN2gZ80s/RloJaq--BXI/AAAAAAAAABw/HX4Ya_XYrEM/s1600-h/font_dpi_300_300.PNG"&gt;&lt;img src="http://bp0.blogger.com/_EgthN2gZ80s/RloJaq--BXI/AAAAAAAAABw/HX4Ya_XYrEM/s320/font_dpi_300_300.PNG" alt="" id="BLOGGER_PHOTO_ID_5069374684378563954" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;These values can be easily altered in the config here:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;i&gt;&lt;span&gt;&lt;span&gt;dpih    = 100&lt;/span&gt;&lt;br /&gt;&lt;span&gt;             dpiv    = 100&lt;/span&gt;&lt;br /&gt;&lt;span&gt;             name    = "arial.ttf"&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the nasty problems I had with FreeType was the lack of choices for building dynamical dllVC6 and I couldn't find any way to build a dll. Changing ftbuild.h didn't help. I solved this by using VC2005. It has an option that allows to changing the output type really easily.&lt;br /&gt;&lt;br /&gt;The freetype2 is now included as part of Galactic Engine 2.</description><link>http://dminator.blogspot.com/2007/05/freetype2-support-added.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-7386663502567256715</guid><pubDate>Fri, 18 May 2007 17:56:00 +0000</pubDate><atom:updated>2007-05-18T21:10:38.958+03:00</atom:updated><title>Stage6 divx high quality videos"</title><description>The &lt;a href="http://stage6.divx.com/"&gt;Stage6.divx.com&lt;/a&gt; offers new video service. The primary feature is that there is practically no limit to video length or size so it is possible to upload and watch the highest quality videos ! &lt;br /&gt;&lt;br /&gt;The primary requirement is availability of special divx plugin and video converted to divx format. I recommend as minimum 1 MB/s download speed for watching.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is blazetris game-play video in original quality, the video size is about 20 MB and it was converted from .wmv file.&lt;br /&gt;&lt;br /&gt;&lt;object codebase="http://go.divx.com/plugin/DivXBrowserPlugin.cab" height="576" width="720" classid="clsid:67DABFBF-D0AB-41fa-9C46-CC0F21721616"&gt;&lt;param name="autoplay" value="false"&gt;&lt;param name="src" value="http://video.stage6.com/1244034/.divx" /&gt;&lt;param name="custommode" value="Stage6" /&gt;&lt;param name="showpostplaybackad" value="false" /&gt;&lt;embed type="video/divx" src="http://video.stage6.com/1244034/.divx" pluginspage="http://go.divx.com/plugin/download/" showpostplaybackad="false" custommode="Stage6" autoplay="false" height="576" width="720"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stage6.divx.com/user/DMINATOR/video/1244034/Blazetris-gameplay"&gt;Direct Link&lt;/a&gt;</description><link>http://dminator.blogspot.com/2007/05/stage6-divx-high-quality-videos.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-5387262325112106306</guid><pubDate>Wed, 09 May 2007 17:11:00 +0000</pubDate><atom:updated>2007-05-09T20:22:18.684+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">trailer</category><category domain="http://www.blogger.com/atom/ns#">AGEIA</category><category domain="http://www.blogger.com/atom/ns#">PhysX</category><category domain="http://www.blogger.com/atom/ns#">cellfactor revolution</category><title>Revolution Is here !</title><description>Finally after some waiting time , the Cellfactor: revoltion is released !&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can freely download the full game here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.cellfactorrevolution.com/"&gt;Cellfactor: revolution&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Trailer:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/t7qMm41QP-c"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/t7qMm41QP-c" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;</description><link>http://dminator.blogspot.com/2007/05/revolution-is-here.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-10918543.post-1310441177923596623</guid><pubDate>Sun, 29 Apr 2007 14:59:00 +0000</pubDate><atom:updated>2007-04-29T18:07:56.198+03:00</atom:updated><title>Galactic Engine 2 Materials with BSP</title><description>For the past few weeks I have been working on the version of BSP map class that would be added to the GE2. Some things are already working but some require the physical engine.&lt;br /&gt;&lt;br /&gt;Currently it is mostly compatible with Quake 3 shader system it allows to animate texture coordinates , colors , vertex deformation. One of the latest additions to the engine itself was the AnimatedTexture. This is the special type of texture that points to multiple textures and selects only one of them depending on the frequency of animation and the elapsed time. This is used to animate the torches of the map.&lt;br /&gt;&lt;br /&gt;Here is the video:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/RdMVdpzkBak"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/RdMVdpzkBak" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=RdMVdpzkBak"&gt;Direct Link&lt;/a&gt;</description><link>http://dminator.blogspot.com/2007/04/galactic-engine-2-materials-with-bsp.html</link><author>noreply@blogger.com (Dmitri Kuznetsov)</author></item></channel></rss>
