<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1249179008376089851</id><updated>2012-02-02T13:27:44.766+01:00</updated><title type='text'>Riven :: code &lt;/&gt; brain :: dump</title><subtitle type='html'>&lt;br&gt;share more code + it makes life hilarious</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-2917875498020961738</id><published>2010-11-30T23:29:00.014+01:00</published><updated>2011-02-13T16:43:34.045+01:00</updated><title type='text'>Java Continuations and Green Threads at native speeds</title><content type='html'>Continuations, or green threads, are a concept mostly seen in scripting languages. Green threads are just like native threads, but you can run multiple of them on a single native thread. Java has no native support for continuations, so we have to transform (instrument) java bytecode with a library that saves localvars and the instruction pointer upon a GreenThread.yield(). Once the green thread is resumed, this information is used to rebuild the stacktrace, with all localvars intact.&lt;br /&gt;&lt;br /&gt;The library used is: &lt;a href='http://l33tlabs.org/Continuations/'&gt;http://l33tlabs.org/Continuations/&lt;/a&gt; written by &lt;a href='http://www.matthiasmann.de/'&gt;Matthias Mann&lt;/a&gt;&lt;br /&gt;His library depends on ASM3 to parse and construct the bytecode: &lt;a href='http://asm.ow2.org/'&gt;http://asm.ow2.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Through the Java Instrumentation Agent that I wrote for the previously mentioned library, there is no need to transform your byteclass ahead of time. The java agent will take care of this at runtime.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;java -javaagent:&lt;a href='http://indiespot.net/files/temp/conti4.jar'&gt;conti4.jar&lt;/a&gt; -cp ./your.jars your.MainClass&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I wrote a wrapper around the continuation library, to lower the bar a bit. I hope the code pretty much speaks for itself, and if not, feel free to ask questions. For additional convenience, I added some demo code and its fascinating output at the bottom.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;import de.matthiasmann.continuations.Coroutine;&lt;br /&gt;import de.matthiasmann.continuations.CoroutineProto;&lt;br /&gt;import de.matthiasmann.continuations.SuspendExecution;&lt;br /&gt;import de.matthiasmann.continuations.Coroutine.State;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Created on Nov 30, 2010&lt;br /&gt; * &lt;br /&gt; * @author Riven&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;public abstract class &lt;span style='color:yellow'&gt;GreenThread&lt;/span&gt; implements CoroutineProto&lt;br /&gt;{&lt;br /&gt;   public static final long EOF = -1L;&lt;br /&gt;&lt;br /&gt;   private final Coroutine  coroutine;&lt;br /&gt;&lt;br /&gt;   public &lt;span style='color:yellow'&gt;GreenThread&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.coroutine = new Coroutine(this);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private long doSleep;&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   &lt;span style='color:green'&gt;// this is where you put your code&lt;/span&gt;&lt;br /&gt;   public abstract void &lt;span style='color:yellow'&gt;coExecute&lt;/span&gt;() throws SuspendExecution;&lt;br /&gt;&lt;br /&gt;   long step()&lt;br /&gt;   {&lt;br /&gt;      coroutine.run();&lt;br /&gt;      if (coroutine.getState() == State.FINISHED)&lt;br /&gt;         return EOF;&lt;br /&gt;      return this.doSleep;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void &lt;span style='color:yellow'&gt;yield&lt;/span&gt;() throws SuspendExecution&lt;br /&gt;   {&lt;br /&gt;      GreenThread.sleep(0L);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void &lt;span style='color:yellow'&gt;sleep&lt;/span&gt;(long ms) throws SuspendExecution&lt;br /&gt;   {&lt;br /&gt;      GreenThread thread = (GreenThread) Coroutine.getActiveCoroutine().getProto();&lt;br /&gt;&lt;br /&gt;      thread.doSleep = Math.max(ms, 0L);&lt;br /&gt;&lt;br /&gt;      Coroutine.yield();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;---------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;import java.util.Comparator;&lt;br /&gt;import java.util.PriorityQueue;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Created on Nov 30, 2010&lt;br /&gt; * &lt;br /&gt; * @author Riven&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;GreenThreadQueue&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   private final PriorityQueue&lt;greenthreadwakeup&gt; queue;&lt;br /&gt;   private final List&lt;greenthreadwakeup&gt;          reschedule;&lt;br /&gt;&lt;br /&gt;   public &lt;span style='color:yellow'&gt;GreenThreadQueue&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.queue = new PriorityQueue&lt;greenthreadwakeup&gt;(16, new GreenThreadWakeupComparator());&lt;br /&gt;      this.reschedule = new ArrayList&lt;greenthreadwakeup&gt;();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style='color:yellow'&gt;start&lt;/span&gt;(&lt;span style='yellow'&gt;GreenThread&lt;/span&gt; thread)&lt;br /&gt;   {&lt;br /&gt;      this.queue.add(new GreenThreadWakeup(thread, 0L));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public boolean &lt;span style='color:yellow'&gt;tick&lt;/span&gt;(long now)&lt;br /&gt;   {&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         while (true)&lt;br /&gt;         {&lt;br /&gt;            GreenThreadWakeup wakeup = this.queue.peek();&lt;br /&gt;            if (wakeup == null)&lt;br /&gt;               return !this.reschedule.isEmpty(); // signal nothing more to do&lt;br /&gt;&lt;br /&gt;            if (wakeup.timestamp &gt; now)&lt;br /&gt;               break;&lt;br /&gt;&lt;br /&gt;            if (this.queue.poll() != wakeup)&lt;br /&gt;               throw new IllegalStateException();&lt;br /&gt;&lt;br /&gt;            long sleep = wakeup.thread.step();&lt;br /&gt;            if (sleep == GreenThread.EOF)&lt;br /&gt;               continue;&lt;br /&gt;&lt;br /&gt;            wakeup.timestamp = now + sleep;&lt;br /&gt;            this.reschedule.add(wakeup);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         return true;&lt;br /&gt;      }&lt;br /&gt;      finally&lt;br /&gt;      {&lt;br /&gt;         for (GreenThreadWakeup wakeup : this.reschedule)&lt;br /&gt;         {&lt;br /&gt;            this.queue.add(wakeup);&lt;br /&gt;         }&lt;br /&gt;         this.reschedule.clear();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   static private class GreenThreadWakeup&lt;br /&gt;   {&lt;br /&gt;      public final GreenThread thread;&lt;br /&gt;      public long              timestamp;&lt;br /&gt;&lt;br /&gt;      public GreenThreadWakeup(GreenThread thread, long timestamp)&lt;br /&gt;      {&lt;br /&gt;         this.thread = thread;&lt;br /&gt;         this.timestamp = timestamp;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   static class GreenThreadWakeupComparator implements Comparator&lt;greenthreadwakeup&gt;&lt;br /&gt;   {&lt;br /&gt;      @Override&lt;br /&gt;      public int compare(GreenThreadWakeup o1, GreenThreadWakeup o2)&lt;br /&gt;      {&lt;br /&gt;         int val = Long.signum(o1.timestamp - o2.timestamp);&lt;br /&gt;         return (val == 0) ? 1 : val;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Demo code&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;GreenThreadQueue queue = new GreenThreadQueue();&lt;br /&gt;&lt;br /&gt;      GreenThread thread1 = new GreenThread()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public void coExecute() throws SuspendExecution&lt;br /&gt;         {&lt;br /&gt;            for (int i = 0; i &lt; 3; i++)&lt;br /&gt;            {&lt;br /&gt;               System.out.println("a" + i);&lt;br /&gt;               GreenThread.sleep(1500);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;&lt;br /&gt;      GreenThread thread2 = new GreenThread()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public void coExecute() throws SuspendExecution&lt;br /&gt;         {&lt;br /&gt;            for (int i = 0; i &lt; 4; i++)&lt;br /&gt;            {&lt;br /&gt;               System.out.println("b" + i);&lt;br /&gt;               GreenThread.sleep(1300);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;&lt;br /&gt;      queue.start(thread1);&lt;br /&gt;      queue.start(thread2);&lt;br /&gt;&lt;br /&gt;      do&lt;br /&gt;      {&lt;br /&gt;         try { Thread.sleep(100); } catch(InterruptedException exc) { /* ignore */ }&lt;br /&gt;      }&lt;br /&gt;      while (queue.tick(System.currentTimeMillis()));&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;b&gt;Fancy output (from 1 thread)&lt;/b&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;a0&lt;br /&gt;b0&lt;br /&gt;b1&lt;br /&gt;a1&lt;br /&gt;b2&lt;br /&gt;a2&lt;br /&gt;b3&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-2917875498020961738?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/2917875498020961738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/11/continuations-and-green-threads-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2917875498020961738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2917875498020961738'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/11/continuations-and-green-threads-in-java.html' title='Java Continuations and Green Threads at native speeds'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-1625689591526486957</id><published>2010-11-24T23:42:00.092+01:00</published><updated>2011-01-11T00:53:12.900+01:00</updated><title type='text'>Lost four words... (pro nouns)</title><content type='html'>&lt;img src="http://matthewsalomon.files.wordpress.com/2008/03/vogon_poetry2.jpg" align="right" hspace="16" vspace="8"&gt;&lt;blockquote&gt;&lt;script type='text/javascript'&gt;function j(){ var arr = Array('s', 'w', 'e', 'j'); for(var i=1; i&lt;=2; i++) {document.getElementById('j'+i).innerHTML = arr.reverse().join(''); arr.reverse(); }} setTimeout(j, 250);&lt;/script&gt;&lt;b&gt;It got cold while she called for juice from &lt;span id='j1'&gt;&lt;/span&gt;, not awaiting the tide and tied a tight knot. A scene never seen again, maybe missed due to the dew or mist on site by a dude with poor sight on one side. A phase etched on the edge of his face. Whether her patients had patience depended on the weather. So take a look at the sea and see: sow and pour it in a poor pore, with any luck, lock it. I'll weigh the way the rained isle was reigned. A pane hid me, then a pain hit me. During the war the witch wore a hat which was won by one bright bride. During the juring descent, she thought and fought the scent. Worn by the sun, I warn my son, as his eye tans tense, 'caus where regular wear hides hides, I knew a new gnu (its dead dad had that dept) that played ball, sipping a bowl for four hours, assuming it was ours, while the cued cheap cute sheep queued. Silence. Deaf by impending death. 'Hear here', she heard hurt. She waited, weighted by lead, led down the stairs by the wrath filled failed ref. Bye Susan, by all means, awe at the whirled world... Eight dodo's ate dough though.&lt;/b&gt;&lt;/blockquote&gt;&lt;table cellpadding=8&gt;&lt;tr&gt;&lt;td valign=top&gt;&lt;pre&gt;&lt;font color=#404040&gt;&lt;br /&gt;cold/called&lt;br /&gt;juice/&lt;span id='j2'&gt;&lt;/span&gt;&lt;br /&gt;not/knot&lt;br /&gt;tide/tight/tied&lt;br /&gt;scene/seen&lt;br /&gt;missed/mist&lt;br /&gt;due/dew&lt;br /&gt;site/side/sight&lt;br /&gt;phase/face&lt;br /&gt;etch/edge&lt;br /&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td valign=top&gt;&lt;pre&gt;&lt;font color=#404040&gt;&lt;br /&gt;whether/weather&lt;br /&gt;patience/patients&lt;br /&gt;suck it/socket&lt;br /&gt;rained/reighed&lt;br /&gt;thought/fought&lt;br /&gt;eight/ate&lt;br /&gt;dodo/though/dough&lt;br /&gt;so/sow&lt;br /&gt;luck/lock&lt;br /&gt;sea/see&lt;br /&gt;pour/pore/poor&lt;br /&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td valign=top&gt;&lt;pre&gt;&lt;font color=#404040&gt;&lt;br /&gt;war/wore&lt;br /&gt;won/one&lt;br /&gt;witch/which&lt;br /&gt;bright/bride&lt;br /&gt;worn/warn&lt;br /&gt;sun/son&lt;br /&gt;tans/tense&lt;br /&gt;where/wear&lt;br /&gt;knew/new/gnu&lt;br /&gt;dead/dad/that/dept&lt;br /&gt;descent/the scent&lt;br /&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td valign=top&gt;&lt;pre&gt;&lt;font color=#404040&gt;&lt;br /&gt;ball/bowl&lt;br /&gt;for/four&lt;br /&gt;hours/ours&lt;br /&gt;cued/cute/queued&lt;br /&gt;cheap/sheep&lt;br /&gt;plug/plaque&lt;br /&gt;deaf/death&lt;br /&gt;hear/here&lt;br /&gt;heard/hurt&lt;br /&gt;waited/weighted&lt;br /&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td valign=top&gt;&lt;pre&gt;&lt;font color=#404040&gt;&lt;br /&gt;lead/led&lt;br /&gt;wrath/ref&lt;br /&gt;filled/failed&lt;br /&gt;bye/by&lt;br /&gt;all/awe&lt;br /&gt;whirled/world&lt;br /&gt;i'll/isle&lt;br /&gt;way/weigh&lt;br /&gt;pain/pane&lt;br /&gt;hit/hid&lt;br /&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;Disclaimer: English is not my native language, so certain words might sound the same for me, while they are clearly distinct for you gays.&lt;!--serial, cereala raw roar came from the bode, as he rowed his boatpray preyshoot chutebe beeblew blueknow nonone nonhi highallowed aloudthrough threwroll rolebye by buythe bored board prays praise for preys--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-1625689591526486957?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/1625689591526486957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/11/oh-vowel-where-art-thou.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1625689591526486957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1625689591526486957'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/11/oh-vowel-where-art-thou.html' title='Lost four words... &lt;font color=&quot;#003300&quot;&gt;(pro nouns)&lt;/font&gt;'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-3593475895052752052</id><published>2010-08-19T19:15:00.008+02:00</published><updated>2010-11-24T17:51:51.404+01:00</updated><title type='text'>Calculate PerlinNoise faster with an optimization to grad()</title><content type='html'>A simple optimization to the gradient function makes the noise function twice as fast.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;PerlinNoise.grad()&lt;/b&gt;&lt;br /&gt;&lt;div class="code" style='height:auto'&gt;&lt;pre&gt;inline float grad(int hash, float x, float y, float z)&lt;br /&gt;   {  &lt;br /&gt; //float u = (h &lt; 8) ? x : y;&lt;br /&gt; //float v = (h &lt; 4) ? y : ((h == 12 || h == 14) ? x : z);&lt;br /&gt; //return ((h &amp; 1) == 0 ? u : -u) + ((h &amp; 2) == 0 ? v : -v);&lt;br /&gt;&lt;br /&gt; switch(hash &amp; 0xF)&lt;br /&gt; {&lt;br /&gt;  case 0x0: return  x + y;&lt;br /&gt;  case 0x1: return -x + y;&lt;br /&gt;  case 0x2: return  x - y;&lt;br /&gt;  case 0x3: return -x - y;&lt;br /&gt;  case 0x4: return  x + z;&lt;br /&gt;  case 0x5: return -x + z;&lt;br /&gt;  case 0x6: return  x - z;&lt;br /&gt;  case 0x7: return -x - z;&lt;br /&gt;  case 0x8: return  y + z;&lt;br /&gt;  case 0x9: return -y + z;&lt;br /&gt;  case 0xA: return  y - z;&lt;br /&gt;  case 0xB: return -y - z;&lt;br /&gt;  case 0xC: return  y + x;&lt;br /&gt;  case 0xD: return -y + z;&lt;br /&gt;  case 0xE: return  y - x;&lt;br /&gt;  case 0xF: return -y - z;&lt;br /&gt;  default: return 0; // never happens&lt;br /&gt; }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;b&gt;PerlinNoise.noise()&lt;/b&gt; (click code to expand)&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;int   perm[512];&lt;br /&gt;&lt;br /&gt;   void initPerlinNoise()&lt;br /&gt;   {&lt;br /&gt;      int i, permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,&lt;br /&gt;         14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };&lt;br /&gt;&lt;br /&gt;      for (i = 0; i &lt; 256; i++)&lt;br /&gt;         perm[256 + i] = perm[i] = permutation[i];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   inline float fade(float t)&lt;br /&gt;   {&lt;br /&gt;      return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   inline float lerp(float t, float a, float b)&lt;br /&gt;   {&lt;br /&gt;      return a + t * (b - a);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   inline float grad(int hash, float x, float y, float z)&lt;br /&gt;   {  &lt;br /&gt; //float u = (h &lt; 8) ? x : y;&lt;br /&gt; //float v = (h &lt; 4) ? y : ((h == 12 || h == 14) ? x : z);&lt;br /&gt; //return ((h &amp; 1) == 0 ? u : -u) + ((h &amp; 2) == 0 ? v : -v);&lt;br /&gt;&lt;br /&gt; switch(hash &amp; 0xF)&lt;br /&gt; {&lt;br /&gt;  case 0x0: return  x + y;&lt;br /&gt;  case 0x1: return -x + y;&lt;br /&gt;  case 0x2: return  x - y;&lt;br /&gt;  case 0x3: return -x - y;&lt;br /&gt;  case 0x4: return  x + x;&lt;br /&gt;  case 0x5: return -x + x;&lt;br /&gt;  case 0x6: return  x - x;&lt;br /&gt;  case 0x7: return -x - x;&lt;br /&gt;  case 0x8: return  y + x;&lt;br /&gt;  case 0x9: return -y + x;&lt;br /&gt;  case 0xA: return  y - x;&lt;br /&gt;  case 0xB: return -y - x;&lt;br /&gt;  case 0xC: return  y + z;&lt;br /&gt;  case 0xD: return -y + x;&lt;br /&gt;  case 0xE: return  y - x;&lt;br /&gt;  case 0xF: return -y - z;&lt;br /&gt;  default: return 0; // never happens&lt;br /&gt; }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   static inline float __fastcall noise(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      jint ix,iy,iz,gx,gy,gz;&lt;br /&gt;      jint a0,b0,aa,ab,ba,bb;&lt;br /&gt;&lt;br /&gt;      float aa0,ab0,ba0,bb0;&lt;br /&gt;      float aa1,ab1,ba1,bb1;&lt;br /&gt;      float a1,a2,a3,a4,a5,a6,a7,a8;&lt;br /&gt;      float u,v,w,a8_5,a4_1;&lt;br /&gt;&lt;br /&gt;      ix = (jint)x; x-=ix;&lt;br /&gt;      iy = (jint)y; y-=iy;&lt;br /&gt;      iz = (jint)z; z-=iz;&lt;br /&gt;&lt;br /&gt;      gx = ix &amp; 0xFF;&lt;br /&gt;      gy = iy &amp; 0xFF;&lt;br /&gt;      gz = iz &amp; 0xFF;&lt;br /&gt;      &lt;br /&gt;      a0 = gy+perm[gx];&lt;br /&gt;      b0 = gy+perm[gx + 1];&lt;br /&gt;      aa = gz+perm[a0];&lt;br /&gt;      ab = gz+perm[a0 + 1];&lt;br /&gt;      ba = gz+perm[b0];&lt;br /&gt;      bb = gz+perm[b0 + 1];&lt;br /&gt;&lt;br /&gt;      aa0 = perm[aa]; aa1 = perm[aa + 1];&lt;br /&gt;      ab0 = perm[ab]; ab1 = perm[ab + 1];&lt;br /&gt;      ba0 = perm[ba]; ba1 = perm[ba + 1];&lt;br /&gt;      bb0 = perm[bb]; bb1 = perm[bb + 1];&lt;br /&gt;&lt;br /&gt;      a1 = grad(bb1, x-1, y-1, z-1);&lt;br /&gt;      a2 = grad(ab1, x  , y-1, z-1);&lt;br /&gt;      a3 = grad(ba1, x-1, y  , z-1);&lt;br /&gt;      a4 = grad(aa1, x  , y  , z-1);&lt;br /&gt;      a5 = grad(bb0, x-1, y-1, z  );&lt;br /&gt;      a6 = grad(ab0, x  , y-1, z  );&lt;br /&gt;      a7 = grad(ba0, x-1, y  , z  );&lt;br /&gt;      a8 = grad(aa0, x  , y  , z  );&lt;br /&gt;&lt;br /&gt;      u = fade(x);&lt;br /&gt;      v = fade(y);&lt;br /&gt;      w = fade(z);&lt;br /&gt;&lt;br /&gt;      a8_5 = lerp(v, lerp(u, a8, a7), lerp(u, a6, a5));&lt;br /&gt;      a4_1 = lerp(v, lerp(u, a4, a3), lerp(u, a2, a1));&lt;br /&gt;      return lerp(w, a8_5, a4_1);&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-3593475895052752052?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/3593475895052752052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3593475895052752052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3593475895052752052'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html' title='Calculate PerlinNoise faster with an optimization to grad()'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5050509420639578487</id><published>2010-07-23T19:28:00.021+02:00</published><updated>2010-07-25T15:02:27.700+02:00</updated><title type='text'>Rhino ClassShutter replacement: SandboxShutter</title><content type='html'>Because the &lt;tt&gt;ClassShutter&lt;/tt&gt; in Rhino doesn't usually provide enough information to make decisions on whether or not certain Java objects, fields or methods should be accessible, I wrote the &lt;tt&gt;SandboxShutter&lt;/tt&gt; which will enable you to control accessibility for each field and each method of each Java object. The performance impact is negligible, because JavaScript itself is an order of magnitude slower than the injected checks. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The SandboxShutter interface:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" style='height:auto'&gt;&lt;pre&gt;public interface &lt;span style='color:yellow'&gt;SandboxShutter&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public boolean allowClassAccess(Class&amp;lt;?&amp;gt; type);&lt;br /&gt;&lt;br /&gt;   public boolean allowFieldAccess(Class&amp;lt;?&amp;gt; type, Object instance, String fieldName);&lt;br /&gt;&lt;br /&gt;   public boolean allowMethodAccess(Class&amp;lt;?&amp;gt; type, Object instance, String methodName);&lt;br /&gt;&lt;br /&gt;   public boolean allowStaticFieldAccess(Class&amp;lt;?&amp;gt; type, String fieldName);&lt;br /&gt;&lt;br /&gt;   public boolean allowStaticMethodAccess(Class&amp;lt;?&amp;gt; type, String methodName);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;When the following javascript code is executed:&lt;/b&gt;&lt;br /&gt;&lt;div class='code' style='height:auto'&gt;&lt;pre&gt;importPackage(Packages.my.game); &lt;span style='color:#00c000'&gt;// assuming the Java class my.game.Player exists&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;var player = new Player("Jake");&lt;br /&gt;player.gender = "female"; &lt;span style='color:#00c000'&gt;// this is a Java method!&lt;/span&gt;&lt;br /&gt;player.setGender("male"); &lt;span style='color:#00c000'&gt;// this the same Java method.&lt;/span&gt;&lt;br /&gt;player.age = 18; &lt;span style='color:#00c000'&gt;// this is a Java field&lt;/span&gt;&lt;br /&gt;player.age += 3;&lt;br /&gt;&lt;br /&gt;var player = new Player("Jane");&lt;br /&gt;player.gender = "male";&lt;br /&gt;player.gender = "female";&lt;br /&gt;player.age = 19;&lt;br /&gt;player.age += 2;&lt;br /&gt;&lt;br /&gt;var count = Player.PLAYER_COUNT;&lt;br /&gt;Player.PLAYER_COUNT += 2;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The following SandboxShutter calls will be made:&lt;/b&gt;&lt;br /&gt;&lt;div class='code' style='height:auto'&gt;&lt;pre&gt;allowClassAccess:       my.game.Player&lt;br /&gt;&lt;br /&gt;allowMethodAccess:      my.game.Player.setGender() instance=Player@2346&lt;br /&gt;allowFieldAccess:       my.game.Player.age         instance=Player@2346&lt;br /&gt;&lt;br /&gt;allowMethodAccess:      my.game.Player.setGender() instance=Player@54326&lt;br /&gt;allowFieldAccess:       my.game.Player.age         instance=Player@54326&lt;br /&gt;&lt;br /&gt;allowStaticFieldAccess: my.game.Player.PLAYER_COUNT&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;As shown, there will be at most one call for each field/method in each object, and one call per class. This allows you to control accessibility per Java object.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Create the SandboxContextFactory:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static class &lt;span style='color:yellow'&gt;SandboxContextFactory&lt;/span&gt; extends ContextFactory&lt;br /&gt;   {&lt;br /&gt;      final SandboxShutter shutter;&lt;br /&gt;&lt;br /&gt;      public SandboxContextFactory(SandboxShutter shutter)&lt;br /&gt;      {&lt;br /&gt;         this.shutter = shutter;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      @Override&lt;br /&gt;      protected Context makeContext()&lt;br /&gt;      {&lt;br /&gt;         Context cx = super.makeContext();&lt;br /&gt;         cx.setWrapFactory(new SandboxWrapFactory());&lt;br /&gt;         cx.setClassShutter(new ClassShutter()&lt;br /&gt;         {&lt;br /&gt;            private final Map&amp;lt;String, Boolean&amp;gt; nameToAccepted = new HashMap&amp;lt;String, Boolean&amp;gt;();&lt;br /&gt;&lt;br /&gt;            @Override&lt;br /&gt;            public boolean visibleToScripts(String name)&lt;br /&gt;            {&lt;br /&gt;               Boolean granted = this.nameToAccepted.get(name);&lt;br /&gt;&lt;br /&gt;               if (granted != null)&lt;br /&gt;               {&lt;br /&gt;                  return granted.booleanValue();&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               Class&amp;lt; ? &amp;gt; staticType;&lt;br /&gt;               try&lt;br /&gt;               {&lt;br /&gt;                  staticType = Class.forName(name);&lt;br /&gt;               }&lt;br /&gt;               catch (Exception exc)&lt;br /&gt;               {&lt;br /&gt;                  this.nameToAccepted.put(name, Boolean.FALSE);&lt;br /&gt;                  return false;&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               boolean grant = shutter.allowClassAccess(staticType);&lt;br /&gt;               this.nameToAccepted.put(name, Boolean.valueOf(grant));&lt;br /&gt;               return grant;&lt;br /&gt;            }&lt;br /&gt;         });&lt;br /&gt;         return cx;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      class SandboxWrapFactory extends WrapFactory&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Scriptable wrapNewObject(Context cx, Scriptable scope, Object obj)&lt;br /&gt;         {&lt;br /&gt;            this.ensureReplacedClass(scope, obj, null);&lt;br /&gt;&lt;br /&gt;            return super.wrapNewObject(cx, scope, obj);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         @Override&lt;br /&gt;         public Object wrap(Context cx, Scriptable scope, Object obj, Class&amp;lt; ? &amp;gt; staticType)&lt;br /&gt;         {&lt;br /&gt;            this.ensureReplacedClass(scope, obj, staticType);&lt;br /&gt;&lt;br /&gt;            return super.wrap(cx, scope, obj, staticType);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         @Override&lt;br /&gt;         public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class&amp;lt; ? &amp;gt; staticType)&lt;br /&gt;         {&lt;br /&gt;            final Class&amp;lt; ? &amp;gt; type = this.ensureReplacedClass(scope, javaObject, staticType);&lt;br /&gt;&lt;br /&gt;            return new NativeJavaObject(scope, javaObject, staticType)&lt;br /&gt;            {&lt;br /&gt;               private final Map&amp;lt;String, Boolean&amp;gt; instanceMethodToAllowed = new HashMap&amp;lt;String, Boolean&amp;gt;();&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public Object get(String name, Scriptable scope)&lt;br /&gt;               {&lt;br /&gt;                  Object wrapped = super.get(name, scope);&lt;br /&gt;&lt;br /&gt;                  if (wrapped instanceof BaseFunction)&lt;br /&gt;                  {&lt;br /&gt;                     String id = type.getName() + "." + name;&lt;br /&gt;                     Boolean allowed = this.instanceMethodToAllowed.get(id);&lt;br /&gt;&lt;br /&gt;                     if (allowed == null)&lt;br /&gt;                     {&lt;br /&gt;                        boolean allow = shutter.allowMethodAccess(type, javaObject, name);&lt;br /&gt;                        this.instanceMethodToAllowed.put(id, allowed = Boolean.valueOf(allow));&lt;br /&gt;                     }&lt;br /&gt;&lt;br /&gt;                     if (!allowed.booleanValue())&lt;br /&gt;                     {&lt;br /&gt;                        return NOT_FOUND;&lt;br /&gt;                     }&lt;br /&gt;                  }&lt;br /&gt;                  else&lt;br /&gt;                  {&lt;br /&gt;                     // NativeJavaObject + only boxed primitive types?&lt;br /&gt;                     if (!shutter.allowFieldAccess(type, javaObject, name))&lt;br /&gt;                     {&lt;br /&gt;                        return NOT_FOUND;&lt;br /&gt;                     }&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;                  return wrapped;&lt;br /&gt;               }&lt;br /&gt;            };&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         //&lt;br /&gt;&lt;br /&gt;         private final Set&amp;lt;Class&amp;lt; ? &amp;gt;&amp;gt; replacedClasses = new HashSet&amp;lt;Class&amp;lt; ? &amp;gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;         private Class&amp;lt; ? &amp;gt; ensureReplacedClass(Scriptable scope, Object obj, Class&amp;lt; ? &amp;gt; staticType)&lt;br /&gt;         {&lt;br /&gt;            final Class&amp;lt; ? &amp;gt; type = (staticType == null &amp;&amp; obj != null) ? obj.getClass() : staticType;&lt;br /&gt;&lt;br /&gt;            if (!type.isPrimitive() &amp;&amp; !type.getName().startsWith("java.") &amp;&amp; this.replacedClasses.add(type))&lt;br /&gt;            {&lt;br /&gt;               this.replaceJavaNativeClass(type, scope);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return type;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         private void replaceJavaNativeClass(final Class&amp;lt; ? &amp;gt; type, Scriptable scope)&lt;br /&gt;         {&lt;br /&gt;            Object clazz = Context.jsToJava(ScriptableObject.getProperty(scope, "Packages"), Object.class);&lt;br /&gt;            Object holder = null;&lt;br /&gt;            for (String part : Text.split(type.getName(), '.'))&lt;br /&gt;            {&lt;br /&gt;               holder = clazz;&lt;br /&gt;               clazz = ScriptableObject.getProperty((Scriptable) clazz, part);&lt;br /&gt;            }&lt;br /&gt;            NativeJavaClass nativeClass = (NativeJavaClass) clazz;&lt;br /&gt;&lt;br /&gt;            nativeClass = new NativeJavaClass(scope, type)&lt;br /&gt;            {&lt;br /&gt;               @Override&lt;br /&gt;               public Object get(String name, Scriptable start)&lt;br /&gt;               {&lt;br /&gt;                  Object wrapped = super.get(name, start);&lt;br /&gt;&lt;br /&gt;                  if (wrapped instanceof BaseFunction)&lt;br /&gt;                  {&lt;br /&gt;                     if (!shutter.allowStaticMethodAccess(type, name))&lt;br /&gt;                     {&lt;br /&gt;                        return NOT_FOUND;&lt;br /&gt;                     }&lt;br /&gt;                  }&lt;br /&gt;                  else&lt;br /&gt;                  {&lt;br /&gt;                     // NativeJavaObject + only boxed primitive types?&lt;br /&gt;                     if (!shutter.allowStaticFieldAccess(type, name))&lt;br /&gt;                     {&lt;br /&gt;                        return NOT_FOUND;&lt;br /&gt;                     }&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;                  return wrapped;&lt;br /&gt;               }&lt;br /&gt;            };&lt;br /&gt;&lt;br /&gt;            ScriptableObject.putProperty((Scriptable) holder, type.getSimpleName(), nativeClass);&lt;br /&gt;            ScriptableObject.putProperty(scope, type.getSimpleName(), nativeClass);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Install the (global) SandboxContextFactory:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" style='height:auto'&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ContextFactory.initGlobal(new &lt;span style='color:yellow'&gt;SandboxContextFactory&lt;/span&gt;(new &lt;span style='color:yellow'&gt;SandboxShutter&lt;/span&gt;()&lt;br /&gt;      {&lt;br /&gt;         ...&lt;br /&gt;      }));&lt;br /&gt;&lt;br /&gt;      &lt;span style='color:#00c000'&gt;// create and initialize Rhino Context&lt;/span&gt;&lt;br /&gt;      Context cx = Context.enter();&lt;br /&gt;      Scriptable prototype = cx.initStandardObjects();&lt;br /&gt;      Scriptable topLevel = new ImporterTopLevel(cx);&lt;br /&gt;      prototype.setParentScope(topLevel);&lt;br /&gt;      Scriptable scope = cx.newObject(prototype);&lt;br /&gt;      scope.setPrototype(prototype);&lt;br /&gt;&lt;br /&gt;      &lt;span style='color:#00c000'&gt;// your scripts&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5050509420639578487?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5050509420639578487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/07/java-rhino-fine-grained-classshutter.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5050509420639578487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5050509420639578487'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/07/java-rhino-fine-grained-classshutter.html' title='Rhino ClassShutter replacement: SandboxShutter'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-8624950222837535328</id><published>2010-07-20T19:58:00.004+02:00</published><updated>2010-07-20T20:07:29.719+02:00</updated><title type='text'>Functions on Iterables :: Consume</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style='color:yellow'&gt;Functional&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   &lt;span style='color:#00c000'&gt;/**&lt;br /&gt;    * Consumes (removes) all items while iterating&lt;t&gt;&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;T&amp;gt; Iterable&amp;lt;T&amp;gt; &lt;span style='color:yellow'&gt;consume&lt;/span&gt;(final Iterable&amp;lt;T&amp;gt; iterable)&lt;br /&gt;   {&lt;br /&gt;      if (iterable == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;&lt;br /&gt;      return new Iterable&amp;lt;T&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Iterator&amp;lt;T&amp;gt; iterator()&lt;br /&gt;         {&lt;br /&gt;            final Iterator&amp;lt;T&amp;gt; iterator = iterable.iterator();&lt;br /&gt;&lt;br /&gt;            return new Iterator&amp;lt;T&amp;gt;()&lt;br /&gt;            {&lt;br /&gt;               @Override&lt;br /&gt;               public boolean hasNext()&lt;br /&gt;               {&lt;br /&gt;                  return iterator.hasNext();&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public T next()&lt;br /&gt;               {&lt;br /&gt;                  T result = iterator.next();&lt;br /&gt;                  iterator.remove();&lt;br /&gt;                  return result;&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public void remove()&lt;br /&gt;               {&lt;br /&gt;                  throw new NoSuchElementException("already removed");&lt;br /&gt;               }&lt;br /&gt;            };&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To remove all short texts in a list:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;List&amp;lt;String&amp;gt; data = ...;&lt;br /&gt;&lt;br /&gt;Filter&amp;lt;String&amp;gt; &lt;span style='color:#00c0c0'&gt;shortText&lt;/span&gt; = new Filter&amp;lt;String&amp;gt;()&lt;br /&gt;{&lt;br /&gt;   public boolean accept(String item) { return item == null || item.length() &lt;= 3; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for(String item: &lt;span style='color:yellow'&gt;consume&lt;/span&gt;(&lt;span style='color:yellow'&gt;filter&lt;/span&gt;(data, &lt;span style='color:#00c0c0'&gt;shortText&lt;/span&gt;)))&lt;br /&gt;{&lt;br /&gt;   System.out.println("By the time you see this, '"+item+"' has been removed.");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-8624950222837535328?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/8624950222837535328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-consume.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/8624950222837535328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/8624950222837535328'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-consume.html' title='Functions on Iterables :: Consume'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5712048815882675233</id><published>2010-07-20T19:35:00.008+02:00</published><updated>2010-07-21T16:57:07.403+02:00</updated><title type='text'>Functions on Iterables :: Event Hooks</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public interface &lt;span style='color:yellow'&gt;Operator&lt;/span&gt;&lt;t&gt;&lt;br /&gt;{&lt;br /&gt;   public void operate(T item);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;Functional&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   &lt;span style='color:#00c000'&gt;/**&lt;br /&gt;    * Performs a callback on each element-visit, and each element removal&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    public static &amp;lt;T&amp;gt; Iterable&amp;lt;T&amp;gt; &lt;span style='color:yellow'&gt;eventHook&lt;/span&gt;(final Iterable&amp;lt;T&amp;gt; iterable,&lt;br /&gt;                                            final Operator&amp;lt;T&amp;gt; onVisit,&lt;br /&gt;                                            final Operator&amp;lt;T&amp;gt; onRemove)&lt;br /&gt;   {&lt;br /&gt;      if (iterable == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;      if (onVisit == null &amp;&amp; onRemove == null)&lt;br /&gt;         throw new NullPointerException("must specify either onVisit, onRemove or both");&lt;br /&gt;&lt;br /&gt;      return new Iterable&amp;lt;T&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Iterator&amp;lt;T&amp;gt; iterator()&lt;br /&gt;         {&lt;br /&gt;            final Iterator&amp;lt;T&amp;gt; iterator = iterable.iterator();&lt;br /&gt;&lt;br /&gt;            return new Iterator&amp;lt;T&amp;gt;()&lt;br /&gt;            {&lt;br /&gt;               @Override&lt;br /&gt;               public boolean hasNext()&lt;br /&gt;               {&lt;br /&gt;                  return iterator.hasNext();&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public T next()&lt;br /&gt;               {&lt;br /&gt;                  this.current = iterator.next();&lt;br /&gt;                  if (onVisit != null)&lt;br /&gt;                     onVisit.operate(this.current);&lt;br /&gt;                  return this.current;&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public void remove()&lt;br /&gt;               {&lt;br /&gt;                  iterator.remove();&lt;br /&gt;                  if (onRemove != null)&lt;br /&gt;                     onRemove.operate(this.current);&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               //&lt;br /&gt;&lt;br /&gt;               private T current;&lt;br /&gt;            };&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;Operator&amp;lt;String&amp;gt; onVisit= new Operator&amp;lt;String&amp;gt;()&lt;br /&gt;{&lt;br /&gt;   public void operate(String text)&lt;br /&gt;   {&lt;br /&gt;      System.out.println("visited: "+text);&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Operator&amp;lt;String&amp;gt; onRemove= new Operator&amp;lt;String&amp;gt;()&lt;br /&gt;{&lt;br /&gt;   public void operate(String text)&lt;br /&gt;   {&lt;br /&gt;      System.out.println("removed: "+text);&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Iterable&amp;lt;String&amp;gt; data = ...;&lt;br /&gt;&lt;br /&gt;for(String item: &lt;span style='color:yellow'&gt;eventHook&lt;/span&gt;(data, onVisit, onRemove))&lt;br /&gt;{&lt;br /&gt;   if(item.length() &gt; String.valueOf(Math.PI))&lt;br /&gt;      System.out.println("this text is longer than PI!");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Once you created an Iterable (say, a filtered view on a List) you can iterate over it as often as you want. No need to create a new Iterable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With the support for closures in Java 7 a lot of the boilerplate code will disappear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5712048815882675233?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5712048815882675233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-event-hooks.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5712048815882675233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5712048815882675233'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-event-hooks.html' title='Functions on Iterables :: Event Hooks'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-4116066620055548415</id><published>2010-07-20T19:31:00.007+02:00</published><updated>2010-07-20T19:39:46.550+02:00</updated><title type='text'>Functions on Iterables :: Transformer</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public interface &lt;span style='color:yellow'&gt;Transformer&lt;/span&gt;&amp;lt;I, O&amp;gt;&lt;br /&gt;{&lt;br /&gt;   public O transform(I item);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;Functional&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   &lt;span style='color:#00c000'&gt;/**&lt;br /&gt;    * Transforms Iterable&amp;lt;I&amp;gt; into Iterable&amp;lt;O&amp;gt; using a Transformer&amp;lt;I, O&amp;gt;&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;I, O&amp;gt; Iterable&amp;lt;O&amp;gt; &lt;span style='color:yellow'&gt;transform&lt;/span&gt;(final Iterable&amp;lt;I&amp;gt; iterable,&lt;br /&gt;                                              final Transformer&amp;lt;I, O&amp;gt; transformer)&lt;br /&gt;   {&lt;br /&gt;      if (iterable == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;      if (transformer == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;&lt;br /&gt;      return new Iterable&amp;lt;O&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Iterator&amp;lt;O&amp;gt; iterator()&lt;br /&gt;         {&lt;br /&gt;            final Iterator&amp;lt;I&amp;gt; iterator = iterable.iterator();&lt;br /&gt;&lt;br /&gt;            return new Iterator&amp;lt;O&amp;gt;()&lt;br /&gt;            {&lt;br /&gt;               @Override&lt;br /&gt;               public boolean hasNext()&lt;br /&gt;               {&lt;br /&gt;                  return iterator.hasNext();&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public O next()&lt;br /&gt;               {&lt;br /&gt;                  return transformer.transform(iterator.next());&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public void remove()&lt;br /&gt;               {&lt;br /&gt;                  iterator.remove();&lt;br /&gt;               }&lt;br /&gt;            };&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;Transformer&amp;lt;String, Integer&amp;gt; textToNumber = new Transformer&amp;lt;String, Integer&amp;gt;()&lt;br /&gt;{&lt;br /&gt;   public Integer transform(String text)&lt;br /&gt;   {&lt;br /&gt;      return Integer.valueOf(text);&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Iterable&amp;lt;String&amp;gt; data = ...;&lt;br /&gt;&lt;br /&gt;for(Integer number: &lt;span style='color:yellow'&gt;transform&lt;/span&gt;(data, textToNumber))&lt;br /&gt;{&lt;br /&gt;   System.out.println("number: "+number.intValue());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-4116066620055548415?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/4116066620055548415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-transformer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4116066620055548415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4116066620055548415'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-transformer.html' title='Functions on Iterables :: Transformer'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-3051097062040131232</id><published>2010-07-20T19:24:00.002+02:00</published><updated>2010-07-20T19:25:31.703+02:00</updated><title type='text'>Functions on Iterables :: Filter</title><content type='html'>Functional programming has its strengths when iterating over data. If you want a &lt;i&gt;view&lt;/i&gt; on a subset data, you can make a filter, and iterate over your data only seeing the elements that the filter accepted:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public interface &lt;span style='color:yellow'&gt;Filter&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;   public boolean &lt;span style='color:yellow'&gt;accept&lt;/span&gt;(T value);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;Functional&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   &lt;span style='color:#00c000'&gt;/**&lt;br /&gt;    * Filter items from the view of the returned Iterable&amp;lt;T&amp;gt;&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;T&amp;gt; Iterable&amp;lt;T&amp;gt; &lt;span style='color:yellow'&gt;filter&lt;/span&gt;(final Iterable&amp;lt;T&amp;gt; iterable, final Filter&amp;lt;T&amp;gt; filter)&lt;br /&gt;   {&lt;br /&gt;      if (iterable == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;      if (filter == null)&lt;br /&gt;         throw new NullPointerException();&lt;br /&gt;&lt;br /&gt;      return new Iterable&amp;lt;T&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Iterator&amp;lt;T&amp;gt; iterator()&lt;br /&gt;         {&lt;br /&gt;            final Iterator&amp;lt;T&amp;gt; iterator = iterable.iterator();&lt;br /&gt;&lt;br /&gt;            return new Iterator&amp;lt;T&amp;gt;()&lt;br /&gt;            {&lt;br /&gt;               @Override&lt;br /&gt;               public boolean hasNext()&lt;br /&gt;               {&lt;br /&gt;                  this.ensureReady();&lt;br /&gt;                  return this.ready;&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public T next()&lt;br /&gt;               {&lt;br /&gt;                  this.ensureReady();&lt;br /&gt;                  if (!this.ready)&lt;br /&gt;                     throw new NoSuchElementException();&lt;br /&gt;&lt;br /&gt;                  T result = this.current;&lt;br /&gt;                  this.ready = false;&lt;br /&gt;                  this.current = null;&lt;br /&gt;                  return result;&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               @Override&lt;br /&gt;               public void remove()&lt;br /&gt;               {&lt;br /&gt;                  iterator.remove();&lt;br /&gt;               }&lt;br /&gt;&lt;br /&gt;               //&lt;br /&gt;&lt;br /&gt;               private boolean ready = false;&lt;br /&gt;               private T       current;&lt;br /&gt;&lt;br /&gt;               private void ensureReady()&lt;br /&gt;               {&lt;br /&gt;                  while (!this.ready &amp;&amp; iterator.hasNext())&lt;br /&gt;                  {&lt;br /&gt;                     T item = iterator.next();&lt;br /&gt;                     if (!filter.accept(item))&lt;br /&gt;                        continue;&lt;br /&gt;&lt;br /&gt;                     this.ready = true;&lt;br /&gt;                     this.current = item;&lt;br /&gt;                  }&lt;br /&gt;               }&lt;br /&gt;            };&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;Filter&amp;lt;String&amp;gt; nonNull = new Filter&amp;lt;String&amp;gt;()&lt;br /&gt;{&lt;br /&gt;   public boolean accept(String value)&lt;br /&gt;   {&lt;br /&gt;      return value != null;&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Iterable&amp;lt;String&amp;gt; data = ...;&lt;br /&gt;&lt;br /&gt;for(String item: &lt;span style='color:yellow'&gt;filter&lt;/span&gt;(data, nonNull))&lt;br /&gt;{&lt;br /&gt;   System.out.println("item: "+item); &lt;span style='color:#00c000'&gt;// guaranteed not to be null&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-3051097062040131232?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/3051097062040131232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-filter.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3051097062040131232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3051097062040131232'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/07/functions-on-iterables-filter.html' title='Functions on Iterables :: Filter'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-6197708303260658718</id><published>2010-04-29T11:10:00.006+02:00</published><updated>2010-04-29T11:26:03.214+02:00</updated><title type='text'>Histogram :: array based</title><content type='html'>For any reasonably sized Histogram, you probably want to look at &lt;a href="http://riven8192.blogspot.com/2009/08/histogram-map-based.html"&gt;this Histogram class based on a HashMap&lt;/a&gt;. However, if your histograms are tiny, say, less than 8 elements occur frequently, this array based histogram is an order of magnitude faster.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Arrays;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.NoSuchElementException;&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;TinyHistogram&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;   private T[]   items;&lt;br /&gt;   private int[] usage;&lt;br /&gt;   private int   size;&lt;br /&gt;&lt;br /&gt;   public &lt;span style='color:yellow'&gt;TinyHistogram&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.items = (T[]) new Object[4];&lt;br /&gt;      this.usage = new int[4];&lt;br /&gt;      this.size = 0;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style='color:yellow'&gt;put&lt;/span&gt;(T item)&lt;br /&gt;   {&lt;br /&gt;      if (item == null)&lt;br /&gt;         throw new IllegalArgumentException();&lt;br /&gt;&lt;br /&gt;      int io = this.indexOfItem(item);&lt;br /&gt;&lt;br /&gt;      if (io != -1)&lt;br /&gt;      {&lt;br /&gt;         int result = ++this.usage[io];&lt;br /&gt;         this.swapIncreasedValue(io);&lt;br /&gt;         return result;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // add item to the end&lt;br /&gt;      if (this.size == this.items.length)&lt;br /&gt;         this.grow();&lt;br /&gt;      this.items[this.size] = item;&lt;br /&gt;      this.usage[this.size] = 1;&lt;br /&gt;      this.size += 1;&lt;br /&gt;      return 1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style='color:yellow'&gt;get&lt;/span&gt;(T item)&lt;br /&gt;   {&lt;br /&gt;      if (item == null)&lt;br /&gt;         throw new IllegalArgumentException();&lt;br /&gt;&lt;br /&gt;      int io = this.indexOfItem(item);&lt;br /&gt;      if (io == -1)&lt;br /&gt;         return 0; // not -1, as the object occurred zero times&lt;br /&gt;      return this.usage[io];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public List&amp;lt;T&amp;gt; &lt;span style='color:yellow'&gt;topKeys&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return this.topKeys(Integer.MAX_VALUE);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public List&amp;lt;T&amp;gt; &lt;span style='color:yellow'&gt;topKeys&lt;/span&gt;(int amount)&lt;br /&gt;   {&lt;br /&gt;      int end = Math.min(this.size, amount);&lt;br /&gt;&lt;br /&gt;      // make a copy, the items are already sorted&lt;br /&gt;      List&amp;lt;T&amp;gt; tops = new ArrayList&amp;lt;T&amp;gt;();&lt;br /&gt;      for (int i = 0; i &amp;lt; end; i++)&lt;br /&gt;         tops.add(this.items[i]);&lt;br /&gt;      return tops;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public List&amp;lt;Pair&amp;lt;T, Integer&amp;gt;&amp;gt; &lt;span style='color:yellow'&gt;topEntries&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return this.topEntries(Integer.MAX_VALUE);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public List&amp;lt;Pair&amp;lt;T, Integer&amp;gt;&amp;gt; &lt;span style='color:yellow'&gt;topEntries&lt;/span&gt;(int amount)&lt;br /&gt;   {&lt;br /&gt;      int end = Math.min(this.size, amount);&lt;br /&gt;&lt;br /&gt;      // make a copy, the items are already sorted&lt;br /&gt;      List&amp;lt;Pair&amp;lt;T, Integer&amp;gt;&amp;gt; tops = new ArrayList&amp;lt;Pair&amp;lt;T, Integer&amp;gt;&amp;gt;();&lt;br /&gt;      for (int i = 0; i &amp;lt; end; i++)&lt;br /&gt;         tops.add(new Pair&amp;lt;T, Integer&amp;gt;(this.items[i], Integer.valueOf(this.usage[i])));&lt;br /&gt;      return tops;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style='color:yellow'&gt;remove&lt;/span&gt;(T item)&lt;br /&gt;   {&lt;br /&gt;      int io = this.indexOfItem(item);&lt;br /&gt;      if (io == -1)&lt;br /&gt;         throw new NoSuchElementException(String.valueOf(item));&lt;br /&gt;&lt;br /&gt;      int result = --this.usage[io];&lt;br /&gt;      if (result == 0)&lt;br /&gt;         return this.removeIndex(io);&lt;br /&gt;&lt;br /&gt;      this.swapDecreasedValue(io);&lt;br /&gt;      return result;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style='color:yellow'&gt;reset&lt;/span&gt;(T item)&lt;br /&gt;   {&lt;br /&gt;      int io = this.indexOfItem(item);&lt;br /&gt;      if (io == -1)&lt;br /&gt;         throw new NoSuchElementException(String.valueOf(item));&lt;br /&gt;      return this.removeIndex(io);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private final void swapDecreasedValue(int index)&lt;br /&gt;   {&lt;br /&gt;      while ((index + 1) &amp;lt; size &amp;&amp; usage[index + 0] &amp;lt; usage[index + 1])&lt;br /&gt;      {&lt;br /&gt;         int a = index + 0;&lt;br /&gt;         int b = index + 1;&lt;br /&gt;&lt;br /&gt;         swapObj(items, a, b);&lt;br /&gt;         swapInt(usage, a, b);&lt;br /&gt;&lt;br /&gt;         index++;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private final void swapIncreasedValue(int index)&lt;br /&gt;   {&lt;br /&gt;      while (index &amp;gt; 0 &amp;&amp; usage[index + 0] &amp;gt; usage[index - 1])&lt;br /&gt;      {&lt;br /&gt;         int a = index - 0;&lt;br /&gt;         int b = index - 1;&lt;br /&gt;&lt;br /&gt;         swapObj(items, a, b);&lt;br /&gt;         swapInt(usage, a, b);&lt;br /&gt;&lt;br /&gt;         index--;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final void swapInt(int[] array, int a, int b)&lt;br /&gt;   {&lt;br /&gt;      int temp = array[a];&lt;br /&gt;      array[a] = array[b];&lt;br /&gt;      array[b] = temp;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final void swapObj(Object[] array, int a, int b)&lt;br /&gt;   {&lt;br /&gt;      Object temp = array[a];&lt;br /&gt;      array[a] = array[b];&lt;br /&gt;      array[b] = temp;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private void grow()&lt;br /&gt;   {&lt;br /&gt;      this.items = Arrays.copyOf(this.items, this.items.length * 2);&lt;br /&gt;      this.usage = Arrays.copyOf(this.usage, this.usage.length * 2);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private int removeIndex(int index)&lt;br /&gt;   {&lt;br /&gt;      int count = this.usage[index];&lt;br /&gt;      int shift = --this.size - index;&lt;br /&gt;      System.arraycopy(this.items, index + 1, this.items, index, shift);&lt;br /&gt;      System.arraycopy(this.usage, index + 1, this.usage, index, shift);&lt;br /&gt;      return count;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private int indexOfItem(T item)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &amp;lt; this.size; i++)&lt;br /&gt;         if (this.items[i] == item || this.items[i].equals(item))&lt;br /&gt;            return i;&lt;br /&gt;      return -1;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-6197708303260658718?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/6197708303260658718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/04/histogram-array-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6197708303260658718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6197708303260658718'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/04/histogram-array-based.html' title='Histogram :: array based'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-7432787170311742435</id><published>2010-04-29T10:58:00.001+02:00</published><updated>2010-04-29T10:58:44.110+02:00</updated><title type='text'>Slicing direct buffers to workaround 4K overhead</title><content type='html'>Direct &lt;tt&gt;ByteBuffers&lt;/tt&gt; can have an unexpected massive overhead. For every allocation, a number of bytes equal to the system pagesize (typically 4K) is added. The reason for this is that &lt;tt&gt;MappedByteBuffers&lt;/tt&gt; must be page-aligned. The code used behind the scenes in &lt;tt&gt;ByteBuffer.allocateDirect(int size)&lt;/tt&gt; looks a little something like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;private static ByteBuffer malloc(int size)&lt;br /&gt;{&lt;br /&gt;   int pageSize = unsafe.getPageSize(); // typically 4096&lt;br /&gt;   long pointer = sun.misc.Unsafe.malloc(size + pageSize);&lt;br /&gt;   long base = (pointer + (pageSize-1)) / pageSize * pageSize;&lt;br /&gt;   ByteBuffer buffer = unsafe.createBufferAt(base);&lt;br /&gt;   return buffer;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Code like this will have a massive overhead:&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;for(int i=0; i&amp;lt;count; i++)&lt;br /&gt;   buffers[i] = ByteBuffer.allocateDirect(64);&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Instead use an approach like below:&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style='color:yellow'&gt;DirectBufferProvider&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   private static final int ALLOCATION_SIZE = 1024*1024;&lt;br /&gt;&lt;br /&gt;   private ByteBuffer currentBuffer = null;&lt;br /&gt;&lt;br /&gt;   public ByteBuffer &lt;span style='color:yellow'&gt;allocate&lt;/span&gt;(int size)&lt;br /&gt;   {&lt;br /&gt;      if(size &amp;gt;= ALLOCATION_SIZE)&lt;br /&gt;         return ByteBuffer.allocateDirect(size);&lt;br /&gt;&lt;br /&gt;      if(currentBuffer == null || size &amp;gt; currentBuffer.remaining())&lt;br /&gt;         currentBuffer = ByteBuffer.allocateDirect(ALLOCATION_SIZE);&lt;br /&gt;&lt;br /&gt;      currentBuffer.limit(currentBuffer.position() + size);&lt;br /&gt;      ByteBuffer result = currentBuffer.slice();&lt;br /&gt;      currentBuffer.position(currentBuffer.limit());&lt;br /&gt;      currentBuffer.limit(currentBuffer.capacity());&lt;br /&gt;      return result;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   private static DirectBufferProvider global_synced = new DirectBufferProvider();&lt;br /&gt;&lt;br /&gt;   public static ByteBuffer &lt;span style='color:yellow'&gt;allocateDirect&lt;/span&gt;(int size)&lt;br /&gt;   {&lt;br /&gt;      synchronized(global_synced)&lt;br /&gt;      {&lt;br /&gt;         return global_synced.allocate(size);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Note that unlike &lt;tt&gt;ByteBuffer.allocateDirect()&lt;/tt&gt;, the code in &lt;tt&gt;DirectBufferProvider.allocate()&lt;/tt&gt; is not threadsafe. The static (convenience) method is synchronized and should thus not be used in heavily multithreaded code. Using &lt;tt&gt;ThreadLocals&lt;/tt&gt; is even worse, performance wise, so just make new &lt;tt&gt;DirectBufferProvider&lt;/tt&gt; instances when you need them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-7432787170311742435?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/7432787170311742435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/04/slicing-direct-buffers-to-workaround-4k.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7432787170311742435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7432787170311742435'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/04/slicing-direct-buffers-to-workaround-4k.html' title='Slicing direct buffers to workaround 4K overhead'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-6775921950204308360</id><published>2010-02-23T16:56:00.037+01:00</published><updated>2010-04-06T16:34:56.291+02:00</updated><title type='text'>Delaying security dialogs in Java until you need them</title><content type='html'>Delaying security dialogs in Java until you need them, is a bit harder than it should be. By default, the dialog appears before the first line of code is executed, scaring off your casual visitor.&lt;br /&gt;&lt;br /&gt;If you only occasionally need to perform actions that require elevated privileges, you can delay the security dialog to the absolute last moment (for example: right before reading/writing a file). The trick is to keep most of your code in an unsigned JAR, and the code that requires elevated privileges into a signed JAR. Use &lt;tt&gt;Class.forName(String)&lt;/tt&gt; to load the signed class, which will prompt the security dialog.&lt;br /&gt;&lt;br /&gt;Using an interface in the unsigned code, and the implementation in the signed code, you can keep your code tidy.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;&lt;br /&gt;The browser will remember the choice of the user, until a *restart* of the browser. To workaround this (when people declined), create a dozen tiny signed JARs (with a dozen different certificates, mind you) and use a roundrobin algorithm, using serverside code or javascript that generates the applet-archive attribute. After a dozen hits and rejections, you can be sure your visitor will never grant access to his system anyway.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;Update:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;&lt;br /&gt;To make it work in MSIE, both classes MUST be in separate packages.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color=red&gt;&lt;b&gt;IMPORTANT: Since 6u19 this doesn't work anymore. You not only get a rather confusing security dialog (clicking [YES] means deny access, clicking [NO] means allow access), the two classes end up in different classloaders that cannot access eachother, resulting in ClassNotFoundException / NoClassDefFoundException. Thanks Oracle, for making Java's user experience even more secure and crap at the same time.&lt;br /&gt;&lt;a href="http://java.sun.com/javase/6/docs/technotes/guides/jweb/mixed_code.html" target="_blank"&gt;http://java.sun.com/javase/6/docs/technotes/guides/jweb/mixed_code.html&lt;/a&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On to the code, which is reasonably simple.&lt;br /&gt;&lt;br /&gt;&lt;span style='color:#80C0E0'&gt;&lt;b&gt;Unsigned JAR:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;package &lt;span style='color:cyan'&gt;some.unsigned.stuff&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;public interface &lt;span style='color:yellow'&gt;SecureAccess&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public byte[] loadFile(File file);&lt;br /&gt;   public void storeFile(File file, byte[] data);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;     // Usage:&lt;br /&gt;&lt;br /&gt;     File file = new File("/home/silly/image.jpg");&lt;br /&gt;     Class&lt; ? &gt; clazz = Class.forName("&lt;span style='color:cyan'&gt;some.signed.stuff&lt;/span&gt;.LocalSecureAccess");&lt;br /&gt;     SecureAccess access = (SecureAccess) clazz.newInstance();&lt;br /&gt;     byte[] data = &lt;span style='color:yellow'&gt;access.loadFile(file);&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style='color:#80C0E0'&gt;&lt;b&gt;Signed JAR:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;package &lt;span style='color:cyan'&gt;some.signed.stuff&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;LocalSecureAccess&lt;/span&gt; implements SecureAccess&lt;br /&gt;{&lt;br /&gt;   public byte[] loadFile(final File file)&lt;br /&gt;   {&lt;br /&gt;      return AccessController.doPrivileged(new PrivilegedAction&amp;lt;byte[]&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public byte[] run()&lt;br /&gt;         {&lt;br /&gt;            return loadFileImpl(file);&lt;br /&gt;         }&lt;br /&gt;      });&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void storeFile(final File file, final byte[] data)&lt;br /&gt;   {&lt;br /&gt;      AccessController.doPrivileged(new PrivilegedAction&amp;lt;Object&amp;gt;()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public Object run()&lt;br /&gt;         {&lt;br /&gt;            storeFileImpl(file, data);&lt;br /&gt;&lt;br /&gt;            return null;&lt;br /&gt;         }&lt;br /&gt;      });&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // implementation&lt;br /&gt;&lt;br /&gt;   static final int MAX_FILE_SIZE = 8 * 1024 * 1024; // prevent applet running out of memory&lt;br /&gt;&lt;br /&gt;   byte[] loadFileImpl(File file)&lt;br /&gt;   {&lt;br /&gt;      DataInputStream input = null;&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         long len = file.length();&lt;br /&gt;         if (len &amp;gt; MAX_FILE_SIZE)&lt;br /&gt;            throw new IllegalStateException("file too big: " + file);&lt;br /&gt;&lt;br /&gt;         byte[] data = new byte[(int) len];&lt;br /&gt;         input = new DataInputStream(new FileInputStream(file));&lt;br /&gt;         input.readFully(data);&lt;br /&gt;         input.close();&lt;br /&gt;         return data;&lt;br /&gt;      }&lt;br /&gt;      catch (IOException exc)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException(exc);&lt;br /&gt;      }&lt;br /&gt;      finally&lt;br /&gt;      {&lt;br /&gt;         try { if(input!=null) input.close(); } catch(IOException exc) {}&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   void storeFileImpl(File file, byte[] data)&lt;br /&gt;   {&lt;br /&gt;      OutputStream output = null;&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         output = new FileOutputStream(file);&lt;br /&gt;         output.write(data);&lt;br /&gt;         output.flush();&lt;br /&gt;      }&lt;br /&gt;      catch (IOException exc)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException(exc);&lt;br /&gt;      }&lt;br /&gt;      finally&lt;br /&gt;      {&lt;br /&gt;         try { if(output!=null) output.close(); } catch(IOException exc) {}&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style='color:#80C0E0'&gt;&lt;b&gt;Jar signing 101: (using DSA keys instead of RSA for Java 1.4 compatibility)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;PATH=%PATH%;path\to\JDK\bin&lt;br /&gt;SET ALIAS=MY_ALIAS&lt;br /&gt;SET PASS=MY_PASSWORD&lt;br /&gt;SET JAR=my.jar&lt;br /&gt;&lt;br /&gt;keytool -delete -storepass %PASS% -alias %ALIAS%&lt;br /&gt;keytool -genkey -storepass %PASS% -keypass %PASS% -keyalg &lt;span style='color:yellow'&gt;DSA&lt;/span&gt; -alias %ALIAS%&lt;br /&gt;   -dname "CN=full.domainname.com, OU=Your unit, O=Your Company,&lt;br /&gt;           L=Your city, ST=Your state, C=CA,&lt;br /&gt;           EMAILADDRESS=your@server.com DC=server, DC=com"&lt;br /&gt;   -validity 999 &lt;span style='color:red'&gt;(put all of this on one line)&lt;/span&gt;&lt;br /&gt;keytool -selfcert -storepass %PASS% -alias %ALIAS% -validity 999&lt;br /&gt;keytool -exportcert -storepass %PASS% -alias %ALIAS% -rfc -file %ALIAS%.cer&lt;br /&gt;jarsigner -storepass %PASS% -keypass %PASS% %JAR% %ALIAS%&lt;br /&gt;pause&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style='color:#80C0E0'&gt;&lt;b&gt;Applet code: (nothing special)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;&amp;nbsp; &amp;nbsp; &amp;lt;applet&lt;br /&gt;      code="package/of/YourApplet.class"&lt;br /&gt;      archive="unsigned.jar,signed.jar"&lt;br /&gt;      width="640"&lt;br /&gt;      height="480"&amp;gt;&lt;br /&gt;      no applet?&lt;br /&gt;    &amp;lt;/applet&amp;gt;  &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-6775921950204308360?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/6775921950204308360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/02/delaying-security-dialogs-in-java-until.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6775921950204308360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6775921950204308360'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/02/delaying-security-dialogs-in-java-until.html' title='Delaying security dialogs in Java until you need them'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-8254159098542542230</id><published>2010-02-04T19:23:00.007+01:00</published><updated>2010-02-04T19:39:54.869+01:00</updated><title type='text'>Image :: Java Animated GIFs (with transparant pixel disposal modes)</title><content type='html'>It's a nightmare to find the code to create animated GIFs in Java. Once you found it, you notice you can't set the frame disposal, and transparent pixels will show pixels in the previous frames. The following code snippet solves this.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style='color:yellow'&gt;GifFrame&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static final String NONE                = "none";&lt;br /&gt;   public static final String DO_NOT_DISPOSE      = "doNotDispose";&lt;br /&gt;   public static final String RESTORE_TO_BGCOLOR  = "restoreToBackgroundColor";&lt;br /&gt;   public static final String RESTORE_TO_PREVIOUS = "restoreToPrevious";&lt;br /&gt;&lt;br /&gt;   public final BufferedImage img;&lt;br /&gt;   public final long          delay; // in millis&lt;br /&gt;   public final String        disposalMethod;&lt;br /&gt;&lt;br /&gt;   public GifFrame(BufferedImage img, long delay)&lt;br /&gt;   {&lt;br /&gt;      this(img, delay, NONE);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public GifFrame(BufferedImage img, long delay, String disposalMethod)&lt;br /&gt;   {&lt;br /&gt;      this.img = img;&lt;br /&gt;      this.delay = delay;&lt;br /&gt;      this.disposalMethod = disposalMethod;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style='color:yellow'&gt;ImageUtil&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static BufferedImage &lt;span style='color:yellow'&gt;convertRGBAToGIF&lt;/span&gt;(BufferedImage src, int transColor)&lt;br /&gt;   {&lt;br /&gt;      BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);&lt;br /&gt;      Graphics g = dst.getGraphics();&lt;br /&gt;      g.setColor(new Color(transColor));&lt;br /&gt;      g.fillRect(0, 0, dst.getWidth(), dst.getHeight());&lt;br /&gt;      {&lt;br /&gt;         IndexColorModel indexedModel = (IndexColorModel) dst.getColorModel();&lt;br /&gt;         WritableRaster raster = dst.getRaster();&lt;br /&gt;         int sample = raster.getSample(0, 0, 0);&lt;br /&gt;         int size = indexedModel.getMapSize();&lt;br /&gt;         byte[] rr = new byte[size];&lt;br /&gt;         byte[] gg = new byte[size];&lt;br /&gt;         byte[] bb = new byte[size];&lt;br /&gt;         indexedModel.getReds(rr);&lt;br /&gt;         indexedModel.getGreens(gg);&lt;br /&gt;         indexedModel.getBlues(bb);&lt;br /&gt;         IndexColorModel newModel = new IndexColorModel(8, size, rr, gg, bb, sample);&lt;br /&gt;         dst = new BufferedImage(newModel, raster, dst.isAlphaPremultiplied(), null);&lt;br /&gt;      }&lt;br /&gt;      dst.createGraphics().drawImage(src, 0, 0, null);&lt;br /&gt;      return dst;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void &lt;span style='color:yellow'&gt;saveAnimatedGIF&lt;/span&gt;(OutputStream out, List&amp;lt;GifFrame&amp;gt; frames, int loopCount) throws Exception&lt;br /&gt;   {&lt;br /&gt;      ImageWriter iw = ImageIO.getImageWritersByFormatName("gif").next();&lt;br /&gt;&lt;br /&gt;      ImageOutputStream ios = ImageIO.createImageOutputStream(out);&lt;br /&gt;      iw.setOutput(ios);&lt;br /&gt;      iw.prepareWriteSequence(null);&lt;br /&gt;&lt;br /&gt;      int p = 0;&lt;br /&gt;      for (GifFrame frame : frames)&lt;br /&gt;      {&lt;br /&gt;         ImageWriteParam iwp = iw.getDefaultWriteParam();&lt;br /&gt;         IIOMetadata metadata = iw.getDefaultImageMetadata(new ImageTypeSpecifier(frame.img), iwp);&lt;br /&gt;         ImageUtil.configureGIFFrame(metadata, String.valueOf(frame.delay / 10L), p++, frame.disposalMethod, loopCount);&lt;br /&gt;         IIOImage ii = new IIOImage(frame.img, null, metadata);&lt;br /&gt;         iw.writeToSequence(ii, null);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      iw.endWriteSequence();&lt;br /&gt;      ios.close();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static void configureGIFFrame(IIOMetadata meta, String delayTime, int imageIndex, String disposalMethod, int loopCount)&lt;br /&gt;   {&lt;br /&gt;      String metaFormat = meta.getNativeMetadataFormatName();&lt;br /&gt;&lt;br /&gt;      if (!"javax_imageio_gif_image_1.0".equals(metaFormat))&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalArgumentException("Unfamiliar gif metadata format: " + metaFormat);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      Node root = meta.getAsTree(metaFormat);&lt;br /&gt;&lt;br /&gt;      Node child = root.getFirstChild();&lt;br /&gt;      while (child != null)&lt;br /&gt;      {&lt;br /&gt;         if ("GraphicControlExtension".equals(child.getNodeName()))&lt;br /&gt;            break;&lt;br /&gt;         child = child.getNextSibling();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      IIOMetadataNode gce = (IIOMetadataNode) child;&lt;br /&gt;      gce.setAttribute("userDelay", "FALSE");&lt;br /&gt;      gce.setAttribute("delayTime", delayTime);&lt;br /&gt;      gce.setAttribute("disposalMethod", disposalMethod);&lt;br /&gt;&lt;br /&gt;      if (imageIndex == 0)&lt;br /&gt;      {&lt;br /&gt;         IIOMetadataNode aes = new IIOMetadataNode("ApplicationExtensions");&lt;br /&gt;         IIOMetadataNode ae = new IIOMetadataNode("ApplicationExtension");&lt;br /&gt;         ae.setAttribute("applicationID", "NETSCAPE");&lt;br /&gt;         ae.setAttribute("authenticationCode", "2.0");&lt;br /&gt;         byte[] uo = new byte[] { 0x1, (byte) (loopCount &amp; 0xFF), (byte) ((loopCount &gt;&gt; 8) &amp; 0xFF) };&lt;br /&gt;         ae.setUserObject(uo);&lt;br /&gt;         aes.appendChild(ae);&lt;br /&gt;         root.appendChild(aes);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         meta.setFromTree(metaFormat, root);&lt;br /&gt;      }&lt;br /&gt;      catch (IIOInvalidTreeException e)&lt;br /&gt;      {&lt;br /&gt;         throw new Error(e);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;List&amp;lt;GifFrame&amp;gt; gifFrames = new ArrayList&amp;lt;GifFrame&amp;gt;();&lt;br /&gt;&lt;br /&gt;   for(BufferedImage image: images)&lt;br /&gt;   {&lt;br /&gt;      int transparantColor = 0xFF00FF; // purple&lt;br /&gt;      BufferedImage gif = convertRGBAToGIF(image, transparantColor);&lt;br /&gt;      long delay = 100; // every frame takes 100ms&lt;br /&gt;      String disposal = GifFrame.RESTORE_TO_BGCOLOR; // make transparent pixels not 'shine through'&lt;br /&gt;      gifFrames.add(new GifFrame(gif, delay, disposal));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   int loopCount = 0; // loop indefinitely&lt;br /&gt;   saveAnimatedGIF(outputStream, gifFrames, loopCount);&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-8254159098542542230?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/8254159098542542230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/02/image-java-animated-gifs.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/8254159098542542230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/8254159098542542230'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/02/image-java-animated-gifs.html' title='Image :: Java Animated GIFs (with transparant pixel disposal modes)'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-478154665222905136</id><published>2010-02-04T19:14:00.008+01:00</published><updated>2010-02-04T19:17:04.086+01:00</updated><title type='text'>Image :: read/write TGA</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public static BufferedImage &lt;span style="color:yellow"&gt;readTGA&lt;/span&gt;(File file) throws IOException&lt;br /&gt;   {&lt;br /&gt;      if (!file.exists())&lt;br /&gt;         throw new FileNotFoundException(file.getAbsolutePath());&lt;br /&gt;&lt;br /&gt;      byte[] header = new byte[18];&lt;br /&gt;      int len = (int) file.length() - header.length;&lt;br /&gt;      if (len &lt; 0)&lt;br /&gt;         throw new IllegalStateException("file not big enough to contain header: " + file.getAbsolutePath());&lt;br /&gt;      byte[] data = new byte[len];&lt;br /&gt;&lt;br /&gt;      RandomAccessFile raf = new RandomAccessFile(file, "r");&lt;br /&gt;      raf.read(header);&lt;br /&gt;      raf.read(data);&lt;br /&gt;      raf.close();&lt;br /&gt;&lt;br /&gt;      if ((header[0] | header[1]) != 0)&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      if (header[2] != 2)&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      int w = 0, h = 0;&lt;br /&gt;      w |= (header[12] &amp; 0xFF) &lt;&lt; 0;&lt;br /&gt;      w |= (header[13] &amp; 0xFF) &lt;&lt; 8;&lt;br /&gt;      h |= (header[14] &amp; 0xFF) &lt;&lt; 0;&lt;br /&gt;      h |= (header[15] &amp; 0xFF) &lt;&lt; 8;&lt;br /&gt;&lt;br /&gt;      boolean alpha;&lt;br /&gt;      if ((w * h) * 3 == data.length)&lt;br /&gt;         alpha = false;&lt;br /&gt;      else if ((w * h) * 4 == data.length)&lt;br /&gt;         alpha = true;&lt;br /&gt;      else&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      if (!alpha &amp;&amp; (header[16] != 24))&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      if (alpha &amp;&amp; (header[16] != 32))&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      if ((header[17] &amp; 15) != (alpha ? 8 : 0))&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;&lt;br /&gt;      BufferedImage dst = new BufferedImage(w, h, alpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);&lt;br /&gt;      int[] pixels = ((DataBufferInt) dst.getRaster().getDataBuffer()).getData();&lt;br /&gt;      if (pixels.length != w * h)&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;      if (data.length != pixels.length * (alpha ? 4 : 3))&lt;br /&gt;         throw new IllegalStateException(file.getAbsolutePath());&lt;br /&gt;&lt;br /&gt;      if (alpha)&lt;br /&gt;      {&lt;br /&gt;         for (int i = 0, p = (pixels.length - 1) * 4; i &lt; pixels.length; i++, p -= 4)&lt;br /&gt;         {&lt;br /&gt;            pixels[i] |= ((data[p + 0]) &amp; 0xFF) &lt;&lt; 0;&lt;br /&gt;            pixels[i] |= ((data[p + 1]) &amp; 0xFF) &lt;&lt; 8;&lt;br /&gt;            pixels[i] |= ((data[p + 2]) &amp; 0xFF) &lt;&lt; 16;&lt;br /&gt;            pixels[i] |= ((data[p + 3]) &amp; 0xFF) &lt;&lt; 24;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         for (int i = 0, p = (pixels.length - 1) * 3; i &lt; pixels.length; i++, p -= 3)&lt;br /&gt;         {&lt;br /&gt;            pixels[i] |= ((data[p + 0]) &amp; 0xFF) &lt;&lt; 0;&lt;br /&gt;            pixels[i] |= ((data[p + 1]) &amp; 0xFF) &lt;&lt; 8;&lt;br /&gt;            pixels[i] |= ((data[p + 2]) &amp; 0xFF) &lt;&lt; 16;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if ((header[17] &gt;&gt; 4) == 1)&lt;br /&gt;      {&lt;br /&gt;         // ok&lt;br /&gt;      }&lt;br /&gt;      else if ((header[17] &gt;&gt; 4) == 0)&lt;br /&gt;      {&lt;br /&gt;         // flip horizontally&lt;br /&gt;&lt;br /&gt;         for (int y = 0; y &lt; h; y++)&lt;br /&gt;         {&lt;br /&gt;            int w2 = w / 2;&lt;br /&gt;            for (int x = 0; x &lt; w2; x++)&lt;br /&gt;            {&lt;br /&gt;               int a = (y * w) + x;&lt;br /&gt;               int b = (y * w) + (w - 1 - x);&lt;br /&gt;               int t = pixels[a];&lt;br /&gt;               pixels[a] = pixels[b];&lt;br /&gt;               pixels[b] = t;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         throw new UnsupportedOperationException(file.getAbsolutePath());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return dst;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void &lt;span style="color:yellow"&gt;writeTGA&lt;/span&gt;(BufferedImage src, File file) throws IOException&lt;br /&gt;   {&lt;br /&gt;      DataBuffer buffer = src.getRaster().getDataBuffer();&lt;br /&gt;      boolean alpha = src.getColorModel().hasAlpha();&lt;br /&gt;      byte[] data;&lt;br /&gt;&lt;br /&gt;      if (buffer instanceof DataBufferByte)&lt;br /&gt;      {&lt;br /&gt;         byte[] pixels = ((DataBufferByte) src.getRaster().getDataBuffer()).getData();&lt;br /&gt;         if (pixels.length != src.getWidth() * src.getHeight() * (alpha ? 4 : 3))&lt;br /&gt;            throw new IllegalStateException();&lt;br /&gt;&lt;br /&gt;         data = new byte[pixels.length];&lt;br /&gt;&lt;br /&gt;         for (int i = 0, p = pixels.length - 1; i &lt; data.length; i++, p--)&lt;br /&gt;         {&lt;br /&gt;            data[i] = pixels[p];&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      else if (buffer instanceof DataBufferInt)&lt;br /&gt;      {&lt;br /&gt;         int[] pixels = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();&lt;br /&gt;         if (pixels.length != src.getWidth() * src.getHeight())&lt;br /&gt;            throw new IllegalStateException();&lt;br /&gt;&lt;br /&gt;         data = new byte[pixels.length * (alpha ? 4 : 3)];&lt;br /&gt;&lt;br /&gt;         if (alpha)&lt;br /&gt;         {&lt;br /&gt;            for (int i = 0, p = pixels.length - 1; i &lt; data.length; i += 4, p--)&lt;br /&gt;            {&lt;br /&gt;               data[i + 0] = (byte) ((pixels[p] &gt;&gt; 0) &amp; 0xFF);&lt;br /&gt;               data[i + 1] = (byte) ((pixels[p] &gt;&gt; 8) &amp; 0xFF);&lt;br /&gt;               data[i + 2] = (byte) ((pixels[p] &gt;&gt; 16) &amp; 0xFF);&lt;br /&gt;               data[i + 3] = (byte) ((pixels[p] &gt;&gt; 24) &amp; 0xFF);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            for (int i = 0, p = pixels.length - 1; i &lt; data.length; i += 3, p--)&lt;br /&gt;            {&lt;br /&gt;               data[i + 0] = (byte) ((pixels[p] &gt;&gt; 0) &amp; 0xFF);&lt;br /&gt;               data[i + 1] = (byte) ((pixels[p] &gt;&gt; 8) &amp; 0xFF);&lt;br /&gt;               data[i + 2] = (byte) ((pixels[p] &gt;&gt; 16) &amp; 0xFF);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         throw new UnsupportedOperationException();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      byte[] header = new byte[18];&lt;br /&gt;      header[2] = 2; // uncompressed, true-color image&lt;br /&gt;      header[12] = (byte) ((src.getWidth() &gt;&gt; 0) &amp; 0xFF);&lt;br /&gt;      header[13] = (byte) ((src.getWidth() &gt;&gt; 8) &amp; 0xFF);&lt;br /&gt;      header[14] = (byte) ((src.getHeight() &gt;&gt; 0) &amp; 0xFF);&lt;br /&gt;      header[15] = (byte) ((src.getHeight() &gt;&gt; 8) &amp; 0xFF);&lt;br /&gt;      header[16] = (byte) (alpha ? 32 : 24); // bits per pixel&lt;br /&gt;      header[17] = (byte) ((alpha ? 8 : 0) | (1 &lt;&lt; 4));&lt;br /&gt;&lt;br /&gt;      RandomAccessFile raf = new RandomAccessFile(file, "rw");&lt;br /&gt;      raf.write(header);&lt;br /&gt;      raf.write(data);&lt;br /&gt;      raf.setLength(raf.getFilePointer()); // trim&lt;br /&gt;      raf.close();&lt;br /&gt;   }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-478154665222905136?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/478154665222905136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/02/image-readwrite-tga.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/478154665222905136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/478154665222905136'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/02/image-readwrite-tga.html' title='Image :: read/write TGA'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5633831202327443418</id><published>2010-02-04T18:56:00.025+01:00</published><updated>2010-12-22T01:16:03.860+01:00</updated><title type='text'>FastMath :: fast floor + ceil</title><content type='html'>Calling Math.floor() simply takes too long. The problem with optimizing is that you can't simply cast the floatingpoint number to an integer, because that will result in invalid results for negative numbers. If we know our input values are in a specific range, we can safely add a certain (big) constant to the input, cast the guaranteed positive value to an integer and subtract the constant again.&lt;br /&gt;&lt;br /&gt;The code is ~9x faster than Math.floor(). Replacing the doubles with floats makes it faster, but the results are rather... random, so don't.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;FastMath&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   private static final int    BIG_ENOUGH_INT   = 16 * 1024;&lt;br /&gt;   private static final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT + 0.0000;&lt;br /&gt;   private static final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5000;&lt;br /&gt;   private static final double BIG_ENOUGH_CEIL  = BIG_ENOUGH_INT + 0.9999;&lt;br /&gt;&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;fastFloor&lt;/span&gt;(float x) {&lt;br /&gt;      return (int) (x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;fastRound&lt;/span&gt;(float x) {&lt;br /&gt;      return (int) (x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;fastCeil&lt;/span&gt;(float x) {&lt;br /&gt;      return (int) (x + BIG_ENOUGH_CEIL) - BIG_ENOUGH_INT;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5633831202327443418?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5633831202327443418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2010/02/fastmath-fast-floor.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5633831202327443418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5633831202327443418'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2010/02/fastmath-fast-floor.html' title='FastMath :: fast floor + ceil'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5337100521118367574</id><published>2009-10-26T15:55:00.007+01:00</published><updated>2009-10-26T17:31:00.921+01:00</updated><title type='text'>Image :: read size of JPG/PNG/BMP/GIF</title><content type='html'>If you would believe Google, everybody is searching for code that reads the dimensions of an image,without loading all those colorful pixels. Oh well, without further ado....&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;ImageUtil&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static Dimension &lt;span style="color:yellow"&gt;getImageDimension&lt;/span&gt;(File file) throws IOException&lt;br /&gt;   {&lt;br /&gt;      return ImageUtil.getImageDimension(new FileInputStream(file));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static Dimension &lt;span style="color:yellow"&gt;getImageDimension&lt;/span&gt;(InputStream in) throws IOException&lt;br /&gt;   {&lt;br /&gt;      DataInputStream dis = new DataInputStream(in);&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         int header = dis.readUnsignedShort();&lt;br /&gt;&lt;br /&gt;         if (header == 0x8950)&lt;br /&gt;         {&lt;br /&gt;            &lt;span style="color:#00C000"&gt;// PNG&lt;/span&gt;&lt;br /&gt;            dis.readFully(new byte[(8 - 2) + 4 + 4]); // thanks Abuse&lt;br /&gt;&lt;br /&gt;            return new Dimension(dis.readInt(), dis.readInt());&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         if (header == 0xffd8)&lt;br /&gt;         {&lt;br /&gt;            &lt;span style="color:#00C000"&gt;// JPG (see below)&lt;/span&gt;&lt;br /&gt;         }&lt;br /&gt;         else if (header == 0x424D)&lt;br /&gt;         {&lt;br /&gt;            &lt;span style="color:#00C000"&gt;// BMP&lt;/span&gt;&lt;br /&gt;            dis.readFully(new byte[16]);&lt;br /&gt;&lt;br /&gt;            int w = dis.read() | (dis.read() &lt;&lt; 8) | (dis.read() &lt;&lt; 16) | (dis.read() &lt;&lt; 24);&lt;br /&gt;            int h = dis.read() | (dis.read() &lt;&lt; 8) | (dis.read() &lt;&lt; 16) | (dis.read() &lt;&lt; 24);&lt;br /&gt;            return new Dimension(w, h);&lt;br /&gt;         }&lt;br /&gt;         else if (header == (('G' &lt;&lt; 8) | ('I' &lt;&lt; 0))) // GIF&lt;br /&gt;         {&lt;br /&gt;            &lt;span style="color:#00C000"&gt;// GIF&lt;/span&gt;&lt;br /&gt;            dis.readFully(new byte[4]);&lt;br /&gt;            int w = dis.read() | (dis.read() &lt;&lt; 8);&lt;br /&gt;            int h = dis.read() | (dis.read() &lt;&lt; 8);&lt;br /&gt;            return new Dimension(w, h);&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            throw new IllegalStateException("unexpected header: " + Integer.toHexString(header));&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         while (true) &lt;span style="color:#00C000"&gt;// JPG is not so straight forward&lt;/span&gt;&lt;br /&gt;         {&lt;br /&gt;            int marker = dis.readUnsignedShort();&lt;br /&gt;&lt;br /&gt;            switch (marker)&lt;br /&gt;            {&lt;br /&gt;               case 0xffd8: // SOI&lt;br /&gt;               case 0xffd0: // RST0&lt;br /&gt;               case 0xffd1: // RST1&lt;br /&gt;               case 0xffd2: // RST2&lt;br /&gt;               case 0xffd3: // RST3&lt;br /&gt;               case 0xffd4: // RST4&lt;br /&gt;               case 0xffd5: // RST5&lt;br /&gt;               case 0xffd6: // RST6&lt;br /&gt;               case 0xffd7: // RST7&lt;br /&gt;               case 0xffd9: // EOI&lt;br /&gt;                  break;&lt;br /&gt;&lt;br /&gt;               case 0xffdd: // DRI&lt;br /&gt;                  dis.readUnsignedShort();&lt;br /&gt;                  break;&lt;br /&gt;&lt;br /&gt;               case 0xffe0: // APP0&lt;br /&gt;               case 0xffe1: // APP1&lt;br /&gt;               case 0xffe2: // APP2&lt;br /&gt;               case 0xffe3: // APP3&lt;br /&gt;               case 0xffe4: // APP4&lt;br /&gt;               case 0xffe5: // APP5&lt;br /&gt;               case 0xffe6: // APP6&lt;br /&gt;               case 0xffe7: // APP7&lt;br /&gt;               case 0xffe8: // APP8&lt;br /&gt;               case 0xffe9: // APP9&lt;br /&gt;               case 0xffea: // APPa&lt;br /&gt;               case 0xffeb: // APPb&lt;br /&gt;               case 0xffec: // APPc&lt;br /&gt;               case 0xffed: // APPd&lt;br /&gt;               case 0xffee: // APPe&lt;br /&gt;               case 0xffef: // APPf&lt;br /&gt;               case 0xfffe: // COM&lt;br /&gt;               case 0xffdb: // DQT&lt;br /&gt;               case 0xffc4: // DHT&lt;br /&gt;               case 0xffda: // SOS&lt;br /&gt;                  dis.readFully(new byte[dis.readUnsignedShort() - 2]);&lt;br /&gt;                  break;&lt;br /&gt;&lt;br /&gt;               case 0xffc0: // SOF0&lt;br /&gt;               case 0xffc2: // SOF2&lt;br /&gt;                  dis.readUnsignedShort();&lt;br /&gt;                  dis.readByte();&lt;br /&gt;                  int height = dis.readUnsignedShort();&lt;br /&gt;                  int width = dis.readUnsignedShort();&lt;br /&gt;                  return new Dimension(width, height);&lt;br /&gt;&lt;br /&gt;               default:&lt;br /&gt;                  throw new IllegalStateException("invalid jpg marker: " + Integer.toHexString(marker));&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      finally&lt;br /&gt;      {&lt;br /&gt;         dis.close();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5337100521118367574?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5337100521118367574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/10/image-fetch-size-of-jpgpngbmpgif.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5337100521118367574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5337100521118367574'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/10/image-fetch-size-of-jpgpngbmpgif.html' title='Image :: read size of JPG/PNG/BMP/GIF'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-4539388427484880335</id><published>2009-08-30T02:18:00.005+02:00</published><updated>2009-08-30T02:21:45.719+02:00</updated><title type='text'>Graycode :: for analog stuff!</title><content type='html'>THIS WAS FUN.&lt;br /&gt;&lt;br /&gt;Proved the math teacher wrong.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;Graycode&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;normalToGray&lt;/span&gt;(int orig)&lt;br /&gt;   {&lt;br /&gt;      int gray = 0;&lt;br /&gt;      for (int n = 0; n &lt; 31; n++)&lt;br /&gt;         gray |= (((orig + (1 &lt;&lt; n)) &gt;&gt; (n + 1)) &amp; 1) &lt;&lt; n;&lt;br /&gt;      return gray;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;grayToNormal&lt;/span&gt;(int gray)&lt;br /&gt;   {&lt;br /&gt;      int parity = 0;&lt;br /&gt;      int norm = 0;&lt;br /&gt;      for (int pos = 31; pos &gt;= 0; pos--)&lt;br /&gt;         norm = (norm &lt;&lt; 1) | (parity ^= ((gray &gt;&gt; pos) &amp; 1));&lt;br /&gt;      return norm;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static int &lt;span style="color:yellow"&gt;changedBitInNextGrayCode&lt;/span&gt;(int gray)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; 31; i++)&lt;br /&gt;         if (parity(gray &gt;&gt; i) == 0)&lt;br /&gt;            return i + 1;&lt;br /&gt;      return -1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static int parity(int v)&lt;br /&gt;   {&lt;br /&gt;      int c = 0;&lt;br /&gt;      for (int i = 0; i &lt; 31; i++)&lt;br /&gt;         c ^= (v &amp; (1 &lt;&lt; i)) &gt;&gt; i;&lt;br /&gt;      return c;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-4539388427484880335?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/4539388427484880335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/graycode-for-your-analog-stuff.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4539388427484880335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4539388427484880335'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/graycode-for-your-analog-stuff.html' title='Graycode :: for analog stuff!'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-7793429129086175468</id><published>2009-08-30T02:02:00.003+02:00</published><updated>2010-01-27T14:40:31.526+01:00</updated><title type='text'>Set :: binary operations</title><content type='html'>Everybody should have these. It's just a drag to rewrite it time and time again.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;SetUtil&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static &amp;lt;T&amp;gt; Set&amp;lt;T&amp;gt; &lt;span style="color:yellow"&gt;and&lt;/span&gt;(Set&amp;lt;T&amp;gt; a, Set&amp;lt;T&amp;gt; b)&lt;br /&gt;   {&lt;br /&gt;      Set&amp;lt;T&amp;gt; c = new HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;      // c.addAll(SetUtil.or(a, b));&lt;br /&gt;      // c.removeAll(SetUtil.xor(a, b));&lt;br /&gt;      c.addAll(a);&lt;br /&gt;      c.retainAll(b);&lt;br /&gt;      return c;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;T&amp;gt; Set&amp;lt;T&amp;gt; &lt;span style="color:yellow"&gt;or&lt;/span&gt;(Set&amp;lt;T&amp;gt; a, Set&amp;lt;T&amp;gt; b)&lt;br /&gt;   {&lt;br /&gt;      Set&amp;lt;T&amp;gt; c = new HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;      c.addAll(a);&lt;br /&gt;      c.addAll(b);&lt;br /&gt;      return c;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static &amp;lt;T&amp;gt; Set&amp;lt;T&amp;gt; &lt;span style="color:yellow"&gt;xor&lt;/span&gt;(Set&amp;lt;T&amp;gt; a, Set&amp;lt;T&amp;gt; b)&lt;br /&gt;   {&lt;br /&gt;      Set&amp;lt;T&amp;gt; a_minus_b = new HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;      a_minus_b.addAll(a);&lt;br /&gt;      a_minus_b.removeAll(b);&lt;br /&gt;&lt;br /&gt;      Set&amp;lt;T&amp;gt; b_minus_a = new HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;      b_minus_a.addAll(b);&lt;br /&gt;      b_minus_a.removeAll(a);&lt;br /&gt;&lt;br /&gt;      Set&amp;lt;T&amp;gt; c = new HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;      c.addAll(a_minus_b);&lt;br /&gt;      c.addAll(b_minus_a);&lt;br /&gt;      return c;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-7793429129086175468?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/7793429129086175468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/set-binary-operations.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7793429129086175468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7793429129086175468'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/set-binary-operations.html' title='Set :: binary operations'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-9080575360886655830</id><published>2009-08-30T01:50:00.003+02:00</published><updated>2009-08-30T01:59:01.620+02:00</updated><title type='text'>ArraySorter :: in-place, pre-calc</title><content type='html'>The point of this class is to pre-calculate the sort-order in advance, so that we're not comparing objects all the time, and then do a proper/fast sort. In-place, meaning not creating an auxillary array, like Arrays.sort() does. This class is thread safe, as in... synchronized.&lt;br /&gt;&lt;br /&gt;The 'chunked' version uses 'bucket sort' and then does a regular sort on the buckets, and merges the result back in the original array.&lt;br /&gt;&lt;br /&gt;The Sortable interface is expected to calculate the sort-index in calcSortIndex() and return that value each and every time in getSortIndex()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public interface &lt;span style="color:yellow"&gt;Sortable&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;calcSortIndex&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;getSortIndex&lt;/span&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style="color:yellow"&gt;ArraySorter&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static final synchronized void &lt;span style="color:yellow"&gt;fineSort&lt;/span&gt;(Sortable[] p, int off, int len)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; len; i++)&lt;br /&gt;         p[off + i].calcSortIndex();&lt;br /&gt;&lt;br /&gt;      ArraySorter.doFineSortImpl(p, off, len);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final synchronized void &lt;span style="color:yellow"&gt;chunkedSort&lt;/span&gt;(Sortable[] p, int off, int len, int min, int max, int chunks)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; len; i++)&lt;br /&gt;         p[off + i].calcSortIndex();&lt;br /&gt;&lt;br /&gt;      ArraySorter.doChunkedSortImpl(p, off, len, min, max, chunks);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * FINE&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   private static final void doFineSortImpl(Sortable[] p, int off, int len)&lt;br /&gt;   {&lt;br /&gt;      if (len &lt; 7)&lt;br /&gt;      {&lt;br /&gt;         for (int i = off; i &lt; len + off; i++)&lt;br /&gt;            for (int j = i; j &gt; off &amp;&amp; p[j - 1].getSortIndex() &gt; p[j].getSortIndex(); j--)&lt;br /&gt;               swap(p, j, j - 1);&lt;br /&gt;&lt;br /&gt;         return;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      int m = off + (len &gt;&gt; 1);&lt;br /&gt;&lt;br /&gt;      if (len &gt; 7)&lt;br /&gt;      {&lt;br /&gt;         int l = off;&lt;br /&gt;         int n = off + len - 1;&lt;br /&gt;&lt;br /&gt;         if (len &gt; 40)&lt;br /&gt;         {&lt;br /&gt;            int s = len &gt;&gt;&gt; 3;&lt;br /&gt;            l = med3(p, l, l + s, l + 2 * s);&lt;br /&gt;            m = med3(p, m - s, m, m + s);&lt;br /&gt;            n = med3(p, n - 2 * s, n - s, n);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         m = med3(p, l, m, n);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      int v = p[m].getSortIndex();&lt;br /&gt;&lt;br /&gt;      int a = off;&lt;br /&gt;      int b = a;&lt;br /&gt;      int c = off + len - 1;&lt;br /&gt;      int d = c;&lt;br /&gt;&lt;br /&gt;      while (true)&lt;br /&gt;      {&lt;br /&gt;         while (b &lt;= c &amp;&amp; p[b].getSortIndex() &lt;= v)&lt;br /&gt;         {&lt;br /&gt;            if (p[b].getSortIndex() == v)&lt;br /&gt;               swap(p, a++, b);&lt;br /&gt;            b++;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         while (c &gt;= b &amp;&amp; p[c].getSortIndex() &gt;= v)&lt;br /&gt;         {&lt;br /&gt;            if (p[c].getSortIndex() == v)&lt;br /&gt;               swap(p, c, d--);&lt;br /&gt;            c--;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         if (b &gt; c)&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;         swap(p, b++, c--);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      int s, n = off + len;&lt;br /&gt;      s = Math.min(a - off, b - a);&lt;br /&gt;      swapRange(p, off, b - s, s);&lt;br /&gt;      s = Math.min(d - c, n - d - 1);&lt;br /&gt;      swapRange(p, b, n - s, s);&lt;br /&gt;&lt;br /&gt;      if ((s = b - a) &gt; 1)&lt;br /&gt;         doFineSortImpl(p, off, s);&lt;br /&gt;&lt;br /&gt;      if ((s = d - c) &gt; 1)&lt;br /&gt;         doFineSortImpl(p, n - s, s);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final void swap(Sortable[] p, int a, int b)&lt;br /&gt;   {&lt;br /&gt;      Sortable q = p[a];&lt;br /&gt;      p[a] = p[b];&lt;br /&gt;      p[b] = q;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final void swapRange(Sortable[] p, int a, int b, int n)&lt;br /&gt;   {&lt;br /&gt;      Sortable q;&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; n; i++, a++, b++)&lt;br /&gt;      {&lt;br /&gt;         q = p[a];&lt;br /&gt;         p[a] = p[b];&lt;br /&gt;         p[b] = q;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final int med3(Sortable[] p, int a, int b, int c)&lt;br /&gt;   {&lt;br /&gt;      int a0 = p[a].getSortIndex();&lt;br /&gt;      int b0 = p[b].getSortIndex();&lt;br /&gt;      int c0 = p[c].getSortIndex();&lt;br /&gt;      return (a0 &lt; b0 ? (b0 &lt; c0 ? b : (a0 &lt; c0 ? c : a)) : (b0 &gt; c0 ? b : (a0 &gt; c0 ? c : a)));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * CHUNKED&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   private static List&amp;lt;Sortable&amp;gt;   less  = new ArrayList&amp;lt;Sortable&amp;gt;();&lt;br /&gt;   private static List&amp;lt;Sortable&amp;gt;[] parts = new List[0];&lt;br /&gt;   private static List&amp;lt;Sortable&amp;gt;   more  = new ArrayList&amp;lt;Sortable&amp;gt;();&lt;br /&gt;   private static Sortable[]       tmp   = new Sortable[64];&lt;br /&gt;&lt;br /&gt;   private static final void doChunkedSortImpl(Sortable[] p, int off, int len, int min, int max, int chunks)&lt;br /&gt;   {&lt;br /&gt;      if (parts.length &lt; chunks)&lt;br /&gt;      {&lt;br /&gt;         parts = new List[chunks];&lt;br /&gt;&lt;br /&gt;         for (int i = 0; i &lt; parts.length; i++)&lt;br /&gt;            parts[i] = new ArrayList&amp;lt;Sortable&amp;gt;();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // sort-index is already calculated here&lt;br /&gt;&lt;br /&gt;      // distribute sortables over lists&lt;br /&gt;      for (int i = 0; i &lt; len; i++)&lt;br /&gt;      {&lt;br /&gt;         Sortable s = p[off + i];&lt;br /&gt;         int index = s.getSortIndex();&lt;br /&gt;&lt;br /&gt;         if (index &lt; min)&lt;br /&gt;            less.add(s);&lt;br /&gt;         else if (index &gt;= max)&lt;br /&gt;            more.add(s);&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            float percent = (float) (s.getSortIndex() - min) / (max - min);&lt;br /&gt;            int arrayIndex = (int) (percent * chunks);&lt;br /&gt;            parts[arrayIndex].add(s);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // sort lists, overwrite P&lt;br /&gt;      tmp = less.toArray(tmp);&lt;br /&gt;      ArraySorter.doFineSortImpl(tmp, 0, less.size());&lt;br /&gt;      System.arraycopy(tmp, 0, p, off, less.size());&lt;br /&gt;      off += less.size();&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; chunks; i++)&lt;br /&gt;      {&lt;br /&gt;         if (parts[i].isEmpty())&lt;br /&gt;            continue;&lt;br /&gt;&lt;br /&gt;         tmp = parts[i].toArray(tmp);&lt;br /&gt;         ArraySorter.doFineSortImpl(tmp, 0, parts[i].size());&lt;br /&gt;         System.arraycopy(tmp, 0, p, off, parts[i].size());&lt;br /&gt;         off += parts[i].size();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      tmp = more.toArray(tmp);&lt;br /&gt;      ArraySorter.doFineSortImpl(tmp, 0, more.size());&lt;br /&gt;      System.arraycopy(tmp, 0, p, off, more.size());&lt;br /&gt;      off += more.size();&lt;br /&gt;&lt;br /&gt;      // clear up all references&lt;br /&gt;      less.clear();&lt;br /&gt;      for (int i = 0; i &lt; chunks; i++)&lt;br /&gt;         parts[i].clear();&lt;br /&gt;      more.clear();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-9080575360886655830?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/9080575360886655830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/arraysorter-in-place-one-thread.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/9080575360886655830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/9080575360886655830'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/arraysorter-in-place-one-thread.html' title='ArraySorter :: in-place, pre-calc'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-3387135267702648605</id><published>2009-08-30T01:27:00.002+02:00</published><updated>2009-08-30T01:33:43.285+02:00</updated><title type='text'>Histogram :: map-based</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;Histogram&lt;/span&gt;&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;   private final Map&amp;lt;T, Integer&amp;gt; map;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;Histogram&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.map = new HashMap&amp;lt;T, Integer&amp;gt;();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;put&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      Integer count = this.map.get(t);&lt;br /&gt;      if (count == null)&lt;br /&gt;         count = Integer.valueOf(0);&lt;br /&gt;      count = Integer.valueOf(count.intValue() + 1);&lt;br /&gt;      this.map.put(t, count);&lt;br /&gt;      return count.intValue();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;get&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      Integer count = this.map.get(t);&lt;br /&gt;      if (count == null)&lt;br /&gt;         return 0;&lt;br /&gt;      return count.intValue();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public List&amp;lt;T&amp;gt; &lt;span style="color:yellow"&gt;topKeys&lt;/span&gt;(int amount)&lt;br /&gt;   {&lt;br /&gt;      //int threshold = Integer.MIN_VALUE;&lt;br /&gt;&lt;br /&gt;      List&amp;lt;T&amp;gt; kList = new ArrayList&amp;lt;T&amp;gt;();&lt;br /&gt;      List&lt;integer&gt; vList = new ArrayList&lt;integer&gt;();&lt;br /&gt;&lt;br /&gt;      for (Entry&lt;T, Integer&gt; e : this.map.entrySet())&lt;br /&gt;      {&lt;br /&gt;         //int val = e.getValue().intValue();&lt;br /&gt;         //if (val &lt;= threshold)&lt;br /&gt;         {&lt;br /&gt;            //continue;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         // when full, remove lowest&lt;br /&gt;         if (vList.size() == amount)&lt;br /&gt;         {&lt;br /&gt;            int index = indexOfMin(vList);&lt;br /&gt;            kList.remove(index);&lt;br /&gt;            vList.remove(index);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         kList.add(e.getKey());&lt;br /&gt;         vList.add(e.getValue());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // bubble sort&lt;br /&gt;      for (int i = 0; i &lt; vList.size(); i++)&lt;br /&gt;      {&lt;br /&gt;         for (int k = i + 1; k &lt; vList.size(); k++)&lt;br /&gt;         {&lt;br /&gt;            if (vList.get(i).intValue() &gt;= vList.get(k).intValue())&lt;br /&gt;            {&lt;br /&gt;               continue;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            Integer a = vList.get(i);&lt;br /&gt;            Integer b = vList.get(k);&lt;br /&gt;            vList.set(k, a);&lt;br /&gt;            vList.set(i, b);&lt;br /&gt;&lt;br /&gt;            T x = kList.get(i);&lt;br /&gt;            T y = kList.get(k);&lt;br /&gt;            kList.set(k, x);&lt;br /&gt;            kList.set(i, y);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return kList;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;remove&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      Integer count = this.map.get(t);&lt;br /&gt;      if (count == null)&lt;br /&gt;         throw new NoSuchElementException(String.valueOf(t));&lt;br /&gt;      if (count.intValue() == 0)&lt;br /&gt;         throw new IllegalStateException("cannot remove");&lt;br /&gt;&lt;br /&gt;      count = Integer.valueOf(count.intValue() - 1);&lt;br /&gt;      if (count.intValue() == 0)&lt;br /&gt;         this.map.remove(t);&lt;br /&gt;      else&lt;br /&gt;         this.map.put(t, count);&lt;br /&gt;&lt;br /&gt;      return count.intValue();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;reset&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      Integer count = this.map.remove(t);&lt;br /&gt;      if (count == null)&lt;br /&gt;         return 0;&lt;br /&gt;      return count.intValue();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;set&lt;/span&gt;(T t, int val)&lt;br /&gt;   {&lt;br /&gt;      if (val &lt; 0)&lt;br /&gt;         throw new IllegalArgumentException();&lt;br /&gt;      Integer count = this.map.get(t);&lt;br /&gt;&lt;br /&gt;      if (count == null)&lt;br /&gt;      {&lt;br /&gt;         if (val != 0)&lt;br /&gt;            this.map.put(t, Integer.valueOf(val));&lt;br /&gt;         return 0;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (val == 0)&lt;br /&gt;         return this.map.remove(t).intValue();&lt;br /&gt;      return this.map.put(t, Integer.valueOf(val)).intValue();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Set&amp;lt;T&amp;gt; &lt;span style="color:yellow"&gt;keys&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return this.map.keySet();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static int indexOfMin(List&amp;lt;Integer&amp;gt; ids)&lt;br /&gt;   {&lt;br /&gt;      int minAt = 0;&lt;br /&gt;      for (int i = 1; i &lt; ids.size(); i++)&lt;br /&gt;         if (ids.get(i).intValue() &lt; ids.get(minAt).intValue())&lt;br /&gt;            minAt = i;&lt;br /&gt;      return minAt;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-3387135267702648605?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/3387135267702648605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/histogram-map-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3387135267702648605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3387135267702648605'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/histogram-map-based.html' title='Histogram :: map-based'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-4893858225001915283</id><published>2009-08-30T01:09:00.005+02:00</published><updated>2009-08-30T01:11:13.102+02:00</updated><title type='text'>Unsafe :: Pointers</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final static Unsafe   unsafe;&lt;br /&gt;   private static long           addressOffset;&lt;br /&gt;   private static long           positionOffset;&lt;br /&gt;   private static long           limitOffset;&lt;br /&gt;   private static long           capacityOffset;&lt;br /&gt;&lt;br /&gt;   public static final long      WORD_SIZE_BITS, HEADER_SIZE;&lt;br /&gt;   public static final long      BYTE_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      SHORT_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      INT_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      LONG_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      FLOAT_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      DOUBLE_ARRAY_BASE_OFFSET;&lt;br /&gt;   public static final long      OBJECT_ARRAY_BASE_OFFSET;&lt;br /&gt;   private static final Object[] holder = new Object[1];&lt;br /&gt;&lt;br /&gt;   static&lt;br /&gt;   {&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         ByteBuffer buffer = ByteBuffer.allocateDirect(1);&lt;br /&gt;         Field unsafeField = buffer.getClass().getDeclaredField("unsafe");&lt;br /&gt;         unsafeField.setAccessible(true);&lt;br /&gt;         unsafe = (Unsafe) unsafeField.get(buffer);&lt;br /&gt;         unsafeField.setAccessible(false);&lt;br /&gt;&lt;br /&gt;         addressOffset = getObjectFieldOffset(buffer, "address");&lt;br /&gt;         positionOffset = getObjectFieldOffset(buffer, "position");&lt;br /&gt;         limitOffset = getObjectFieldOffset(buffer, "limit");&lt;br /&gt;         capacityOffset = getObjectFieldOffset(buffer, "capacity");&lt;br /&gt;&lt;br /&gt;         buffer.flip();&lt;br /&gt;         buffer = null;&lt;br /&gt;      }&lt;br /&gt;      catch (Exception exc)&lt;br /&gt;      {&lt;br /&gt;         exc.printStackTrace();&lt;br /&gt;         throw new InternalError();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      WORD_SIZE_BITS = unsafe.addressSize() * 8;&lt;br /&gt;      if (WORD_SIZE_BITS != 32 &amp;&amp; WORD_SIZE_BITS != 64)&lt;br /&gt;         throw new IllegalStateException("WORD_SIZE: " + WORD_SIZE_BITS);&lt;br /&gt;      HEADER_SIZE = WORD_SIZE_BITS / 8 * 2;&lt;br /&gt;&lt;br /&gt;      BYTE_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new byte[4].getClass());&lt;br /&gt;      SHORT_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new short[4].getClass());&lt;br /&gt;      INT_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new int[4].getClass());&lt;br /&gt;      LONG_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new long[4].getClass());&lt;br /&gt;      FLOAT_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new float[4].getClass());&lt;br /&gt;      DOUBLE_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new double[4].getClass());&lt;br /&gt;      OBJECT_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(new Object[4].getClass());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final long getObjectAddress(Object obj)&lt;br /&gt;   {&lt;br /&gt;      holder[0] = obj;&lt;br /&gt;&lt;br /&gt;      if (WORD_SIZE_BITS == 32)&lt;br /&gt;         return unsafe.getInt(holder, OBJECT_ARRAY_BASE_OFFSET);&lt;br /&gt;      if (WORD_SIZE_BITS == 64)&lt;br /&gt;         return unsafe.getLong(holder, OBJECT_ARRAY_BASE_OFFSET);&lt;br /&gt;&lt;br /&gt;      throw new IllegalStateException();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final Object getObjectAtAddress(long addr)&lt;br /&gt;   {&lt;br /&gt;      if (WORD_SIZE_BITS == 32)&lt;br /&gt;         unsafe.putInt(holder, OBJECT_ARRAY_BASE_OFFSET, (int) (addr &amp; 0xFFFFFFFF));&lt;br /&gt;      if (WORD_SIZE_BITS == 64)&lt;br /&gt;         unsafe.putLong(holder, OBJECT_ARRAY_BASE_OFFSET, addr);&lt;br /&gt;&lt;br /&gt;      return holder[0];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final FloatBuffer createFloatBufferAt(long pntr, int len)&lt;br /&gt;   {&lt;br /&gt;      Native.zeroOut(pntr, len &lt;&lt; 2);&lt;br /&gt;&lt;br /&gt;      FloatBuffer buf = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asFloatBuffer();&lt;br /&gt;      NativeHacks.setBufferProperties(buf, pntr, 0, len, len);&lt;br /&gt;      buf.clear();&lt;br /&gt;&lt;br /&gt;      return buf;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float[] createFloatArrayAt(long pntr, int len)&lt;br /&gt;   {&lt;br /&gt;      NativeHacks.copyObjectHeaderTo(new float[0], pntr);&lt;br /&gt;&lt;br /&gt;      // write length&lt;br /&gt;      unsafe.putInt(pntr + HEADER_SIZE, len);&lt;br /&gt;&lt;br /&gt;      return (float[]) NativeHacks.fakePointerAsObject(pntr);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final void copyObjectHeaderTo(Object obj, long pntr)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; HEADER_SIZE; i++)&lt;br /&gt;         unsafe.putByte(pntr + i, unsafe.getByte(obj, (long) i));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final Object fakePointerAsObject(long addr)&lt;br /&gt;   {&lt;br /&gt;      if (WORD_SIZE_BITS == 32)&lt;br /&gt;         unsafe.putInt(holder, OBJECT_ARRAY_BASE_OFFSET, (int) (addr &amp; 0xFFFFFFFF));&lt;br /&gt;      else if (WORD_SIZE_BITS == 64)&lt;br /&gt;         unsafe.putLong(holder, OBJECT_ARRAY_BASE_OFFSET, addr);&lt;br /&gt;      else&lt;br /&gt;         throw new IllegalStateException();&lt;br /&gt;&lt;br /&gt;      return holder[0];&lt;br /&gt;   }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-4893858225001915283?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/4893858225001915283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/unsafe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4893858225001915283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4893858225001915283'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/unsafe.html' title='Unsafe :: Pointers'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-1968605133503156042</id><published>2009-08-25T03:48:00.006+02:00</published><updated>2009-08-25T04:00:27.312+02:00</updated><title type='text'>Thread :: monitor CPU usage</title><content type='html'>If you want to monitor CPU usage, per thread, things couldn't get easier!&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:#808080"&gt;ThreadGroupMonitor gmonitor = new ThreadGroupMonitor();&lt;br /&gt;&lt;br /&gt;while(true)&lt;br /&gt;{&lt;br /&gt;   gmonitor.poll();&lt;br /&gt;&lt;br /&gt;   for(ThreadMonitor tmon: gmonitor.getAliveThreadMonitors())&lt;br /&gt;   {&lt;br /&gt;      double avg = tmon.getCpuTimeStats().avg();  // avg of last polls&lt;br /&gt;      double avg = tmon.getCpuTimeStats().avg(3); // avg of last 3 polls&lt;br /&gt;      double avg = tmon.getCpuTimeStats().avg(5); // avg of last 5 polls&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   for(ThreadMonitor tmon: gmonitor.getDeadThreadMonitors())&lt;br /&gt;   {&lt;br /&gt;      double total = tmon.getTotalCpuTime();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // sleep for a bit&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Even dead threads...&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class ThreadMonitor&lt;br /&gt;{&lt;br /&gt;   private static ThreadMXBean tmxb;&lt;br /&gt;&lt;br /&gt;   static&lt;br /&gt;   {&lt;br /&gt;      tmxb = ManagementFactory.getThreadMXBean();&lt;br /&gt;      tmxb.setThreadCpuTimeEnabled(true);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private long                tid;&lt;br /&gt;   private CyclicUsageHistory  cpuTimeHistory;&lt;br /&gt;   private CyclicUsageHistory  userTimeHistory;&lt;br /&gt;   private CyclicUsageHistory  cpuUsageHistory;&lt;br /&gt;   private CyclicUsageHistory  userUsageHistory;&lt;br /&gt;&lt;br /&gt;   public ThreadMonitor(long tid, int slots)&lt;br /&gt;   {&lt;br /&gt;      this.tid = tid;&lt;br /&gt;      this.cpuTimeHistory = new CyclicUsageHistory(slots);&lt;br /&gt;      this.userTimeHistory = new CyclicUsageHistory(slots);&lt;br /&gt;      this.cpuUsageHistory = new CyclicUsageHistory(slots);&lt;br /&gt;      this.userUsageHistory = new CyclicUsageHistory(slots);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public long getId()&lt;br /&gt;   {&lt;br /&gt;      return tid;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private double totalCpuTime;&lt;br /&gt;   private double totalUserTime;&lt;br /&gt;   &lt;br /&gt;   public double getTotalCpuTime()&lt;br /&gt;   {&lt;br /&gt;      return this.totalCpuTime;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   public double getTotalUserTime()&lt;br /&gt;   {&lt;br /&gt;      return this.totalUserTime;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void poll()&lt;br /&gt;   {&lt;br /&gt;      // a time of -1 means not alive&lt;br /&gt;&lt;br /&gt;      double cpuTime = tmxb.getThreadCpuTime(this.tid) / 1000000000.0;&lt;br /&gt;      this.totalCpuTime += cpuTime &lt; 0 ? 0 : cpuTime;&lt;br /&gt;      cpuTimeHistory.log(cpuTime &lt; 0 ? 0 : cpuTime);&lt;br /&gt;      cpuUsageHistory.log(cpuTimeHistory.previous(0) - cpuTimeHistory.previous(1));&lt;br /&gt;&lt;br /&gt;      double userTime = tmxb.getThreadUserTime(this.tid) / 1000000000.0;&lt;br /&gt;      this.totalUserTime += userTime &lt; 0 ? 0 : userTime;&lt;br /&gt;      userTimeHistory.log(userTime &lt; 0 ? 0 : userTime);&lt;br /&gt;      userUsageHistory.log(userTimeHistory.previous(0) - userTimeHistory.previous(1));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public CyclicUsageHistory getCpuTimeStats()&lt;br /&gt;   {&lt;br /&gt;      return this.cpuUsageHistory;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public CyclicUsageHistory getUserTimeStats()&lt;br /&gt;   {&lt;br /&gt;      return this.userUsageHistory;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ThreadGroupMonitor&lt;br /&gt;{&lt;br /&gt;   public ThreadGroupMonitor()&lt;br /&gt;   {&lt;br /&gt;      this(Thread.currentThread().getThreadGroup());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public ThreadGroupMonitor(ThreadGroup group)&lt;br /&gt;   {&lt;br /&gt;      this.group = group;&lt;br /&gt;      this.lastThreadIds = new long[0];&lt;br /&gt;      this.aliveId2mon = new HashMap&lt;Long, ThreadMonitor&gt;();&lt;br /&gt;      this.deadId2mon = new HashMap&lt;Long, ThreadMonitor&gt;();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private final ThreadGroup group;&lt;br /&gt;&lt;br /&gt;   public ThreadGroup getThreadGroup()&lt;br /&gt;   {&lt;br /&gt;      return group;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private int totalDeadThreadCount = 0;&lt;br /&gt;&lt;br /&gt;   public synchronized int getTotalDeadThreadCount()&lt;br /&gt;   {&lt;br /&gt;      return this.totalDeadThreadCount;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private int regularThreadCount = 0;&lt;br /&gt;&lt;br /&gt;   public synchronized int getRegularThreadCount()&lt;br /&gt;   {&lt;br /&gt;      return this.regularThreadCount;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private int deamonThreadCount = 0;&lt;br /&gt;&lt;br /&gt;   public synchronized int getDeamonThreadCount()&lt;br /&gt;   {&lt;br /&gt;      return this.deamonThreadCount;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private static final int         default_slots = 3600;&lt;br /&gt;&lt;br /&gt;   private long[]                   lastThreadIds;&lt;br /&gt;   private Map&lt;Long, ThreadMonitor&gt; aliveId2mon;&lt;br /&gt;   private Map&lt;Long, ThreadMonitor&gt; deadId2mon;&lt;br /&gt;&lt;br /&gt;   public synchronized void poll()&lt;br /&gt;   {&lt;br /&gt;      Thread[] threads = this.findAllThreads();&lt;br /&gt;&lt;br /&gt;      long[] currThreadIds = this.findAllThreadIds(threads);&lt;br /&gt;      long[] newIds = this.findNewThreadIds(this.lastThreadIds, currThreadIds);&lt;br /&gt;      long[] deadIds = this.findDeadThreadIds(this.lastThreadIds, currThreadIds);&lt;br /&gt;&lt;br /&gt;      this.totalDeadThreadCount += deadIds.length;&lt;br /&gt;&lt;br /&gt;      for (long newId : newIds)&lt;br /&gt;         aliveId2mon.put(Long.valueOf(newId), new ThreadMonitor(newId, default_slots));&lt;br /&gt;      for (long deadId : deadIds)&lt;br /&gt;         deadId2mon.put(Long.valueOf(deadId), aliveId2mon.remove(Long.valueOf(deadId)));&lt;br /&gt;&lt;br /&gt;      for (ThreadMonitor mon : aliveId2mon.values())&lt;br /&gt;         mon.poll();&lt;br /&gt;      for (ThreadMonitor mon : deadId2mon.values())&lt;br /&gt;         mon.poll();&lt;br /&gt;&lt;br /&gt;      this.analyzeThreads(threads);&lt;br /&gt;&lt;br /&gt;      this.lastThreadIds = currThreadIds;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public synchronized double getAvgCpuTimeStats(int pollCount)&lt;br /&gt;   {&lt;br /&gt;      double sum = 0.0;&lt;br /&gt;      for (ThreadMonitor mon : aliveId2mon.values())&lt;br /&gt;         sum += mon.getCpuTimeStats().avg(pollCount);&lt;br /&gt;      return sum;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public synchronized double getAvgUserTimeStats(int pollCount)&lt;br /&gt;   {&lt;br /&gt;      double sum = 0.0;&lt;br /&gt;      for (ThreadMonitor mon : aliveId2mon.values())&lt;br /&gt;         sum += mon.getUserTimeStats().avg(pollCount);&lt;br /&gt;      return sum;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Collection&lt;threadmonitor&gt; getAliveThreadMonitors()&lt;br /&gt;   {&lt;br /&gt;      return Collections.unmodifiableCollection(this.aliveId2mon.values());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Collection&lt;threadmonitor&gt; getDeadThreadMonitors()&lt;br /&gt;   {&lt;br /&gt;      return Collections.unmodifiableCollection(this.deadId2mon.values());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private void analyzeThreads(Thread[] threads)&lt;br /&gt;   {&lt;br /&gt;      int deamonThreadCount = 0;&lt;br /&gt;      int regularThreadCount = 0;&lt;br /&gt;&lt;br /&gt;      for (Thread thread : threads)&lt;br /&gt;      {&lt;br /&gt;         if (!thread.isAlive())&lt;br /&gt;            continue;&lt;br /&gt;         if (thread.isDaemon())&lt;br /&gt;            deamonThreadCount++;&lt;br /&gt;         else&lt;br /&gt;            regularThreadCount++;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.deamonThreadCount = deamonThreadCount;&lt;br /&gt;      this.regularThreadCount = regularThreadCount;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Thread[] findAllThreads()&lt;br /&gt;   {&lt;br /&gt;      int threadCount;&lt;br /&gt;&lt;br /&gt;      Thread[] tempThreadArray = new Thread[8];&lt;br /&gt;      while ((threadCount = this.group.enumerate(tempThreadArray)) == tempThreadArray.length)&lt;br /&gt;         tempThreadArray = ArrayUtil.growTo(tempThreadArray, tempThreadArray.length * 2);&lt;br /&gt;&lt;br /&gt;      Thread[] threadArray = new Thread[threadCount];&lt;br /&gt;      System.arraycopy(tempThreadArray, 0, threadArray, 0, threadCount);&lt;br /&gt;      return threadArray;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private long[] findAllThreadIds(Thread[] threads)&lt;br /&gt;   {&lt;br /&gt;      long[] allThreadIds = new long[threads.length];&lt;br /&gt;      for (int i = 0; i &lt; allThreadIds.length; i++)&lt;br /&gt;         allThreadIds[i] = threads[i].getId();&lt;br /&gt;      return allThreadIds;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private long[] findNewThreadIds(long[] lastThreads, long[] currThreads)&lt;br /&gt;   {&lt;br /&gt;      long[] newThreadIds = new long[currThreads.length];&lt;br /&gt;      int newThreadIndex = 0;&lt;br /&gt;&lt;br /&gt;      outer: for (int i = 0; i &lt; currThreads.length; i++)&lt;br /&gt;      {&lt;br /&gt;         for (int k = 0; k &lt; lastThreads.length; k++)&lt;br /&gt;            if (currThreads[i] == lastThreads[k])&lt;br /&gt;               continue outer;&lt;br /&gt;         newThreadIds[newThreadIndex++] = currThreads[i];&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      long[] ids = new long[newThreadIndex];&lt;br /&gt;      System.arraycopy(newThreadIds, 0, ids, 0, newThreadIndex);&lt;br /&gt;      return ids;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private long[] findDeadThreadIds(long[] lastThreads, long[] currThreads)&lt;br /&gt;   {&lt;br /&gt;      long[] deadThreadIds = new long[lastThreads.length];&lt;br /&gt;      int deadThreadIndex = 0;&lt;br /&gt;&lt;br /&gt;      outer: for (int i = 0; i &lt; lastThreads.length; i++)&lt;br /&gt;      {&lt;br /&gt;         for (int k = 0; k &lt; currThreads.length; k++)&lt;br /&gt;            if (lastThreads[i] == currThreads[k])&lt;br /&gt;               continue outer;&lt;br /&gt;         deadThreadIds[deadThreadIndex++] = lastThreads[i];&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      long[] ids = new long[deadThreadIndex];&lt;br /&gt;      System.arraycopy(deadThreadIds, 0, ids, 0, deadThreadIndex);&lt;br /&gt;      return ids;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class CyclicUsageHistory&lt;br /&gt;{&lt;br /&gt;   private final double[] values;&lt;br /&gt;&lt;br /&gt;   public CyclicUsageHistory(int slots)&lt;br /&gt;   {&lt;br /&gt;      this.values = new double[slots];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private int addIndex;&lt;br /&gt;&lt;br /&gt;   public void log(double value)&lt;br /&gt;   {&lt;br /&gt;      this.values[this.addIndex++ % this.values.length] = value;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public double previous()&lt;br /&gt;   {&lt;br /&gt;      return this.previous(0);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public double previous(int age)&lt;br /&gt;   {&lt;br /&gt;      int len = this.values.length;&lt;br /&gt;      return this.values[(((this.addIndex - 1 - age) % len) + len) % len];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public double max()&lt;br /&gt;   {&lt;br /&gt;      return this.max(this.values.length);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public double max(int slots)&lt;br /&gt;   {&lt;br /&gt;      int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1));&lt;br /&gt;&lt;br /&gt;      double max = 0.0;&lt;br /&gt;      for (int i = 0; i &lt; count; i++)&lt;br /&gt;         if (this.previous(i) &gt; max)&lt;br /&gt;            max = this.previous(i);&lt;br /&gt;      return max;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public double sum()&lt;br /&gt;   {&lt;br /&gt;      return this.sum(this.values.length);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public double sum(int slots)&lt;br /&gt;   {&lt;br /&gt;      int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1));&lt;br /&gt;&lt;br /&gt;      double sum = 0.0;&lt;br /&gt;      for (int i = 0; i &lt; count; i++)&lt;br /&gt;         sum += this.previous(i);&lt;br /&gt;      return sum;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public double avg()&lt;br /&gt;   {&lt;br /&gt;      return this.avg(this.values.length);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public double avg(int slots)&lt;br /&gt;   {&lt;br /&gt;      int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1));&lt;br /&gt;&lt;br /&gt;      return this.sum(slots) / count;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public double nom()&lt;br /&gt;   {&lt;br /&gt;      return this.nom(this.values.length);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public double nom(int slots)&lt;br /&gt;   {&lt;br /&gt;      int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1));&lt;br /&gt;      if (count == 0)&lt;br /&gt;         return 0.0;&lt;br /&gt;&lt;br /&gt;      double[] arr = new double[count];&lt;br /&gt;      for (int i = 0; i &lt; count; i++)&lt;br /&gt;         arr[i] = this.previous(i);&lt;br /&gt;      Arrays.sort(arr);&lt;br /&gt;      return arr[arr.length / 2];&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-1968605133503156042?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/1968605133503156042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/thread-monitor-cpu-usage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1968605133503156042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1968605133503156042'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/thread-monitor-cpu-usage.html' title='Thread :: monitor CPU usage'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5597044302008927185</id><published>2009-08-25T02:00:00.026+02:00</published><updated>2009-08-25T03:03:35.844+02:00</updated><title type='text'>Swappable Jar ClassLoader</title><content type='html'>So you have this pluggable stuff, and you want to support realtime loading of new classes. That's not so hard, but what if old classes try to load old classes, and the JAR has been replaced? Right! Native crash. Blehh.&lt;br /&gt;&lt;br /&gt;With DynamicJarClassLoader you can do this:&lt;br /&gt;&lt;pre style="color:#808080"&gt;ClassLoader loader = new DynamicJarClassLoader(parent, file);&lt;br /&gt;Class&lt;?&gt; clzz1 = loader.loadClass("my.package.MyClass");&lt;br /&gt;// ...&lt;br /&gt;// JAR is replaced&lt;br /&gt;// ...&lt;br /&gt;Class&lt;?&gt; clzz2 = loader.loadClass("my.package.MyClass");&lt;br /&gt;// ...&lt;br /&gt;clzz1.newInstance(); // loads old "other.package.OtherClass"&lt;br /&gt;clzz2.newInstance(); // loads new "other.package.OtherClass"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Let's say MyClass will also load "other.package.OtherClass" sooner or later. The classloader will keep that data loaded, so that &lt;tt&gt;clzz1&lt;/tt&gt; and &lt;tt&gt;clzz2&lt;/tt&gt; have access to their own version of OtherClass.&lt;br /&gt;&lt;br /&gt;Fancy stuff!&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;DynamicJarClassLoader&lt;/span&gt; extends DynamicClassLoader&lt;br /&gt;{&lt;br /&gt;   private final File        jar;&lt;br /&gt;   private long              prevLastModified;&lt;br /&gt;   private final Set&lt;string&gt; resourceNames;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;DynamicJarClassLoader&lt;/span&gt;(ClassLoader parent, File jar)&lt;br /&gt;   {&lt;br /&gt;      super(parent);&lt;br /&gt;&lt;br /&gt;      this.jar = jar;&lt;br /&gt;      this.prevLastModified = -1L;&lt;br /&gt;      this.resourceNames = new HashSet&lt;string&gt;();&lt;br /&gt;&lt;br /&gt;      this.ensureLatestClassLoader();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public File &lt;span style="color:yellow"&gt;getJar&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return this.jar;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Set&lt;string&gt; &lt;span style="color:yellow"&gt;getResourceNames&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return Collections.unmodifiableSet(this.resourceNames);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final long file_idle_timeout = 3 * 1000;&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public boolean &lt;span style="color:yellow"&gt;isUpdated&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      long jarLastModified = this.jar.lastModified();&lt;br /&gt;&lt;br /&gt;      boolean willBeUpdated = jarLastModified != this.prevLastModified;&lt;br /&gt;&lt;br /&gt;      if (willBeUpdated &amp;&amp; this.prevLastModified != -1L)&lt;br /&gt;      {&lt;br /&gt;         if (this.jar.lastModified() &gt; System.currentTimeMillis() - file_idle_timeout)&lt;br /&gt;         {&lt;br /&gt;            Logger.notification("Pending new JAR file: %s", this.jar.getAbsolutePath());&lt;br /&gt;            willBeUpdated = false;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (willBeUpdated)&lt;br /&gt;      {&lt;br /&gt;         Logger.notification("Loading new JAR file: %s", this.jar.getAbsolutePath());&lt;br /&gt;         this.prevLastModified = jarLastModified;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return willBeUpdated;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public ClassLoader &lt;span style="color:yellow"&gt;createClassLoader&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      final Map&lt;String, byte[]&gt; resources;&lt;br /&gt;&lt;br /&gt;      this.resourceNames.clear();&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         resources = this.loadCompleteJarFile();&lt;br /&gt;      }&lt;br /&gt;      catch (IOException exc)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException("Failed to load JAR file: " + this.jar.getAbsolutePath(), exc);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.resourceNames.addAll(resources.keySet());&lt;br /&gt;&lt;br /&gt;      ClassLoader loader = new BytesClassLoader(this.getParent())&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public byte[] readBytes(String name)&lt;br /&gt;         {&lt;br /&gt;            return resources.get(name);&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;&lt;br /&gt;      return loader;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private final Map&lt;String, byte[]&gt; loadCompleteJarFile() throws IOException&lt;br /&gt;   {&lt;br /&gt;      Map&lt;String, byte[]&gt; map = new HashMap&lt;String, byte[]&gt;();&lt;br /&gt;&lt;br /&gt;      JarFile jf = new JarFile(this.jar);&lt;br /&gt;      Enumeration&lt;jarentry&gt; entries = jf.entries();&lt;br /&gt;      while (entries.hasMoreElements())&lt;br /&gt;      {&lt;br /&gt;         byte[] buf = null;&lt;br /&gt;&lt;br /&gt;         JarEntry entry = entries.nextElement();&lt;br /&gt;&lt;br /&gt;         if (!entry.isDirectory())&lt;br /&gt;         {&lt;br /&gt;            buf = new byte[(int) entry.getSize()];&lt;br /&gt;            InputStream in = jf.getInputStream(entry);&lt;br /&gt;            int off = 0;&lt;br /&gt;            while (off != buf.length)&lt;br /&gt;            {&lt;br /&gt;               int justRead = in.read(buf, off, buf.length - off);&lt;br /&gt;               if (justRead == -1)&lt;br /&gt;                  throw new EOFException("Could not fully read JAR file entry: " + entry.getName());&lt;br /&gt;               off += justRead;&lt;br /&gt;            }&lt;br /&gt;            in.close();&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         map.put(entry.getName(), buf);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      jf.close();&lt;br /&gt;&lt;br /&gt;      return map;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public abstract class DynamicClassLoader extends ClassLoader&lt;br /&gt;{&lt;br /&gt;   private ClassLoader currentLoader;&lt;br /&gt;&lt;br /&gt;   public DynamicClassLoader(ClassLoader parent)&lt;br /&gt;   {&lt;br /&gt;      super(parent);&lt;br /&gt;      this.currentLoader = null;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public abstract boolean isUpdated();&lt;br /&gt;&lt;br /&gt;   public abstract ClassLoader createClassLoader();&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public URL &lt;span style="color:yellow"&gt;getResource&lt;/span&gt;(String name)&lt;br /&gt;   {&lt;br /&gt;      this.ensureLatestClassLoader();&lt;br /&gt;&lt;br /&gt;      URL url = this.getParent().getResource(name);&lt;br /&gt;      if (url != null)&lt;br /&gt;         return url;&lt;br /&gt;&lt;br /&gt;      return this.currentLoader.getResource(name);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public Enumeration&lt;url&gt; &lt;span style="color:yellow"&gt;getResources&lt;/span&gt;(String name) throws IOException&lt;br /&gt;   {&lt;br /&gt;      this.ensureLatestClassLoader();&lt;br /&gt;&lt;br /&gt;      Enumeration&lt;url&gt; urls = this.getParent().getResources(name);&lt;br /&gt;      if (urls != null)&lt;br /&gt;         return urls;&lt;br /&gt;&lt;br /&gt;      return this.currentLoader.getResources(name);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public InputStream &lt;span style="color:yellow"&gt;getResourceAsStream&lt;/span&gt;(String name)&lt;br /&gt;   {&lt;br /&gt;      this.ensureLatestClassLoader();&lt;br /&gt;&lt;br /&gt;      InputStream in = this.getParent().getResourceAsStream(name);&lt;br /&gt;      if (in != null)&lt;br /&gt;         return in;&lt;br /&gt;&lt;br /&gt;      return this.currentLoader.getResourceAsStream(name);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public synchronized Class&lt; ? &gt; &lt;span style="color:yellow"&gt;loadClass&lt;/span&gt;(String name) throws ClassNotFoundException&lt;br /&gt;   {&lt;br /&gt;      this.ensureLatestClassLoader();&lt;br /&gt;&lt;br /&gt;      return this.currentLoader.loadClass(name);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private long lastChecked;&lt;br /&gt;   private long minCheckInterval = 0;&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;setMinCheckInterval&lt;/span&gt;(long minCheckInterval)&lt;br /&gt;   {&lt;br /&gt;      this.minCheckInterval = minCheckInterval;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final boolean &lt;span style="color:yellow"&gt;checkForUpdate&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      long now = System.currentTimeMillis();&lt;br /&gt;      long elapsed = now - this.lastChecked;&lt;br /&gt;&lt;br /&gt;      if (elapsed &lt; this.minCheckInterval)&lt;br /&gt;      {&lt;br /&gt;         // if we checked less than N ms ago,&lt;br /&gt;         // just assume the loader is not updated.&lt;br /&gt;         // otherwise we put a major strain on&lt;br /&gt;         // the file system (?) for no real gain&lt;br /&gt;         return false;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.lastChecked = now;&lt;br /&gt;&lt;br /&gt;      return this.isUpdated();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;ensureLatestClassLoader&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      if (this.checkForUpdate())&lt;br /&gt;      {&lt;br /&gt;         this.replaceClassLoader();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   protected void replaceClassLoader()&lt;br /&gt;   {&lt;br /&gt;      this.currentLoader = this.createClassLoader();&lt;br /&gt;&lt;br /&gt;      // protected, so do stuff, if you wish&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public abstract class BytesClassLoader extends ClassLoader&lt;br /&gt;{&lt;br /&gt;   public BytesClassLoader(ClassLoader parent)&lt;br /&gt;   {&lt;br /&gt;      super(parent);&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   protected abstract byte[] readBytes(String path);&lt;br /&gt;&lt;br /&gt;   public synchronized Class&lt; ? &gt; loadClass(String name) throws ClassNotFoundException&lt;br /&gt;   {&lt;br /&gt;      Class&lt; ? &gt; found = this.findLoadedClass(name);&lt;br /&gt;      if (found != null)&lt;br /&gt;      {&lt;br /&gt;         return found;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      String path = name.replace('.', '/').concat(".class");&lt;br /&gt;&lt;br /&gt;      byte[] raw = this.readBytes(path);&lt;br /&gt;&lt;br /&gt;      if (raw == null)&lt;br /&gt;      {&lt;br /&gt;         return this.getParent().loadClass(name);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return super.defineClass(name, raw, 0, raw.length);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public InputStream getResourceAsStream(String path)&lt;br /&gt;   {&lt;br /&gt;      byte[] raw = this.readBytes(path);&lt;br /&gt;      if (raw == null)&lt;br /&gt;         return null;&lt;br /&gt;      return new ByteArrayInputStream(raw);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public URL getResource(String name)&lt;br /&gt;   {&lt;br /&gt;      // who uses this anyway?&lt;br /&gt;      throw new UnsupportedOperationException();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public Enumeration&lt;url&gt; getResources(String name) throws IOException&lt;br /&gt;   {&lt;br /&gt;      // who uses this anyway?&lt;br /&gt;      throw new UnsupportedOperationException();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5597044302008927185?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5597044302008927185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/swappable-jar-classloader.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5597044302008927185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5597044302008927185'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/swappable-jar-classloader.html' title='Swappable Jar ClassLoader'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-1584747265279914981</id><published>2009-08-25T01:48:00.007+02:00</published><updated>2009-08-25T03:04:29.887+02:00</updated><title type='text'>Basic HTML to BufferedImage</title><content type='html'>This is truely a poor man's HTML renderer. It basically uses JLabel under the hood, and even has rather limited CSS support. It's all rather crude, but it might do the job for you.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;BasicHTMLRenderer&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static synchronized void &lt;span style="color:yellow"&gt;render&lt;/span&gt;(&lt;br /&gt;                      final BufferedImage img,&lt;br /&gt;                      final String html,&lt;br /&gt;                      final boolean makeTransparant)&lt;br /&gt;   {&lt;br /&gt;      if (!inited)&lt;br /&gt;         init();&lt;br /&gt;&lt;br /&gt;      Runnable task = new Runnable()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public void run()&lt;br /&gt;         {&lt;br /&gt;            htmlRender.setText("&amp;lt;html&amp;gt;" + html);&lt;br /&gt;            Dimension dim = new Dimension(img.getWidth(), img.getHeight());&lt;br /&gt;            htmlRender.setPreferredSize(dim);&lt;br /&gt;            htmlHolder.pack();&lt;br /&gt;&lt;br /&gt;            if (makeTransparant)&lt;br /&gt;            {&lt;br /&gt;               Graphics2D g2d = img.createGraphics();&lt;br /&gt;               g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));&lt;br /&gt;               g2d.fillRect(0, 0, img.getWidth(), img.getHeight());&lt;br /&gt;               g2d.dispose();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            Graphics g = img.getGraphics();&lt;br /&gt;            htmlRender.paint(g);&lt;br /&gt;            g.dispose();&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         SwingUtilities.invokeAndWait(task);&lt;br /&gt;      }&lt;br /&gt;      catch (InterruptedException exc)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException(exc);&lt;br /&gt;      }&lt;br /&gt;      catch (InvocationTargetException exc)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException(exc);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   static boolean inited;&lt;br /&gt;   static JFrame  htmlHolder;&lt;br /&gt;   static JLabel  htmlRender;&lt;br /&gt;&lt;br /&gt;   private static synchronized void init()&lt;br /&gt;   {&lt;br /&gt;      Runnable task = new Runnable()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public void run()&lt;br /&gt;         {&lt;br /&gt;            htmlRender = new JLabel("&amp;lt;html&amp;gt;");&lt;br /&gt;            htmlRender.setVerticalAlignment(SwingConstants.TOP);&lt;br /&gt;&lt;br /&gt;            htmlHolder = new JFrame();&lt;br /&gt;            htmlHolder.getContentPane().setLayout(new BorderLayout());&lt;br /&gt;            htmlHolder.getContentPane().add(htmlRender);&lt;br /&gt;&lt;br /&gt;            synchronized (BasicHTMLRenderer.class)&lt;br /&gt;            {&lt;br /&gt;               inited = true;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;      SwingUtilities.invokeLater(task);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static synchronized void &lt;span style="color:yellow"&gt;dispose&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      if (!inited)&lt;br /&gt;         return;&lt;br /&gt;&lt;br /&gt;      Runnable task = new Runnable()&lt;br /&gt;      {&lt;br /&gt;         @Override&lt;br /&gt;         public void run()&lt;br /&gt;         {&lt;br /&gt;            htmlRender = null;&lt;br /&gt;&lt;br /&gt;            htmlHolder.dispose();&lt;br /&gt;            htmlHolder = null;&lt;br /&gt;&lt;br /&gt;            synchronized (BasicHTMLRenderer.class)&lt;br /&gt;            {&lt;br /&gt;               inited = false;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;      SwingUtilities.invokeLater(task);&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-1584747265279914981?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/1584747265279914981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/basic-html-to-image.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1584747265279914981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/1584747265279914981'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/basic-html-to-image.html' title='Basic HTML to BufferedImage'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5695624562741032877</id><published>2009-08-25T01:35:00.007+02:00</published><updated>2009-08-25T03:04:37.642+02:00</updated><title type='text'>Spline :: 2D</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;Spline2D&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public &lt;span style="color:yellow"&gt;Spline2D&lt;/span&gt;(float[][] points)&lt;br /&gt;   {&lt;br /&gt;      this.count = points.length;&lt;br /&gt;&lt;br /&gt;      float[] x = new float[count];&lt;br /&gt;      float[] y = new float[count];&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; count; i++)&lt;br /&gt;      {&lt;br /&gt;         x[i] = points[i][0];&lt;br /&gt;         y[i] = points[i][1];&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.x = Curve.calcCurve(count - 1, x);&lt;br /&gt;      this.y = Curve.calcCurve(count - 1, y);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   final int count;&lt;br /&gt;   private final Cubic[] x, y;&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * POINT COUNT&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   public final int &lt;span style="color:yellow"&gt;pointCount&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return count;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * POSITION&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   public final float[] &lt;span style="color:yellow"&gt;getPositionAt&lt;/span&gt;(float param)&lt;br /&gt;   {&lt;br /&gt;      float[] v = new float[2];&lt;br /&gt;      this.getPositionAt(param, v);&lt;br /&gt;      return v;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;getPositionAt&lt;/span&gt;(float param, float[] result)&lt;br /&gt;   {&lt;br /&gt;      // clamp&lt;br /&gt;      if (param &lt; 0.0f)&lt;br /&gt;         param = 0.0f;&lt;br /&gt;      if (param &gt;= count - 1)&lt;br /&gt;         param = (count - 1) - Math.ulp(count - 1);&lt;br /&gt;&lt;br /&gt;      // split&lt;br /&gt;      int ti = (int) param;&lt;br /&gt;      float tf = param - ti;&lt;br /&gt;&lt;br /&gt;      // eval&lt;br /&gt;      result[0] = x[ti].eval(tf);&lt;br /&gt;      result[1] = y[ti].eval(tf);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private List&lt;cacheitem&gt; travelCache;&lt;br /&gt;   private float           maxTravelStep;&lt;br /&gt;   private float           posStep;&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;enabledTripCaching&lt;/span&gt;(float maxTravelStep, float posStep)&lt;br /&gt;   {&lt;br /&gt;      this.maxTravelStep = maxTravelStep;&lt;br /&gt;      this.posStep = posStep;&lt;br /&gt;&lt;br /&gt;      float x = this.x[0].eval(0.0f);&lt;br /&gt;      float y = this.y[0].eval(0.0f);&lt;br /&gt;&lt;br /&gt;      this.travelCache = new ArrayList&lt;cacheitem&gt;();&lt;br /&gt;      this.travelCache.add(new CacheItem(x, y, 0.0f));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public boolean &lt;span style="color:yellow"&gt;getTripPosition&lt;/span&gt;(float totalTrip, float[] coords)&lt;br /&gt;   {&lt;br /&gt;      boolean isValid = true;&lt;br /&gt;&lt;br /&gt;      CacheItem last = this.travelCache.get(this.travelCache.size() - 1);&lt;br /&gt;&lt;br /&gt;      // build cache&lt;br /&gt;      while (last.travelled &lt; totalTrip)&lt;br /&gt;      {&lt;br /&gt;         if (totalTrip == 0.0f)&lt;br /&gt;         {&lt;br /&gt;            // don't even bother&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         float travel = Math.min(totalTrip - last.travelled, maxTravelStep);&lt;br /&gt;&lt;br /&gt;         CacheItem curr = this.getSteppingPosition(last.position, travel, posStep);&lt;br /&gt;&lt;br /&gt;         if (curr.position &gt;= this.count)&lt;br /&gt;         {&lt;br /&gt;            // reached end of spline&lt;br /&gt;            isValid = false;&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         // only cache if we travelled far enough&lt;br /&gt;         if (curr.travelled &gt; this.maxTravelStep * 0.95f)&lt;br /&gt;         {&lt;br /&gt;            this.travelCache.add(curr);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         curr.travelled += last.travelled;&lt;br /&gt;&lt;br /&gt;         last = curr;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // figure out position&lt;br /&gt;&lt;br /&gt;      int lo = 0;&lt;br /&gt;      int hi = this.travelCache.size() - 1;&lt;br /&gt;&lt;br /&gt;      while (true)&lt;br /&gt;      {&lt;br /&gt;         int mid = (lo + hi) / 2;&lt;br /&gt;&lt;br /&gt;         last = this.travelCache.get(mid);&lt;br /&gt;&lt;br /&gt;         if (last.travelled &lt; totalTrip)&lt;br /&gt;         {&lt;br /&gt;            if (lo == mid)&lt;br /&gt;               break;&lt;br /&gt;            lo = mid;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            if (hi == mid)&lt;br /&gt;               break;&lt;br /&gt;            hi = mid;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      for (int i = lo; i &lt;= hi; i++)&lt;br /&gt;      {&lt;br /&gt;         CacheItem item = this.travelCache.get(i);&lt;br /&gt;&lt;br /&gt;         if (item.travelled &lt;= totalTrip)&lt;br /&gt;         {&lt;br /&gt;            last = item;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float travel = totalTrip - last.travelled;&lt;br /&gt;      last = this.getSteppingPosition(last.position, travel, posStep);&lt;br /&gt;      coords[0] = last.xpos;&lt;br /&gt;      coords[1] = last.ypos;&lt;br /&gt;&lt;br /&gt;      return isValid;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private CacheItem getSteppingPosition(float posOffset, float travel, float segmentStep)&lt;br /&gt;   {&lt;br /&gt;      float pos = posOffset;&lt;br /&gt;      float[] last = this.getPositionAt(pos);&lt;br /&gt;&lt;br /&gt;      float travelled = 0.0f;&lt;br /&gt;&lt;br /&gt;      while (travelled &lt; travel &amp;&amp; pos &lt; this.count)&lt;br /&gt;      {&lt;br /&gt;         float[] curr = this.getPositionAt(pos += segmentStep);&lt;br /&gt;         travelled += Spline2D.dist(last, curr);&lt;br /&gt;         last = curr;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      CacheItem item = new CacheItem(last[0], last[1], 0.0f);&lt;br /&gt;      item.position = pos;&lt;br /&gt;      item.travelled = travelled;&lt;br /&gt;      return item;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float dist(float[] a, float[] b)&lt;br /&gt;   {&lt;br /&gt;      float dx = b[0] - a[0];&lt;br /&gt;      float dy = b[1] - a[1];&lt;br /&gt;&lt;br /&gt;      return (float) Math.sqrt(dx * dx + dy * dy);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * CURVE CLASS&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   private static class Curve&lt;br /&gt;   {&lt;br /&gt;      static final Cubic[] calcCurve(int n, float[] axis)&lt;br /&gt;      {&lt;br /&gt;         float[] gamma = new float[n + 1];&lt;br /&gt;         float[] delta = new float[n + 1];&lt;br /&gt;         float[] d = new float[n + 1];&lt;br /&gt;         Cubic[] c = new Cubic[n + 0];&lt;br /&gt;&lt;br /&gt;         // gamma&lt;br /&gt;         gamma[0] = 0.5f;&lt;br /&gt;         for (int i = 1; i &lt; n; i++)&lt;br /&gt;            gamma[i] = 1.0f / (4.0f - gamma[i - 1]);&lt;br /&gt;         gamma[n] = 1.0f / (2.0f - gamma[n - 1]);&lt;br /&gt;&lt;br /&gt;         // delta&lt;br /&gt;         delta[0] = 3.0f * (axis[1] - axis[0]) * gamma[0];&lt;br /&gt;         for (int i = 1; i &lt; n; i++)&lt;br /&gt;            delta[i] = (3.0f * (axis[i + 1] - axis[i - 1]) - delta[i - 1]) * gamma[i];&lt;br /&gt;         delta[n] = (3.0f * (axis[n] - axis[n - 1]) - delta[n - 1]) * gamma[n];&lt;br /&gt;&lt;br /&gt;         // d&lt;br /&gt;         d[n] = delta[n];&lt;br /&gt;         for (int i = n - 1; i &gt;= 0; i--)&lt;br /&gt;            d[i] = delta[i] - gamma[i] * d[i + 1];&lt;br /&gt;&lt;br /&gt;         // c&lt;br /&gt;         for (int i = 0; i &lt; n; i++)&lt;br /&gt;         {&lt;br /&gt;            float x0 = axis[i + 0];&lt;br /&gt;            float x1 = axis[i + 1];&lt;br /&gt;            float d0 = d[i + 0];&lt;br /&gt;            float d1 = d[i + 1];&lt;br /&gt;            c[i] = new Cubic(x0, d0, 3.0f * (x1 - x0) - 2.0f * d0 - d1, 2.0f * (x0 - x1) + d0 + d1);&lt;br /&gt;         }&lt;br /&gt;         return c;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * CUBIC CLASS&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   static class Cubic&lt;br /&gt;   {&lt;br /&gt;      private final float a, b, c, d;&lt;br /&gt;&lt;br /&gt;      Cubic(float a, float b, float c, float d)&lt;br /&gt;      {&lt;br /&gt;         this.a = a;&lt;br /&gt;         this.b = b;&lt;br /&gt;         this.c = c;&lt;br /&gt;         this.d = d;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      final float eval(float u)&lt;br /&gt;      {&lt;br /&gt;         return (((d * u) + c) * u + b) * u + a;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5695624562741032877?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5695624562741032877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/splane-2d.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5695624562741032877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5695624562741032877'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/splane-2d.html' title='Spline :: 2D'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-4410477287984397917</id><published>2009-08-25T01:32:00.002+02:00</published><updated>2009-08-25T03:04:44.324+02:00</updated><title type='text'>Spline :: 3D</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;Spline3D&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public &lt;span style="color:yellow"&gt;Spline3D&lt;/span&gt;(float[][] points)&lt;br /&gt;   {&lt;br /&gt;      count = points.length;&lt;br /&gt;&lt;br /&gt;      float[] x = new float[count];&lt;br /&gt;      float[] y = new float[count];&lt;br /&gt;      float[] z = new float[count];&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; count; i++)&lt;br /&gt;      {&lt;br /&gt;         x[i] = points[i][0];&lt;br /&gt;         y[i] = points[i][1];&lt;br /&gt;         z[i] = points[i][2];&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.x = Curve.calcCurve(count - 1, x);&lt;br /&gt;      this.y = Curve.calcCurve(count - 1, y);&lt;br /&gt;      this.z = Curve.calcCurve(count - 1, z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   final int count;&lt;br /&gt;   private final Cubic[] x, y, z;&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * POINT COUNT&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   public final int &lt;span style="color:yellow"&gt;pointCount&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return count;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * POSITION&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   public final float[] &lt;span style="color:yellow"&gt;getPositionAt&lt;/span&gt;(float param)&lt;br /&gt;   {&lt;br /&gt;      float[] v = new float[3];&lt;br /&gt;      this.getPositionAt(param, v);&lt;br /&gt;      return v;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;getPositionAt&lt;/span&gt;(float param, float[] result)&lt;br /&gt;   {&lt;br /&gt;      // clamp&lt;br /&gt;      if (param &lt; 0.0f)&lt;br /&gt;         param = 0.0f;&lt;br /&gt;      if (param &gt;= count - 1)&lt;br /&gt;         param = (count - 1) - Math.ulp(count - 1);&lt;br /&gt;&lt;br /&gt;      // split&lt;br /&gt;      int ti = (int) param;&lt;br /&gt;      float tf = param - ti;&lt;br /&gt;&lt;br /&gt;      // eval&lt;br /&gt;      result[0] = x[ti].eval(tf);&lt;br /&gt;      result[1] = y[ti].eval(tf);&lt;br /&gt;      result[2] = z[ti].eval(tf);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private List&lt;cacheitem&gt; travelCache;&lt;br /&gt;   private float           maxTravelStep;&lt;br /&gt;   private float           posStep;&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;enabledTripCaching&lt;/span&gt;(float maxTravelStep, float posStep)&lt;br /&gt;   {&lt;br /&gt;      this.maxTravelStep = maxTravelStep;&lt;br /&gt;      this.posStep = posStep;&lt;br /&gt;&lt;br /&gt;      float x = this.x[0].eval(0.0f);&lt;br /&gt;      float y = this.y[0].eval(0.0f);&lt;br /&gt;      float z = this.z[0].eval(0.0f);&lt;br /&gt;&lt;br /&gt;      this.travelCache = new ArrayList&lt;cacheitem&gt;();&lt;br /&gt;      this.travelCache.add(new CacheItem(x, y, z));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public float[] &lt;span style="color:yellow"&gt;getTripPosition&lt;/span&gt;(float totalTrip)&lt;br /&gt;   {&lt;br /&gt;      CacheItem last = this.travelCache.get(this.travelCache.size() - 1);&lt;br /&gt;&lt;br /&gt;      // build cache&lt;br /&gt;      while (last.travelled &lt; totalTrip)&lt;br /&gt;      {&lt;br /&gt;         if (totalTrip == 0.0f)&lt;br /&gt;         {&lt;br /&gt;            // don't even bother&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         float travel = Math.min(totalTrip - last.travelled, maxTravelStep);&lt;br /&gt;&lt;br /&gt;         CacheItem curr = this.getSteppingPosition(last.position, travel, posStep);&lt;br /&gt;&lt;br /&gt;         if (curr.position &gt;= this.count)&lt;br /&gt;         {&lt;br /&gt;            // reached end of spline&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         // only cache if we travelled far enough&lt;br /&gt;         if (curr.travelled &gt; this.maxTravelStep * 0.95f)&lt;br /&gt;         {&lt;br /&gt;            this.travelCache.add(curr);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         curr.travelled += last.travelled;&lt;br /&gt;&lt;br /&gt;         last = curr;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // figure out position&lt;br /&gt;&lt;br /&gt;      int lo = 0;&lt;br /&gt;      int hi = this.travelCache.size() - 1;&lt;br /&gt;&lt;br /&gt;      while (true)&lt;br /&gt;      {&lt;br /&gt;         int mid = (lo + hi) / 2;&lt;br /&gt;&lt;br /&gt;         last = this.travelCache.get(mid);&lt;br /&gt;&lt;br /&gt;         if (last.travelled &lt; totalTrip)&lt;br /&gt;         {&lt;br /&gt;            if (lo == mid)&lt;br /&gt;               break;&lt;br /&gt;            lo = mid;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            if (hi == mid)&lt;br /&gt;               break;&lt;br /&gt;            hi = mid;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      for (int i = lo; i &lt;= hi; i++)&lt;br /&gt;      {&lt;br /&gt;         CacheItem item = this.travelCache.get(i);&lt;br /&gt;&lt;br /&gt;         if (item.travelled &lt;= totalTrip)&lt;br /&gt;         {&lt;br /&gt;            last = item;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float travel = totalTrip - last.travelled;&lt;br /&gt;      last = this.getSteppingPosition(last.position, travel, posStep);&lt;br /&gt;      return new float[] { last.xpos, last.ypos };&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private CacheItem getSteppingPosition(float posOffset, float travel, float segmentStep)&lt;br /&gt;   {&lt;br /&gt;      float pos = posOffset;&lt;br /&gt;      float[] last = this.getPositionAt(pos);&lt;br /&gt;&lt;br /&gt;      float travelled = 0.0f;&lt;br /&gt;&lt;br /&gt;      while (travelled &lt; travel &amp;&amp; pos &lt; this.count)&lt;br /&gt;      {&lt;br /&gt;         float[] curr = this.getPositionAt(pos += segmentStep);&lt;br /&gt;         travelled += Spline3D.dist(last, curr);&lt;br /&gt;         last = curr;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      CacheItem item = new CacheItem(last[0], last[1], last[2]);&lt;br /&gt;      item.position = pos;&lt;br /&gt;      item.travelled = travelled;&lt;br /&gt;      return item;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float dist(float[] a, float[] b)&lt;br /&gt;   {&lt;br /&gt;      float dx = b[0] - a[0];&lt;br /&gt;      float dy = b[1] - a[1];&lt;br /&gt;      float dz = b[2] - a[2];&lt;br /&gt;&lt;br /&gt;      return (float) Math.sqrt(dx * dx + dy * dy + dz * dz);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * CURVE CLASS&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   private static class Curve&lt;br /&gt;   {&lt;br /&gt;      static final Cubic[] calcCurve(int n, float[] axis)&lt;br /&gt;      {&lt;br /&gt;         float[] gamma = new float[n + 1];&lt;br /&gt;         float[] delta = new float[n + 1];&lt;br /&gt;         float[] d = new float[n + 1];&lt;br /&gt;         Cubic[] c = new Cubic[n];&lt;br /&gt;&lt;br /&gt;         // gamma&lt;br /&gt;         gamma[0] = 0.5F;&lt;br /&gt;         for (int i = 1; i &lt; n; i++)&lt;br /&gt;            gamma[i] = 1.0F / (4.0F - gamma[i - 1]);&lt;br /&gt;         gamma[n] = 1.0F / (2.0F - gamma[n - 1]);&lt;br /&gt;&lt;br /&gt;         // delta&lt;br /&gt;         delta[0] = 3.0F * (axis[1] - axis[0]) * gamma[0];&lt;br /&gt;         for (int i = 1; i &lt; n; i++)&lt;br /&gt;            delta[i] = (3.0F * (axis[i + 1] - axis[i - 1]) - delta[i - 1]) * gamma[i];&lt;br /&gt;         delta[n] = (3.0F * (axis[n] - axis[n - 1]) - delta[n - 1]) * gamma[n];&lt;br /&gt;&lt;br /&gt;         // d&lt;br /&gt;         d[n] = delta[n];&lt;br /&gt;         for (int i = n - 1; i &gt;= 0; i--)&lt;br /&gt;            d[i] = delta[i] - gamma[i] * d[i + 1];&lt;br /&gt;&lt;br /&gt;         // c&lt;br /&gt;         for (int i = 0; i &lt; n; i++)&lt;br /&gt;         {&lt;br /&gt;            float x0 = axis[i];&lt;br /&gt;            float x1 = axis[i + 1];&lt;br /&gt;            float d0 = d[i];&lt;br /&gt;            float d1 = d[i + 1];&lt;br /&gt;            c[i] = new Cubic(x0, d0, 3.0F * (x1 - x0) - 2.0F * d0 - d1, 2.0F * (x0 - x1) + d0 + d1);&lt;br /&gt;         }&lt;br /&gt;         return c;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * CUBIC CLASS&lt;br /&gt;    */&lt;br /&gt;&lt;br /&gt;   static class Cubic&lt;br /&gt;   {&lt;br /&gt;      private final float a, b, c, d;&lt;br /&gt;&lt;br /&gt;      Cubic(float a, float b, float c, float d)&lt;br /&gt;      {&lt;br /&gt;         this.a = a;&lt;br /&gt;         this.b = b;&lt;br /&gt;         this.c = c;&lt;br /&gt;         this.d = d;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      final float eval(float u)&lt;br /&gt;      {&lt;br /&gt;         return (((d * u) + c) * u + b) * u + a;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-4410477287984397917?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/4410477287984397917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/spline-3d.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4410477287984397917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/4410477287984397917'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/spline-3d.html' title='Spline :: 3D'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-836194885090270558</id><published>2009-08-25T01:28:00.003+02:00</published><updated>2009-10-26T17:35:14.321+01:00</updated><title type='text'>BezierCurve :: 2D</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;BezierCurve&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static Vec2 &lt;span style="color:yellow"&gt;interpolate4&lt;/span&gt;(float t, Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4)&lt;br /&gt;   {&lt;br /&gt;      float invT = 1.0f - t;&lt;br /&gt;&lt;br /&gt;      float m1 = pow3(invT) * 1.0f * pow0(t);&lt;br /&gt;      float m2 = pow2(invT) * 3.0f * pow1(t);&lt;br /&gt;      float m3 = pow1(invT) * 3.0f * pow2(t);&lt;br /&gt;      float m4 = pow0(invT) * 1.0f * pow3(t);&lt;br /&gt;&lt;br /&gt;      float x = 0.0f;&lt;br /&gt;      float y = 0.0f;&lt;br /&gt;&lt;br /&gt;      x += p1.x * m1;&lt;br /&gt;      y += p1.y * m1;&lt;br /&gt;&lt;br /&gt;      x += p2.x * m2;&lt;br /&gt;      y += p2.y * m2;&lt;br /&gt;&lt;br /&gt;      x += p3.x * m3;&lt;br /&gt;      y += p3.y * m3;&lt;br /&gt;&lt;br /&gt;      x += p4.x * m4;&lt;br /&gt;      y += p4.y * m4;&lt;br /&gt;&lt;br /&gt;      return new Vec2(x, y);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static Vec2 &lt;span style="color:yellow"&gt;interpolate&lt;/span&gt;(float t, Vec2... ps)&lt;br /&gt;   {&lt;br /&gt;      float x = 0.0f;&lt;br /&gt;      float y = 0.0f;&lt;br /&gt;&lt;br /&gt;      final int n = ps.length - 1;&lt;br /&gt;&lt;br /&gt;      for (int k = 0; k &lt;= n; k++)&lt;br /&gt;      {&lt;br /&gt;         float m = pow(1.0f - t, n - k) * coeff(n, k) * pow(t, k);&lt;br /&gt;&lt;br /&gt;         x += ps[k].x * m;&lt;br /&gt;         y += ps[k].y * m;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return new Vec2(x, y);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;  @SuppressWarnings("unused")&lt;br /&gt;   private static float pow0(float t)&lt;br /&gt;   {&lt;br /&gt;      return 1.0f;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float pow1(float t)&lt;br /&gt;   {&lt;br /&gt;      return t;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float pow2(float t)&lt;br /&gt;   {&lt;br /&gt;      return t * t;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float pow3(float t)&lt;br /&gt;   {&lt;br /&gt;      return t * t * t;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float pow(float t, int times)&lt;br /&gt;   {&lt;br /&gt;      float tt = 1.0f;&lt;br /&gt;      for (int i = 0; i &lt; times; i++)&lt;br /&gt;         tt *= t;&lt;br /&gt;      return tt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static float coeff(int n, int k)&lt;br /&gt;   {&lt;br /&gt;      return (float) (fact(n) / (fact(k) * fact(n - k)));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static double fact(int n)&lt;br /&gt;   {&lt;br /&gt;      double val = 1.0;&lt;br /&gt;      for (int i = 2; i &lt;= n; i++)&lt;br /&gt;         val *= i;&lt;br /&gt;      return val;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-836194885090270558?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/836194885090270558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/beziercurve-2d.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/836194885090270558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/836194885090270558'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/beziercurve-2d.html' title='BezierCurve :: 2D'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-2369045589605766971</id><published>2009-08-25T01:22:00.006+02:00</published><updated>2009-08-25T03:18:34.484+02:00</updated><title type='text'>Image :: alpha / write jpg</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;ImageUtil&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static void &lt;span style="color:yellow"&gt;makeTransparant&lt;/span&gt;(BufferedImage img)&lt;br /&gt;   {&lt;br /&gt;      Graphics2D g = img.createGraphics();&lt;br /&gt;      g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));&lt;br /&gt;      g.fillRect(0, 0, img.getWidth(), img.getHeight());&lt;br /&gt;      g.dispose();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void &lt;span style="color:yellow"&gt;writeJPG&lt;/span&gt;(BufferedImage img, File file, float quality) throws IOException&lt;br /&gt;   {&lt;br /&gt;      Iterator&lt;imagewriter&gt; iter = ImageIO.getImageWritersByFormatName("jpeg");&lt;br /&gt;      ImageWriter writer = iter.next();&lt;br /&gt;      ImageWriteParam iwp = writer.getDefaultWriteParam();&lt;br /&gt;      iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);&lt;br /&gt;      iwp.setCompressionQuality(quality);&lt;br /&gt;&lt;br /&gt;      FileImageOutputStream output = new FileImageOutputStream(file);&lt;br /&gt;      writer.setOutput(output);&lt;br /&gt;      IIOImage image = new IIOImage(img, null, null);&lt;br /&gt;      writer.write(null, image, iwp);&lt;br /&gt;      writer.dispose();&lt;br /&gt;      output.close();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-2369045589605766971?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/2369045589605766971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/image-jpg-transparancy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2369045589605766971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2369045589605766971'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/image-jpg-transparancy.html' title='Image :: alpha / write jpg'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-2779078411027137557</id><published>2009-08-25T01:18:00.009+02:00</published><updated>2009-08-25T03:05:12.607+02:00</updated><title type='text'>Image :: mipmap with gamma</title><content type='html'>Most people don't realize that when you scale down an image, the gamma changes. For those who care, here is the code to fixy fixy:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;ImageUtil&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static BufferedImage &lt;span style="color:yellow"&gt;mipmapGammaCorrected&lt;/span&gt;(&lt;br /&gt;                     BufferedImage src,&lt;br /&gt;                     int level)&lt;br /&gt;   {&lt;br /&gt;      if (level &lt; 1)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalArgumentException();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; level; i++)&lt;br /&gt;      {&lt;br /&gt;         BufferedImage tmp = mipmapGammaCorrected(src);&lt;br /&gt;         if (i != 0)&lt;br /&gt;            src.flush(); // do not flush argument&lt;br /&gt;         src = tmp;&lt;br /&gt;      }&lt;br /&gt;      return src;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static BufferedImage &lt;span style="color:yellow"&gt;mipmapGammaCorrected&lt;/span&gt;(BufferedImage src)&lt;br /&gt;   {&lt;br /&gt;      int wSrc = src.getWidth();&lt;br /&gt;      int hSrc = src.getHeight();&lt;br /&gt;&lt;br /&gt;      if (wSrc % 2 != 0 || hSrc % 2 != 0)&lt;br /&gt;      {&lt;br /&gt;         throw new IllegalStateException("dimensions must be multiple of 2");&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      int wDst = wSrc / 2;&lt;br /&gt;      int hDst = hSrc / 2;&lt;br /&gt;&lt;br /&gt;      int[] argbFull = src.getRGB(0, 0, wSrc, hSrc, null, 0, wSrc);&lt;br /&gt;&lt;br /&gt;      int type = BufferedImage.TYPE_INT_RGB;&lt;br /&gt;      if (src.getAlphaRaster() != null)&lt;br /&gt;      {&lt;br /&gt;         type = BufferedImage.TYPE_INT_ARGB;&lt;br /&gt;&lt;br /&gt;         // merge alpha into RGB values&lt;br /&gt;         int[] alphaFull = src.getAlphaRaster().getPixels(0, 0, wSrc, hSrc, (int[]) null);&lt;br /&gt;         for (int i = 0; i &lt; alphaFull.length; i++)&lt;br /&gt;         {&lt;br /&gt;            argbFull[i] = (alphaFull[i] &lt;&lt; 24) | (argbFull[i] &amp; 0x00FFFFFF);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      BufferedImage half = new BufferedImage(wDst, hDst, type);&lt;br /&gt;&lt;br /&gt;      int[] argbHalf = new int[argbFull.length &gt;&gt;&gt; 2];&lt;br /&gt;&lt;br /&gt;      for (int y = 0; y &lt; hDst; y++)&lt;br /&gt;      {&lt;br /&gt;         for (int x = 0; x &lt; wDst; x++)&lt;br /&gt;         {&lt;br /&gt;            int p0 = argbFull[((y &lt;&lt; 1) | 0) * wSrc + ((x &lt;&lt; 1) | 0)];&lt;br /&gt;            int p1 = argbFull[((y &lt;&lt; 1) | 1) * wSrc + ((x &lt;&lt; 1) | 0)];&lt;br /&gt;            int p2 = argbFull[((y &lt;&lt; 1) | 1) * wSrc + ((x &lt;&lt; 1) | 1)];&lt;br /&gt;            int p3 = argbFull[((y &lt;&lt; 1) | 0) * wSrc + ((x &lt;&lt; 1) | 1)];&lt;br /&gt;&lt;br /&gt;            int a = gammaCorrectedAverage(p0, p1, p2, p3, 24);&lt;br /&gt;            int r = gammaCorrectedAverage(p0, p1, p2, p3, 16);&lt;br /&gt;            int g = gammaCorrectedAverage(p0, p1, p2, p3, 8);&lt;br /&gt;            int b = gammaCorrectedAverage(p0, p1, p2, p3, 0);&lt;br /&gt;&lt;br /&gt;            argbHalf[y * wDst + x] = (a &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      half.setRGB(0, 0, wDst, hDst, argbHalf, 0, wDst);&lt;br /&gt;      if (type == BufferedImage.TYPE_INT_ARGB)&lt;br /&gt;      {&lt;br /&gt;         // extract alpha from ARGB values&lt;br /&gt;         int[] alpha = new int[argbHalf.length];&lt;br /&gt;         for (int i = 0; i &lt; alpha.length; i++)&lt;br /&gt;            alpha[i] = (argbHalf[i] &gt;&gt; 24) &amp; 0xFF;&lt;br /&gt;         half.getAlphaRaster().setPixels(0, 0, wDst, hDst, alpha);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return half;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   static int &lt;span style="color:yellow"&gt;gammaCorrectedAverage&lt;/span&gt;(int a, int b, int c, int d, int shift)&lt;br /&gt;   {&lt;br /&gt;      float x = ((a &gt;&gt; shift) &amp; 0xFF) / 255.0f;&lt;br /&gt;      float y = ((b &gt;&gt; shift) &amp; 0xFF) / 255.0f;&lt;br /&gt;      float z = ((c &gt;&gt; shift) &amp; 0xFF) / 255.0f;&lt;br /&gt;      float w = ((d &gt;&gt; shift) &amp; 0xFF) / 255.0f;&lt;br /&gt;&lt;br /&gt;      float e = x * x + y * y + z * z + w * w;&lt;br /&gt;      e = (float) Math.sqrt(e * 0.25f);&lt;br /&gt;      return (int) (e * 255.0f);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-2779078411027137557?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/2779078411027137557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/image-gamma-corrected-scaling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2779078411027137557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2779078411027137557'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/image-gamma-corrected-scaling.html' title='Image :: mipmap with gamma'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-830885556287453084</id><published>2009-08-25T00:46:00.006+02:00</published><updated>2009-08-25T03:05:29.979+02:00</updated><title type='text'>Verlet :: collision math / spring</title><content type='html'>Below is the code to do the actual collisions, verlet style. You might scratch your head and wonder how such basic math will handle all your physics. In reality it simply won't: it will only get more or less realistic when you start connecting lots of particles with lots of springs to create a representation of physical bodies.&lt;br /&gt;&lt;br /&gt;With physics, it's all about how you structure your data. You don't want to collide everything against everything. How to design and optimize a spatial datastructure is left as an exercise to the reader. Such code is too big to post.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;VerletMath&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color:green"&gt;// plane &lt;--&gt; sphere&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   public static final boolean &lt;span style="color:yellow"&gt;collides&lt;/span&gt;(VerletPlane a, VerletSphere b)&lt;br /&gt;   {&lt;br /&gt;      float dx = b.particle.now.x - a.nx * a.d;&lt;br /&gt;      float dy = b.particle.now.y - a.ny * a.d;&lt;br /&gt;      float dz = b.particle.now.z - a.nz * a.d;&lt;br /&gt;&lt;br /&gt;      return ((a.nx * dx) + (a.ny * dy) + (a.nz * dz) - b.radius) &lt; 0.0f;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style="color:yellow"&gt;collide&lt;/span&gt;(VerletPlane a, VerletSphere b)&lt;br /&gt;   {&lt;br /&gt;      float bx = b.particle.now.x;&lt;br /&gt;      float by = b.particle.now.y;&lt;br /&gt;      float bz = b.particle.now.z;&lt;br /&gt;      float bd = b.radius;&lt;br /&gt;&lt;br /&gt;      float dx = bx - a.nx * a.d;&lt;br /&gt;      float dy = by - a.ny * a.d;&lt;br /&gt;      float dz = bz - a.nz * a.d;&lt;br /&gt;&lt;br /&gt;      float dst = (a.nx * dx) + (a.ny * dy) + (a.nz * dz) - bd;&lt;br /&gt;      if (dst &gt;= 0.0f)&lt;br /&gt;         return 0.0f;&lt;br /&gt;&lt;br /&gt;      // impl true bounce, using speed&lt;br /&gt;      // push out along normal of plane&lt;br /&gt;&lt;br /&gt;      b.particle.now.x = bx - dst * a.nx;&lt;br /&gt;      b.particle.now.y = by - dst * a.ny;&lt;br /&gt;      b.particle.now.z = bz - dst * a.nz;&lt;br /&gt;&lt;br /&gt;      return -dst;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:green"&gt;// sphere &lt;--&gt; sphere&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   public static final void &lt;span style="color:yellow"&gt;collide&lt;/span&gt;(VerletSphere target, Bag&amp;lt;VerletSphere&amp;gt; all)&lt;br /&gt;   {&lt;br /&gt;      int size = all.size();&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; size; i++)&lt;br /&gt;      {&lt;br /&gt;         VerletSphere sphere = all.get(i);&lt;br /&gt;&lt;br /&gt;         if (VerletMath.collides(sphere, target))&lt;br /&gt;         {&lt;br /&gt;            VerletMath.collide(sphere, target);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final boolean &lt;span style="color:yellow"&gt;collides&lt;/span&gt;(VerletSphere a, VerletSphere b)&lt;br /&gt;   {&lt;br /&gt;      Vec3 va = a.particle.now;&lt;br /&gt;      Vec3 vb = b.particle.now;&lt;br /&gt;      float d = a.radius + b.radius;&lt;br /&gt;&lt;br /&gt;      float x = va.x - vb.x;&lt;br /&gt;      float y = va.y - vb.y;&lt;br /&gt;      float z = va.z - vb.z;&lt;br /&gt;&lt;br /&gt;      return (x * x + y * y + z * z) &lt; (d * d);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style="color:yellow"&gt;collide&lt;/span&gt;(VerletSphere a, VerletSphere b)&lt;br /&gt;   {&lt;br /&gt;      Vec3 anow = a.particle.now;&lt;br /&gt;      Vec3 bnow = b.particle.now;&lt;br /&gt;&lt;br /&gt;      float ax = anow.x;&lt;br /&gt;      float ay = anow.y;&lt;br /&gt;      float az = anow.z;&lt;br /&gt;      float aiw = a.particle.invWeight;&lt;br /&gt;&lt;br /&gt;      float bx = bnow.x;&lt;br /&gt;      float by = bnow.y;&lt;br /&gt;      float bz = bnow.z;&lt;br /&gt;      float biw = b.particle.invWeight;&lt;br /&gt;&lt;br /&gt;      float dx = bx - ax;&lt;br /&gt;      float dy = by - ay;&lt;br /&gt;      float dz = bz - az;&lt;br /&gt;      float d2 = dx * dx + dy * dy + dz * dz;&lt;br /&gt;&lt;br /&gt;      if (d2 &lt;= ulp_zero)&lt;br /&gt;      {&lt;br /&gt;         // sharing position, oh oh!&lt;br /&gt;         // big problem! if we collide&lt;br /&gt;         // it, it will explode &lt;br /&gt;         return 0.0f;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float dMin = a.radius + b.radius;&lt;br /&gt;      if (d2 &gt; (dMin * dMin))&lt;br /&gt;         return 0.0f;&lt;br /&gt;&lt;br /&gt;      // apply spring -&gt; push out of eachother&lt;br /&gt;&lt;br /&gt;      //final float tension = 1.0f;&lt;br /&gt;      float d = (float) Math.sqrt(d2);&lt;br /&gt;      float f = (d - dMin) / dMin * 0.5f;//* tension;&lt;br /&gt;&lt;br /&gt;      float f1 = f * aiw / (aiw + biw);&lt;br /&gt;      anow.x = ax + dx * f1;&lt;br /&gt;      anow.y = ay + dy * f1;&lt;br /&gt;      anow.z = az + dz * f1;&lt;br /&gt;&lt;br /&gt;      float f2 = f * biw / (aiw + biw);&lt;br /&gt;      bnow.x = bx - dx * f2;&lt;br /&gt;      bnow.y = by - dy * f2;&lt;br /&gt;      bnow.z = bz - dz * f2;&lt;br /&gt;&lt;br /&gt;      return (dMin - d);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float ulp_zero = Math.ulp(0.0f);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style="color:yellow"&gt;VerletSpring&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static final int FIXED_LENGTH = 0;&lt;br /&gt;   public static final int MIN_LENGTH   = 1;&lt;br /&gt;   public static final int MAX_LENGTH   = 2;&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final VerletParticle a, b;&lt;br /&gt;&lt;br /&gt;   public float                len, stf;&lt;br /&gt;   public int                  how;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;VerletSpring&lt;/span&gt;(VerletParticle a, VerletParticle b)&lt;br /&gt;   {&lt;br /&gt;      this.a = a;&lt;br /&gt;      this.b = b;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final float &lt;span style="color:yellow"&gt;setCurrentDistanceAsLength&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      float dx = b.now.x - a.now.x;&lt;br /&gt;      float dy = b.now.y - a.now.y;&lt;br /&gt;      float dz = b.now.z - a.now.z;&lt;br /&gt;      float d = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);&lt;br /&gt;&lt;br /&gt;      this.len = d;&lt;br /&gt;&lt;br /&gt;      return d;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final float &lt;span style="color:yellow"&gt;tick&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      float ax = a.now.x;&lt;br /&gt;      float ay = a.now.y;&lt;br /&gt;      float az = a.now.z;&lt;br /&gt;&lt;br /&gt;      float bx = b.now.x;&lt;br /&gt;      float by = b.now.y;&lt;br /&gt;      float bz = b.now.z;&lt;br /&gt;&lt;br /&gt;      float dx = ax - bx;&lt;br /&gt;      float dy = ay - by;&lt;br /&gt;      float dz = az - bz;&lt;br /&gt;      float dist = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);&lt;br /&gt;&lt;br /&gt;      if (how == MIN_LENGTH)&lt;br /&gt;      {&lt;br /&gt;         if (dist &gt; len)&lt;br /&gt;            return 0.0f;&lt;br /&gt;      }&lt;br /&gt;      else if (how == MAX_LENGTH)&lt;br /&gt;      {&lt;br /&gt;         if (dist &lt; len)&lt;br /&gt;            return 0.0f;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float tension = (len - dist) / dist;&lt;br /&gt;      float force = tension * this.stf;&lt;br /&gt;&lt;br /&gt;      float aw = a.invWeight;&lt;br /&gt;      float bw = b.invWeight;&lt;br /&gt;&lt;br /&gt;      float f1 = force * aw / (aw + bw);&lt;br /&gt;      float f2 = force * bw / (aw + bw);&lt;br /&gt;&lt;br /&gt;      a.now.x = ax + dx * f1;&lt;br /&gt;      a.now.y = ay + dy * f1;&lt;br /&gt;      a.now.z = az + dz * f1;&lt;br /&gt;&lt;br /&gt;      b.now.x = bx - dx * f2;&lt;br /&gt;      b.now.y = by - dy * f2;&lt;br /&gt;      b.now.z = bz - dz * f2;&lt;br /&gt;&lt;br /&gt;      return tension;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-830885556287453084?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/830885556287453084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/verlet-math.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/830885556287453084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/830885556287453084'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/verlet-math.html' title='Verlet :: collision math / spring'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-997762464501450983</id><published>2009-08-25T00:39:00.002+02:00</published><updated>2009-08-25T03:05:36.708+02:00</updated><title type='text'>Verlet :: particle/sphere/plane</title><content type='html'>&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;VerletParticle&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public final Vec3 now, old;&lt;br /&gt;   public float      invWeight;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;VerletParticle&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.old = new Vec3();&lt;br /&gt;      this.now = new Vec3();&lt;br /&gt;      this.invWeight = 1.0f;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   public void &lt;span style="color:yellow"&gt;setInfiniteWeight&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this.invWeight = 0.0f;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;setWeight&lt;/span&gt;(float weight)&lt;br /&gt;   {&lt;br /&gt;      this.invWeight = 1.0f / weight;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;setPosition&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      this.setPosition(vec.x, vec.y, vec.z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;setPosition&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      float xVel = now.x - old.x;&lt;br /&gt;      float yVel = now.y - old.y;&lt;br /&gt;      float zVel = now.z - old.z;&lt;br /&gt;&lt;br /&gt;      now.x = x;&lt;br /&gt;      now.y = y;&lt;br /&gt;      now.z = z;&lt;br /&gt;&lt;br /&gt;      old.x = x - xVel;&lt;br /&gt;      old.y = y - yVel;&lt;br /&gt;      old.z = z - zVel;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;getPosition&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      vec.x = now.x;&lt;br /&gt;      vec.y = now.y;&lt;br /&gt;      vec.z = now.z;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;translate&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      this.translate(vec.x, vec.y, vec.z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;translate&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      this.setPosition(now.x + x, now.y + y, now.z + z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;addForce&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      this.addForce(vec.x, vec.y, vec.z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;addForce&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      this.addVelocity(x * invWeight, y * invWeight, z * invWeight);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;setVelocity&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      this.setVelocity(vec.x, vec.y, vec.z);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;setVelocity&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      old.x = now.x - x;&lt;br /&gt;      old.y = now.y - y;&lt;br /&gt;      old.z = now.z - z;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;addVelocity&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      old.x = old.x - x;&lt;br /&gt;      old.y = old.y - y;&lt;br /&gt;      old.z = old.z - z;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;getVelocity&lt;/span&gt;(Vec3 vec)&lt;br /&gt;   {&lt;br /&gt;      vec.x = now.x - old.x;&lt;br /&gt;      vec.y = now.y - old.y;&lt;br /&gt;      vec.z = now.z - old.z;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;mulVelocity&lt;/span&gt;(float factor)&lt;br /&gt;   {&lt;br /&gt;      float xNow = now.x;&lt;br /&gt;      float yNow = now.y;&lt;br /&gt;      float zNow = now.z;&lt;br /&gt;&lt;br /&gt;      old.x = xNow - (xNow - old.x) * factor;&lt;br /&gt;      old.y = yNow - (yNow - old.y) * factor;&lt;br /&gt;      old.z = zNow - (zNow - old.z) * factor;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;tick&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      float xOld = old.x;&lt;br /&gt;      float yOld = old.y;&lt;br /&gt;      float zOld = old.z;&lt;br /&gt;&lt;br /&gt;      old.x = now.x;&lt;br /&gt;      old.y = now.y;&lt;br /&gt;      old.z = now.z;&lt;br /&gt;&lt;br /&gt;      now.x += now.x - xOld;&lt;br /&gt;      now.y += now.y - yOld;&lt;br /&gt;      now.z += now.z - zOld;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style="color:yellow"&gt;VerletPlane&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public float nx, ny, nz, d;&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;inferValues&lt;/span&gt;(Vec3 src, Vec3 dst)&lt;br /&gt;   {&lt;br /&gt;      float nx = dst.x - src.x;&lt;br /&gt;      float ny = dst.y - src.y;&lt;br /&gt;      float nz = dst.z - src.z;&lt;br /&gt;&lt;br /&gt;      float d = (float) Math.sqrt(nx * nx + ny * ny + nz * nz);&lt;br /&gt;      nx /= d;&lt;br /&gt;      ny /= d;&lt;br /&gt;      nz /= d;&lt;br /&gt;&lt;br /&gt;      float d2 = VecMath.dot(src, src);&lt;br /&gt;      d2 = (d2 == 0.0f) ? 1.0f : (float) Math.sqrt(d2);&lt;br /&gt;      float nx2 = src.x / d2;&lt;br /&gt;      float ny2 = src.y / d2;&lt;br /&gt;      float nz2 = src.z / d2;&lt;br /&gt;&lt;br /&gt;      d2 *= nx * nx2 + ny * ny2 + nz * nz2;&lt;br /&gt;&lt;br /&gt;      this.nx = nx;&lt;br /&gt;      this.ny = ny;&lt;br /&gt;      this.nz = nz;&lt;br /&gt;      this.d = d2;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final static VerletPlane &lt;span style="color:yellow"&gt;infer&lt;/span&gt;(Vec3 src, Vec3 dst)&lt;br /&gt;   {&lt;br /&gt;      VerletPlane plane = new VerletPlane();&lt;br /&gt;      plane.inferValues(src, dst);&lt;br /&gt;      return plane;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class &lt;span style="color:yellow"&gt;VerletSphere&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public final VerletParticle particle;&lt;br /&gt;   public float                radius;&lt;br /&gt;   public float                invFriction = 0.1f;&lt;br /&gt;   public float                drag        = 0.0f;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;VerletSphere&lt;/span&gt;(float rad)&lt;br /&gt;   {&lt;br /&gt;      this(new VerletParticle(), rad);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;VerletSphere&lt;/span&gt;(VerletParticle p, float rad)&lt;br /&gt;   {&lt;br /&gt;      this.particle = p;&lt;br /&gt;      this.radius = rad;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;setFriction&lt;/span&gt;(float friction)&lt;br /&gt;   {&lt;br /&gt;      this.invFriction = 1.0f - friction;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public VerletParticle &lt;span style="color:yellow"&gt;getParticle&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return particle;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-997762464501450983?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/997762464501450983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/verlet-particle.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/997762464501450983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/997762464501450983'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/verlet-particle.html' title='Verlet :: particle/sphere/plane'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-6985088348547432276</id><published>2009-08-25T00:23:00.005+02:00</published><updated>2009-08-25T03:05:47.018+02:00</updated><title type='text'>Color :: HSL &lt;&gt; RGB</title><content type='html'>Hue Saturation Lightness (not to be confused with Hue Saturation Brightness) should be imagined as a double cone. The top of the upper-cone will be white. The bottom of the lower-cone will be black. The circle (where the cones touch) has the full range of colors in the rainbow, the center is gray.&lt;br /&gt;&lt;br /&gt;Vertical axis: Lightness [0.0 .. 1.0]&lt;br /&gt;Polar angle: Hue [0.0 .. 1.0] (wraps: 1.2 becomes 0.2)&lt;br /&gt;Polar distance: Saturation [0.0 .. 1.0]&lt;br /&gt;&lt;br /&gt;You can grab a RGB pixel, convert to HSL, modify it, and convert it back to RGB. Results are nice. When applied to a specific region of a photo, you can make a single object radically change color. Have fun.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;ColorHSL&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   public static final void &lt;span style="color:yellow"&gt;rgb2hsl&lt;/span&gt;(int[] rgb, float[] hsl)&lt;br /&gt;   {&lt;br /&gt;      float R = rgb[0] / 255.0f;&lt;br /&gt;      float G = rgb[1] / 255.0f;&lt;br /&gt;      float B = rgb[2] / 255.0f;&lt;br /&gt;&lt;br /&gt;      float MAX = max(R, max(G, B));&lt;br /&gt;      float MIN = min(R, min(G, B));&lt;br /&gt;      float H, L, S;&lt;br /&gt;&lt;br /&gt;      if (MIN == MAX)&lt;br /&gt;         H = 0.0f;&lt;br /&gt;      else if (R == MAX)&lt;br /&gt;         H = 0.16666666f * ((G - B) / (MAX - MIN)) + 0.00000000f;&lt;br /&gt;      else if (G == MAX)&lt;br /&gt;         H = 0.16666666f * ((B - R) / (MAX - MIN)) + 0.33333333f;&lt;br /&gt;      else&lt;br /&gt;         H = 0.16666666f * ((R - G) / (MAX - MIN)) + 0.66666666f;&lt;br /&gt;&lt;br /&gt;      L = 0.5f * (MIN + MAX);&lt;br /&gt;      if (L == 0.0f || (MIN == MAX))&lt;br /&gt;         S = 0.0f;&lt;br /&gt;      else if (L &lt;= 0.5f)&lt;br /&gt;         S = (MAX - MIN) / (2 * L);&lt;br /&gt;      else&lt;br /&gt;         S = (MAX - MIN) / (2 - 2 * L);&lt;br /&gt;&lt;br /&gt;      hsl[0] = absMod(H, 1.0f);&lt;br /&gt;      hsl[1] = S;&lt;br /&gt;      hsl[2] = L;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final int[] &lt;span style="color:yellow"&gt;hsl2rgb&lt;/span&gt;(float[] hsl, int[] rgb)&lt;br /&gt;   {&lt;br /&gt;      float H = hsl[0];&lt;br /&gt;      float S = hsl[1];&lt;br /&gt;      float L = hsl[2];&lt;br /&gt;&lt;br /&gt;      float R, G, B;&lt;br /&gt;&lt;br /&gt;      if (S == 0.0f)&lt;br /&gt;      {&lt;br /&gt;         R = G = B = L;&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         float Q = (L &lt; 0.5f) ? (L * (1.0f + S)) : ((L + S) - (L * S));&lt;br /&gt;         float P = 2.0f * L - Q;&lt;br /&gt;         float Hk = absMod(H, 1.0f);&lt;br /&gt;&lt;br /&gt;         R = convert(Q, P, Hk + 0.33333333333f);&lt;br /&gt;         G = convert(Q, P, Hk + 0.00000000000f);&lt;br /&gt;         B = convert(Q, P, Hk - 0.33333333333f);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      rgb[0] = (int) (clamp(R, 0.0f, 1.0f) * 255.0f);&lt;br /&gt;      rgb[1] = (int) (clamp(G, 0.0f, 1.0f) * 255.0f);&lt;br /&gt;      rgb[2] = (int) (clamp(B, 0.0f, 1.0f) * 255.0f);&lt;br /&gt;&lt;br /&gt;      return rgb;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float convert(float Q, float P, float Tx)&lt;br /&gt;   {&lt;br /&gt;      Tx = absMod(Tx, 1.0f);&lt;br /&gt;      if (Tx &lt; 1.0f / 6.0f)&lt;br /&gt;         return P + ((Q - P) * 6.0f * Tx);&lt;br /&gt;      if (Tx &lt; 3.0f / 6.0f)&lt;br /&gt;         return Q;&lt;br /&gt;      if (Tx &lt; 4.0f / 6.0f)&lt;br /&gt;         return P + ((Q - P) * 6.0f * (4.0f / 6.0f - Tx));&lt;br /&gt;      return P;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float absMod(float val, float max)&lt;br /&gt;   {&lt;br /&gt;      return ((val % max) + max) % max;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float clamp(float cur, float min, float max)&lt;br /&gt;   {&lt;br /&gt;      return (cur &lt; min ? min : (cur &gt; max ? max : cur));&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-6985088348547432276?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/6985088348547432276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/color-hsl-rgb.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6985088348547432276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/6985088348547432276'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/color-hsl-rgb.html' title='Color :: HSL &lt;&gt; RGB'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-7737203822053940791</id><published>2009-08-25T00:03:00.002+02:00</published><updated>2009-08-25T03:05:55.308+02:00</updated><title type='text'>PerlinNoise :: smooth/turbulent</title><content type='html'>Nothing too fancy. Copy and paste if you need it.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;public class &lt;span style="color:yellow"&gt;PerlinNoise&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   private float xo, yo, zo;&lt;br /&gt;&lt;br /&gt;   public final void &lt;span style="color:yellow"&gt;offset&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      this.xo = x;&lt;br /&gt;      this.yo = y;&lt;br /&gt;      this.zo = z;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final float &lt;span style="color:yellow"&gt;smoothNoise&lt;/span&gt;(float x, float y, float z, int octaves)&lt;br /&gt;   {&lt;br /&gt;      float height = 0.0f;&lt;br /&gt;      for (int octave = 1; octave &lt;= octaves; octave++)&lt;br /&gt;         height += noise(x, y, z, octave);&lt;br /&gt;      return height;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final float &lt;span style="color:yellow"&gt;turbulentNoise&lt;/span&gt;(float x, float y, float z, int octaves)&lt;br /&gt;   {&lt;br /&gt;      float height = 0.0f;&lt;br /&gt;      for (int octave = 1; octave &lt;= octaves; octave++)&lt;br /&gt;      {&lt;br /&gt;         float h = noise(x0, y0, z0, octave);&lt;br /&gt;         if (h &lt; 0.0f) h *= -1.0f;&lt;br /&gt;         height += h;&lt;br /&gt;      }&lt;br /&gt;      return height;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public final float &lt;span style="color:yellow"&gt;noise&lt;/span&gt;(float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      float fx = floor(x);&lt;br /&gt;      float fy = floor(y);&lt;br /&gt;      float fz = floor(z);&lt;br /&gt;&lt;br /&gt;      int gx = (int) fx &amp; 0xFF;&lt;br /&gt;      int gy = (int) fy &amp; 0xFF;&lt;br /&gt;      int gz = (int) fz &amp; 0xFF;&lt;br /&gt;&lt;br /&gt;      float u = fade(x -= fx);&lt;br /&gt;      float v = fade(y -= fy);&lt;br /&gt;      float w = fade(z -= fz);&lt;br /&gt;&lt;br /&gt;      int a0 = perm[gx + 0] + gy;&lt;br /&gt;      int b0 = perm[gx + 1] + gy;&lt;br /&gt;      int aa = perm[a0 + 0] + gz;&lt;br /&gt;      int ab = perm[a0 + 1] + gz;&lt;br /&gt;      int ba = perm[b0 + 0] + gz;&lt;br /&gt;      int bb = perm[b0 + 1] + gz;&lt;br /&gt;&lt;br /&gt;      float a1 = grad(perm[bb + 1], x - 1, y - 1, z - 1);&lt;br /&gt;      float a2 = grad(perm[ab + 1], x - 0, y - 1, z - 1);&lt;br /&gt;      float a3 = grad(perm[ba + 1], x - 1, y - 0, z - 1);&lt;br /&gt;      float a4 = grad(perm[aa + 1], x - 0, y - 0, z - 1);&lt;br /&gt;      float a5 = grad(perm[bb + 0], x - 1, y - 1, z - 0);&lt;br /&gt;      float a6 = grad(perm[ab + 0], x - 0, y - 1, z - 0);&lt;br /&gt;      float a7 = grad(perm[ba + 0], x - 1, y - 0, z - 0);&lt;br /&gt;      float a8 = grad(perm[aa + 0], x - 0, y - 0, z - 0);&lt;br /&gt;&lt;br /&gt;      float a2_1 = lerp(u, a2, a1);&lt;br /&gt;      float a4_3 = lerp(u, a4, a3);&lt;br /&gt;      float a6_5 = lerp(u, a6, a5);&lt;br /&gt;      float a8_7 = lerp(u, a8, a7);&lt;br /&gt;      float a8_5 = lerp(v, a8_7, a6_5);&lt;br /&gt;      float a4_1 = lerp(v, a4_3, a2_1);&lt;br /&gt;      float a8_1 = lerp(w, a8_5, a4_1);&lt;br /&gt;&lt;br /&gt;      return a8_1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   //&lt;br /&gt;&lt;br /&gt;   private final float noise(float x, float y, float z, int octave)&lt;br /&gt;   {&lt;br /&gt;      float p = pow[octave];&lt;br /&gt;      return this.noise(x * p + this.xo, y * p + this.yo, z * p + this.zo) / p;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float floor(float v)&lt;br /&gt;   {&lt;br /&gt;      return (int) v;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float fade(float t)&lt;br /&gt;   {&lt;br /&gt;      return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float lerp(float t, float a, float b)&lt;br /&gt;   {&lt;br /&gt;      return a + t * (b - a);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float grad(int hash, float x, float y, float z)&lt;br /&gt;   {&lt;br /&gt;      int h = hash &amp; 15;&lt;br /&gt;      float u = (h &lt; 8) ? x : y;&lt;br /&gt;      float v = (h &lt; 4) ? y : ((h == 12 || h == 14) ? x : z);&lt;br /&gt;      return ((h &amp; 1) == 0 ? u : -u) + ((h &amp; 2) == 0 ? v : -v);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float[] pow  = new float[32];&lt;br /&gt;&lt;br /&gt;   private static final int[]   perm = new int[512];&lt;br /&gt;&lt;br /&gt;   static&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; pow.length; i++)&lt;br /&gt;      {&lt;br /&gt;         pow[i] = (float) Math.pow(2, i);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      int[] permutation = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,&lt;br /&gt;         14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };&lt;br /&gt;&lt;br /&gt;      if (permutation.length != 256)&lt;br /&gt;         throw new IllegalStateException();&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; 256; i++)&lt;br /&gt;         perm[256 + i] = perm[i] = permutation[i];&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-7737203822053940791?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/7737203822053940791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/perlinnoise.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7737203822053940791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/7737203822053940791'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/perlinnoise.html' title='PerlinNoise :: smooth/turbulent'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-2631615657219434222</id><published>2009-08-24T23:24:00.004+02:00</published><updated>2010-04-10T21:27:23.109+02:00</updated><title type='text'>Bag :: fast insert, fast remove</title><content type='html'>This Bag is an unordered list. Putting an element will append it to the backing array. Taking an element will move the last element in the array to the index of the element to be taken, nulling the last index. You get the elements by their index. There's not much too it.&lt;br /&gt;&lt;br /&gt;The primary focus is on performance of inserting and removing from &lt;i&gt;small&lt;/i&gt; collections.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;import java.util.Arrays;&lt;br /&gt;import java.util.NoSuchElementException;&lt;br /&gt;&lt;br /&gt;public class &lt;span style="color:yellow"&gt;Bag&lt;/span&gt;&lt;T&gt;&lt;br /&gt;{&lt;br /&gt;   private T[] data;&lt;br /&gt;   private int size;&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;Bag&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      this(4);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public &lt;span style="color:yellow"&gt;Bag&lt;/span&gt;(int space)&lt;br /&gt;   {&lt;br /&gt;      this.data = (T[]) new Object[space];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;put&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      if (this.size == this.data.length)&lt;br /&gt;      {&lt;br /&gt;         this.data = Arrays.copyOf(this.data, Math.max((int) (this.size * 1.75f), 8));&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      this.data[size++] = t;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;putAll&lt;/span&gt;(Bag&lt;T&gt; bag)&lt;br /&gt;   {&lt;br /&gt;      if (bag.size == 0)&lt;br /&gt;         return;&lt;br /&gt;&lt;br /&gt;      int reqSize = this.size + bag.size;&lt;br /&gt;      if (this.data.length &lt; reqSize)&lt;br /&gt;      {&lt;br /&gt;         // calculate new length&lt;br /&gt;         int makeSize = this.data.length;&lt;br /&gt;         while (makeSize &lt; reqSize)&lt;br /&gt;            makeSize = Math.max((int) (makeSize * 1.75f), 8);&lt;br /&gt;&lt;br /&gt;         // create array, copy elements&lt;br /&gt;         this.data = Arrays.copyOf(this.data, makeSize);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // copy 'remote' elements to own array&lt;br /&gt;      System.arraycopy(bag.data, 0, this.data, this.size, bag.size);&lt;br /&gt;      this.size += bag.size;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public T &lt;span style="color:yellow"&gt;get&lt;/span&gt;(int i)&lt;br /&gt;   {&lt;br /&gt;      if (i &gt;= size)&lt;br /&gt;         throw new ArrayIndexOutOfBoundsException();&lt;br /&gt;      return data[i];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public T &lt;span style="color:yellow"&gt;take&lt;/span&gt;(int i)&lt;br /&gt;   {&lt;br /&gt;      if (i &gt;= size)&lt;br /&gt;         throw new ArrayIndexOutOfBoundsException();&lt;br /&gt;&lt;br /&gt;      T took = data[i];&lt;br /&gt;      data[i] = data[--size];&lt;br /&gt;      data[size] = null;&lt;br /&gt;      return took;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public T &lt;span style="color:yellow"&gt;take&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      int i = this.indexOf(t);&lt;br /&gt;      if (i == -1)&lt;br /&gt;         throw new NoSuchElementException();&lt;br /&gt;      return this.take(i);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;fillArray&lt;/span&gt;(T[] holder)&lt;br /&gt;   {&lt;br /&gt;      if (holder == null || holder.length &lt; this.size)&lt;br /&gt;         throw new IllegalStateException();&lt;br /&gt;      System.arraycopy(this.data, 0, holder, 0, size);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public boolean &lt;span style="color:yellow"&gt;contains&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      return this.indexOf(t) != -1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;indexOf&lt;/span&gt;(T t)&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; size; i++)&lt;br /&gt;         if (data[i] == t)&lt;br /&gt;            return i;&lt;br /&gt;      return -1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;shrink&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      if (this.data.length &gt; 8)&lt;br /&gt;      {&lt;br /&gt;         int factor = 4;&lt;br /&gt;&lt;br /&gt;         if (this.size &lt; this.data.length / factor)&lt;br /&gt;         {&lt;br /&gt;            int newSize = Math.max(4, this.size);&lt;br /&gt;            T[] newData = (T[]) new Object[newSize];&lt;br /&gt;            System.arraycopy(this.data, 0, newData, 0, this.size);&lt;br /&gt;            this.data = newData;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void &lt;span style="color:yellow"&gt;clear&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; size; i++)&lt;br /&gt;         data[i] = null;&lt;br /&gt;      this.size = 0;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;capacity&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return this.data.length;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int &lt;span style="color:yellow"&gt;size&lt;/span&gt;()&lt;br /&gt;   {&lt;br /&gt;      return size;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-2631615657219434222?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/2631615657219434222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/bag-unordered-list-fast-remove.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2631615657219434222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/2631615657219434222'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/bag-unordered-list-fast-remove.html' title='Bag :: fast insert, fast remove'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-5825147309653944118</id><published>2009-08-24T23:09:00.006+02:00</published><updated>2010-02-05T20:10:48.638+01:00</updated><title type='text'>FastMath :: atan2 lookup</title><content type='html'>Math.atan2() is very convenient, yet very slow. A lookup table will be roughly 8x faster. You lose accuracy, but heck, that's obvious.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;&lt;br /&gt;   public static final float &lt;span style='color:yellow'&gt;atan2Deg&lt;/span&gt;(float y, float x)&lt;br /&gt;   {&lt;br /&gt;      return FastMath.atan2(y, x) * DEG;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style='color:yellow'&gt;atan2DegStrict&lt;/span&gt;(float y, float x)&lt;br /&gt;   {&lt;br /&gt;      return (float) Math.atan2(y, x) * DEG;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style='color:yellow'&gt;atan2&lt;/span&gt;(float y, float x)&lt;br /&gt;   {&lt;br /&gt;      float add, mul;&lt;br /&gt;&lt;br /&gt;      if (x &lt; 0.0f)&lt;br /&gt;      {&lt;br /&gt;         if (y &lt; 0.0f)&lt;br /&gt;         {&lt;br /&gt;            x = -x;&lt;br /&gt;            y = -y;&lt;br /&gt;&lt;br /&gt;            mul = 1.0f;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            x = -x;&lt;br /&gt;            mul = -1.0f;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         add = -3.141592653f;&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         if (y &lt; 0.0f)&lt;br /&gt;         {&lt;br /&gt;            y = -y;&lt;br /&gt;            mul = -1.0f;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            mul = 1.0f;&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         add = 0.0f;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float invDiv = ATAN2_DIM_MINUS_1 / ((x &lt; y) ? y : x);&lt;br /&gt;&lt;br /&gt;      int xi = (int) (x * invDiv);&lt;br /&gt;      int yi = (int) (y * invDiv);&lt;br /&gt;&lt;br /&gt;      return (atan2[yi * ATAN2_DIM + xi] + add) * mul;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;private static final int     ATAN2_BITS        = 7;&lt;br /&gt;&lt;br /&gt;   private static final int     ATAN2_BITS2       = ATAN2_BITS &lt;&lt; 1;&lt;br /&gt;   private static final int     ATAN2_MASK        = ~(-1 &lt;&lt; ATAN2_BITS2);&lt;br /&gt;   private static final int     ATAN2_COUNT       = ATAN2_MASK + 1;&lt;br /&gt;   private static final int     ATAN2_DIM         = (int) Math.sqrt(ATAN2_COUNT);&lt;br /&gt;&lt;br /&gt;   private static final float   ATAN2_DIM_MINUS_1 = (ATAN2_DIM - 1);&lt;br /&gt;&lt;br /&gt;   private static final float[] atan2             = new float[ATAN2_COUNT];&lt;br /&gt;&lt;br /&gt;   static&lt;br /&gt;   {&lt;br /&gt;      for (int i = 0; i &lt; ATAN2_DIM; i++)&lt;br /&gt;      {&lt;br /&gt;         for (int j = 0; j &lt; ATAN2_DIM; j++)&lt;br /&gt;         {&lt;br /&gt;            float x0 = (float) i / ATAN2_DIM;&lt;br /&gt;            float y0 = (float) j / ATAN2_DIM;&lt;br /&gt;&lt;br /&gt;            atan2[j * ATAN2_DIM + i] = (float) Math.atan2(y0, x0);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;And some test code:&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;int dim = 633 * 2; // random number times 2&lt;br /&gt;&lt;br /&gt;      float maxDiff = 0.0f;&lt;br /&gt;      float sumDiff = 0.0f;&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; dim * dim; i++)&lt;br /&gt;      {&lt;br /&gt;         float x = (float) ((i % dim) - (dim / 2)) / (dim / 2);&lt;br /&gt;         float y = (float) ((i / dim) - (dim / 2)) / (dim / 2);&lt;br /&gt;         float slow = (float) Math.atan2(y, x);&lt;br /&gt;         float fast = FastMath.atan2(y, x);&lt;br /&gt;         float diff = Math.abs(slow - fast);&lt;br /&gt;         if (diff &gt; maxDiff)&lt;br /&gt;            maxDiff = diff;&lt;br /&gt;         sumDiff += diff;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      float avgDiff = sumDiff / (dim * dim);&lt;br /&gt;&lt;br /&gt;      System.out.println("maxDiff=" + maxDiff); // 0.007858515&lt;br /&gt;      System.out.println("avgDiff=" + avgDiff); // 0.002910751&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-5825147309653944118?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/5825147309653944118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/fastmath-atan2-lookup-table.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5825147309653944118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/5825147309653944118'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/fastmath-atan2-lookup-table.html' title='FastMath :: atan2 lookup'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1249179008376089851.post-3941007513250370182</id><published>2009-08-24T23:06:00.003+02:00</published><updated>2009-08-25T03:06:28.149+02:00</updated><title type='text'>FastMath :: sin/cos lookup</title><content type='html'>Math.sin() is slow. Using a lookup table for sin/cos is roughly 50x faster. The loss of accuracy is minimal, maximum error is roughly 0,001. You can probably get away with it.&lt;br /&gt;&lt;br /&gt;&lt;div class="code" onClick="this.style.height='auto';"&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static final float &lt;span style="color:yellow"&gt;sin&lt;/span&gt;(float rad)&lt;br /&gt;   {&lt;br /&gt;      return sin[(int) (rad * radToIndex) &amp; SIN_MASK];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style="color:yellow"&gt;cos&lt;/span&gt;(float rad)&lt;br /&gt;   {&lt;br /&gt;      return cos[(int) (rad * radToIndex) &amp; SIN_MASK];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style="color:yellow"&gt;sinDeg&lt;/span&gt;(float deg)&lt;br /&gt;   {&lt;br /&gt;      return sin[(int) (deg * degToIndex) &amp; SIN_MASK];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static final float &lt;span style="color:yellow"&gt;cosDeg&lt;/span&gt;(float deg)&lt;br /&gt;   {&lt;br /&gt;      return cos[(int) (deg * degToIndex) &amp; SIN_MASK];&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final float   RAD,DEG;&lt;br /&gt;   private static final int     SIN_BITS,SIN_MASK,SIN_COUNT;&lt;br /&gt;   private static final float   radFull,radToIndex;&lt;br /&gt;   private static final float   degFull,degToIndex;&lt;br /&gt;   private static final float[] sin, cos;&lt;br /&gt;&lt;br /&gt;   static&lt;br /&gt;   {&lt;br /&gt;      RAD = (float) Math.PI / 180.0f;&lt;br /&gt;      DEG = 180.0f / (float) Math.PI;&lt;br /&gt;&lt;br /&gt;      SIN_BITS  = 12;&lt;br /&gt;      SIN_MASK  = ~(-1 &lt;&lt; SIN_BITS);&lt;br /&gt;      SIN_COUNT = SIN_MASK + 1;&lt;br /&gt;&lt;br /&gt;      radFull    = (float) (Math.PI * 2.0);&lt;br /&gt;      degFull    = (float) (360.0);&lt;br /&gt;      radToIndex = SIN_COUNT / radFull;&lt;br /&gt;      degToIndex = SIN_COUNT / degFull;&lt;br /&gt;&lt;br /&gt;      sin = new float[SIN_COUNT];&lt;br /&gt;      cos = new float[SIN_COUNT];&lt;br /&gt;&lt;br /&gt;      for (int i = 0; i &lt; SIN_COUNT; i++)&lt;br /&gt;      {&lt;br /&gt;         sin[i] = (float) Math.sin((i + 0.5f) / SIN_COUNT * radFull);&lt;br /&gt;         cos[i] = (float) Math.cos((i + 0.5f) / SIN_COUNT * radFull);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1249179008376089851-3941007513250370182?l=riven8192.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://riven8192.blogspot.com/feeds/3941007513250370182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://riven8192.blogspot.com/2009/08/fastmath-sincos-lookup-tables.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3941007513250370182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1249179008376089851/posts/default/3941007513250370182'/><link rel='alternate' type='text/html' href='http://riven8192.blogspot.com/2009/08/fastmath-sincos-lookup-tables.html' title='FastMath :: sin/cos lookup'/><author><name>Riven</name><uri>http://www.blogger.com/profile/12170038557837985530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_6XowJZtOqJg/SpMV21N_SwI/AAAAAAAAAAM/3EyJUoNebKk/s1600-R/logo4.png'/></author><thr:total>0</thr:total></entry></feed>
