OSDN Git Service

[added] Angle backend. Experimental. Texture loading needs to be fixed, expects RGBA...
authorbadlogicgames <badlogicgames@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Mon, 13 Dec 2010 16:38:02 +0000 (16:38 +0000)
committerbadlogicgames <badlogicgames@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Mon, 13 Dec 2010 16:38:02 +0000 (16:38 +0000)
16 files changed:
backends/gdx-backends-angle/.classpath [new file with mode: 0644]
backends/gdx-backends-angle/.project [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleApplication.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudio.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioDevice.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioRecorder.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFileHandle.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFiles.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGLES0.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGraphics.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleInput.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleMusic.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AnglePixmap.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleSound.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleTexture.java [new file with mode: 0644]
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/PNGDecoder.java [new file with mode: 0644]

diff --git a/backends/gdx-backends-angle/.classpath b/backends/gdx-backends-angle/.classpath
new file mode 100644 (file)
index 0000000..189a657
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry combineaccessrules="false" kind="src" path="/dependencies"/>\r
+       <classpathentry combineaccessrules="false" exported="true" kind="src" path="/gdx"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/angle.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/javazoom-spi.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/jl1.0.1.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/jorbis.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/tritonus-utils.jar"/>\r
+       <classpathentry exported="true" kind="lib" path="/dependencies/gdx-natives.jar"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/backends/gdx-backends-angle/.project b/backends/gdx-backends-angle/.project
new file mode 100644 (file)
index 0000000..b89e958
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>gdx-backend-angle</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleApplication.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleApplication.java
new file mode 100644 (file)
index 0000000..ddb2be6
--- /dev/null
@@ -0,0 +1,144 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import com.badlogic.anglejni.ESLoop;\r
+import com.badlogic.anglejni.ESUtil;\r
+import com.badlogic.gdx.Application;\r
+import com.badlogic.gdx.ApplicationListener;\r
+import com.badlogic.gdx.Audio;\r
+import com.badlogic.gdx.Files;\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.Graphics;\r
+import com.badlogic.gdx.Input;\r
+import com.badlogic.gdx.Version;\r
+\r
+public class AngleApplication implements Application, ESLoop {\r
+       AngleGraphics graphics;\r
+       AngleAudio audio;\r
+       AngleInput input;\r
+       AngleFiles files;\r
+       ESUtil utils;\r
+       ApplicationListener listener;\r
+       boolean created = false;\r
+       \r
+       public AngleApplication(final ApplicationListener listener,final String title,final int width,final int height,final boolean fullscreen) {\r
+               new Thread(new Runnable() {\r
+                       public void run() {                                             \r
+                               Version.loadLibrary();\r
+                               \r
+                               AngleApplication.this.listener = listener;\r
+                               utils = new ESUtil(title, width, height, ESUtil.ES_WINDOW_DEPTH | (fullscreen?ESUtil.ES_WINDOW_FULLSCREEN:0));\r
+                               graphics = new AngleGraphics(width, height);\r
+                               audio = new AngleAudio();\r
+                               input = new AngleInput();\r
+                               files = new AngleFiles();\r
+                               \r
+                               Gdx.app = AngleApplication.this;\r
+                               Gdx.graphics = graphics;\r
+                               Gdx.audio = audio;\r
+                               Gdx.input = input;\r
+                               Gdx.files = files;\r
+                               Gdx.gl = graphics.getGL20();\r
+                               Gdx.gl20 = graphics.getGL20();          \r
+                               utils.run(AngleApplication.this);\r
+                       }\r
+               }).run();\r
+       }\r
+       \r
+       @Override\r
+       public Graphics getGraphics() {\r
+               return graphics;\r
+       }\r
+\r
+       @Override\r
+       public Audio getAudio() {\r
+               return audio;\r
+       }\r
+\r
+       @Override\r
+       public Input getInput() {\r
+               return input;\r
+       }\r
+\r
+       @Override\r
+       public Files getFiles() {\r
+               return files;\r
+       }\r
+\r
+       @Override\r
+       public void log(String tag, String message) {\r
+               System.out.println(tag + ": " + message);               \r
+       }\r
+\r
+       @Override\r
+       public ApplicationType getType() {\r
+               return ApplicationType.Desktop;\r
+       }\r
+\r
+       @Override\r
+       public int getVersion() {\r
+               return 0;\r
+       }\r
+\r
+       @Override\r
+       public long getJavaHeap() {\r
+               return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();\r
+       }\r
+\r
+       @Override\r
+       public long getNativeHeap() {\r
+               return getJavaHeap();\r
+       }\r
+\r
+\r
+       @Override\r
+       public void onKey(int action, int key, int keyCode) {\r
+               input.registerKeyEvent(action, key, keyCode);\r
+       }\r
+\r
+\r
+       @Override\r
+       public void onMouse(int action, int x, int y, int button) {\r
+               if(action != ES_MOUSE_WHEEL)\r
+                       input.registerMouseEvent(action, x, y, button);\r
+       }\r
+\r
+\r
+       @Override\r
+       public void quit() {\r
+               listener.pause();\r
+               listener.dispose();\r
+       }\r
+\r
+\r
+       @Override\r
+       public void render() {\r
+               if(!created) {\r
+                       listener.create();\r
+                       listener.resume();\r
+                       created = true;\r
+               }\r
+               input.processEvents();\r
+               listener.render();                      \r
+       }\r
+\r
+\r
+       @Override\r
+       public void resize(int width, int height) {\r
+               graphics.width = width;\r
+               graphics.height = height;\r
+               if(!created)\r
+                       listener.resize(width, height);\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudio.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudio.java
new file mode 100644 (file)
index 0000000..b01f0c2
--- /dev/null
@@ -0,0 +1,207 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import javax.sound.sampled.AudioFormat;\r
+import javax.sound.sampled.AudioSystem;\r
+import javax.sound.sampled.SourceDataLine;\r
+\r
+import com.badlogic.gdx.Audio;\r
+import com.badlogic.gdx.audio.AudioDevice;\r
+import com.badlogic.gdx.audio.AudioRecorder;\r
+import com.badlogic.gdx.audio.Music;\r
+import com.badlogic.gdx.audio.Sound;\r
+import com.badlogic.gdx.files.FileHandle;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/**\r
+ * An implementation of the {@link Audio} interface for the desktop.\r
+ * \r
+ * @author mzechner\r
+ * \r
+ */\r
+final class AngleAudio implements Audio, Runnable {\r
+       /** the audio line for sound effects **/\r
+       private SourceDataLine line;\r
+\r
+       /** The current buffers to play **/\r
+       private final List<AngleSoundBuffer> buffers = new ArrayList<AngleSoundBuffer>();\r
+\r
+       /** The sound effects thread **/\r
+       private Thread thread;\r
+       \r
+       private volatile boolean run = false;\r
+\r
+       /**\r
+        * Helper class for playing back sound effects concurrently.\r
+        * \r
+        * @author mzechner\r
+        * \r
+        */\r
+       class AngleSoundBuffer {\r
+               private final float[] samples;\r
+               private final AudioFormat format;\r
+               private final float volume;\r
+               private int writtenSamples = 0;\r
+\r
+               public AngleSoundBuffer (AngleSound sound, float volume) throws Exception {\r
+                       samples = sound.getAudioData();\r
+                       format = sound.getAudioFormat();\r
+                       this.volume = volume;\r
+               }\r
+\r
+               /**\r
+                * Writes the next numFrames frames to the line for playback\r
+                * @return whether playback is done or not.\r
+                */\r
+               public boolean writeSamples (int numSamples, float[] buffer) {\r
+                       if (format.getChannels() == 1) {\r
+                               int remainingSamples = Math.min(samples.length, writtenSamples + numSamples / 2);\r
+                               for (int i = writtenSamples, j = 0; i < remainingSamples; i++, j += 2) {\r
+                                       buffer[j] += samples[i] * volume;\r
+                                       buffer[j + 1] += samples[i] * volume;\r
+                                       writtenSamples++;\r
+                               }\r
+                       } else {\r
+                               int remainingSamples = Math.min(samples.length, writtenSamples + numSamples);\r
+                               for (int i = writtenSamples, j = 0; i < remainingSamples; i += 2, j += 2) {\r
+                                       buffer[j] += samples[i] * volume;\r
+                                       buffer[j + 1] += samples[i + 1] * volume;\r
+                                       writtenSamples += 2;\r
+                               }\r
+                       }\r
+\r
+                       if (writtenSamples >= samples.length)\r
+                               return false;\r
+                       else\r
+                               return true;\r
+               }\r
+       }\r
+\r
+       AngleAudio () {\r
+               try {\r
+                       AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false);\r
+                       line = AudioSystem.getSourceDataLine(format);\r
+                       line.open(format, 4410);\r
+                       line.start();\r
+                       thread = new Thread(this, "LWJGL Audio");\r
+                       thread.setDaemon(true);\r
+                       thread.start();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+       public AudioDevice newAudioDevice (boolean isMono) {\r
+               return new AngleAudioDevice(isMono);\r
+       }\r
+\r
+       public Music newMusic (FileHandle file) {\r
+               try {\r
+                       AngleMusic music = new AngleMusic(((AngleFileHandle)file));\r
+                       return music;\r
+               } catch (Throwable e) {\r
+                       throw new GdxRuntimeException("Couldn't create Music instance from file '" + file + "'", e);\r
+               }\r
+       }\r
+\r
+       public Sound newSound (FileHandle file) {\r
+               try {\r
+                       AngleSound sound = new AngleSound(this, ((AngleFileHandle)file));\r
+                       return sound;\r
+               } catch (Exception e) {\r
+                       throw new GdxRuntimeException("Couldn't create Sound instance from file '" + file + "'", e);\r
+               }\r
+       }\r
+\r
+       protected void enqueueSound (AngleSound sound, float volume) {\r
+               try {\r
+                       synchronized (this) {\r
+                               buffers.add(new AngleSoundBuffer(sound, volume));\r
+                       }\r
+               } catch (Exception ex) {\r
+                       ex.printStackTrace();\r
+               }\r
+       }\r
+\r
+       public void run () {\r
+\r
+               int NUM_SAMPLES = 44100 * 2;\r
+               float[] buffer = new float[NUM_SAMPLES];\r
+               byte[] bytes = new byte[2 * NUM_SAMPLES];\r
+\r
+               run = true;\r
+               \r
+               while (run) {\r
+                       int samplesToWrite = line.available() / 2;\r
+\r
+                       if (samplesToWrite > 0) {\r
+                               fillBuffer(buffer, bytes, samplesToWrite);\r
+                               int writtenBytes = line.write(bytes, 0, samplesToWrite * 2);\r
+                               while (writtenBytes != samplesToWrite * 2)\r
+                                       writtenBytes += line.write(bytes, writtenBytes, samplesToWrite - writtenBytes);\r
+                       }\r
+\r
+                       try {\r
+                               Thread.sleep(5);\r
+                       } catch (InterruptedException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void fillBuffer (float[] buffer, byte[] bytes, int samplesToWrite) {\r
+               for (int i = 0; i < buffer.length; i++)\r
+                       buffer[i] = 0.0f;\r
+               for (int i = 0; i < bytes.length; i++)\r
+                       bytes[i] = 0;\r
+\r
+               int numBuffers = buffers.size();\r
+               synchronized (this) {\r
+                       Iterator<AngleSoundBuffer> bufferIter = buffers.iterator();\r
+                       while (bufferIter.hasNext()) {\r
+                               AngleSoundBuffer soundBuffer = bufferIter.next();\r
+                               if (!soundBuffer.writeSamples(samplesToWrite, buffer)) bufferIter.remove();\r
+                       }\r
+               }\r
+               if (numBuffers > 0) {\r
+                       for (int i = 0, j = 0; i < samplesToWrite; i++, j += 2) {\r
+                               float fValue = buffer[i];\r
+                               if (fValue > 1) fValue = 1;\r
+                               if (fValue < -1) fValue = -1;\r
+                               short value = (short)(fValue * Short.MAX_VALUE);\r
+                               bytes[j] = (byte)(value | 0xff);\r
+                               bytes[j + 1] = (byte)(value >> 8);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public AudioRecorder newAudioRecoder (int samplingRate, boolean isMono) {\r
+               return new AngleAudioRecorder(samplingRate, isMono);\r
+       }\r
+       \r
+       void dispose ( ) {\r
+               run = false;\r
+               try {\r
+                       if(thread != null)\r
+                               thread.join();\r
+                       if(line != null)\r
+                               line.close();\r
+               } catch (InterruptedException e) {\r
+               }\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioDevice.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioDevice.java
new file mode 100644 (file)
index 0000000..d2fa549
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import javax.sound.sampled.AudioFormat;\r
+import javax.sound.sampled.AudioSystem;\r
+import javax.sound.sampled.SourceDataLine;\r
+\r
+import com.badlogic.gdx.audio.AudioDevice;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/**\r
+ * Implementation of the {@link AudioDevice} interface for the desktop using Java Sound.\r
+ * \r
+ * @author mzechner\r
+ * \r
+ */\r
+final class AngleAudioDevice implements AudioDevice {\r
+       /** the audio line **/\r
+       private SourceDataLine line;\r
+\r
+       /** whether this device is mono **/\r
+       private final boolean isMono;\r
+\r
+       /** byte buffer **/\r
+       private byte[] bytes = new byte[44100 * 2 * 2];\r
+\r
+       public AngleAudioDevice (boolean isMono) {\r
+               this.isMono = isMono;\r
+\r
+               try {\r
+                       AudioFormat format = new AudioFormat(44100.0f, 16, isMono ? 1 : 2, true, false);\r
+                       line = AudioSystem.getSourceDataLine(format);\r
+                       line.open(format, 4410 * 2);\r
+                       line.start();\r
+               } catch (Exception e) {\r
+                       throw new GdxRuntimeException("Couldn't createa AudioDevice", e);\r
+               }\r
+       }\r
+\r
+       public void dispose () {\r
+               line.drain();\r
+               line.close();\r
+       }\r
+\r
+       public boolean isMono () {\r
+               return isMono;\r
+       }\r
+\r
+       public void writeSamples (short[] samples, int offset, int numSamples) {\r
+               if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2];\r
+\r
+               for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) {\r
+                       short value = samples[i];\r
+                       bytes[j + 1] = (byte)(value & 0xff);\r
+                       bytes[j] = (byte)(value >> 8);\r
+               }\r
+\r
+               int writtenBytes = line.write(bytes, 0, numSamples * 2);\r
+               while (writtenBytes != numSamples * 2)\r
+                       writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes);\r
+       }\r
+\r
+       public void writeSamples (float[] samples, int offset, int numSamples) {\r
+               if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2];\r
+\r
+               for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) {\r
+                       float fValue = samples[i];\r
+                       if (fValue > 1) fValue = 1;\r
+                       if (fValue < -1) fValue = -1;\r
+                       short value = (short)(fValue * Short.MAX_VALUE);\r
+                       bytes[j] = (byte)(value | 0xff);\r
+                       bytes[j + 1] = (byte)(value >> 8);\r
+               }\r
+\r
+               int writtenBytes = line.write(bytes, 0, numSamples * 2);\r
+               while (writtenBytes != numSamples * 2)\r
+                       writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes);\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioRecorder.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleAudioRecorder.java
new file mode 100644 (file)
index 0000000..c271647
--- /dev/null
@@ -0,0 +1,66 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import javax.sound.sampled.AudioFormat;\r
+import javax.sound.sampled.AudioFormat.Encoding;\r
+import javax.sound.sampled.AudioSystem;\r
+import javax.sound.sampled.TargetDataLine;\r
+\r
+import com.badlogic.gdx.audio.AudioRecorder;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/**\r
+ * {@link AudioRecorder} implementation for the desktop using the java sound API.\r
+ * \r
+ * @author badlogicgames@gmail.com\r
+ * \r
+ */\r
+final class AngleAudioRecorder implements AudioRecorder {\r
+       /** the line we read the audio from **/\r
+       private TargetDataLine line;\r
+\r
+       /** the buffer to temporarily store the samples **/\r
+       private byte[] buffer = new byte[1024 * 4];\r
+\r
+       public AngleAudioRecorder (int samplingRate, boolean isMono) {\r
+               try {\r
+                       AudioFormat format = new AudioFormat(Encoding.PCM_SIGNED, samplingRate, 16, isMono ? 1 : 2, isMono ? 2 : 4,\r
+                               samplingRate, false);\r
+                       line = AudioSystem.getTargetDataLine(format);\r
+                       line.open(format, buffer.length);\r
+                       line.start();\r
+               } catch (Exception ex) {\r
+                       throw new GdxRuntimeException("Couldn't create AudioRecorder", ex);\r
+               }\r
+       }\r
+\r
+       public void read (short[] samples, int offset, int numSamples) {\r
+               if (buffer.length < numSamples * 2) buffer = new byte[numSamples * 2];\r
+\r
+               int toRead = numSamples * 2;\r
+               int read = 0;\r
+\r
+               while (read != toRead)\r
+                       read += line.read(buffer, read, toRead - read);\r
+\r
+               for (int i = 0, j = 0; i < numSamples * 2; i += 2, j++) {\r
+                       samples[offset + j] = (short)((buffer[i] << 8) | (buffer[i + 1] & 0xff));\r
+               }\r
+       }\r
+\r
+       public void dispose () {\r
+               line.close();\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFileHandle.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFileHandle.java
new file mode 100644 (file)
index 0000000..50be368
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.io.File;\r
+\r
+import com.badlogic.gdx.Files.FileType;\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.files.FileHandle;\r
+\r
+/**\r
+ * @author mzechner\r
+ * @author Nathan Sweet <misc@n4te.com>\r
+ */\r
+final class AngleFileHandle extends FileHandle {\r
+       AngleFileHandle (String fileName, FileType type) {\r
+               super(fileName, type);\r
+       }\r
+\r
+       AngleFileHandle (File file, FileType type) {\r
+               super(file, type);\r
+       }\r
+\r
+       public FileHandle child (String name) {\r
+               return new AngleFileHandle(new File(file, name), type);\r
+       }\r
+\r
+       public FileHandle parent () {\r
+               File parent = file.getParentFile();\r
+               if (parent == null) {\r
+                       switch (type) {\r
+                       case Classpath:\r
+                       case Absolute:\r
+                               parent = new File("/");\r
+                               break;\r
+                       case Internal:\r
+                               parent = new File("");\r
+                               break;\r
+                       case External:\r
+                               parent = new File(Gdx.files.getExternalStoragePath());\r
+                               break;\r
+                       }\r
+               }\r
+               return new AngleFileHandle(parent, type);\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFiles.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleFiles.java
new file mode 100644 (file)
index 0000000..0567a77
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import com.badlogic.gdx.Files;\r
+import com.badlogic.gdx.files.FileHandle;\r
+\r
+public class AngleFiles implements Files {\r
+       private final String externalPath = System.getProperty("user.home") + "/";\r
+\r
+       @Override public FileHandle getFileHandle (String fileName, FileType type) {\r
+               return new AngleFileHandle(fileName, type);\r
+       }\r
+\r
+       @Override public FileHandle classpath (String path) {\r
+               return new AngleFileHandle(path, FileType.Classpath);\r
+       }\r
+\r
+       @Override public FileHandle internal (String path) {\r
+               return new AngleFileHandle(path, FileType.Internal);\r
+       }\r
+\r
+       @Override public FileHandle external (String path) {\r
+               return new AngleFileHandle(path, FileType.External);\r
+       }\r
+\r
+       @Override public FileHandle absolute (String path) {\r
+               return new AngleFileHandle(path, FileType.Absolute);\r
+       }\r
+\r
+       @Override public String getExternalStoragePath () {\r
+               return externalPath;\r
+       }\r
+\r
+       @Override public boolean isExternalStorageAvailable () {\r
+               return true;\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGLES0.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGLES0.java
new file mode 100644 (file)
index 0000000..e916adc
--- /dev/null
@@ -0,0 +1,317 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.nio.Buffer;\r
+import java.nio.FloatBuffer;\r
+import java.nio.IntBuffer;\r
+\r
+import com.badlogic.gdx.graphics.GL20;\r
+\r
+public class AngleGLES0 implements GL20\r
+{\r
+       static\r
+       {                               \r
+               init( );\r
+       }       \r
+       \r
+       private static native void init( );     \r
+       \r
+       public native void glActiveTexture ( int texture );\r
+\r
+       public native void glAttachShader ( int program, int shader );\r
+\r
+       public native void glBindAttribLocation ( int program, int index, String name );\r
+\r
+       public native void glBindBuffer ( int target, int buffer );\r
+\r
+       public native void glBindFramebuffer ( int target, int framebuffer );\r
+\r
+       public native void glBindRenderbuffer ( int target, int renderbuffer );\r
+\r
+       public native void glBindTexture ( int target, int texture );\r
+\r
+       public native void glBlendColor ( float red, float green, float blue, float alpha );\r
+\r
+       public native void glBlendEquation (  int mode  );\r
+\r
+       public native void glBlendEquationSeparate ( int modeRGB, int modeAlpha );\r
+\r
+       public native void glBlendFunc ( int sfactor, int dfactor );\r
+\r
+       public native void glBlendFuncSeparate ( int srcRGB, int dstRGB, int srcAlpha, int dstAlpha );\r
+\r
+       public native void glBufferData ( int target, int size, Buffer data, int usage );\r
+\r
+       public native void glBufferSubData ( int target, int offset, int size, Buffer data );\r
+\r
+       public native int glCheckFramebufferStatus ( int target );\r
+\r
+       public native void glClear ( int mask );\r
+\r
+       public native void glClearColor ( float red, float green, float blue, float alpha );\r
+\r
+       public native void glClearDepthf ( float depth );\r
+\r
+       public native void glClearStencil ( int s );\r
+\r
+       public native void glColorMask ( boolean red, boolean green, boolean blue, boolean alpha );\r
+\r
+       public native void glCompileShader ( int shader );\r
+\r
+       public native void glCompressedTexImage2D ( int target, int level, int internalformat, int width, int height, int border, int imageSize, Buffer data );\r
+\r
+       public native void glCompressedTexSubImage2D ( int target, int level, int xoffset, int yoffset, int width, int height, int format, int imageSize, Buffer data );\r
+\r
+       public native void glCopyTexImage2D ( int target, int level, int internalformat, int x, int y, int width, int height, int border );\r
+\r
+       public native void glCopyTexSubImage2D ( int target, int level, int xoffset, int yoffset, int x, int y, int width, int height );\r
+\r
+       public native int glCreateProgram (  );\r
+\r
+       public native int glCreateShader ( int type );\r
+\r
+       public native void glCullFace ( int mode );\r
+\r
+       public native void glDeleteBuffers ( int n, IntBuffer buffers );\r
+\r
+       public native void glDeleteFramebuffers ( int n, IntBuffer framebuffers );\r
+\r
+       public native void glDeleteProgram ( int program );\r
+\r
+       public native void glDeleteRenderbuffers ( int n, IntBuffer renderbuffers );\r
+\r
+       public native void glDeleteShader ( int shader );\r
+\r
+       public native void glDeleteTextures ( int n, IntBuffer textures );\r
+\r
+       public native void glDepthFunc ( int func );\r
+\r
+       public native void glDepthMask ( boolean flag );\r
+\r
+       public native void glDepthRangef ( float zNear, float zFar );\r
+\r
+       public native void glDetachShader ( int program, int shader );\r
+\r
+       public native void glDisable ( int cap );\r
+\r
+       public native void glDisableVertexAttribArray ( int index );\r
+\r
+       public native void glDrawArrays ( int mode, int first, int count );\r
+\r
+       public native void glDrawElements ( int mode, int count, int type, Buffer indices );\r
+       \r
+       public native void glDrawElements ( int mode, int count, int type, int indices );\r
+\r
+       public native void glEnable ( int cap );\r
+\r
+       public native void glEnableVertexAttribArray ( int index );\r
+\r
+       public native void glFinish (  );\r
+\r
+       public native void glFlush (  );\r
+\r
+       public native void glFramebufferRenderbuffer ( int target, int attachment, int renderbuffertarget, int renderbuffer );\r
+\r
+       public native void glFramebufferTexture2D ( int target, int attachment, int textarget, int texture, int level );\r
+\r
+       public native void glFrontFace ( int mode );\r
+\r
+       public native void glGenBuffers ( int n, IntBuffer buffers );\r
+\r
+       public native void glGenerateMipmap ( int target );\r
+\r
+       public native void glGenFramebuffers ( int n, IntBuffer framebuffers );\r
+\r
+       public native void glGenRenderbuffers ( int n, IntBuffer renderbuffers );\r
+\r
+       public native void glGenTextures ( int n, IntBuffer textures );\r
+\r
+       public native String glGetActiveAttrib ( int program, int index, IntBuffer size, Buffer type );\r
+\r
+       public native String glGetActiveUniform ( int program, int index, IntBuffer size, Buffer type );\r
+\r
+       public native void glGetAttachedShaders ( int program, int maxcount, Buffer count, IntBuffer shaders );\r
+\r
+       public native int glGetAttribLocation ( int program, String name );\r
+\r
+       public native void glGetBooleanv ( int pname, Buffer params );\r
+\r
+       public native void glGetBufferParameteriv ( int target, int pname, IntBuffer params );\r
+\r
+       public native int glGetError (  );\r
+\r
+       public native void glGetFloatv ( int pname, FloatBuffer params );\r
+\r
+       public native void glGetFramebufferAttachmentParameteriv ( int target, int attachment, int pname, IntBuffer params );\r
+\r
+       public native void glGetIntegerv ( int pname, IntBuffer params );\r
+\r
+       public native void glGetProgramiv ( int program, int pname, IntBuffer params );\r
+\r
+       public native String glGetProgramInfoLog ( int program );\r
+\r
+       public native void glGetRenderbufferParameteriv ( int target, int pname, IntBuffer params );\r
+\r
+       public native void glGetShaderiv ( int shader, int pname, IntBuffer params );\r
+\r
+       public native String glGetShaderInfoLog ( int shader );\r
+\r
+       public native void glGetShaderPrecisionFormat ( int shadertype, int precisiontype, IntBuffer range, IntBuffer precision );\r
+\r
+       public native void glGetShaderSource ( int shader, int bufsize, Buffer length, String source );\r
+\r
+       public native String glGetString ( int name );\r
+\r
+       public native void glGetTexParameterfv ( int target, int pname, FloatBuffer params );\r
+\r
+       public native void glGetTexParameteriv ( int target, int pname, IntBuffer params );\r
+\r
+       public native void glGetUniformfv ( int program, int location, FloatBuffer params );\r
+\r
+       public native void glGetUniformiv ( int program, int location, IntBuffer params );\r
+\r
+       public native int glGetUniformLocation ( int program, String name );\r
+\r
+       public native void glGetVertexAttribfv ( int index, int pname, FloatBuffer params );\r
+\r
+       public native void glGetVertexAttribiv ( int index, int pname, IntBuffer params );\r
+\r
+       public native void glGetVertexAttribPointerv ( int index, int pname, Buffer pointer );\r
+\r
+       public native void glHint ( int target, int mode );\r
+\r
+       public native boolean glIsBuffer ( int buffer );\r
+\r
+       public native boolean glIsEnabled ( int cap );\r
+\r
+       public native boolean glIsFramebuffer ( int framebuffer );\r
+\r
+       public native boolean glIsProgram ( int program );\r
+\r
+       public native boolean glIsRenderbuffer ( int renderbuffer );\r
+\r
+       public native boolean glIsShader ( int shader );\r
+\r
+       public native boolean glIsTexture ( int texture );\r
+\r
+       public native void glLineWidth ( float width );\r
+\r
+       public native void glLinkProgram ( int program );\r
+\r
+       public native void glPixelStorei ( int pname, int param );\r
+\r
+       public native void glPolygonOffset ( float factor, float units );\r
+\r
+       public native void glReadPixels ( int x, int y, int width, int height, int format, int type, Buffer pixels );\r
+\r
+       public native void glReleaseShaderCompiler (  );\r
+\r
+       public native void glRenderbufferStorage ( int target, int internalformat, int width, int height );\r
+\r
+       public native void glSampleCoverage ( float value, boolean invert );\r
+\r
+       public native void glScissor ( int x, int y, int width, int height );\r
+\r
+       public native void glShaderBinary ( int n, IntBuffer shaders, int binaryformat, Buffer binary, int length );\r
+\r
+       public native void glShaderSource ( int shader, String string );\r
+\r
+       public native void glStencilFunc ( int func, int ref, int mask );\r
+\r
+       public native void glStencilFuncSeparate ( int face, int func, int ref, int mask );\r
+\r
+       public native void glStencilMask ( int mask );\r
+\r
+       public native void glStencilMaskSeparate ( int face, int mask );\r
+\r
+       public native void glStencilOp ( int fail, int zfail, int zpass );\r
+\r
+       public native void glStencilOpSeparate ( int face, int fail, int zfail, int zpass );\r
+\r
+       public native void glTexImage2D ( int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels );\r
+\r
+       public native void glTexParameterf ( int target, int pname, float param );\r
+\r
+       public native void glTexParameterfv ( int target, int pname, FloatBuffer params );\r
+\r
+       public native void glTexParameteri ( int target, int pname, int param );\r
+\r
+       public native void glTexParameteriv ( int target, int pname, IntBuffer params );\r
+\r
+       public native void glTexSubImage2D ( int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, Buffer pixels );\r
+\r
+       public native void glUniform1f ( int location, float x );\r
+\r
+       public native void glUniform1fv ( int location, int count, FloatBuffer v );\r
+\r
+       public native void glUniform1i ( int location, int x );\r
+\r
+       public native void glUniform1iv ( int location, int count, IntBuffer v );\r
+\r
+       public native void glUniform2f ( int location, float x, float y );\r
+\r
+       public native void glUniform2fv ( int location, int count, FloatBuffer v );\r
+\r
+       public native void glUniform2i ( int location, int x, int y );\r
+\r
+       public native void glUniform2iv ( int location, int count, IntBuffer v );\r
+\r
+       public native void glUniform3f ( int location, float x, float y, float z );\r
+\r
+       public native void glUniform3fv ( int location, int count, FloatBuffer v );\r
+\r
+       public native void glUniform3i ( int location, int x, int y, int z );\r
+\r
+       public native void glUniform3iv ( int location, int count, IntBuffer v );\r
+\r
+       public native void glUniform4f ( int location, float x, float y, float z, float w );\r
+\r
+       public native void glUniform4fv ( int location, int count, FloatBuffer v );\r
+\r
+       public native void glUniform4i ( int location, int x, int y, int z, int w );\r
+\r
+       public native void glUniform4iv ( int location, int count, IntBuffer v );\r
+\r
+       public native void glUniformMatrix2fv ( int location, int count, boolean transpose, FloatBuffer value );\r
+\r
+       public native void glUniformMatrix3fv ( int location, int count, boolean transpose, FloatBuffer value );\r
+\r
+       public native void glUniformMatrix4fv ( int location, int count, boolean transpose, FloatBuffer value );\r
+\r
+       public native void glUseProgram ( int program );\r
+\r
+       public native void glValidateProgram ( int program );\r
+\r
+       public native void glVertexAttrib1f ( int indx, float x );\r
+\r
+       public native void glVertexAttrib1fv ( int indx, FloatBuffer values );\r
+\r
+       public native void glVertexAttrib2f ( int indx, float x, float y );\r
+\r
+       public native void glVertexAttrib2fv ( int indx, FloatBuffer values );\r
+\r
+       public native void glVertexAttrib3f ( int indx, float x, float y, float z );\r
+\r
+       public native void glVertexAttrib3fv ( int indx, FloatBuffer values );\r
+\r
+       public native void glVertexAttrib4f ( int indx, float x, float y, float z, float w );\r
+\r
+       public native void glVertexAttrib4fv ( int indx, FloatBuffer values );\r
+\r
+       public native void glVertexAttribPointer ( int indx, int size, int type, boolean normalized, int stride, Buffer ptr );\r
+       \r
+       public native void glVertexAttribPointer ( int indx, int size, int type, boolean normalized, int stride, int ptr );\r
+\r
+       public native void glViewport ( int x, int y, int width, int height );\r
+}
\ No newline at end of file
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGraphics.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleGraphics.java
new file mode 100644 (file)
index 0000000..d19011c
--- /dev/null
@@ -0,0 +1,212 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.awt.Toolkit;\r
+import java.awt.image.BufferedImage;\r
+import java.io.InputStream;\r
+\r
+import javax.imageio.ImageIO;\r
+\r
+import com.badlogic.gdx.Graphics;\r
+import com.badlogic.gdx.files.FileHandle;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.GL11;\r
+import com.badlogic.gdx.graphics.GL20;\r
+import com.badlogic.gdx.graphics.GLCommon;\r
+import com.badlogic.gdx.graphics.Pixmap;\r
+import com.badlogic.gdx.graphics.Pixmap.Format;\r
+import com.badlogic.gdx.graphics.Texture;\r
+import com.badlogic.gdx.graphics.Texture.TextureFilter;\r
+import com.badlogic.gdx.graphics.Texture.TextureWrap;\r
+import com.badlogic.gdx.graphics.TextureData;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+import com.badlogic.gdx.utils.MathUtils;\r
+\r
+public class AngleGraphics implements Graphics {\r
+       GL20 gl;\r
+       int width;\r
+       int height;\r
+       long lastTime = System.nanoTime();\r
+       long frameStart = System.nanoTime();\r
+       int fps;\r
+       int frames;\r
+       float deltaTime = 0;\r
+       \r
+       AngleGraphics(int width, int height) {\r
+               gl = new AngleGLES20();\r
+       }\r
+       \r
+       @Override\r
+       public boolean isGL11Available() {\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public boolean isGL20Available() {\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public GLCommon getGLCommon() {\r
+               return gl;\r
+       }\r
+\r
+       @Override\r
+       public GL10 getGL10() {\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public GL11 getGL11() {\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public GL20 getGL20() {\r
+               return gl;\r
+       }\r
+\r
+       @Override\r
+       public int getWidth() {\r
+               return width;\r
+       }\r
+\r
+       @Override\r
+       public int getHeight() {\r
+               return height;\r
+       }\r
+\r
+       @Override\r
+       public float getDeltaTime() {\r
+               return deltaTime;\r
+       }\r
+\r
+       @Override\r
+       public int getFramesPerSecond() {\r
+               return fps;\r
+       }\r
+\r
+       @Override\r
+       public Pixmap newPixmap(int width, int height, Format format) {\r
+               return new AnglePixmap(width, height, format);\r
+       }\r
+\r
+       @Override\r
+       public Pixmap newPixmap(InputStream in) {\r
+               try {\r
+                       BufferedImage img = (BufferedImage) ImageIO.read(in);\r
+                       return new AnglePixmap(img);\r
+               } catch (Exception ex) {\r
+                       throw new GdxRuntimeException(\r
+                                       "Couldn't load Pixmap from InputStream", ex);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public Pixmap newPixmap(FileHandle file) {\r
+               return newPixmap(file.read());\r
+       }\r
+\r
+       @Override\r
+       public Pixmap newPixmap(Object nativePixmap) {\r
+               return new AnglePixmap((BufferedImage) nativePixmap);\r
+       }\r
+\r
+       @Override\r
+       public Texture newUnmanagedTexture(int width, int height, Format format,\r
+                       TextureFilter minFilter, TextureFilter magFilter,\r
+                       TextureWrap uWrap, TextureWrap vWrap) {\r
+               if (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height))\r
+                       throw new GdxRuntimeException(\r
+                                       "Texture dimensions must be a power of two: " + width + "x"\r
+                                                       + height);\r
+\r
+               if (format == Format.Alpha)\r
+                       return new AngleTexture(width, height,\r
+                                       BufferedImage.TYPE_BYTE_GRAY, minFilter, magFilter, uWrap,\r
+                                       vWrap, false);\r
+               else\r
+                       return new AngleTexture(width, height,\r
+                                       BufferedImage.TYPE_4BYTE_ABGR, minFilter, magFilter, uWrap,\r
+                                       vWrap, false);\r
+       }\r
+\r
+       @Override\r
+       public Texture newUnmanagedTexture(Pixmap pixmap, TextureFilter minFilter,\r
+                       TextureFilter magFilter, TextureWrap uWrap, TextureWrap vWrap) {\r
+               if (!MathUtils.isPowerOfTwo(pixmap.getHeight())\r
+                               || !MathUtils.isPowerOfTwo(pixmap.getWidth()))\r
+                       throw new GdxRuntimeException(\r
+                                       "Texture dimensions must be a power of two: " + width + "x"\r
+                                                       + height);\r
+\r
+               return new AngleTexture((BufferedImage) pixmap.getNativePixmap(),\r
+                               minFilter, magFilter, uWrap, vWrap, false);\r
+       }\r
+\r
+       @Override\r
+       public Texture newTexture(FileHandle file, TextureFilter minFilter,\r
+                       TextureFilter magFilter, TextureWrap uWrap, TextureWrap vWrap) {                \r
+               Pixmap pixmap = newPixmap(file);\r
+               if (!MathUtils.isPowerOfTwo(pixmap.getHeight()) || !MathUtils.isPowerOfTwo(pixmap.getWidth()))\r
+                       throw new GdxRuntimeException("Texture dimensions must be a power of two: " + file + " (" + pixmap.getWidth() + "x"\r
+                               + pixmap.getHeight() + ")");            \r
+\r
+               return new AngleTexture(file, minFilter, magFilter, uWrap, vWrap, false);\r
+       }\r
+\r
+       @Override\r
+       public Texture newTexture(TextureData textureData, TextureFilter minFilter,\r
+                       TextureFilter magFilter, TextureWrap uWrap, TextureWrap vWrap) {\r
+               return new AngleTexture(textureData, minFilter, magFilter, uWrap, vWrap);\r
+       }\r
+\r
+       @Override\r
+       public GraphicsType getType() {\r
+               return GraphicsType.Angle;\r
+       }\r
+\r
+       @Override\r
+       public float getPpiX() {\r
+               return Toolkit.getDefaultToolkit().getScreenResolution();\r
+       }\r
+\r
+       @Override\r
+       public float getPpiY() {\r
+               return Toolkit.getDefaultToolkit().getScreenResolution();\r
+       }\r
+\r
+       @Override\r
+       public float getPpcX() {\r
+               return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);\r
+       }\r
+\r
+       @Override\r
+       public float getPpcY() {\r
+               return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);\r
+       }\r
+       \r
+       void updateTime () {\r
+               long time = System.nanoTime();\r
+               deltaTime = (time - lastTime) / 1000000000.0f;\r
+               lastTime = time;\r
+\r
+               if (time - frameStart >= 1000000000) {\r
+                       fps = frames;\r
+                       frames = 0;\r
+                       frameStart = time;\r
+               }\r
+               frames++;\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleInput.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleInput.java
new file mode 100644 (file)
index 0000000..0036681
--- /dev/null
@@ -0,0 +1,272 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+\r
+import javax.swing.JOptionPane;\r
+import javax.swing.SwingUtilities;\r
+\r
+import com.badlogic.anglejni.ESLoop;\r
+import com.badlogic.gdx.Input;\r
+import com.badlogic.gdx.InputProcessor;\r
+import com.badlogic.gdx.utils.Pool;\r
+import com.badlogic.gdx.utils.Pool.PoolObjectFactory;\r
+\r
+public class AngleInput implements Input {\r
+\r
+       class KeyEvent {\r
+               static final int KEY_DOWN = 0;\r
+               static final int KEY_UP = 1;\r
+               static final int KEY_TYPED = 2;\r
+\r
+               int type;\r
+               int keyCode;\r
+               char keyChar;\r
+       }\r
+\r
+       class TouchEvent {\r
+               static final int TOUCH_DOWN = 0;\r
+               static final int TOUCH_UP = 1;\r
+               static final int TOUCH_DRAGGED = 2;\r
+\r
+               int type;\r
+               int x;\r
+               int y;\r
+               int pointer;\r
+       }\r
+\r
+       Pool<KeyEvent> freeKeyEvents = new Pool<KeyEvent>(\r
+                       new PoolObjectFactory<KeyEvent>() {\r
+\r
+                               @Override\r
+                               public KeyEvent createObject() {\r
+                                       return new KeyEvent();\r
+                               }\r
+                       }, 1000);\r
+\r
+       Pool<TouchEvent> freeTouchEvents = new Pool<TouchEvent>(\r
+                       new PoolObjectFactory<TouchEvent>() {\r
+\r
+                               @Override\r
+                               public TouchEvent createObject() {\r
+                                       return new TouchEvent();\r
+                               }\r
+                       }, 1000);\r
+\r
+       List<KeyEvent> keyEvents = new ArrayList<KeyEvent>();\r
+       List<TouchEvent> touchEvents = new ArrayList<TouchEvent>();\r
+       boolean mousePressed = false;\r
+       int mouseX = 0;\r
+       int mouseY = 0;\r
+       HashSet<Integer> pressedKeys = new HashSet<Integer>();\r
+\r
+       private InputProcessor processor;\r
+       \r
+       public float getAccelerometerX () {\r
+               return 0;\r
+       }\r
+\r
+       public float getAccelerometerY () {\r
+               return 0;\r
+       }\r
+\r
+       public float getAccelerometerZ () {\r
+               return 0;\r
+       }\r
+\r
+       public void getTextInput (final TextInputListener listener, final String title, final String text) {\r
+               SwingUtilities.invokeLater(new Runnable() {\r
+                       public void run () {\r
+                               String output = JOptionPane.showInputDialog(null, title, text);\r
+                               listener.input(output);\r
+                       }\r
+               });\r
+       }\r
+\r
+       public int getX () {\r
+               // FIXME\r
+               return 0;\r
+       }\r
+\r
+       public int getY () {\r
+               // FIXME\r
+               return 0;\r
+       }\r
+\r
+       public boolean isAccelerometerAvailable () {\r
+               return false;\r
+       }\r
+\r
+       public boolean isKeyPressed (int key) {\r
+               // FIXME\r
+               return false;\r
+       }\r
+\r
+       public boolean isTouched () {\r
+               // FIXME                \r
+               return false;\r
+       }\r
+\r
+       public int getX (int pointer) {\r
+               if (pointer > 0)\r
+                       return 0;\r
+               else\r
+                       return getX();\r
+       }\r
+\r
+       public int getY (int pointer) {\r
+               if (pointer > 0)\r
+                       return 0;\r
+               else\r
+                       return getY();\r
+       }\r
+\r
+       public boolean isTouched (int pointer) {\r
+               if (pointer > 0)\r
+                       return false;\r
+               else\r
+                       return isTouched();\r
+       }\r
+\r
+       public boolean supportsMultitouch () {\r
+               return false;\r
+       }\r
+\r
+       @Override public void setOnscreenKeyboardVisible (boolean visible) {\r
+               \r
+       }\r
+\r
+       @Override public boolean supportsOnscreenKeyboard () {\r
+               return false;\r
+       }\r
+       \r
+       @Override public void setCatchBackKey (boolean catchBack) {\r
+               \r
+       }\r
+\r
+       void processEvents() {\r
+               synchronized(this) {\r
+                       if(processor!=null) {   \r
+                               InputProcessor processor = this.processor;\r
+                               int len = keyEvents.size();\r
+                               for(int i=0; i < len; i++) {\r
+                                       KeyEvent e = keyEvents.get(i);\r
+                                       switch(e.type) {\r
+                                       case KeyEvent.KEY_DOWN:\r
+                                               processor.keyDown(e.keyCode);\r
+                                               break;\r
+                                       case KeyEvent.KEY_UP:\r
+                                               processor.keyUp(e.keyCode);\r
+                                               break;\r
+                                       case KeyEvent.KEY_TYPED:\r
+                                               processor.keyTyped(e.keyChar);\r
+                                       }\r
+                                       freeKeyEvents.free(e);\r
+                               }                                       \r
+                               \r
+                               len = touchEvents.size();\r
+                               for(int i=0; i < len; i++) {\r
+                                       TouchEvent e = touchEvents.get(i);\r
+                                       switch(e.type) {\r
+                                       case TouchEvent.TOUCH_DOWN:\r
+                                               processor.touchDown(e.x, e.y, e.pointer);\r
+                                               break;\r
+                                       case TouchEvent.TOUCH_UP:\r
+                                               processor.touchUp(e.x, e.y, e.pointer);\r
+                                               break;\r
+                                       case TouchEvent.TOUCH_DRAGGED:\r
+                                               processor.touchDragged(e.x, e.y, e.pointer);\r
+                                       }\r
+                                       freeTouchEvents.free(e);\r
+                               }\r
+                       } else {\r
+                               int len = touchEvents.size();\r
+                               for(int i=0; i < len; i++) {\r
+                                       freeTouchEvents.free(touchEvents.get(i));\r
+                               }\r
+                               \r
+                               len = keyEvents.size();\r
+                               for(int i=0; i < len; i++) {\r
+                                       freeKeyEvents.free(keyEvents.get(i));\r
+                               }\r
+                       }\r
+                       \r
+                       keyEvents.clear();\r
+                       touchEvents.clear();\r
+               }\r
+       }       \r
+       \r
+       \r
+       boolean isButtonPressed () { \r
+               return mousePressed;\r
+       }\r
+\r
+       @Override\r
+       public void setInputProcessor(InputProcessor processor) {\r
+               this.processor = processor;\r
+       }\r
+\r
+       void registerKeyEvent(int action, int key, int uniCode) {\r
+               synchronized(this) {\r
+                       KeyEvent event = freeKeyEvents.newObject();\r
+                       event.keyChar = (char)uniCode;\r
+                       event.keyCode = translateKey(key);                      \r
+                       \r
+                       switch(action) {\r
+                       case ESLoop.ES_KEY_DOWN:\r
+                               event.type = KeyEvent.KEY_DOWN;\r
+                               break;\r
+                       case ESLoop.ES_KEY_UP:\r
+                               event.type = KeyEvent.KEY_UP;\r
+                               break;\r
+                       case ESLoop.ES_KEY_TYPED:\r
+                               event.type = KeyEvent.KEY_TYPED;\r
+                               break;\r
+                       }\r
+                       \r
+                       keyEvents.add(event);\r
+               }               \r
+       }\r
+\r
+       void registerMouseEvent(int action, int x, int y, int button) {\r
+               if(button != 1)\r
+                       return;\r
+               \r
+               synchronized(this) {\r
+                       TouchEvent event = freeTouchEvents.newObject();\r
+                       event.x = x;\r
+                       event.y = y;\r
+                       event.pointer = 0;\r
+                       \r
+                       switch(action) {\r
+                       case ESLoop.ES_MOUSE_DOWN:\r
+                               event.type = TouchEvent.TOUCH_DOWN;\r
+                               break;\r
+                       case ESLoop.ES_MOUSE_UP:\r
+                               event.type = TouchEvent.TOUCH_UP;\r
+                               break;\r
+                       case ESLoop.ES_MOUSE_MOVE:                              \r
+                               event.type = TouchEvent.TOUCH_DRAGGED;\r
+                               break;\r
+                       }\r
+               }               \r
+       }\r
+       \r
+       int translateKey(int keyCode) {\r
+               // FIXME\r
+               return keyCode;\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleMusic.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleMusic.java
new file mode 100644 (file)
index 0000000..4e51bcc
--- /dev/null
@@ -0,0 +1,171 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.IOException;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import javax.sound.sampled.AudioFormat;\r
+import javax.sound.sampled.AudioInputStream;\r
+import javax.sound.sampled.AudioSystem;\r
+import javax.sound.sampled.FloatControl;\r
+import javax.sound.sampled.LineUnavailableException;\r
+import javax.sound.sampled.SourceDataLine;\r
+import javax.sound.sampled.UnsupportedAudioFileException;\r
+\r
+import com.badlogic.gdx.audio.Music;\r
+import com.badlogic.gdx.files.FileHandle;\r
+\r
+final class AngleMusic implements Music, Runnable {\r
+       private final int Playing = 0;\r
+       private final int Stopped = 1;\r
+       private final int Paused = 2;\r
+\r
+       private AtomicInteger state = new AtomicInteger(Stopped);\r
+       private final Thread thread;\r
+       private final FileHandle handle;\r
+       private AudioInputStream ain;\r
+       private final SourceDataLine line;\r
+       private final byte[] buffer;\r
+       private AtomicBoolean looping = new AtomicBoolean(false);\r
+       private boolean disposed = false;\r
+\r
+       public AngleMusic (FileHandle handle) throws UnsupportedAudioFileException, IOException, LineUnavailableException {\r
+               this.handle = handle;\r
+\r
+               openAudioInputStream();\r
+               AudioFormat audioFormat = ain.getFormat();\r
+               line = AudioSystem.getSourceDataLine(audioFormat);\r
+               line.open(audioFormat); // FIXME reduce latency, gotta reimplement the playback thread.\r
+               line.start();\r
+               buffer = new byte[10000 * ain.getFormat().getFrameSize()];\r
+               ain.close();\r
+               ain = null;\r
+\r
+               thread = new Thread(this);\r
+               thread.setDaemon(true);\r
+               thread.start();\r
+       }\r
+\r
+       private void openAudioInputStream () throws UnsupportedAudioFileException, IOException {\r
+               ain = AudioSystem.getAudioInputStream(new BufferedInputStream(handle.read()));\r
+               AudioFormat baseFormat = ain.getFormat();\r
+               AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,\r
+                       baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);\r
+\r
+               ain = AudioSystem.getAudioInputStream(decodedFormat, ain);\r
+       }\r
+\r
+       @Override public void dispose () {\r
+               disposed = true;\r
+               try {\r
+                       thread.join();\r
+                       line.close();\r
+                       ain.close();\r
+               } catch (Exception e) {\r
+                       // nothing we can do here\r
+               }\r
+       }\r
+\r
+       @Override public boolean isLooping () {\r
+               return looping.get();\r
+       }\r
+\r
+       @Override public boolean isPlaying () {\r
+               return state.get() == Playing;\r
+       }\r
+\r
+       @Override public void pause () {\r
+               state.compareAndSet(Playing, Paused);\r
+       }\r
+\r
+       @Override public void play () {\r
+               state.set(Playing);\r
+       }\r
+\r
+       @Override public void stop () {\r
+               state.set(Stopped);\r
+       }\r
+\r
+       @Override public void setLooping (boolean isLooping) {\r
+               looping.set(isLooping);\r
+       }\r
+\r
+       @Override public void setVolume (float volume) {\r
+               try {\r
+                       volume = Math.min(1, volume);\r
+                       volume = Math.max(0, volume);\r
+                       FloatControl control = (FloatControl)line.getControl(FloatControl.Type.MASTER_GAIN);\r
+                       control.setValue(-80 + volume * 80);\r
+               } catch (IllegalArgumentException ex) {\r
+                       ex.printStackTrace();\r
+               }\r
+       }\r
+\r
+       @Override public void run () {\r
+               int readBytes = 0;\r
+               long readSamples = 0;\r
+\r
+               while (!disposed) {\r
+                       int curState = state.get();\r
+                       if (curState == Playing) {\r
+                               try {\r
+                                       if (ain == null) openAudioInputStream();\r
+                                       readBytes = ain.read(buffer);\r
+\r
+                                       if (readBytes != -1) {\r
+                                               int writtenBytes = line.write(buffer, 0, readBytes);\r
+                                               while (writtenBytes != readBytes)\r
+                                                       writtenBytes += line.write(buffer, writtenBytes, readBytes - writtenBytes);\r
+                                               readSamples += readBytes / ain.getFormat().getFrameSize();\r
+                                       } else {\r
+                                               System.out.println("samples: " + readSamples);\r
+                                               ain.close();\r
+                                               if (!isLooping()) state.set(Stopped);\r
+                                               else openAudioInputStream();\r
+                                       }\r
+                               } catch (Exception ex) {\r
+                                       try {\r
+                                               ain.close();\r
+                                       } catch (IOException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                                       line.close();\r
+                                       ex.printStackTrace();\r
+                                       state.set(Stopped);\r
+                                       return;\r
+                               }\r
+                       }\r
+                       else if (curState == Stopped && ain != null)\r
+                       {\r
+                               try {\r
+                                       ain.close();\r
+                               } catch (IOException e) {\r
+                                       e.printStackTrace();\r
+                               }\r
+                               ain = null;\r
+                               line.flush();\r
+                       }\r
+\r
+                       try {\r
+                               Thread.sleep(10);\r
+                       } catch (InterruptedException e) {\r
+                               // TODO Auto-generated catch block\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AnglePixmap.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AnglePixmap.java
new file mode 100644 (file)
index 0000000..f4697cb
--- /dev/null
@@ -0,0 +1,176 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.awt.AlphaComposite;\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Composite;\r
+import java.awt.Graphics2D;\r
+import java.awt.RenderingHints;\r
+import java.awt.image.BufferedImage;\r
+\r
+import com.badlogic.gdx.graphics.Pixmap;\r
+\r
+/**\r
+ * An implementation of Pixmap based on the java graphics framework.\r
+ * \r
+ * @author badlogicgames@gmail.com\r
+ * \r
+ */\r
+final class AnglePixmap implements Pixmap {\r
+       BufferedImage pixmap;\r
+       Composite composite;\r
+       Color color = new Color(0);\r
+       int strokeWidth = 1;\r
+\r
+       AnglePixmap (int width, int height, Pixmap.Format format) {\r
+               int internalformat = getInternalFormat(format);\r
+               pixmap = new BufferedImage(width, height, internalformat);\r
+               Graphics2D g = pixmap.createGraphics();\r
+               g.setComposite(AlphaComposite.Clear);\r
+               g.setColor(new Color(0, 0, 0, 0));\r
+               g.fillRect(0, 0, pixmap.getWidth(), pixmap.getHeight());\r
+               g.dispose();\r
+               composite = AlphaComposite.SrcOver;\r
+       }\r
+\r
+       AnglePixmap (BufferedImage image) {\r
+               if (image == null) throw new IllegalArgumentException("image cannot be null.");\r
+               pixmap = convert(image);\r
+       }\r
+\r
+       private BufferedImage convert (BufferedImage image) {\r
+               BufferedImage out = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);\r
+               Graphics2D g = out.createGraphics();\r
+               g.setComposite(AlphaComposite.Clear);\r
+               g.fillRect(0, 0, image.getWidth(), image.getHeight());\r
+               g.setComposite(AlphaComposite.SrcOver);\r
+               g.drawImage(image, 0, 0, null);\r
+               g.dispose();\r
+               return out;\r
+       }\r
+\r
+       private int getInternalFormat (Pixmap.Format format) {\r
+               return BufferedImage.TYPE_4BYTE_ABGR;\r
+       }\r
+\r
+       public void drawCircle (int x, int y, int radius) {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.setStroke(new BasicStroke(strokeWidth));\r
+               g.drawRect(x, y, radius * 2, radius * 2);\r
+               g.dispose();\r
+\r
+       }\r
+\r
+       public void drawLine (int x, int y, int x2, int y2) {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.setStroke(new BasicStroke(strokeWidth));\r
+               g.drawLine(x, y, x2, y2);\r
+               g.dispose();\r
+\r
+       }\r
+\r
+       public void drawRectangle (int x, int y, int width, int height) {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.setStroke(new BasicStroke(strokeWidth));\r
+               g.drawRect(x, y, width, height);\r
+               g.dispose();\r
+       }\r
+\r
+       public void fill () {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.fillRect(0, 0, pixmap.getWidth(), pixmap.getHeight());\r
+               g.dispose();\r
+       }\r
+\r
+       public void fillCircle (int x, int y, int radius) {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.fillOval(x, y, radius * 2, radius * 2);\r
+               g.dispose();\r
+       }\r
+\r
+       public void fillRectangle (int x, int y, int width, int height) {\r
+               Graphics2D g = (Graphics2D)pixmap.getGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+               g.setComposite(composite);\r
+               g.setColor(color);\r
+               g.fillRect(x, y, width, height);\r
+               g.dispose();\r
+       }\r
+\r
+       public Object getNativePixmap () {\r
+               return pixmap;\r
+       }\r
+\r
+       public void setColor (float r, float g, float b, float a) {\r
+               color = new Color(r, g, b, a);\r
+       }\r
+\r
+       public void setStrokeWidth (int width) {\r
+               strokeWidth = width;\r
+       }\r
+\r
+       public int getPixel (int x, int y) {\r
+               if (x < 0 || x >= pixmap.getWidth()) return 0;\r
+               if (y < 0 || y >= pixmap.getHeight()) return 0;\r
+               return pixmap.getRGB(x, y);\r
+       }\r
+\r
+       public int getHeight () {\r
+               return pixmap.getHeight();\r
+       }\r
+\r
+       public int getWidth () {\r
+               return pixmap.getWidth();\r
+       }\r
+\r
+       public void drawPixmap (Pixmap pixmap, int x, int y, int srcx, int srcy, int width, int height) {\r
+               BufferedImage image = (BufferedImage)pixmap.getNativePixmap();\r
+\r
+               Graphics2D g = (Graphics2D)this.pixmap.getGraphics();\r
+               g.setComposite(composite);\r
+               g.drawImage(image, x, y, x + width, y + height, srcx, srcy, srcx + width, srcy + height, null);\r
+               g.dispose();\r
+\r
+       }\r
+\r
+       public void dispose () {\r
+\r
+       }\r
+\r
+       public void getPixelRow (int[] pixels, int y) {\r
+               for (int x = 0; x < pixmap.getWidth(); x++) {\r
+                       pixels[x] = pixmap.getRGB(x, y);\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleSound.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleSound.java
new file mode 100644 (file)
index 0000000..94a9c0c
--- /dev/null
@@ -0,0 +1,160 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.nio.ByteBuffer;\r
+import java.nio.ByteOrder;\r
+import java.nio.ShortBuffer;\r
+\r
+import javax.sound.sampled.AudioFormat;\r
+import javax.sound.sampled.AudioInputStream;\r
+import javax.sound.sampled.AudioSystem;\r
+import javax.sound.sampled.Clip;\r
+import javax.sound.sampled.UnsupportedAudioFileException;\r
+\r
+import com.badlogic.gdx.audio.Sound;\r
+\r
+/**\r
+ * Implements the {@link Sound} interface for the desktop using {@link Clip}s internally.\r
+ * @author mzechner\r
+ * \r
+ */\r
+final class AngleSound implements Sound {\r
+       /** the audio format **/\r
+       private final AudioFormat format;\r
+\r
+       /** the audio data **/\r
+       private final byte[] originalSamples;\r
+\r
+       /** the float audio data **/\r
+       private float[] samples;\r
+\r
+       /** the audio instance **/\r
+       private final AngleAudio audio;\r
+\r
+       public AngleSound (AngleAudio audio, AngleFileHandle file) throws UnsupportedAudioFileException, IOException {\r
+               this.audio = audio;\r
+               InputStream fin = new BufferedInputStream(file.read());\r
+               AudioInputStream ain = AudioSystem.getAudioInputStream(fin);\r
+               AudioFormat baseFormat = ain.getFormat();\r
+               AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,\r
+                       baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);\r
+\r
+               ain = AudioSystem.getAudioInputStream(decodedFormat, ain);\r
+               ByteArrayOutputStream bytes = new ByteArrayOutputStream();\r
+               byte[] buffer = new byte[1024 * 10];\r
+               int readBytes = ain.read(buffer);\r
+               while (readBytes != -1) {\r
+                       bytes.write(buffer, 0, readBytes);\r
+                       readBytes = ain.read(buffer);\r
+               }\r
+               ain.close();\r
+               System.out.println(decodedFormat);\r
+               format = decodedFormat;\r
+               originalSamples = bytes.toByteArray();\r
+\r
+               ByteBuffer tmpBuffer = ByteBuffer.wrap(originalSamples);\r
+               tmpBuffer.order(ByteOrder.LITTLE_ENDIAN);\r
+               ShortBuffer shorts = tmpBuffer.asShortBuffer();\r
+               samples = new float[originalSamples.length / 2];\r
+               for (int i = 0; i < samples.length; i++) {\r
+                       float value = shorts.get(i) / (float)Short.MAX_VALUE;\r
+                       if (value < -1) value = -1;\r
+                       if (value > 1) value = 1;\r
+                       samples[i] = value;\r
+               }\r
+\r
+               samples = resample(samples, decodedFormat.getSampleRate(), decodedFormat.getChannels() == 1);\r
+       }\r
+\r
+       private float[] resample (float[] samples, float sampleRate, boolean isMono) {\r
+               if (sampleRate == 44100) return samples;\r
+\r
+               float idxInc = sampleRate / 44100;\r
+               int numSamples = (int)((samples.length / (float)sampleRate) * 44100);\r
+               if (!isMono && numSamples % 2 != 0) numSamples--;\r
+\r
+               float[] newSamples = new float[numSamples];\r
+\r
+               if (isMono) {\r
+                       float idx = 0;\r
+                       for (int i = 0; i < newSamples.length; i++) {\r
+                               int intIdx = (int)idx;\r
+                               if (intIdx >= samples.length - 1) break;\r
+\r
+                               float value = samples[intIdx] + samples[intIdx + 1];\r
+                               value /= 2;\r
+                               if (value > 1) value = 1;\r
+                               if (value < -1) value = -1;\r
+                               newSamples[i] = value;\r
+                               idx += idxInc;\r
+                       }\r
+               } else {\r
+                       float idx = 0;\r
+                       for (int i = 0; i < newSamples.length; i += 2) {\r
+                               int intIdxL = (int)idx * 2;\r
+                               int intIdxR = (int)idx * 2 + 1;\r
+                               if (intIdxL >= samples.length - 2) break;\r
+\r
+                               float value = samples[intIdxL] + samples[intIdxL + 2];\r
+                               value /= 2;\r
+                               if (value > 1) value = 1;\r
+                               if (value < -1) value = -1;\r
+                               newSamples[i] = value;\r
+\r
+                               value = samples[intIdxR] + samples[intIdxR + 2];\r
+                               value /= 2;\r
+                               if (value > 1) value = 1;\r
+                               if (value < -1) value = -1;\r
+                               newSamples[i + 1] = value;\r
+\r
+                               idx += idxInc;\r
+                       }\r
+               }\r
+\r
+               return newSamples;\r
+       }\r
+\r
+       public void dispose () {\r
+\r
+       }\r
+\r
+       public void play () {\r
+               audio.enqueueSound(this, 1);\r
+       }\r
+\r
+       public void play (float volume) {\r
+               audio.enqueueSound(this, volume);\r
+       }\r
+\r
+       /**\r
+        * @return the {@link AudioFormat} of the audio data\r
+        */\r
+       public AudioFormat getAudioFormat () {\r
+               return format;\r
+       }\r
+\r
+       /**\r
+        * @return the audio samples in form of a byte array\r
+        */\r
+       public float[] getAudioData () {\r
+               return samples;\r
+       }\r
+\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleTexture.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleTexture.java
new file mode 100644 (file)
index 0000000..ce35dcf
--- /dev/null
@@ -0,0 +1,339 @@
+/*\r
+ * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
+ * License. You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
+ * governing permissions and limitations under the License.\r
+ */\r
+\r
+package com.badlogic.gdx.backends.angle;\r
+\r
+import java.awt.Graphics2D;\r
+import java.awt.RenderingHints;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.ColorModel;\r
+import java.awt.image.DataBufferInt;\r
+import java.awt.image.Raster;\r
+import java.io.IOException;\r
+import java.nio.ByteBuffer;\r
+import java.nio.ByteOrder;\r
+import java.nio.IntBuffer;\r
+\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.backends.angle.PNGDecoder.Format;\r
+import com.badlogic.gdx.files.FileHandle;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.GL20;\r
+import com.badlogic.gdx.graphics.Pixmap;\r
+import com.badlogic.gdx.graphics.Texture;\r
+import com.badlogic.gdx.graphics.TextureData;\r
+import com.badlogic.gdx.utils.BufferUtils;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/**\r
+ * @author badlogicgames@gmail.com\r
+ * @author Nathan Sweet <misc@n4te.com>\r
+ */\r
+final class AngleTexture implements Texture {\r
+       /** height in pixels of texture **/\r
+       private int texHeight;\r
+       /** width in pixels of texture **/\r
+       private int texWidth;\r
+       /** whether this textures i managed or not **/\r
+       private final boolean isManaged;\r
+       private int textureID;\r
+       private final boolean isMipMapped;\r
+\r
+       /** global number of textures **/\r
+       public static int textures = 0;\r
+\r
+       static private ByteBuffer buffer;\r
+       static private IntBuffer intBuffer;\r
+       static private final PNGDecoder pngDecoder = new PNGDecoder();\r
+\r
+       AngleTexture (FileHandle file, TextureFilter minFilter, TextureFilter maxFilter, TextureWrap uWrap, TextureWrap vWrap,\r
+               boolean managed) {\r
+               this.isManaged = managed;\r
+               this.isMipMapped = TextureFilter.isMipMap(minFilter);\r
+\r
+               if (!isMipMapped && file.path().endsWith(".png")) {\r
+                       // Fast path.\r
+                       loadPNG(file);\r
+               } else {\r
+                       BufferedImage image = (BufferedImage)Gdx.graphics.newPixmap(file).getNativePixmap();\r
+                       loadMipMap(image);\r
+               }\r
+               bind();\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, getTextureFilter(minFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, getTextureFilter(maxFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, getTextureWrap(uWrap));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, getTextureWrap(vWrap));\r
+               textures++;\r
+       }\r
+\r
+       AngleTexture (BufferedImage image, TextureFilter minFilter, TextureFilter maxFilter, TextureWrap uWrap, TextureWrap vWrap,\r
+               boolean managed) {\r
+               this.isManaged = managed;\r
+               this.isMipMapped = TextureFilter.isMipMap(minFilter);\r
+\r
+               BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);\r
+               loadMipMap(img);\r
+               this.draw(Gdx.graphics.newPixmap(image), 0, 0);\r
+               bind();\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, getTextureFilter(minFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, getTextureFilter(maxFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, getTextureWrap(uWrap));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, getTextureWrap(vWrap));\r
+               textures++;\r
+       }\r
+\r
+       AngleTexture (int width, int height, int format, TextureFilter minFilter, TextureFilter maxFilter, TextureWrap uWrap,\r
+               TextureWrap vWrap, boolean managed) {\r
+               this.isManaged = managed;\r
+               this.isMipMapped = TextureFilter.isMipMap(minFilter);\r
+\r
+               BufferedImage image = new BufferedImage(width, height, format);\r
+               loadMipMap(image);\r
+               bind();\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, getTextureFilter(minFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, getTextureFilter(maxFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, getTextureWrap(uWrap));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, getTextureWrap(vWrap));\r
+               textures++;\r
+       }\r
+\r
+       public AngleTexture (TextureData textureData, TextureFilter minFilter, TextureFilter magFilter, TextureWrap uWrap,\r
+               TextureWrap vWrap) {\r
+               isManaged = false;\r
+               this.isMipMapped = TextureFilter.isMipMap(minFilter);\r
+\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               IntBuffer buffer = BufferUtils.newIntBuffer(1);\r
+               gl.glGenTextures(1, buffer);\r
+               textureID = buffer.get(0);\r
+               bind();         \r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, getTextureFilter(minFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, getTextureFilter(magFilter));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, getTextureWrap(uWrap));\r
+               gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, getTextureWrap(vWrap));\r
+\r
+               textureData.load();\r
+               texWidth = textureData.getWidth();\r
+               texHeight = textureData.getHeight();\r
+\r
+               textures++;\r
+       }\r
+\r
+       private void loadPNG (FileHandle file) {\r
+               try {\r
+                       pngDecoder.decodeHeader(file.read());\r
+                       texWidth = pngDecoder.getWidth();\r
+                       texHeight = pngDecoder.getHeight();\r
+                       int stride = texWidth * 4;\r
+                       ensureBufferSize(stride * texHeight);\r
+\r
+                       Format pngFormat = pngDecoder.decideTextureFormat(PNGDecoder.Format.RGBA);\r
+                       int glFormat, glInternalFormat;\r
+                       switch (pngFormat) {\r
+                       case ALPHA:\r
+                               glFormat = GL10.GL_ALPHA;\r
+                               glInternalFormat = GL10.GL_ALPHA;\r
+                               break;\r
+                       case LUMINANCE:\r
+                               glFormat = GL10.GL_LUMINANCE;\r
+                               glInternalFormat = GL10.GL_LUMINANCE;\r
+                               break;\r
+                       case LUMINANCE_ALPHA:\r
+                               glFormat = GL10.GL_LUMINANCE_ALPHA;\r
+                               glInternalFormat = GL10.GL_LUMINANCE_ALPHA;\r
+                               break;\r
+                       case RGB:\r
+                               glFormat = GL10.GL_RGB;\r
+                               glInternalFormat = GL10.GL_RGB;\r
+                               break;\r
+                       case RGBA:\r
+                               glFormat = GL10.GL_RGBA;\r
+                               glInternalFormat = GL10.GL_RGBA;\r
+                               break;\r
+//                     case BGRA:\r
+//                             glFormat = GL10.GL_BGRA;\r
+//                             glInternalFormat = GL10.GL_BGRA;\r
+//                             break;\r
+                       default:\r
+                               throw new UnsupportedOperationException("PNG format not handled: " + pngFormat);\r
+                       }\r
+                       pngDecoder.decode(buffer, stride, pngFormat);\r
+                       buffer.flip();\r
+\r
+                       GL20 gl = Gdx.graphics.getGL20();\r
+                       IntBuffer buffer = BufferUtils.newIntBuffer(1);\r
+                       gl.glGenTextures(1, buffer);\r
+                       textureID = buffer.get(0);                      \r
+                       gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);\r
+                       gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, glInternalFormat, texWidth, texHeight, 0, glFormat, GL10.GL_UNSIGNED_BYTE, buffer);\r
+               } catch (IOException ex) {\r
+                       throw new GdxRuntimeException("Error loading image file: " + file, ex);\r
+               }\r
+       }\r
+\r
+       private ByteBuffer toByteBuffer (BufferedImage image) {\r
+               int width = image.getWidth();\r
+               int height = image.getHeight();\r
+               ensureBufferSize(width * height * 4);\r
+\r
+               Raster raster = image.getRaster();\r
+               if (image.getType() == BufferedImage.TYPE_INT_ARGB)\r
+                       intBuffer.put(((DataBufferInt)raster.getDataBuffer()).getData(), 0, width * height);\r
+               else {\r
+                       // Same as image.getRGB() without allocating a large int[].\r
+                       ColorModel colorModel = image.getColorModel();\r
+                       Object data = raster.getDataElements(0, 0, null);\r
+                       for (int y = 0; y < height; y++)\r
+                               for (int x = 0; x < width; x++)\r
+                                       intBuffer.put(colorModel.getRGB(raster.getDataElements(x, y, data)));\r
+               }\r
+\r
+               buffer.limit(intBuffer.position() * 4);\r
+               return buffer;\r
+       }\r
+\r
+       private void ensureBufferSize (int size) {\r
+               if (buffer == null || buffer.capacity() < size) {\r
+                       buffer = BufferUtils.newByteBuffer(size);\r
+                       ByteBuffer temp = buffer.slice();\r
+                       temp.order(ByteOrder.LITTLE_ENDIAN);\r
+                       intBuffer = temp.asIntBuffer();\r
+               } else {\r
+                       buffer.clear();\r
+                       intBuffer.clear();\r
+               }\r
+       }\r
+\r
+       private BufferedImage scaleDown (BufferedImage image) {\r
+               BufferedImage scaled = new BufferedImage(image.getWidth() / 2, image.getHeight() / 2, BufferedImage.TYPE_4BYTE_ABGR_PRE);\r
+               Graphics2D g = scaled.createGraphics();\r
+               g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);\r
+               g.drawImage(image, 0, 0, scaled.getWidth(), scaled.getHeight(), null);\r
+               g.dispose();\r
+               return scaled;\r
+       }\r
+\r
+       private void loadMipMap (BufferedImage image) {\r
+               int level = 0;\r
+               int height = image.getHeight();\r
+               int width = image.getWidth();\r
+               texWidth = width;\r
+               texHeight = height;\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               IntBuffer buffer = BufferUtils.newIntBuffer(1);\r
+               gl.glGenTextures(1, buffer);\r
+               textureID = buffer.get(0);              \r
+               gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);\r
+\r
+               while (height >= 1 || width >= 1 && level < 4) {\r
+                       ByteBuffer imageBuffer = toByteBuffer(image);\r
+                       gl.glTexImage2D(GL10.GL_TEXTURE_2D, level, GL10.GL_RGBA, width, height, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, imageBuffer);\r
+                       if (height == 1 || width == 1 || isMipMapped == false) break;\r
+\r
+                       level++;\r
+                       if (height > 1) height /= 2;\r
+                       if (width > 1) width /= 2;\r
+\r
+                       image = scaleDown(image);\r
+               }\r
+       }\r
+\r
+       private int getTextureFilter (TextureFilter filter) {\r
+               if (filter == TextureFilter.Linear)\r
+                       return GL10.GL_LINEAR;\r
+               else if (filter == TextureFilter.Nearest)\r
+                       return GL10.GL_NEAREST;\r
+               else if (filter == TextureFilter.MipMap)\r
+                       return GL10.GL_LINEAR_MIPMAP_LINEAR;\r
+               else if (filter == TextureFilter.MipMapNearestNearest)\r
+                       return GL10.GL_NEAREST_MIPMAP_NEAREST;\r
+               else if (filter == TextureFilter.MipMapNearestLinear)\r
+                       return GL10.GL_NEAREST_MIPMAP_LINEAR;\r
+               else if (filter == TextureFilter.MipMapLinearNearest)\r
+                       return GL10.GL_LINEAR_MIPMAP_NEAREST;\r
+               else if (filter == TextureFilter.MipMapLinearLinear)\r
+                       return GL10.GL_LINEAR_MIPMAP_LINEAR;\r
+               else\r
+                       return GL10.GL_LINEAR_MIPMAP_LINEAR;\r
+       }\r
+\r
+       private int getTextureWrap (TextureWrap wrap) {\r
+               if (wrap == TextureWrap.ClampToEdge)\r
+                       return GL10.GL_CLAMP_TO_EDGE;\r
+               else\r
+                       return GL10.GL_REPEAT;\r
+       }\r
+\r
+       public boolean isManaged () {\r
+               return isManaged;\r
+       }\r
+\r
+       public void bind () {\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);\r
+       }\r
+\r
+       public void dispose () {\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               IntBuffer buffer = BufferUtils.newIntBuffer(1);\r
+               buffer.put(textureID);\r
+               buffer.flip();\r
+               gl.glDeleteTextures(1, buffer);\r
+               textures--;\r
+       }\r
+\r
+       public int getHeight () {\r
+               return texHeight;\r
+       }\r
+\r
+       public int getWidth () {\r
+               return texWidth;\r
+       }\r
+\r
+       public void draw (Pixmap pixmap, int x, int y) {\r
+               if (isManaged) throw new GdxRuntimeException("Can't draw to a managed texture");\r
+               BufferedImage image = (BufferedImage)pixmap.getNativePixmap();\r
+\r
+               int level = 0;\r
+               int height = image.getHeight();\r
+               int width = image.getWidth();\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               bind();\r
+               while (height >= 1 || width >= 1 && level < 4) {\r
+                       ByteBuffer imageBuffer = toByteBuffer(image);\r
+                       gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, level, x, y, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, imageBuffer);\r
+                       if (height == 1 || width == 1 || isMipMapped == false) break;\r
+\r
+                       level++;\r
+                       if (height > 1) height /= 2;\r
+                       if (width > 1) width /= 2;\r
+\r
+                       image = scaleDown(image);\r
+               }\r
+\r
+       }\r
+\r
+       public int getTextureObjectHandle () {\r
+               return textureID;\r
+       }\r
+\r
+       public void setWrap (TextureWrap x, TextureWrap y) {\r
+               bind();\r
+               GL20 gl = Gdx.graphics.getGL20();\r
+               gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, x == TextureWrap.Repeat ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE);\r
+               gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, y == TextureWrap.Repeat ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE);\r
+       }\r
+}\r
diff --git a/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/PNGDecoder.java b/backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/PNGDecoder.java
new file mode 100644 (file)
index 0000000..b9ee740
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * Copyright (c) 2008-2010, Matthias Mann
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ * 
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of Matthias Mann nor the names of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.badlogic.gdx.backends.angle;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.zip.CRC32;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+/**
+ * Decodes A PNG directly a ByteBuffer.
+ * 
+ * @author Matthias Mann
+ * @author Nathan Sweet <misc@n4te.com> (minor edits to avoid allocation)
+ */
+final class PNGDecoder {
+       public enum Format {
+               ALPHA(1, true), LUMINANCE(1, false), LUMINANCE_ALPHA(2, true), RGB(3, false), RGBA(4, true), BGRA(4, true), ABGR(4, true);
+
+               final int numComponents;
+               final boolean hasAlpha;
+
+               private Format (int numComponents, boolean hasAlpha) {
+                       this.numComponents = numComponents;
+                       this.hasAlpha = hasAlpha;
+               }
+
+               public int getNumComponents () {
+                       return numComponents;
+               }
+
+               public boolean isHasAlpha () {
+                       return hasAlpha;
+               }
+       }
+
+       private static final byte[] SIGNATURE = {(byte)137, 80, 78, 71, 13, 10, 26, 10};
+
+       private static final int IHDR = 0x49484452;
+       private static final int PLTE = 0x504C5445;
+       private static final int tRNS = 0x74524E53;
+       private static final int IDAT = 0x49444154;
+       private static final int IEND = 0x49454E44;
+
+       private static final byte COLOR_GREYSCALE = 0;
+       private static final byte COLOR_TRUECOLOR = 2;
+       private static final byte COLOR_INDEXED = 3;
+       private static final byte COLOR_GREYALPHA = 4;
+       private static final byte COLOR_TRUEALPHA = 6;
+
+       private InputStream input;
+       private final CRC32 crc;
+       private final byte[] buffer;
+
+       private int chunkLength;
+       private int chunkType;
+       private int chunkRemaining;
+
+       private int width;
+       private int height;
+       private int bitdepth;
+       private int colorType;
+       private int bytesPerPixel;
+       private byte[] palette;
+       private byte[] paletteA;
+       private byte[] transPixel;
+
+       public PNGDecoder () {
+               this.crc = new CRC32();
+               this.buffer = new byte[4096];
+       }
+
+       public void decodeHeader (InputStream input) throws IOException {
+               this.input = input;
+
+               readFully(buffer, 0, SIGNATURE.length);
+               if (!checkSignatur(buffer)) {
+                       throw new IOException("Not a valid PNG file");
+               }
+
+               openChunk(IHDR);
+               readIHDR();
+               closeChunk();
+
+               searchIDAT:
+               for (;;) {
+                       openChunk();
+                       switch (chunkType) {
+                       case IDAT:
+                               break searchIDAT;
+                       case PLTE:
+                               readPLTE();
+                               break;
+                       case tRNS:
+                               readtRNS();
+                               break;
+                       }
+                       closeChunk();
+               }
+
+               if (colorType == COLOR_INDEXED && palette == null) {
+                       throw new IOException("Missing PLTE chunk");
+               }
+       }
+
+       public int getHeight () {
+               return height;
+       }
+
+       public int getWidth () {
+               return width;
+       }
+
+       public boolean hasAlpha () {
+               return colorType == COLOR_TRUEALPHA || paletteA != null || transPixel != null;
+       }
+
+       public boolean isRGB () {
+               return colorType == COLOR_TRUEALPHA || colorType == COLOR_TRUECOLOR || colorType == COLOR_INDEXED;
+       }
+
+       /**
+        * Computes the implemented format conversion for the desired format.
+        * 
+        * @param fmt the desired format
+        * @return format which best matches the desired format
+        * @throws UnsupportedOperationException if this PNG file can't be decoded
+        */
+       public Format decideTextureFormat (Format fmt) {
+               switch (colorType) {
+               case COLOR_TRUECOLOR:
+                       switch (fmt) {
+                       case ABGR:
+                       case RGBA:
+                       case BGRA:
+                       case RGB:
+                               return fmt;
+                       default:
+                               return Format.RGB;
+                       }
+               case COLOR_TRUEALPHA:
+                       switch (fmt) {
+                       case ABGR:
+                       case RGBA:
+                       case BGRA:
+                       case RGB:
+                               return fmt;
+                       default:
+                               return Format.RGBA;
+                       }
+               case COLOR_GREYSCALE:
+                       switch (fmt) {
+                       case LUMINANCE:
+                       case ALPHA:
+                               return fmt;
+                       default:
+                               return Format.LUMINANCE;
+                       }
+               case COLOR_GREYALPHA:
+                       return Format.LUMINANCE_ALPHA;
+               case COLOR_INDEXED:
+                       switch (fmt) {
+                       case ABGR:
+                       case RGBA:
+                       case BGRA:
+                               return fmt;
+                       default:
+                               return Format.RGBA;
+                       }
+               default:
+                       throw new UnsupportedOperationException("Not yet implemented");
+               }
+       }
+
+       public void decode (ByteBuffer buffer, int stride, Format fmt) throws IOException {
+               final int offset = buffer.position();
+               final int lineSize = ((width * bitdepth + 7) / 8) * bytesPerPixel;
+               byte[] curLine = new byte[lineSize + 1];
+               byte[] prevLine = new byte[lineSize + 1];
+               byte[] palLine = (bitdepth < 8) ? new byte[width + 1] : null;
+
+               final Inflater inflater = new Inflater();
+               try {
+                       for (int y = 0; y < height; y++) {
+                               readChunkUnzip(inflater, curLine, 0, curLine.length);
+                               unfilter(curLine, prevLine);
+
+                               buffer.position(offset + y * stride);
+
+                               switch (colorType) {
+                               case COLOR_TRUECOLOR:
+                                       switch (fmt) {
+                                       case ABGR:
+                                               copyRGBtoABGR(buffer, curLine);
+                                               break;
+                                       case RGBA:
+                                               copyRGBtoRGBA(buffer, curLine);
+                                               break;
+                                       case BGRA:
+                                               copyRGBtoBGRA(buffer, curLine);
+                                               break;
+                                       case RGB:
+                                               copy(buffer, curLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported format for this image");
+                                       }
+                                       break;
+                               case COLOR_TRUEALPHA:
+                                       switch (fmt) {
+                                       case ABGR:
+                                               copyRGBAtoABGR(buffer, curLine);
+                                               break;
+                                       case RGBA:
+                                               copy(buffer, curLine);
+                                               break;
+                                       case BGRA:
+                                               copyRGBAtoBGRA(buffer, curLine);
+                                               break;
+                                       case RGB:
+                                               copyRGBAtoRGB(buffer, curLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported format for this image");
+                                       }
+                                       break;
+                               case COLOR_GREYSCALE:
+                                       switch (fmt) {
+                                       case LUMINANCE:
+                                       case ALPHA:
+                                               copy(buffer, curLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported format for this image");
+                                       }
+                                       break;
+                               case COLOR_GREYALPHA:
+                                       switch (fmt) {
+                                       case LUMINANCE_ALPHA:
+                                               copy(buffer, curLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported format for this image");
+                                       }
+                                       break;
+                               case COLOR_INDEXED:
+                                       switch (bitdepth) {
+                                       case 8:
+                                               palLine = curLine;
+                                               break;
+                                       case 4:
+                                               expand4(curLine, palLine);
+                                               break;
+                                       case 2:
+                                               expand2(curLine, palLine);
+                                               break;
+                                       case 1:
+                                               expand1(curLine, palLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported bitdepth for this image");
+                                       }
+                                       switch (fmt) {
+                                       case ABGR:
+                                               copyPALtoABGR(buffer, palLine);
+                                               break;
+                                       case RGBA:
+                                               copyPALtoRGBA(buffer, palLine);
+                                               break;
+                                       case BGRA:
+                                               copyPALtoBGRA(buffer, palLine);
+                                               break;
+                                       default:
+                                               throw new UnsupportedOperationException("Unsupported format for this image");
+                                       }
+                                       break;
+                               default:
+                                       throw new UnsupportedOperationException("Not yet implemented");
+                               }
+
+                               byte[] tmp = curLine;
+                               curLine = prevLine;
+                               prevLine = tmp;
+                       }
+               } finally {
+                       inflater.end();
+               }
+       }
+
+       private void copy (ByteBuffer buffer, byte[] curLine) {
+               buffer.put(curLine, 1, curLine.length - 1);
+       }
+
+       private void copyRGBtoABGR (ByteBuffer buffer, byte[] curLine) {
+               if (transPixel != null) {
+                       byte tr = transPixel[1];
+                       byte tg = transPixel[3];
+                       byte tb = transPixel[5];
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               byte r = curLine[i];
+                               byte g = curLine[i + 1];
+                               byte b = curLine[i + 2];
+                               byte a = (byte)0xFF;
+                               if (r == tr && g == tg && b == tb) {
+                                       a = 0;
+                               }
+                               buffer.put(a).put(b).put(g).put(r);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               buffer.put((byte)0xFF).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
+                       }
+               }
+       }
+
+       private void copyRGBtoRGBA (ByteBuffer buffer, byte[] curLine) {
+               if (transPixel != null) {
+                       byte tr = transPixel[1];
+                       byte tg = transPixel[3];
+                       byte tb = transPixel[5];
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               byte r = curLine[i];
+                               byte g = curLine[i + 1];
+                               byte b = curLine[i + 2];
+                               byte a = (byte)0xFF;
+                               if (r == tr && g == tg && b == tb) {
+                                       a = 0;
+                               }
+                               buffer.put(r).put(g).put(b).put(a);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]).put((byte)0xFF);
+                       }
+               }
+       }
+
+       private void copyRGBtoBGRA (ByteBuffer buffer, byte[] curLine) {
+               if (transPixel != null) {
+                       byte tr = transPixel[1];
+                       byte tg = transPixel[3];
+                       byte tb = transPixel[5];
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               byte r = curLine[i];
+                               byte g = curLine[i + 1];
+                               byte b = curLine[i + 2];
+                               byte a = (byte)0xFF;
+                               if (r == tr && g == tg && b == tb) {
+                                       a = 0;
+                               }
+                               buffer.put(b).put(g).put(r).put(a);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 3) {
+                               buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]).put((byte)0xFF);
+                       }
+               }
+       }
+
+       private void copyRGBAtoABGR (ByteBuffer buffer, byte[] curLine) {
+               for (int i = 1, n = curLine.length; i < n; i += 4) {
+                       buffer.put(curLine[i + 3]).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
+               }
+       }
+
+       private void copyRGBAtoBGRA (ByteBuffer buffer, byte[] curLine) {
+               for (int i = 1, n = curLine.length; i < n; i += 4) {
+                       buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i + 0]).put(curLine[i + 3]);
+               }
+       }
+
+       private void copyRGBAtoRGB (ByteBuffer buffer, byte[] curLine) {
+               for (int i = 1, n = curLine.length; i < n; i += 4) {
+                       buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]);
+               }
+       }
+
+       private void copyPALtoABGR (ByteBuffer buffer, byte[] curLine) {
+               if (paletteA != null) {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = paletteA[idx];
+                               buffer.put(a).put(b).put(g).put(r);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = (byte)0xFF;
+                               buffer.put(a).put(b).put(g).put(r);
+                       }
+               }
+       }
+
+       private void copyPALtoRGBA (ByteBuffer buffer, byte[] curLine) {
+               if (paletteA != null) {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = paletteA[idx];
+                               buffer.put(r).put(g).put(b).put(a);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = (byte)0xFF;
+                               buffer.put(r).put(g).put(b).put(a);
+                       }
+               }
+       }
+
+       private void copyPALtoBGRA (ByteBuffer buffer, byte[] curLine) {
+               if (paletteA != null) {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = paletteA[idx];
+                               buffer.put(b).put(g).put(r).put(a);
+                       }
+               } else {
+                       for (int i = 1, n = curLine.length; i < n; i += 1) {
+                               int idx = curLine[i] & 255;
+                               byte r = palette[idx * 3 + 0];
+                               byte g = palette[idx * 3 + 1];
+                               byte b = palette[idx * 3 + 2];
+                               byte a = (byte)0xFF;
+                               buffer.put(b).put(g).put(r).put(a);
+                       }
+               }
+       }
+
+       private void expand4 (byte[] src, byte[] dst) {
+               for (int i = 1, n = dst.length; i < n; i += 2) {
+                       int val = src[1 + (i >> 1)] & 255;
+                       switch (n - i) {
+                       default:
+                               dst[i + 1] = (byte)(val & 15);
+                       case 1:
+                               dst[i] = (byte)(val >> 4);
+                       }
+               }
+       }
+
+       private void expand2 (byte[] src, byte[] dst) {
+               for (int i = 1, n = dst.length; i < n; i += 4) {
+                       int val = src[1 + (i >> 2)] & 255;
+                       switch (n - i) {
+                       default:
+                               dst[i + 3] = (byte)((val) & 3);
+                       case 3:
+                               dst[i + 2] = (byte)((val >> 2) & 3);
+                       case 2:
+                               dst[i + 1] = (byte)((val >> 4) & 3);
+                       case 1:
+                               dst[i] = (byte)((val >> 6));
+                       }
+               }
+       }
+
+       private void expand1 (byte[] src, byte[] dst) {
+               for (int i = 1, n = dst.length; i < n; i += 8) {
+                       int val = src[1 + (i >> 3)] & 255;
+                       switch (n - i) {
+                       default:
+                               dst[i + 7] = (byte)((val) & 1);
+                       case 7:
+                               dst[i + 6] = (byte)((val >> 1) & 1);
+                       case 6:
+                               dst[i + 5] = (byte)((val >> 2) & 1);
+                       case 5:
+                               dst[i + 4] = (byte)((val >> 3) & 1);
+                       case 4:
+                               dst[i + 3] = (byte)((val >> 4) & 1);
+                       case 3:
+                               dst[i + 2] = (byte)((val >> 5) & 1);
+                       case 2:
+                               dst[i + 1] = (byte)((val >> 6) & 1);
+                       case 1:
+                               dst[i] = (byte)((val >> 7));
+                       }
+               }
+       }
+
+       private void unfilter (byte[] curLine, byte[] prevLine) throws IOException {
+               switch (curLine[0]) {
+               case 0: // none
+                       break;
+               case 1:
+                       unfilterSub(curLine);
+                       break;
+               case 2:
+                       unfilterUp(curLine, prevLine);
+                       break;
+               case 3:
+                       unfilterAverage(curLine, prevLine);
+                       break;
+               case 4:
+                       unfilterPaeth(curLine, prevLine);
+                       break;
+               default:
+                       throw new IOException("invalide filter type in scanline: " + curLine[0]);
+               }
+       }
+
+       private void unfilterSub (byte[] curLine) {
+               final int bpp = this.bytesPerPixel;
+               for (int i = bpp + 1, n = curLine.length; i < n; ++i) {
+                       curLine[i] += curLine[i - bpp];
+               }
+       }
+
+       private void unfilterUp (byte[] curLine, byte[] prevLine) {
+               for (int i = 1, n = curLine.length; i < n; ++i) {
+                       curLine[i] += prevLine[i];
+               }
+       }
+
+       private void unfilterAverage (byte[] curLine, byte[] prevLine) {
+               final int bpp = this.bytesPerPixel;
+
+               int i;
+               for (i = 1; i <= bpp; ++i) {
+                       curLine[i] += (byte)((prevLine[i] & 0xFF) >>> 1);
+               }
+               for (int n = curLine.length; i < n; ++i) {
+                       curLine[i] += (byte)(((prevLine[i] & 0xFF) + (curLine[i - bpp] & 0xFF)) >>> 1);
+               }
+       }
+
+       private void unfilterPaeth (byte[] curLine, byte[] prevLine) {
+               final int bpp = this.bytesPerPixel;
+
+               int i;
+               for (i = 1; i <= bpp; ++i) {
+                       curLine[i] += prevLine[i];
+               }
+               for (int n = curLine.length; i < n; ++i) {
+                       int a = curLine[i - bpp] & 255;
+                       int b = prevLine[i] & 255;
+                       int c = prevLine[i - bpp] & 255;
+                       int p = a + b - c;
+                       int pa = p - a;
+                       if (pa < 0) pa = -pa;
+                       int pb = p - b;
+                       if (pb < 0) pb = -pb;
+                       int pc = p - c;
+                       if (pc < 0) pc = -pc;
+                       if (pa <= pb && pa <= pc)
+                               c = a;
+                       else if (pb <= pc) c = b;
+                       curLine[i] += (byte)c;
+               }
+       }
+
+       private void readIHDR () throws IOException {
+               checkChunkLength(13);
+               readChunk(buffer, 0, 13);
+               width = readInt(buffer, 0);
+               height = readInt(buffer, 4);
+               bitdepth = buffer[8] & 255;
+               colorType = buffer[9] & 255;
+
+               switch (colorType) {
+               case COLOR_GREYSCALE:
+                       if (bitdepth != 8) {
+                               throw new IOException("Unsupported bit depth: " + bitdepth);
+                       }
+                       bytesPerPixel = 1;
+                       break;
+               case COLOR_GREYALPHA:
+                       if (bitdepth != 8) {
+                               throw new IOException("Unsupported bit depth: " + bitdepth);
+                       }
+                       bytesPerPixel = 2;
+                       break;
+               case COLOR_TRUECOLOR:
+                       if (bitdepth != 8) {
+                               throw new IOException("Unsupported bit depth: " + bitdepth);
+                       }
+                       bytesPerPixel = 3;
+                       break;
+               case COLOR_TRUEALPHA:
+                       if (bitdepth != 8) {
+                               throw new IOException("Unsupported bit depth: " + bitdepth);
+                       }
+                       bytesPerPixel = 4;
+                       break;
+               case COLOR_INDEXED:
+                       switch (bitdepth) {
+                       case 8:
+                       case 4:
+                       case 2:
+                       case 1:
+                               bytesPerPixel = 1;
+                               break;
+                       default:
+                               throw new IOException("Unsupported bit depth: " + bitdepth);
+                       }
+                       break;
+               default:
+                       throw new IOException("unsupported color format: " + colorType);
+               }
+
+               if (buffer[10] != 0) {
+                       throw new IOException("unsupported compression method");
+               }
+               if (buffer[11] != 0) {
+                       throw new IOException("unsupported filtering method");
+               }
+               if (buffer[12] != 0) {
+                       throw new IOException("unsupported interlace method");
+               }
+       }
+
+       private void readPLTE () throws IOException {
+               int paletteEntries = chunkLength / 3;
+               if (paletteEntries < 1 || paletteEntries > 256 || (chunkLength % 3) != 0) {
+                       throw new IOException("PLTE chunk has wrong length");
+               }
+               palette = new byte[paletteEntries * 3];
+               readChunk(palette, 0, palette.length);
+       }
+
+       private void readtRNS () throws IOException {
+               switch (colorType) {
+               case COLOR_GREYSCALE:
+                       checkChunkLength(2);
+                       transPixel = new byte[2];
+                       readChunk(transPixel, 0, 2);
+                       break;
+               case COLOR_TRUECOLOR:
+                       checkChunkLength(6);
+                       transPixel = new byte[6];
+                       readChunk(transPixel, 0, 6);
+                       break;
+               case COLOR_INDEXED:
+                       if (palette == null) {
+                               throw new IOException("tRNS chunk without PLTE chunk");
+                       }
+                       paletteA = new byte[palette.length / 3];
+                       Arrays.fill(paletteA, (byte)0xFF);
+                       readChunk(paletteA, 0, paletteA.length);
+                       break;
+               default:
+                       // just ignore it
+               }
+       }
+
+       private void closeChunk () throws IOException {
+               if (chunkRemaining > 0) {
+                       // just skip the rest and the CRC
+                       skip(chunkRemaining + 4);
+               } else {
+                       readFully(buffer, 0, 4);
+                       int expectedCrc = readInt(buffer, 0);
+                       int computedCrc = (int)crc.getValue();
+                       if (computedCrc != expectedCrc) {
+                               throw new IOException("Invalid CRC");
+                       }
+               }
+               chunkRemaining = 0;
+               chunkLength = 0;
+               chunkType = 0;
+       }
+
+       private void openChunk () throws IOException {
+               readFully(buffer, 0, 8);
+               chunkLength = readInt(buffer, 0);
+               chunkType = readInt(buffer, 4);
+               chunkRemaining = chunkLength;
+               crc.reset();
+               crc.update(buffer, 4, 4); // only chunkType
+       }
+
+       private void openChunk (int expected) throws IOException {
+               openChunk();
+               if (chunkType != expected) {
+                       throw new IOException("Expected chunk: " + Integer.toHexString(expected));
+               }
+       }
+
+       private void checkChunkLength (int expected) throws IOException {
+               if (chunkLength != expected) {
+                       throw new IOException("Chunk has wrong size");
+               }
+       }
+
+       private int readChunk (byte[] buffer, int offset, int length) throws IOException {
+               if (length > chunkRemaining) {
+                       length = chunkRemaining;
+               }
+               readFully(buffer, offset, length);
+               crc.update(buffer, offset, length);
+               chunkRemaining -= length;
+               return length;
+       }
+
+       private void refillInflater (Inflater inflater) throws IOException {
+               while (chunkRemaining == 0) {
+                       closeChunk();
+                       openChunk(IDAT);
+               }
+               int read = readChunk(buffer, 0, buffer.length);
+               inflater.setInput(buffer, 0, read);
+       }
+
+       private void readChunkUnzip (Inflater inflater, byte[] buffer, int offset, int length) throws IOException {
+               assert (buffer != this.buffer);
+               try {
+                       do {
+                               int read = inflater.inflate(buffer, offset, length);
+                               if (read <= 0) {
+                                       if (inflater.finished()) {
+                                               throw new EOFException();
+                                       }
+                                       if (inflater.needsInput()) {
+                                               refillInflater(inflater);
+                                       } else {
+                                               throw new IOException("Can't inflate " + length + " bytes");
+                                       }
+                               } else {
+                                       offset += read;
+                                       length -= read;
+                               }
+                       } while (length > 0);
+               } catch (DataFormatException ex) {
+                       throw (IOException)(new IOException("inflate error").initCause(ex));
+               }
+       }
+
+       private void readFully (byte[] buffer, int offset, int length) throws IOException {
+               do {
+                       int read = input.read(buffer, offset, length);
+                       if (read < 0) {
+                               throw new EOFException();
+                       }
+                       offset += read;
+                       length -= read;
+               } while (length > 0);
+       }
+
+       private int readInt (byte[] buffer, int offset) {
+               return ((buffer[offset]) << 24) | ((buffer[offset + 1] & 255) << 16) | ((buffer[offset + 2] & 255) << 8)
+                       | ((buffer[offset + 3] & 255));
+       }
+
+       private void skip (long amount) throws IOException {
+               while (amount > 0) {
+                       long skipped = input.skip(amount);
+                       if (skipped < 0) {
+                               throw new EOFException();
+                       }
+                       amount -= skipped;
+               }
+       }
+
+       private static boolean checkSignatur (byte[] buffer) {
+               for (int i = 0; i < SIGNATURE.length; i++) {
+                       if (buffer[i] != SIGNATURE[i]) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+}