+{
+ public void onEvent(T particle);
+}
diff --git a/src/com/axe/fx/ParticleModifier.java b/src/com/axe/fx/ParticleModifier.java
new file mode 100644
index 0000000..97079aa
--- /dev/null
+++ b/src/com/axe/fx/ParticleModifier.java
@@ -0,0 +1,8 @@
+package com.axe.fx;
+
+import com.axe.game.GameState;
+
+public interface ParticleModifier
+{
+ public void modify( P[] particles, int particleCount, Particle particle, GameState state );
+}
diff --git a/src/com/axe/fx/Particles.java b/src/com/axe/fx/Particles.java
new file mode 100644
index 0000000..74350e0
--- /dev/null
+++ b/src/com/axe/fx/Particles.java
@@ -0,0 +1,20 @@
+package com.axe.fx;
+
+import com.axe.math.Vec;
+import com.axe.node.Node;
+import com.axe.node.Nodes;
+
+public class Particles, N extends Node> extends Nodes
+{
+
+ public ParticlesTemplate template;
+ public ParticleListener[] initializers;
+ public ParticleListener[] finalizers;
+
+ @Override
+ protected void destroyNode(N node)
+ {
+ template.memory.free( node );
+ }
+
+}
diff --git a/src/com/axe/fx/ParticlesTemplate.java b/src/com/axe/fx/ParticlesTemplate.java
new file mode 100644
index 0000000..e0a20b8
--- /dev/null
+++ b/src/com/axe/fx/ParticlesTemplate.java
@@ -0,0 +1,10 @@
+package com.axe.fx;
+
+import com.axe.mem.Memory;
+
+public class ParticlesTemplate
+{
+
+ public Memory
memory;
+
+}
diff --git a/src/com/axe/game/AbstractGame.java b/src/com/axe/game/AbstractGame.java
new file mode 100644
index 0000000..be013f0
--- /dev/null
+++ b/src/com/axe/game/AbstractGame.java
@@ -0,0 +1,262 @@
+package com.axe.game;
+
+import java.util.concurrent.TimeUnit;
+
+import com.axe.Axe;
+import com.axe.Scene;
+import com.axe.collect.ListArray;
+import com.axe.event.EventMap;
+import com.axe.loop.Loop;
+import com.axe.loop.LoopVariable;
+import com.axe.math.Vec;
+import com.axe.window.Window;
+import com.axe2d.Scene2;
+import com.axe3d.Scene3;
+
+public abstract class AbstractGame implements Game
+{
+
+ public EventMap events;
+ public Loop loop;
+ public GameState state;
+ public ListArray scenes;
+ public ListArray windows;
+ public Window focusedWindow;
+ public boolean playing;
+ public long hiddenSleepTime;
+ public int liveWindows;
+ public int hiddenWindows;
+ public Object data;
+
+ public AbstractGame()
+ {
+ this.events = new EventMap();
+ this.loop = new LoopVariable(100, TimeUnit.MILLISECONDS);
+ this.state = new GameState();
+ this.scenes = ListArray.compacted();
+ this.windows = ListArray.compacted();
+ this.hiddenSleepTime = DEFAULT_HIDDEN_SLEEP_TIME;
+ }
+
+ @Override
+ public EventMap getEvents()
+ {
+ return events;
+ }
+
+ @Override
+ public Loop getLoop()
+ {
+ return loop;
+ }
+
+ @Override
+ public Game setLoop(Loop loop)
+ {
+ this.loop = loop;
+ return this;
+ }
+
+ @Override
+ public GameState getState()
+ {
+ return state;
+ }
+
+ @Override
+ public ListArray getScenes()
+ {
+ return scenes;
+ }
+
+ @Override
+ public T getData()
+ {
+ return (T) data;
+ }
+
+ @Override
+ public void setData(Object data)
+ {
+ this.data = data;
+ }
+
+ @Override
+ public , S extends Scene> S newScene(int dimensions)
+ {
+ Scene scene = null;
+
+ switch (dimensions) {
+ case 2: scene = new Scene2(); break;
+ case 3: scene = new Scene3(); break;
+ }
+
+ if (scene == null)
+ {
+ throw new RuntimeException(dimensions + " is not a supported dimension");
+ }
+
+ scenes.add( scene );
+
+ return (S)scene;
+ }
+
+ @Override
+ public ListArray getWindows()
+ {
+ return windows;
+ }
+
+ @Override
+ public boolean isPlaying()
+ {
+ return playing;
+ }
+
+ @Override
+ public long getHiddenSleepTime()
+ {
+ return hiddenSleepTime;
+ }
+
+ @Override
+ public void setHiddenSleepTime(long hiddenSleepTime)
+ {
+ this.hiddenSleepTime = hiddenSleepTime;
+ }
+
+ @Override
+ public void stop()
+ {
+ playing = false;
+ }
+
+ @Override
+ public Window getFocusedWindow()
+ {
+ return focusedWindow;
+ }
+
+ @Override
+ public void show()
+ {
+ windows.forAll(window -> window.show());
+ }
+
+ @Override
+ public void run()
+ {
+ show();
+
+ listeners(GameEvent.Start).onEvent(this);
+
+ loop.onStart(state);
+
+ prepare();
+
+ scenes.forAll( scene -> scene.activate() );
+
+ playing = true;
+
+ while (playing)
+ {
+ liveWindows = 0;
+ hiddenWindows = 0;
+
+ windows.forAll((window)->
+ {
+ if ( window.isCloseRequest() )
+ {
+ window.close();
+ }
+ else
+ {
+ liveWindows++;
+
+ if ( window.isHidden() )
+ {
+ hiddenWindows++;
+ }
+ else if ( window.isFocused() )
+ {
+ focusedWindow = window;
+ }
+ }
+ });
+
+ if ( liveWindows == 0 )
+ {
+ break;
+ }
+
+ if ( hiddenWindows == liveWindows )
+ {
+ sleep();
+
+ continue;
+ }
+
+ windows.forAll( window -> window.update() );
+
+ processInput();
+
+ loop.onLoop( state );
+
+ if ( state.updates > 0 )
+ {
+ windows.forAll( window -> window.updateMouse() );
+
+ for (int i = 0; i < state.updates; i++)
+ {
+ listeners( GameEvent.UpdateStart ).onEvent( this );
+
+ scenes.forAll( scene -> scene.update( state ) );
+
+ listeners( GameEvent.UpdateEnd ).onEvent( this );
+ }
+
+ flushInput();
+ }
+
+ if ( state.draw )
+ {
+ listeners( GameEvent.DrawStart ).onEvent( this );
+
+ windows.forAll(window ->
+ {
+ if ( !window.isHidden() )
+ {
+ window.draw( state );
+ }
+ });
+
+ listeners( GameEvent.DrawEnd ).onEvent( this );
+ }
+ }
+
+ listeners( GameEvent.Stop ).onEvent( this );
+
+ destroy();
+ }
+
+ protected void sleep()
+ {
+ try
+ {
+ Thread.sleep( hiddenSleepTime );
+ }
+ catch (InterruptedException e)
+ {
+ Axe.logger.log(e);
+ }
+ }
+
+ protected abstract void prepare();
+
+ protected abstract void processInput();
+
+ protected abstract void flushInput();
+
+ protected abstract void destroy();
+
+}
diff --git a/src/com/axe/game/Game.java b/src/com/axe/game/Game.java
new file mode 100644
index 0000000..0acd73d
--- /dev/null
+++ b/src/com/axe/game/Game.java
@@ -0,0 +1,44 @@
+package com.axe.game;
+
+import com.axe.Scene;
+import com.axe.collect.ListArray;
+import com.axe.core.HasData;
+import com.axe.event.HasEvents;
+import com.axe.loop.Loop;
+import com.axe.math.Vec;
+import com.axe.window.Window;
+
+public interface Game extends HasEvents, HasData
+{
+
+ public static final long DEFAULT_HIDDEN_SLEEP_TIME = 100;
+
+ public Loop getLoop();
+
+ public Game setLoop(Loop loop);
+
+ public GameState getState();
+
+ public ListArray getScenes();
+
+ public , S extends Scene> S newScene(int dimensions);
+
+ public ListArray getWindows();
+
+ public Window newWindow();
+
+ public Window getFocusedWindow();
+
+ public boolean isPlaying();
+
+ public long getHiddenSleepTime();
+
+ public void setHiddenSleepTime(long hiddenSleepTime);
+
+ public void show();
+
+ public void run();
+
+ public void stop();
+
+}
\ No newline at end of file
diff --git a/src/com/axe/game/GameEvent.java b/src/com/axe/game/GameEvent.java
new file mode 100644
index 0000000..b0200ff
--- /dev/null
+++ b/src/com/axe/game/GameEvent.java
@@ -0,0 +1,26 @@
+package com.axe.game;
+
+import com.axe.event.Event;
+
+public class GameEvent
+{
+
+ public static final Event Start =
+ new Event<>(0, GameEventListener.class);
+
+ public static final Event DrawStart =
+ new Event<>(1, GameEventListener.class);
+
+ public static final Event DrawEnd =
+ new Event<>(2, GameEventListener.class);
+
+ public static final Event UpdateStart =
+ new Event<>(3, GameEventListener.class);
+
+ public static final Event UpdateEnd =
+ new Event<>(4, GameEventListener.class);
+
+ public static final Event Stop =
+ new Event<>(5, GameEventListener.class);
+
+}
\ No newline at end of file
diff --git a/src/com/axe/game/GameEventListener.java b/src/com/axe/game/GameEventListener.java
new file mode 100644
index 0000000..8e6954e
--- /dev/null
+++ b/src/com/axe/game/GameEventListener.java
@@ -0,0 +1,5 @@
+package com.axe.game;
+
+public interface GameEventListener {
+ public void onEvent(Game game);
+}
\ No newline at end of file
diff --git a/src/com/axe/game/GameSettings.java b/src/com/axe/game/GameSettings.java
new file mode 100644
index 0000000..1ddd2d4
--- /dev/null
+++ b/src/com/axe/game/GameSettings.java
@@ -0,0 +1,2 @@
+package com.axe.game;
+public class GameSettings {}
\ No newline at end of file
diff --git a/src/com/axe/game/GameState.java b/src/com/axe/game/GameState.java
new file mode 100644
index 0000000..9a4f5a4
--- /dev/null
+++ b/src/com/axe/game/GameState.java
@@ -0,0 +1,38 @@
+package com.axe.game;
+
+public class GameState
+{
+
+ public float seconds;
+ public long millis;
+ public long nanos;
+ public long micros;
+ public long startTime;
+ public long lastTime;
+ public long currentTime;
+ public float interpolation = 0;
+ public float reverse = 0;
+ public int updates = 1;
+ public boolean draw = true;
+
+ public long reset()
+ {
+ return ( startTime = lastTime = currentTime = System.nanoTime() );
+ }
+
+ public long tick()
+ {
+ lastTime = currentTime;
+ currentTime = System.nanoTime();
+ return (currentTime - lastTime);
+ }
+
+ public void setElapsed(long nanosElapsed)
+ {
+ nanos = nanosElapsed;
+ micros = nanosElapsed / 1000L;
+ millis = nanosElapsed / 1000000L;
+ seconds = (float)(nanosElapsed * 0.000000001);
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/AbstractTexture.java b/src/com/axe/gfx/AbstractTexture.java
new file mode 100644
index 0000000..c42abfb
--- /dev/null
+++ b/src/com/axe/gfx/AbstractTexture.java
@@ -0,0 +1,155 @@
+package com.axe.gfx;
+
+
+public abstract class AbstractTexture implements Texture
+{
+
+ public TextureInfo info;
+
+ // original width of the image in pixels
+ public int imageWidth;
+ // original height of the image in pixels
+ public int imageHeight;
+
+ // computed image width in pixels
+ public int width;
+ // computed image height in pixels
+ public int height;
+
+ // the normalized width of a pixel (1 / width)
+ public float pixelW;
+ // half of the width of a pixel (used for coordinate correction).
+ public float offW;
+
+ // the normalized height of a pixel (1 / height)
+ public float pixelH;
+ // half of the height of a pixel (used for coordinate correction).
+ public float offH;
+
+ // The texture wrapping function
+ public Wrap wrap = Wrap.Default;
+ // The texture minification function
+ public Minify min = Minify.Linear;
+ // The texture magnification function
+ public Magnify mag = Magnify.Linear;
+
+ // The anisotropic filter
+ public int anisotrophy = 1;
+
+
+ public AbstractTexture(TextureInfo info, int imageWidth, int imageHeight, int textureWidth, int textureHeight)
+ {
+ this.info = info;
+ this.imageWidth = imageWidth;
+ this.imageHeight = imageHeight;
+ this.width = textureWidth;
+ this.pixelW = 1f / textureWidth;
+ this.offW = pixelW * 0.5f;
+ this.height = textureHeight;
+ this.pixelH = 1f / textureHeight;
+ this.offH = pixelH * 0.5f;
+ }
+
+ @Override
+ public TextureInfo getInfo()
+ {
+ return info;
+ }
+
+ @Override
+ public int width()
+ {
+ return width;
+ }
+
+ @Override
+ public int height()
+ {
+ return height;
+ }
+
+ @Override
+ public int getImageHeight()
+ {
+ return imageHeight;
+ }
+
+ @Override
+ public int getImageWidth()
+ {
+ return imageWidth;
+ }
+
+ @Override
+ public float getPixelWidth()
+ {
+ return pixelW;
+ }
+
+ @Override
+ public float getPixelOffsetX()
+ {
+ return offW;
+ }
+
+ @Override
+ public float getPixelHeight()
+ {
+ return pixelH;
+ }
+
+ @Override
+ public float getPixelOffsetY()
+ {
+ return offH;
+ }
+
+ @Override
+ public Magnify magnify()
+ {
+ return mag;
+ }
+
+ @Override
+ public void magnify(Magnify mag)
+ {
+ this.mag = mag;
+ }
+
+ @Override
+ public Minify minify()
+ {
+ return min;
+ }
+
+ @Override
+ public void minify(Minify min)
+ {
+ this.min = min;
+ }
+
+ @Override
+ public Wrap wrap()
+ {
+ return wrap;
+ }
+
+ @Override
+ public void wrap(Wrap wrap)
+ {
+ this.wrap = wrap;
+ }
+
+ @Override
+ public int anisotrophy()
+ {
+ return anisotrophy;
+ }
+
+ @Override
+ public void anisotrophy(int anisotrophy)
+ {
+ this.anisotrophy = anisotrophy;
+ }
+
+}
diff --git a/src/com/axe/gfx/AbstractVertexBuffer.java b/src/com/axe/gfx/AbstractVertexBuffer.java
new file mode 100755
index 0000000..b3a3dfe
--- /dev/null
+++ b/src/com/axe/gfx/AbstractVertexBuffer.java
@@ -0,0 +1,63 @@
+package com.axe.gfx;
+
+public abstract class AbstractVertexBuffer implements VertexBuffer
+{
+
+ protected VertexMesh mesh;
+ protected int position;
+
+ protected AbstractVertexBuffer()
+ {
+ }
+
+ public void reset(VertexMesh mesh)
+ {
+ this.mesh = mesh;
+ this.position = 0;
+ this.data().position( 0 );
+ }
+
+ public VertexMesh mesh()
+ {
+ return mesh;
+ }
+
+ public void next()
+ {
+ final int s = mesh.format().stride;
+
+ data().position( position += s );
+ }
+
+ public void vertex(int index)
+ {
+ final int s = mesh.format().stride;
+
+ data().position( position = index * s );
+ }
+
+ public int capacity()
+ {
+ final int s = mesh.format().stride;
+
+ return data().capacity() / s;
+ }
+
+ public int vertices()
+ {
+ final int s = mesh.format().stride;
+ final int p = data().position();
+
+ return (p + s - 1) / s;
+ }
+
+ public int remaining()
+ {
+ final int s = mesh.format().stride;
+ final int p = data().position();
+ final int r = data().remaining();
+
+ return (r + p % s) / s;
+ }
+
+}
diff --git a/src/com/axe/gfx/Blend.java b/src/com/axe/gfx/Blend.java
new file mode 100755
index 0000000..e4a1231
--- /dev/null
+++ b/src/com/axe/gfx/Blend.java
@@ -0,0 +1,15 @@
+
+package com.axe.gfx;
+
+public enum Blend
+{
+ Add,
+ AlphaAdd,
+ Alpha,
+ Color,
+ Minus,
+ PremultAlpha,
+ Modulate,
+ Xor,
+ None
+}
diff --git a/src/com/axe/gfx/ColorOperation.java b/src/com/axe/gfx/ColorOperation.java
new file mode 100755
index 0000000..ec16f2a
--- /dev/null
+++ b/src/com/axe/gfx/ColorOperation.java
@@ -0,0 +1,22 @@
+
+package com.axe.gfx;
+
+public enum ColorOperation
+{
+ Clear,
+ Set,
+ Copy,
+ CopyInverted,
+ Noop,
+ Inverted,
+ And,
+ NAnd,
+ Or,
+ NOr,
+ XOr,
+ Equiv,
+ AndReverse,
+ AndInverted,
+ OrReverse,
+ OrInverted
+}
diff --git a/src/com/axe/gfx/Coord.java b/src/com/axe/gfx/Coord.java
new file mode 100755
index 0000000..ba8bdc7
--- /dev/null
+++ b/src/com/axe/gfx/Coord.java
@@ -0,0 +1,54 @@
+
+package com.axe.gfx;
+
+import com.axe.core.Attribute;
+import com.axe.core.Factory;
+import com.axe.math.calc.CalculatorCoord;
+
+
+public class Coord implements Attribute
+{
+
+ public static Factory Factory = new Factory() {
+ public Coord create()
+ {
+ return new Coord();
+ }
+ };
+
+ public float s, t;
+
+ public Coord()
+ {
+ }
+
+ public Coord( float s, float t )
+ {
+ set( s, t );
+ }
+
+ public void set( float s, float t )
+ {
+ this.s = s;
+ this.t = t;
+ }
+
+ @Override
+ public Coord get()
+ {
+ return this;
+ }
+
+ @Override
+ public Coord clone()
+ {
+ return new Coord( s, t );
+ }
+
+ @Override
+ public CalculatorCoord getCalculator()
+ {
+ return CalculatorCoord.INSTANCE;
+ }
+
+}
diff --git a/src/com/axe/gfx/DataType.java b/src/com/axe/gfx/DataType.java
new file mode 100755
index 0000000..314b9be
--- /dev/null
+++ b/src/com/axe/gfx/DataType.java
@@ -0,0 +1,21 @@
+package com.axe.gfx;
+
+
+public enum DataType
+{
+ Byte( 1 ),
+ Ubyte( 1 ),
+ Short( 2 ),
+ Ushort( 2 ),
+ Integer( 4 ),
+ Uint ( 4 ),
+ Float( 4 ),
+ Double( 8 );
+
+ public final int bytes;
+
+ private DataType(int bytes)
+ {
+ this.bytes = bytes;
+ }
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/FogMode.java b/src/com/axe/gfx/FogMode.java
new file mode 100644
index 0000000..ebb4af6
--- /dev/null
+++ b/src/com/axe/gfx/FogMode.java
@@ -0,0 +1,8 @@
+package com.axe.gfx;
+
+public enum FogMode
+{
+ Exp,
+ Exp2,
+ Linear
+}
diff --git a/src/com/axe/gfx/GraphicsEngine.java b/src/com/axe/gfx/GraphicsEngine.java
new file mode 100644
index 0000000..206455a
--- /dev/null
+++ b/src/com/axe/gfx/GraphicsEngine.java
@@ -0,0 +1,60 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+import com.axe.util.Buffers;
+
+public interface GraphicsEngine
+{
+
+ public VertexMesh newVertexMesh(VertexMeshType type, VertexFormat format);
+
+ public VertexBuffer newVertexBuffer(int chunkSizeInBytes, boolean autoExpand);
+
+ default public VertexBuffer newVertexBufferFor(VertexMeshType type, VertexFormat format, int chunkSizeInVertices, boolean autoExpand)
+ {
+ VertexMesh mesh = newVertexMesh( type, format );
+ VertexBuffer buffer = newVertexBuffer( format.stride * chunkSizeInVertices, autoExpand );
+
+ buffer.reset( mesh );
+
+ return buffer;
+ }
+
+ default public ByteBuffer newDataBuffer(int count, DataType type)
+ {
+ return Buffers.bytes( count * type.bytes );
+ }
+
+ default public ShortBuffer newIndexBuffer(int indexCount)
+ {
+ return Buffers.shorts( indexCount );
+ }
+
+ default public IntBuffer newLargeIndexBuffer(int indexCount)
+ {
+ return Buffers.ints( indexCount );
+ }
+
+ default public ByteBuffer newSmallIndexBuffer(int indexCount)
+ {
+ return Buffers.bytes( indexCount );
+ }
+
+ public ShaderObject newShaderObject( ShaderObjectType type, String code );
+
+ public Shader newShader( ShaderObject ... objects );
+
+ public Shader newShader( String ... objectPaths );
+
+ public Shader newShader( Class> enumClass, ShaderObject ... objects );
+
+ public Shader newShader( Class> enumClass, String ... objectPaths );
+
+ public String getVersion();
+
+ public String getGraphicsCard();
+
+}
diff --git a/src/com/axe/gfx/Magnify.java b/src/com/axe/gfx/Magnify.java
new file mode 100755
index 0000000..6c083cc
--- /dev/null
+++ b/src/com/axe/gfx/Magnify.java
@@ -0,0 +1,8 @@
+
+package com.axe.gfx;
+
+public enum Magnify
+{
+ Nearest,
+ Linear
+}
diff --git a/src/com/axe/gfx/Minify.java b/src/com/axe/gfx/Minify.java
new file mode 100755
index 0000000..15c38fd
--- /dev/null
+++ b/src/com/axe/gfx/Minify.java
@@ -0,0 +1,12 @@
+
+package com.axe.gfx;
+
+public enum Minify
+{
+ Nearest,
+ Linear,
+ NearestNearest,
+ LinearNearest,
+ NearestLinear,
+ LinearLinear
+}
diff --git a/src/com/axe/gfx/Mode.java b/src/com/axe/gfx/Mode.java
new file mode 100755
index 0000000..8f2df85
--- /dev/null
+++ b/src/com/axe/gfx/Mode.java
@@ -0,0 +1,19 @@
+
+package com.axe.gfx;
+
+public enum Mode
+{
+ AlphaTest,
+ Blend,
+ Texture,
+ Culling,
+ Depth,
+ Lighting,
+ Normalize,
+ Smooth,
+ Clipping,
+ LineSmooth,
+ DepthMask,
+ Fog,
+ LogicalOperation
+}
diff --git a/src/com/axe/gfx/Primitive.java b/src/com/axe/gfx/Primitive.java
new file mode 100755
index 0000000..2e35c22
--- /dev/null
+++ b/src/com/axe/gfx/Primitive.java
@@ -0,0 +1,16 @@
+package com.axe.gfx;
+
+
+public enum Primitive
+{
+ Point,
+ Line,
+ LineStrip,
+ LineLoop,
+ Triangle,
+ TriangleStrip,
+ TriangleFan,
+ Quad,
+ QuadStrip,
+ Polygon;
+}
diff --git a/src/com/axe/gfx/ProjectionOutside.java b/src/com/axe/gfx/ProjectionOutside.java
new file mode 100644
index 0000000..7224862
--- /dev/null
+++ b/src/com/axe/gfx/ProjectionOutside.java
@@ -0,0 +1,8 @@
+package com.axe.gfx;
+
+public enum ProjectionOutside
+{
+ Ignore,
+ Clamp,
+ Relative
+}
diff --git a/src/com/axe/gfx/ReadableVertex.java b/src/com/axe/gfx/ReadableVertex.java
new file mode 100755
index 0000000..27a29c9
--- /dev/null
+++ b/src/com/axe/gfx/ReadableVertex.java
@@ -0,0 +1,8 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+
+public interface ReadableVertex
+{
+ public void read( ByteBuffer buffer );
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/Shader.java b/src/com/axe/gfx/Shader.java
new file mode 100755
index 0000000..4e70b5c
--- /dev/null
+++ b/src/com/axe/gfx/Shader.java
@@ -0,0 +1,337 @@
+package com.axe.gfx;
+
+import com.axe.color.Color;
+import com.axe.math.Scalarf;
+import com.axe.math.Scalari;
+import com.axe.math.Vec2f;
+import com.axe.math.Vec2i;
+import com.axe.math.Vec3f;
+import com.axe.math.Vec3i;
+import com.axe.math.Vec4f;
+import com.axe.resource.Resource;
+
+public interface Shader extends Resource
+{
+
+ public ShaderObject[] getObjects();
+
+ public void bind();
+
+ public void unbind();
+
+ // Direct Location
+
+ public void set( int location, boolean x );
+
+ public void set( int location, float x );
+
+ public void set( int location, float[] x );
+
+ public void set( int location, Scalarf v );
+
+ public void set( int location, float x, float y );
+
+ public void set( int location, Vec2f v );
+
+ public void set( int location, Vec2f[] v );
+
+ public void set( int location, float x, float y, float z );
+
+ public void set( int location, Vec3f v );
+
+ public void set( int location, Vec3f[] v );
+
+ public void set( int location, float x, float y, float z, float w );
+
+ public void set( int location, Vec4f v );
+
+ public void set( int location, Color color );
+
+ public void set( int location, Vec4f[] v );
+
+ public void set( int location, Color[] v );
+
+ public void set( int location, int x );
+
+ public void set( int location, int[] x );
+
+ public void set( int location, Scalari v );
+
+ public void set( int location, int x, int y );
+
+ public void set( int location, Vec2i v );
+
+ public void set( int location, Vec2i[] v );
+
+ public void set( int location, int x, int y, int z );
+
+ public void set( int location, Vec3i v );
+
+ public void set( int location, Vec3i[] v );
+
+ public void set( int location, int x, int y, int z, int w );
+
+ public int getLocation( Enum> enumConstant );
+
+ public int getLocation( String name );
+
+ public int getAttributeLocation( String name );
+
+ public > int getAttributeLocation( E enumConstant );
+
+
+ // Enumerated Variables
+
+ default public void set( Enum> enumConstant, boolean x )
+ {
+ set( getLocation( enumConstant ), x );
+ }
+
+ default public void set( Enum> enumConstant, float x )
+ {
+ set( getLocation( enumConstant ), x );
+ }
+
+ default public void set( Enum> enumConstant, float[] x )
+ {
+ set( getLocation( enumConstant ), x );
+ }
+
+ default public void set( Enum> enumConstant, Scalarf v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, float x, float y )
+ {
+ set( getLocation( enumConstant ), x, y );
+ }
+
+ default public void set( Enum> enumConstant, Vec2f v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, Vec2f[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, float x, float y, float z )
+ {
+ set( getLocation( enumConstant ), x, y, z );
+ }
+
+ default public void set( Enum> enumConstant, Vec3f v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, Vec3f[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, float x, float y, float z, float w )
+ {
+ set( getLocation( enumConstant ), x, y, z, w );
+ }
+
+ default public void set( Enum> enumConstant, Vec4f v )
+ {
+ set( getLocation( enumConstant ), v.x, v.y, v.z, v.w );
+ }
+
+ default public void set( Enum> enumConstant, Color color )
+ {
+ set( getLocation( enumConstant ), color );
+ }
+
+ default public void set( Enum> enumConstant, Vec4f[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, Color[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, int x )
+ {
+ set( getLocation( enumConstant ), x );
+ }
+
+ default public void set( Enum> enumConstant, int[] x )
+ {
+ set( getLocation( enumConstant ), x );
+ }
+
+ default public void set( Enum> enumConstant, Scalari v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, int x, int y )
+ {
+ set( getLocation( enumConstant ), x, y );
+ }
+
+ default public void set( Enum> enumConstant, Vec2i v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, Vec2i[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, int x, int y, int z )
+ {
+ set( getLocation( enumConstant ), x, y, z );
+ }
+
+ default public void set( Enum> enumConstant, Vec3i v )
+ {
+ set( getLocation( enumConstant ), v.x, v.y, v.z );
+ }
+
+ default public void set( Enum> enumConstant, Vec3i[] v )
+ {
+ set( getLocation( enumConstant ), v );
+ }
+
+ default public void set( Enum> enumConstant, int x, int y, int z, int w )
+ {
+ set( getLocation( enumConstant ), x, y, z, w );
+ }
+
+ // Dynamic Variables
+
+ default public void set( String name, boolean x )
+ {
+ set( getLocation( name ), x );
+ }
+
+ default public void set( String name, float x )
+ {
+ set( getLocation( name ), x );
+ }
+
+ default public void set( String name, float[] x )
+ {
+ set( getLocation( name ), x );
+ }
+
+ default public void set( String name, Scalarf v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, float x, float y )
+ {
+ set( getLocation( name ), x, y );
+ }
+
+ default public void set( String name, Vec2f v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, Vec2f[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, float x, float y, float z )
+ {
+ set( getLocation( name ), x, y, z );
+ }
+
+ default public void set( String name, Vec3f v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, Vec3f[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, float x, float y, float z, float w )
+ {
+ set( getLocation( name ), x, y, z, w );
+ }
+
+ default public void set( String name, Vec4f v )
+ {
+ set( getLocation( name ), v.x, v.y, v.z, v.w );
+ }
+
+ default public void set( String name, Color color )
+ {
+ set( getLocation( name ), color );
+ }
+
+ default public void set( String name, Vec4f[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, Color[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, int x )
+ {
+ set( getLocation( name ), x );
+ }
+
+ default public void set( String name, int[] x )
+ {
+ set( getLocation( name ), x );
+ }
+
+ default public void set( String name, Scalari v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, int x, int y )
+ {
+ set( getLocation( name ), x, y );
+ }
+
+ default public void set( String name, Vec2i v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, Vec2i[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, int x, int y, int z )
+ {
+ set( getLocation( name ), x, y, z );
+ }
+
+ default public void set( String name, Vec3i v )
+ {
+ set( getLocation( name ), v.x, v.y, v.z );
+ }
+
+ default public void set( String name, Vec3i[] v )
+ {
+ set( getLocation( name ), v );
+ }
+
+ default public void set( String name, int x, int y, int z, int w )
+ {
+ set( getLocation( name ), x, y, z, w );
+ }
+
+}
diff --git a/src/com/axe/gfx/ShaderObject.java b/src/com/axe/gfx/ShaderObject.java
new file mode 100755
index 0000000..62ae2e5
--- /dev/null
+++ b/src/com/axe/gfx/ShaderObject.java
@@ -0,0 +1,16 @@
+package com.axe.gfx;
+
+import org.magnos.asset.AssetInfo;
+
+import com.axe.resource.Resource;
+
+public interface ShaderObject extends Resource
+{
+
+ public CharSequence getCode();
+
+ public ShaderObjectType getType();
+
+ public AssetInfo getInfo();
+
+}
diff --git a/src/com/axe/gfx/ShaderObjectType.java b/src/com/axe/gfx/ShaderObjectType.java
new file mode 100755
index 0000000..9e7597a
--- /dev/null
+++ b/src/com/axe/gfx/ShaderObjectType.java
@@ -0,0 +1,10 @@
+package com.axe.gfx;
+
+public enum ShaderObjectType
+{
+ Fragment,
+ Vertex,
+ Geometry,
+ TesselationControl,
+ TesselationEvaluation
+}
diff --git a/src/com/axe/gfx/Texture.java b/src/com/axe/gfx/Texture.java
new file mode 100644
index 0000000..12892a2
--- /dev/null
+++ b/src/com/axe/gfx/Texture.java
@@ -0,0 +1,175 @@
+package com.axe.gfx;
+
+import com.axe.math.Bound2i;
+import com.axe.resource.Resource;
+import com.axe.tile.Tile;
+
+public interface Texture extends Resource
+{
+
+ public TextureInfo getInfo();
+
+ public void bind();
+
+ public void unbind();
+
+ default public float s(float x)
+ {
+ return x * getPixelWidth() + getPixelOffsetX();
+ }
+
+ default public float t(float y)
+ {
+ return y * getPixelHeight() + getPixelOffsetY();
+ }
+
+ default public Coord coord(float x, float y)
+ {
+ return new Coord(
+ x * getPixelWidth() + getPixelOffsetX(),
+ y * getPixelHeight() + getPixelOffsetY()
+ );
+ }
+
+ default public Tile tileExact(float x, float y, float width, float height)
+ {
+ return tileExact( x, y, width, height, new Tile() );
+ }
+
+ default public Tile tileExact(float x, float y, float width, float height, Tile out)
+ {
+ float pixelW = getPixelWidth();
+ float pixelH = getPixelHeight();
+
+ float left = x * pixelW;
+ float top = y * pixelH;
+ float right = (x + width) * pixelW;
+ float bottom = (y + height) * pixelH;
+
+ return out.set(this, left, right, top, bottom);
+ }
+
+ default public Tile tile(float x, float y, float width, float height)
+ {
+ return tile( x, y, width, height, new Tile() );
+ }
+
+ default public Tile tile(float x, float y, float width, float height, Tile out)
+ {
+ float pixelW = getPixelWidth();
+ float pixelH = getPixelHeight();
+ float offW = getPixelOffsetX();
+ float offH = getPixelOffsetY();
+
+ float left = x * pixelW + offW;
+ float top = y * pixelH + offH;
+ float right = (x + width) * pixelW - offW;
+ float bottom = (y + height) * pixelH - offH;
+
+ return out.set( this, left, right, top, bottom );
+ }
+
+ default public Tile tile()
+ {
+ return tile(0, 0, getImageWidth(), getImageHeight() );
+ }
+
+ default public Tile tile(Tile out)
+ {
+ return tile(0, 0, getImageWidth(), getImageHeight(), out );
+ }
+
+ default public Tile tileExact()
+ {
+ return tileExact( 0, 0, getImageWidth(), getImageHeight() );
+ }
+
+ default public Tile tileExact(Tile out)
+ {
+ return tileExact( 0, 0, getImageWidth(), getImageHeight(), out );
+ }
+
+ default public void unpad(Tile tile)
+ {
+ float offW = getPixelOffsetX();
+ float offH = getPixelOffsetY();
+
+ tile.s0 -= offW;
+ tile.s1 += offW;
+ tile.t0 -= offH;
+ tile.t1 += offH;
+ }
+
+ default public void unpad(Tile[] tiles)
+ {
+ for (int i = 0; i < tiles.length; i++)
+ {
+ unpad( tiles[i] );
+ }
+ }
+
+ default public void pad(Tile tile)
+ {
+ float offW = getPixelOffsetX();
+ float offH = getPixelOffsetY();
+
+ tile.s0 += offW;
+ tile.s1 -= offW;
+ tile.t0 += offH;
+ tile.t1 -= offH;
+ }
+
+ default public void pad(Tile[] tiles)
+ {
+ for (int i = 0; i < tiles.length; i++)
+ {
+ pad( tiles[i] );
+ }
+ }
+
+ default public Bound2i bound(Tile tile)
+ {
+ return bound( tile, new Bound2i() );
+ }
+
+ default public Bound2i bound(Tile tile, Bound2i out)
+ {
+ float offW = getPixelOffsetX();
+ float offH = getPixelOffsetY();
+ int w = width();
+ int h = height();
+
+ out.l = (int)((tile.s0 - offW) * w);
+ out.t = (int)((tile.t0 - offH) * h);
+ out.r = (int)((tile.s1 + offW) * w);
+ out.b = (int)((tile.t1 + offH) * h);
+
+ return out;
+ }
+
+ public int width();
+ public int height();
+
+ public int getImageHeight();
+ public int getImageWidth();
+
+ public boolean hasAlpha();
+
+ public float getPixelWidth();
+ public float getPixelOffsetX();
+ public float getPixelHeight();
+ public float getPixelOffsetY();
+
+ public Magnify magnify();
+ public void magnify(Magnify mag);
+
+ public Minify minify();
+ public void minify(Minify min);
+
+ public Wrap wrap();
+ public void wrap(Wrap wrap);
+
+ public int anisotrophy();
+ public void anisotrophy(int anisotrophy);
+
+}
diff --git a/src/com/axe/gfx/TextureInfo.java b/src/com/axe/gfx/TextureInfo.java
new file mode 100755
index 0000000..76dd205
--- /dev/null
+++ b/src/com/axe/gfx/TextureInfo.java
@@ -0,0 +1,175 @@
+
+package com.axe.gfx;
+
+import org.magnos.asset.base.BaseAssetInfo;
+
+import com.axe.io.DataModel;
+import com.axe.io.InputModel;
+import com.axe.io.OutputModel;
+
+
+public class TextureInfo extends BaseAssetInfo implements DataModel
+{
+
+ protected boolean mipmap;
+ protected Wrap wrap;
+ protected Minify minify;
+ protected Magnify magnify;
+ protected int anisotrophy = 1;
+
+ public TextureInfo()
+ {
+ this( defaultMipMap, defaultWrap, defaultMinify, defaultMagnify, defaultAnisotrophy );
+ }
+
+ public TextureInfo( boolean mipmap, Wrap wrap )
+ {
+ this( mipmap, wrap, defaultMinify, defaultMagnify, defaultAnisotrophy );
+ }
+
+ public TextureInfo( boolean mipmap, Wrap wrap, Minify minify, Magnify magnify )
+ {
+ this( mipmap, wrap, minify, magnify, defaultAnisotrophy );
+ }
+
+ public TextureInfo( boolean mipmap, Wrap wrap, Minify minify, Magnify magnify, int anisotrophy )
+ {
+ super( Texture.class );
+
+ this.mipmap = mipmap;
+ this.wrap = wrap;
+ this.minify = minify;
+ this.magnify = magnify;
+ this.anisotrophy = anisotrophy;
+ }
+
+ public boolean isMipMap()
+ {
+ return mipmap;
+ }
+
+ public void setMipMap( boolean mipmap )
+ {
+ this.mipmap = mipmap;
+ }
+
+ public Wrap getWrap()
+ {
+ return wrap;
+ }
+
+ public void setWrap( Wrap wrap )
+ {
+ this.wrap = wrap;
+ }
+
+ public Minify getMinify()
+ {
+ return minify;
+ }
+
+ public void setMinify( Minify minify )
+ {
+ this.minify = minify;
+ }
+
+ public Magnify getMagnify()
+ {
+ return magnify;
+ }
+
+ public void setMagnify( Magnify magnify )
+ {
+ this.magnify = magnify;
+ }
+
+ public int getAnisotrophy()
+ {
+ return anisotrophy;
+ }
+
+ public void setAnisotrophy( int anisotrophy )
+ {
+ this.anisotrophy = anisotrophy;
+ }
+
+ public boolean equals( Object o )
+ {
+ if (o instanceof TextureInfo)
+ {
+ TextureInfo other = (TextureInfo)o;
+ return (other.anisotrophy == anisotrophy &&
+ other.mipmap == mipmap &&
+ other.magnify == magnify &&
+ other.minify == minify && other.wrap == wrap);
+ }
+ return false;
+ }
+
+ protected static boolean defaultMipMap = true;
+ protected static Wrap defaultWrap = Wrap.Edge;
+ protected static Minify defaultMinify = Minify.Linear;
+ protected static Magnify defaultMagnify = Magnify.Linear;
+ protected static int defaultAnisotrophy = 1;
+
+ public static Wrap getDefaultWrap()
+ {
+ return defaultWrap;
+ }
+
+ public static void setDefaultWrap( Wrap wrap )
+ {
+ defaultWrap = wrap;
+ }
+
+ public static Minify getDefaultMinify()
+ {
+ return defaultMinify;
+ }
+
+ public static void setDefaultMinify( Minify minify )
+ {
+ defaultMinify = minify;
+ }
+
+ public static Magnify getDefaultMagnify()
+ {
+ return defaultMagnify;
+ }
+
+ public static void setDefaultMagnify( Magnify magnify )
+ {
+ defaultMagnify = magnify;
+ }
+
+ public static int getDefaultAnisotrophy()
+ {
+ return defaultAnisotrophy;
+ }
+
+ public static void setDefaultAnisotrophy( int anisotrophy )
+ {
+ defaultAnisotrophy = anisotrophy;
+ }
+
+ @Override
+ public void read( InputModel input )
+ {
+ mipmap = input.readBoolean( "mipmap" );
+ wrap = input.readEnum( "wrap", Wrap.class );
+ minify = input.readEnum( "minify", Minify.class );
+ magnify = input.readEnum( "magnify", Magnify.class );
+ anisotrophy = input.readInt( "anistrophy" );
+ }
+
+ @Override
+ public void write( OutputModel output )
+ {
+ output.write( "mipmap", mipmap );
+ output.writeEnum( "wrap", wrap );
+ output.writeEnum( "minify", minify );
+ output.writeEnum( "magnify", magnify );
+ output.write( "anistrophy", anisotrophy );
+ }
+
+}
diff --git a/src/com/axe/gfx/VertexBuffer.java b/src/com/axe/gfx/VertexBuffer.java
new file mode 100644
index 0000000..8a5de17
--- /dev/null
+++ b/src/com/axe/gfx/VertexBuffer.java
@@ -0,0 +1,142 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+
+public interface VertexBuffer
+{
+
+ // clear buffer data
+ public void reset(VertexMesh vb);
+
+ // select mesh for reading
+ default public boolean load()
+ {
+ return load( mesh(), 0, mesh().vertices() );
+ }
+
+ default public boolean load(VertexMesh mesh)
+ {
+ return load( mesh, 0, mesh.vertices() );
+ }
+
+ public boolean load(VertexMesh mesh, int offset, int count);
+
+ // the current mesh being read or written to.
+ public VertexMesh mesh();
+
+ // move position to next vertex. only necessary when writing or
+ // reading directly.
+ public void next();
+
+ // set position given vertex index
+ public void vertex(int index);
+
+ // maximum number of vertex
+ public int capacity();
+
+ // number of vertices currently written
+ public int vertices();
+
+ // number of vertices currently available
+ public int remaining();
+
+ // the current byte buffer being written to
+ public ByteBuffer data();
+
+
+ default public boolean write(WritableVertex vertex)
+ {
+ final boolean has = remaining() > 0;
+
+ if (has)
+ {
+ vertex.write( data() );
+ next();
+ }
+
+ return has;
+ }
+
+ default public int write(WritableVertex[] vertex)
+ {
+ return write( vertex, 0, vertex.length );
+ }
+
+ default public int write(WritableVertex[] vertex, int offset)
+ {
+ return write( vertex, offset, vertex.length - offset );
+ }
+
+ default public int write(WritableVertex[] vertex, int offset, int length)
+ {
+ final int end = offset + length;
+ int written = 0;
+
+ for (int i = offset; i < end; i++)
+ {
+ if ( write( vertex[ i ] ) )
+ {
+ written++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return written;
+ }
+
+ default public boolean read(ReadableVertex vertex)
+ {
+ final boolean has = remaining() > 0;
+
+ if (has)
+ {
+ vertex.read( data() );
+ next();
+ }
+
+ return has;
+ }
+
+ default public int read(ReadableVertex[] vertex)
+ {
+ return read( vertex, 0, vertex.length );
+ }
+
+ default public int read(ReadableVertex[] vertex, int offset)
+ {
+ return read( vertex, offset, vertex.length - offset );
+ }
+
+ default public int read(ReadableVertex[] vertex, int offset, int length)
+ {
+ final int end = offset + length;
+ int read = 0;
+
+ for (int i = offset; i < end; i++)
+ {
+ if ( read( vertex[ i ] ) )
+ {
+ read++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return read;
+ }
+
+ // with the current - update the given buffer
+ default public boolean save()
+ {
+ return save( 0 );
+ }
+
+ // update part of the buffer
+ public boolean save(int offset);
+
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/VertexFormat.java b/src/com/axe/gfx/VertexFormat.java
new file mode 100755
index 0000000..298c2df
--- /dev/null
+++ b/src/com/axe/gfx/VertexFormat.java
@@ -0,0 +1,119 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.axe.util.Buffers;
+
+public class VertexFormat
+{
+ public final Primitive primitive;
+ public final int vertexDimension;
+ public final DataType vertexType;
+ public final int colorComponents;
+ public final DataType colorType;
+ public final int secondaryColorComponents;
+ public final DataType secondaryColorType;
+ public final int normalDimension;
+ public final DataType normalType;
+ public final int textures;
+ public final int[] textureDimension;
+ public final DataType[] textureType;
+ public final int attributes;
+ public final int[] attributeIndex;
+ public final int[] attributeSize;
+ public final DataType[] attributeType;
+ public final boolean[] attributeNormalize;
+
+ public final boolean aligned;
+ public final int size;
+ public final int stride;
+ public final int padding;
+ public final int vertexOffset;
+ public final int normalOffset;
+ public final int colorOffset;
+ public final int secondaryColorOffset;
+ public final int[] textureOffsets;
+ public final int[] attributeOffset;
+
+ public final VertexFormatBuilder builder;
+
+ public VertexFormat( VertexFormatBuilder builder )
+ {
+ this.builder = builder;
+
+ this.primitive = builder.getPrimitive();
+ this.vertexDimension = builder.getVertexDimension();
+ this.vertexType = builder.getVertexType();
+ this.colorComponents = builder.getColorComponents();
+ this.colorType = builder.getColorType();
+ this.secondaryColorComponents = builder.getSecondaryColorComponents();
+ this.secondaryColorType = builder.getSecondaryColorType();
+ this.normalDimension = builder.getNormalDimension();
+ this.normalType = builder.getNormalType();
+ this.textures = builder.getTextures();
+ this.textureDimension = builder.getTextureDimension();
+ this.textureType = builder.getTextureType();
+ this.attributes = builder.getAttributes();
+ this.attributeIndex = builder.getAttributeIndex();
+ this.attributeSize = builder.getAttributeSize();
+ this.attributeType = builder.getAttributeType();
+ this.attributeNormalize = builder.getAttributeNormalize();
+
+ this.aligned = builder.isAligned();
+ this.size = builder.getSize();
+ this.stride = (aligned ? builder.getStride() : size);
+ this.padding = builder.getPadding();
+ this.vertexOffset = builder.getVertexOffset();
+ this.normalOffset = builder.getNormalOffset();
+ this.colorOffset = builder.getColorOffset();
+ this.secondaryColorOffset = builder.getSecondaryColorOffset();
+ this.textureOffsets = builder.getTextureOffsets();
+ this.attributeOffset = builder.getAttributeOffsets();
+ }
+
+ public VertexFormat( Primitive primitive, VertexMeshType type, int vertexDimension, DataType vertexType, int colorComponents, DataType colorType, int secondaryColorComponents, DataType secondaryColorType, int normalDimension, DataType normalType, int textures, int[] textureDimension, DataType[] textureType, int attributes, int[] attributeIndex, int[] attributeSize, DataType[] attributeType, boolean[] attributeNormalize, boolean aligned, int size, int stride, int padding, int vertexOffset, int normalOffset, int colorOffset, int secondaryColorOffset, int[] textureOffsets, int[] attributeOffset )
+ {
+ this.builder = null;
+
+ this.primitive = primitive;
+ this.vertexDimension = vertexDimension;
+ this.vertexType = vertexType;
+ this.colorComponents = colorComponents;
+ this.colorType = colorType;
+ this.secondaryColorComponents = secondaryColorComponents;
+ this.secondaryColorType = secondaryColorType;
+ this.normalDimension = normalDimension;
+ this.normalType = normalType;
+ this.textures = textures;
+ this.textureDimension = textureDimension;
+ this.textureType = textureType;
+ this.attributes = attributes;
+ this.attributeIndex = attributeIndex;
+ this.attributeSize = attributeSize;
+ this.attributeType = attributeType;
+ this.attributeNormalize = attributeNormalize;
+ this.aligned = aligned;
+ this.size = size;
+ this.stride = (aligned ? stride : size);
+ this.padding = padding;
+ this.vertexOffset = vertexOffset;
+ this.normalOffset = normalOffset;
+ this.colorOffset = colorOffset;
+ this.secondaryColorOffset = secondaryColorOffset;
+ this.textureOffsets = textureOffsets;
+ this.attributeOffset = attributeOffset;
+ }
+
+ public ByteBuffer getBuffer( int vertices )
+ {
+ return Buffers.bytes( vertices * stride );
+ }
+
+ @Override
+ public String toString()
+ {
+ return "VertexFormat [primitive=" + primitive + ", vertexDimension=" + vertexDimension + ", vertexType=" + vertexType + ", colorComponents=" + colorComponents + ", colorType=" + colorType + ", secondaryColorComponents=" + secondaryColorComponents + ", secondaryColorType=" + secondaryColorType + ", normalDimension=" + normalDimension + ", normalType=" + normalType + ", textures=" + textures + ", textureDimension=" + Arrays.toString( textureDimension ) + ", textureType=" + Arrays.toString( textureType ) + ", attributes=" + attributes + ", attributeIndex=" + Arrays.toString( attributeIndex ) + ", attributeSize=" + Arrays.toString( attributeSize ) + ", attributeType=" + Arrays.toString( attributeType ) + ", attributeNormalize=" + Arrays.toString( attributeNormalize ) + ", aligned=" + aligned + ", size=" + size + ", stride=" + stride + ", padding=" + padding + ", vertexOffset=" + vertexOffset + ", normalOffset=" + normalOffset + ", colorOffset=" + colorOffset + ", secondaryColorOffset=" + secondaryColorOffset + ", textureOffsets=" + Arrays.toString( textureOffsets ) + ", attributeOffset=" + Arrays.toString( attributeOffset ) + ", builder=" + builder + "]";
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/VertexFormatBuilder.java b/src/com/axe/gfx/VertexFormatBuilder.java
new file mode 100755
index 0000000..0c91d8c
--- /dev/null
+++ b/src/com/axe/gfx/VertexFormatBuilder.java
@@ -0,0 +1,544 @@
+
+package com.axe.gfx;
+
+import java.util.Arrays;
+
+import com.axe.core.Factory;
+import com.axe.util.Array;
+
+
+public class VertexFormatBuilder implements Factory
+{
+
+ public Primitive primitive = Primitive.Triangle;
+ public int vertexDimension = 3; // 2,3,4
+ public DataType vertexType = DataType.Float;
+ public int colorComponents = 0; // 0,3,4
+ public DataType colorType = DataType.Byte;
+ public int secondaryColorComponents = 0; // 0,3,4
+ public DataType secondaryColorType = DataType.Byte;
+ public int normalDimension = 0; // 0,3
+ public DataType normalType = DataType.Float;
+ public int textures = 1; // 0,1,2,3..GL_MAX_TEXTURE_COORDS-1
+ public int[] textureDimension = { 2 }; // 1,2,3,4
+ public DataType[] textureType = { DataType.Float };
+ public int attributes = 0;
+ public int[] attributeIndex = {};
+ public int[] attributeSize = {};
+ public DataType[] attributeType = {};
+ public boolean[] attributeNormalize = {};
+ public boolean aligned = true;
+
+ public boolean isValid()
+ {
+ return isVertexValid() && isColorValid() && isSecondaryColorValid() && isNormalValid() && isTextureValid() && isAttributesValid();
+ }
+
+ public boolean isVertexValid()
+ {
+ if (vertexDimension != 2 && vertexDimension != 3 && vertexDimension != 4)
+ {
+ return false;
+ }
+
+ if (vertexType == null ||
+ (vertexType != DataType.Short && vertexType != DataType.Integer &&
+ vertexType != DataType.Float && vertexType != DataType.Double))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isColorValid()
+ {
+ if (colorComponents != 0 && colorComponents != 3 && colorComponents != 4)
+ {
+ return false;
+ }
+
+ if (colorType == null)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isSecondaryColorValid()
+ {
+ if (secondaryColorComponents != 0 && secondaryColorComponents != 3 && secondaryColorComponents != 4)
+ {
+ return false;
+ }
+
+ if (secondaryColorType == null)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isNormalValid()
+ {
+ if (normalDimension != 0 && normalDimension != 3)
+ {
+ return false;
+ }
+
+ if (normalType == null ||
+ (normalType != DataType.Short && normalType != DataType.Integer &&
+ normalType != DataType.Float && normalType != DataType.Double))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isTextureValid()
+ {
+ /*
+ if (textures < 0 || textures >= glGetInteger( GL_MAX_TEXTURE_COORDS ))
+ {
+ return false;
+ }
+ */
+
+ if (textureDimension.length != textures)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < textures; i++)
+ {
+ int td = textureDimension[i];
+
+ if (td != 1 && td != 2 && td != 3 && td != 4)
+ {
+ return false;
+ }
+ }
+
+ if (textureType.length != textures)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < textures; i++)
+ {
+ DataType tt = textureType[i];
+
+ if (tt == null || (tt != DataType.Short && tt != DataType.Integer && tt != DataType.Float && tt != DataType.Double))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean isAttributesValid()
+ {
+ for (int i = 0; i < attributes; i++)
+ {
+ if (attributeSize[i] < 1 || attributeSize[i] > 4)
+ {
+ return false;
+ }
+
+ if (attributeType[i] == null)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int getStride()
+ {
+ int stride = getSize();
+
+ stride--;
+ stride |= (stride >> 1);
+ stride |= (stride >> 2);
+ stride |= (stride >> 4);
+ stride |= (stride >> 8);
+ stride |= (stride >> 16);
+ stride++;
+
+ return stride;
+ }
+
+ public int getPadding()
+ {
+ return getStride() - getSize();
+ }
+
+ public int getSize()
+ {
+ int size = 0;
+
+ size += vertexDimension * vertexType.bytes;
+ size += normalDimension * normalType.bytes;
+ size += colorComponents * colorType.bytes;
+ size += secondaryColorComponents * secondaryColorType.bytes;
+
+ for (int i = 0; i < textures; i++)
+ {
+ size += textureDimension[i] * textureType[i].bytes;
+ }
+
+ for (int i = 0; i < attributes; i++)
+ {
+ size += attributeSize[i] * attributeType[i].bytes;
+ }
+
+ return size;
+ }
+
+ public boolean isAligned()
+ {
+ return aligned;
+ }
+
+ public VertexFormatBuilder setAligned( boolean aligned )
+ {
+ this.aligned = aligned;
+ return this;
+ }
+
+ public int getVertexOffset()
+ {
+ return 0;
+ }
+
+ public int getNormalOffset()
+ {
+ return (vertexDimension * vertexType.bytes);
+ }
+
+ public int getColorOffset()
+ {
+ return (vertexDimension * vertexType.bytes) +
+ (normalDimension * normalType.bytes);
+ }
+
+ public int getSecondaryColorOffset()
+ {
+ return (vertexDimension * vertexType.bytes) +
+ (normalDimension * normalType.bytes) +
+ (colorComponents * colorType.bytes);
+ }
+
+ public int[] getTextureOffsets()
+ {
+ int start = (vertexDimension * vertexType.bytes) +
+ (normalDimension * normalType.bytes) +
+ (colorComponents * colorType.bytes) +
+ (secondaryColorComponents * secondaryColorType.bytes);
+
+ int[] offsets = new int[textures];
+
+ for (int i = 0; i < textures; i++)
+ {
+ offsets[i] = start;
+
+ start += textureDimension[i] * textureType[i].bytes;
+ }
+
+ return offsets;
+ }
+
+ public int[] getAttributeOffsets()
+ {
+ int start = (vertexDimension * vertexType.bytes) +
+ (normalDimension * normalType.bytes) +
+ (colorComponents * colorType.bytes) +
+ (secondaryColorComponents * secondaryColorType.bytes);
+
+ for (int i = 0; i < textures; i++)
+ {
+ start += textureDimension[i] * textureType[i].bytes;
+ }
+
+ int[] offsets = new int[attributes];
+
+ for (int i = 0; i < attributes; i++)
+ {
+ offsets[i] = start;
+
+ start += attributeSize[i] * attributeType[i].bytes;
+ }
+
+ return offsets;
+ }
+
+ public Primitive getPrimitive()
+ {
+ return primitive;
+ }
+
+ public VertexFormatBuilder setPrimitive( Primitive primitive )
+ {
+ this.primitive = primitive;
+ return this;
+ }
+
+ public VertexFormatBuilder setVertex( int vertexDimension, DataType vertexType )
+ {
+ this.vertexDimension = vertexDimension;
+ this.vertexType = vertexType;
+ return this;
+ }
+
+ public int getVertexDimension()
+ {
+ return vertexDimension;
+ }
+
+ public VertexFormatBuilder setVertexDimension( int vertexDimension )
+ {
+ this.vertexDimension = vertexDimension;
+ return this;
+ }
+
+ public DataType getVertexType()
+ {
+ return vertexType;
+ }
+
+ public VertexFormatBuilder setVertexType( DataType vertexType )
+ {
+ this.vertexType = vertexType;
+ return this;
+ }
+
+ public VertexFormatBuilder setColor( int colorComponents, DataType colorType )
+ {
+ this.colorComponents = colorComponents;
+ this.colorType = colorType;
+ return this;
+ }
+
+ public int getColorComponents()
+ {
+ return colorComponents;
+ }
+
+ public VertexFormatBuilder setColorComponents( int colorComponents )
+ {
+ this.colorComponents = colorComponents;
+ return this;
+ }
+
+ public DataType getColorType()
+ {
+ return colorType;
+ }
+
+ public VertexFormatBuilder setColorType( DataType colorType )
+ {
+ this.colorType = colorType;
+ return this;
+ }
+
+
+ public VertexFormatBuilder setSecondaryColor( int secondaryColorComponents, DataType secondaryColorType )
+ {
+ this.secondaryColorComponents = secondaryColorComponents;
+ this.secondaryColorType = secondaryColorType;
+ return this;
+ }
+
+ public int getSecondaryColorComponents()
+ {
+ return secondaryColorComponents;
+ }
+
+ public VertexFormatBuilder setSecondaryColorComponents( int secondaryColorComponents )
+ {
+ this.secondaryColorComponents = secondaryColorComponents;
+ return this;
+ }
+
+ public DataType getSecondaryColorType()
+ {
+ return secondaryColorType;
+ }
+
+ public VertexFormatBuilder setSecondaryColorType( DataType secondaryColorType )
+ {
+ this.secondaryColorType = secondaryColorType;
+ return this;
+ }
+
+ public VertexFormatBuilder setNormal( int normalDimension, DataType normalType )
+ {
+ this.normalDimension = normalDimension;
+ this.normalType = normalType;
+ return this;
+ }
+
+ public int getNormalDimension()
+ {
+ return normalDimension;
+ }
+
+ public VertexFormatBuilder setNormalDimension( int normalDimension )
+ {
+ this.normalDimension = normalDimension;
+ return this;
+ }
+
+ public DataType getNormalType()
+ {
+ return normalType;
+ }
+
+ public VertexFormatBuilder setNormalType( DataType normalType )
+ {
+ this.normalType = normalType;
+ return this;
+ }
+
+ public VertexFormatBuilder setTextures( int textures, int[] textureDimension, DataType[] textureType )
+ {
+ this.textures = textures;
+ this.textureDimension = textureDimension;
+ this.textureType = textureType;
+ return this;
+ }
+
+ public int getTextures()
+ {
+ return textures;
+ }
+
+ public VertexFormatBuilder setTextures( int textures )
+ {
+ this.textures = textures;
+
+ if (textures != textureDimension.length)
+ {
+ textureDimension = Arrays.copyOf( textureDimension, textures );
+ }
+
+ if (textures != textureType.length)
+ {
+ textureType = Arrays.copyOf( textureType, textures );
+ }
+
+ return this;
+ }
+
+ public VertexFormatBuilder addTexture( int dimensions, DataType type )
+ {
+ textures++;
+
+ textureDimension = Arrays.copyOf( textureDimension, textures );
+ textureDimension[textures - 1] = dimensions;
+
+ textureType = Arrays.copyOf( textureType, textures );
+ textureType[textures - 1] = type;
+
+ return this;
+ }
+
+ public int[] getTextureDimension()
+ {
+ return textureDimension;
+ }
+
+ public VertexFormatBuilder setTextureDimension( int ... textureDimension )
+ {
+ this.textureDimension = textureDimension;
+ return this;
+ }
+
+ public DataType[] getTextureType()
+ {
+ return textureType;
+ }
+
+ public VertexFormatBuilder setTextureType( DataType ... textureType )
+ {
+ this.textureType = textureType;
+ return this;
+ }
+
+ public VertexFormatBuilder addAttribute( int index, int size, DataType type, boolean normalize )
+ {
+ attributeIndex = Array.add( index, attributeIndex );
+ attributeType = Array.add( type, attributeType );
+ attributeSize = Array.add( size, attributeSize );
+ attributeNormalize = Array.add( normalize, attributeNormalize );
+ attributes++;
+ return this;
+ }
+
+ public int getAttributes()
+ {
+ return attributes;
+ }
+
+ public VertexFormatBuilder setAttributes( int attributes )
+ {
+ this.attributes = attributes;
+ return this;
+ }
+
+ public int[] getAttributeSize()
+ {
+ return attributeSize;
+ }
+
+ public VertexFormatBuilder setAttributeSize( int[] attributeSize )
+ {
+ this.attributeSize = attributeSize;
+ return this;
+ }
+
+ public DataType[] getAttributeType()
+ {
+ return attributeType;
+ }
+
+ public VertexFormatBuilder setAttributeType( DataType[] attributeType )
+ {
+ this.attributeType = attributeType;
+ return this;
+ }
+
+ public boolean[] getAttributeNormalize()
+ {
+ return attributeNormalize;
+ }
+
+ public VertexFormatBuilder setAttributeNormalize( boolean[] attributeNormalize )
+ {
+ this.attributeNormalize = attributeNormalize;
+ return this;
+ }
+
+ public int[] getAttributeIndex()
+ {
+ return attributeIndex;
+ }
+
+ public VertexFormatBuilder setAttributeIndex( int[] attributeIndex )
+ {
+ this.attributeIndex = attributeIndex;
+ return this;
+ }
+
+ @Override
+ public VertexFormat create()
+ {
+ return new VertexFormat( this );
+ }
+
+}
diff --git a/src/com/axe/gfx/VertexMesh.java b/src/com/axe/gfx/VertexMesh.java
new file mode 100644
index 0000000..c0955cf
--- /dev/null
+++ b/src/com/axe/gfx/VertexMesh.java
@@ -0,0 +1,59 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+import com.axe.util.Buffers;
+
+public interface VertexMesh
+{
+
+ public VertexFormat format();
+
+ public VertexMeshType type();
+
+ public int vertices();
+
+ public int size();
+
+ public void destroy();
+
+ // is the given mesh valid?
+ public boolean isValid();
+
+ // draw entire mesh
+ default public void draw()
+ {
+ draw( 0, vertices() );
+ }
+
+ // draw part of mesh
+ public void draw(int offset, int vertices);
+
+ // draw vertices at the given indices
+
+ default public void draw(short[] indices)
+ {
+ draw( Buffers.shorts( indices ) );
+ }
+
+ default public void draw(int[] indices)
+ {
+ draw( Buffers.ints( indices ) );
+ }
+
+ default public void draw(byte[] indices)
+ {
+ draw( Buffers.bytes( indices ) );
+ }
+
+ public void draw(ShortBuffer indices);
+
+ public void draw(IntBuffer indices);
+
+ public void draw(ByteBuffer indices);
+
+ public void draw(ByteBuffer indices, DataType indexType);
+
+}
\ No newline at end of file
diff --git a/src/com/axe/gfx/VertexMeshType.java b/src/com/axe/gfx/VertexMeshType.java
new file mode 100755
index 0000000..92f6498
--- /dev/null
+++ b/src/com/axe/gfx/VertexMeshType.java
@@ -0,0 +1,27 @@
+package com.axe.gfx;
+
+public enum VertexMeshType
+{
+ /* Static = set once, draw many times */
+ /* Dynamic = set each frame draw many times */
+ /* Stream = one time use */
+
+ Static,
+
+ StaticRead,
+
+ StaticCopy,
+
+ Dynamic,
+
+ DynamicRead,
+
+ DynamicCopy,
+
+ Stream,
+
+ StreamRead,
+
+ StreamCopy
+
+}
diff --git a/src/com/axe/gfx/Wrap.java b/src/com/axe/gfx/Wrap.java
new file mode 100755
index 0000000..bad4977
--- /dev/null
+++ b/src/com/axe/gfx/Wrap.java
@@ -0,0 +1,10 @@
+package com.axe.gfx;
+
+public enum Wrap
+{
+ Edge,
+ Border,
+ Default,
+ Repeat,
+ Mirror
+}
diff --git a/src/com/axe/gfx/WritableVertex.java b/src/com/axe/gfx/WritableVertex.java
new file mode 100755
index 0000000..b68e19d
--- /dev/null
+++ b/src/com/axe/gfx/WritableVertex.java
@@ -0,0 +1,8 @@
+package com.axe.gfx;
+
+import java.nio.ByteBuffer;
+
+public interface WritableVertex
+{
+ public void write( ByteBuffer buffer );
+}
\ No newline at end of file
diff --git a/src/com/axe/input/AbstractKeyEngine.java b/src/com/axe/input/AbstractKeyEngine.java
new file mode 100644
index 0000000..7589ae0
--- /dev/null
+++ b/src/com/axe/input/AbstractKeyEngine.java
@@ -0,0 +1,255 @@
+package com.axe.input;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+import com.axe.window.Window;
+
+public abstract class AbstractKeyEngine implements KeyEngine
+{
+
+ public KeyState[] states;
+ public InputStateAny shift;
+ public KeyState leftShift;
+ public KeyState rightShift;
+ public InputStateAny control;
+ public InputStateAny meta;
+ public InputStateAny command;
+ public InputStateAny alt;
+ public Queue queue;
+ public float pressDelay;
+ public float pressInterval;
+ public char[][] keyChars;
+
+ public AbstractKeyEngine()
+ {
+ int n = Key.values().length;
+
+ this.states = new KeyState[ n ];
+
+ while (--n >= 0)
+ {
+ this.states[n] = new KeyState(n);
+ }
+
+ this.leftShift = getKey( Key.LEFT_SHIFT );
+ this.rightShift = getKey( Key.RIGHT_SHIFT );
+ this.shift = new InputStateAny(
+ this.leftShift,
+ this.rightShift
+ );
+
+ this.control = new InputStateAny(
+ getKey( Key.LEFT_CONTROL ),
+ getKey( Key.RIGHT_CONTROL )
+ );
+
+ this.command = new InputStateAny(
+ getKey( Key.LEFT_COMMAND ),
+ getKey( Key.RIGHT_COMMAND )
+ );
+
+ this.alt = new InputStateAny(
+ getKey( Key.LEFT_ALT ),
+ getKey( Key.RIGHT_ALT )
+ );
+
+ this.meta = new InputStateAny(
+ getKey( Key.LEFT_COMMAND ),
+ getKey( Key.RIGHT_COMMAND ),
+ getKey( Key.LEFT_CONTROL ),
+ getKey( Key.RIGHT_CONTROL )
+ );
+
+ this.queue = new ArrayDeque<>();
+
+ this.pressDelay = DEFAULT_PRESS_DELAY;
+ this.pressInterval = DEFAULT_PRESS_INTERVAL;
+
+ this.keyChars = new char[Key.values().length][2];
+ this.loadChars();
+ }
+
+ public void init(long startTime)
+ {
+ for (int i = 0; i < states.length; i++)
+ {
+ states[ i ].changeTime = startTime;
+ }
+ }
+
+ public void tick(long currentTime)
+ {
+ for (int i = 0; i < states.length; i++)
+ {
+ states[ i ].tick( currentTime, pressDelay, pressInterval );
+ }
+
+ shift.update();
+ control.update();
+ command.update();
+ alt.update();
+ meta.update();
+
+ int charIndex = shift.down ? 1 : 0;
+
+ for (int i = 0; i < states.length; i++)
+ {
+ states[ i ].character = keyChars[ i ][ charIndex ];
+ }
+ }
+
+ public void queueKeyState(Key key, boolean down, long inputTime, Window inputWindow)
+ {
+ int charIndex = leftShift.down || rightShift.down ? 1 : 0;
+
+ KeyState state = new KeyState( key );
+
+ state.setDown( down, inputTime, inputWindow );
+ state.character = keyChars[ state.input ][ charIndex ];
+
+ queue.offer( state );
+ }
+
+ public void loadChars()
+ {
+ keyChars[ Key.N1.ordinal() ] = new char[] {'1', '!'};
+ keyChars[ Key.N2.ordinal() ] = new char[] {'2', '@'};
+ keyChars[ Key.N3.ordinal() ] = new char[] {'3', '#'};
+ keyChars[ Key.N4.ordinal() ] = new char[] {'4', '$'};
+ keyChars[ Key.N5.ordinal() ] = new char[] {'5', '%'};
+ keyChars[ Key.N6.ordinal() ] = new char[] {'6', '^'};
+ keyChars[ Key.N7.ordinal() ] = new char[] {'7', '&'};
+ keyChars[ Key.N8.ordinal() ] = new char[] {'8', '*'};
+ keyChars[ Key.N9.ordinal() ] = new char[] {'9', '('};
+ keyChars[ Key.N0.ordinal() ] = new char[] {'0', ')'};
+ keyChars[ Key.MINUS.ordinal() ] = new char[] {'-', '_'};
+ keyChars[ Key.EQUALS.ordinal() ] = new char[] {'=', '+'};
+ keyChars[ Key.BACK.ordinal() ] = new char[] {'\b', '\b'};
+ keyChars[ Key.TAB.ordinal() ] = new char[] {'\t', '\t'};
+ keyChars[ Key.Q.ordinal() ] = new char[] {'q', 'Q'};
+ keyChars[ Key.W.ordinal() ] = new char[] {'w', 'W'};
+ keyChars[ Key.E.ordinal() ] = new char[] {'e', 'E'};
+ keyChars[ Key.R.ordinal() ] = new char[] {'r', 'R'};
+ keyChars[ Key.T.ordinal() ] = new char[] {'t', 'T'};
+ keyChars[ Key.Y.ordinal() ] = new char[] {'y', 'Y'};
+ keyChars[ Key.U.ordinal() ] = new char[] {'u', 'U'};
+ keyChars[ Key.I.ordinal() ] = new char[] {'i', 'I'};
+ keyChars[ Key.O.ordinal() ] = new char[] {'o', 'O'};
+ keyChars[ Key.P.ordinal() ] = new char[] {'p', 'P'};
+ keyChars[ Key.LEFT_BRACKET.ordinal() ] = new char[] {'[', '{'};
+ keyChars[ Key.RIGHT_BRACKET.ordinal() ] = new char[] {']', '}'};
+ keyChars[ Key.RETURN.ordinal() ] = new char[] {'\n', '\n'};
+ keyChars[ Key.A.ordinal() ] = new char[] {'a', 'A'};
+ keyChars[ Key.S.ordinal() ] = new char[] {'s', 'S'};
+ keyChars[ Key.D.ordinal() ] = new char[] {'d', 'D'};
+ keyChars[ Key.F.ordinal() ] = new char[] {'f', 'F'};
+ keyChars[ Key.G.ordinal() ] = new char[] {'g', 'G'};
+ keyChars[ Key.H.ordinal() ] = new char[] {'h', 'H'};
+ keyChars[ Key.J.ordinal() ] = new char[] {'j', 'J'};
+ keyChars[ Key.K.ordinal() ] = new char[] {'k', 'K'};
+ keyChars[ Key.L.ordinal() ] = new char[] {'l', 'L'};
+ keyChars[ Key.SEMICOLON.ordinal() ] = new char[] {';', ':'};
+ keyChars[ Key.APOSTROPHE.ordinal() ] = new char[] {'\'', '"'};
+ keyChars[ Key.BACKSLASH.ordinal() ] = new char[] {'\\', '|'};
+ keyChars[ Key.Z.ordinal() ] = new char[] {'z', 'Z'};
+ keyChars[ Key.X.ordinal() ] = new char[] {'x', 'X'};
+ keyChars[ Key.C.ordinal() ] = new char[] {'c', 'C'};
+ keyChars[ Key.V.ordinal() ] = new char[] {'v', 'V'};
+ keyChars[ Key.B.ordinal() ] = new char[] {'b', 'B'};
+ keyChars[ Key.N.ordinal() ] = new char[] {'n', 'N'};
+ keyChars[ Key.M.ordinal() ] = new char[] {'m', 'M'};
+ keyChars[ Key.COMMA.ordinal() ] = new char[] {',', '<'};
+ keyChars[ Key.PERIOD.ordinal() ] = new char[] {'.', '>'};
+ keyChars[ Key.SLASH.ordinal() ] = new char[] {'/', '?'};
+ keyChars[ Key.MULTIPLY.ordinal() ] = new char[] {'*', '*'};
+ keyChars[ Key.SPACE.ordinal() ] = new char[] {' ', ' '};
+ keyChars[ Key.NUMPAD7.ordinal() ] = new char[] {'7', '7'};
+ keyChars[ Key.NUMPAD8.ordinal() ] = new char[] {'8', '8'};
+ keyChars[ Key.NUMPAD9.ordinal() ] = new char[] {'9', '9'};
+ keyChars[ Key.SUBTRACT.ordinal() ] = new char[] {'-', '-'};
+ keyChars[ Key.NUMPAD4.ordinal() ] = new char[] {'4', '4'};
+ keyChars[ Key.NUMPAD5.ordinal() ] = new char[] {'5', '5'};
+ keyChars[ Key.NUMPAD6.ordinal() ] = new char[] {'6', '6'};
+ keyChars[ Key.ADD.ordinal() ] = new char[] {'+', '+'};
+ keyChars[ Key.NUMPAD1.ordinal() ] = new char[] {'1', '1'};
+ keyChars[ Key.NUMPAD2.ordinal() ] = new char[] {'2', '2'};
+ keyChars[ Key.NUMPAD3.ordinal() ] = new char[] {'3', '3'};
+ keyChars[ Key.NUMPAD0.ordinal() ] = new char[] {'0', '0'};
+ keyChars[ Key.DECIMAL.ordinal() ] = new char[] {'.', '.'};
+ keyChars[ Key.NUMPADEQUALS.ordinal() ] = new char[] {'=', '='};
+ keyChars[ Key.AT.ordinal() ] = new char[] {'@', '@'};
+ keyChars[ Key.COLON.ordinal() ] = new char[] {':', ':'};
+ keyChars[ Key.UNDERLINE.ordinal() ] = new char[] {'_', '_'};
+ keyChars[ Key.NUMPADENTER.ordinal() ] = new char[] {'\n', '\n'};
+ keyChars[ Key.NUMPADCOMMA.ordinal() ] = new char[] {',', ','};
+ keyChars[ Key.DIVIDE.ordinal() ] = new char[] {'/', '/'};
+ }
+
+ @Override
+ public KeyState getKey(Key key)
+ {
+ return states[ key.ordinal() ];
+ }
+
+ @Override
+ public InputState getShift()
+ {
+ return shift;
+ }
+
+ @Override
+ public InputState getControl()
+ {
+ return control;
+ }
+
+ @Override
+ public InputState getMeta()
+ {
+ return meta;
+ }
+
+ @Override
+ public InputState getCommand()
+ {
+ return command;
+ }
+
+ @Override
+ public InputState getAlt()
+ {
+ return alt;
+ }
+
+ @Override
+ public Queue getQueue()
+ {
+ return queue;
+ }
+
+ @Override
+ public void setPressInterval(float pressInterval)
+ {
+ this.pressInterval = pressInterval;
+ }
+
+ @Override
+ public float getPressInterval()
+ {
+ return pressInterval;
+ }
+
+ @Override
+ public void setPressDelay(float pressDelay)
+ {
+ this.pressDelay = pressDelay;
+ }
+
+ @Override
+ public float getPressDelay()
+ {
+ return pressDelay;
+ }
+
+}
diff --git a/src/com/axe/input/AbstractMouseEngine.java b/src/com/axe/input/AbstractMouseEngine.java
new file mode 100644
index 0000000..3bec165
--- /dev/null
+++ b/src/com/axe/input/AbstractMouseEngine.java
@@ -0,0 +1,119 @@
+package com.axe.input;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+import com.axe.window.Window;
+
+
+public abstract class AbstractMouseEngine implements MouseEngine
+{
+
+ public static final int MAX_BUTTONS = 3;
+
+ public InputState[] states;
+ public MouseState mouse;
+ public Queue queue;
+ public boolean grabbed;
+ public boolean hidden;
+ public float pressDelay;
+ public float pressInterval;
+
+ public AbstractMouseEngine()
+ {
+ this.states = new InputState[ MAX_BUTTONS ];
+ this.mouse = new MouseState();
+
+ for (int i = 0; i < MAX_BUTTONS; i++)
+ {
+ this.states[i] = new InputState(i);
+ }
+
+ this.queue = new ArrayDeque<>();
+
+ this.pressDelay = DEFAULT_PRESS_DELAY;
+ this.pressInterval = DEFAULT_PRESS_INTERVAL;
+ }
+
+ public void init(long startTime)
+ {
+ for (int i = 0; i < states.length; i++)
+ {
+ states[ i ].changeTime = startTime;
+ }
+ }
+
+ public void tick(long currentTime)
+ {
+ for (int i = 0; i < states.length; i++)
+ {
+ states[ i ].tick( currentTime, pressDelay, pressInterval );
+ }
+ }
+
+ public void queueButtonState(int button, boolean down, long inputTime, Window inputWindow)
+ {
+ MouseButtonState state = new MouseButtonState( button );
+
+ state.setDown( down, inputTime, inputWindow );
+ state.x = inputWindow.getMouse().x;
+ state.y = inputWindow.getMouse().y;
+
+ queue.offer( state );
+ }
+
+ @Override
+ public InputState getButton(int button)
+ {
+ return states[ button ];
+ }
+
+ @Override
+ public MouseState getMouse()
+ {
+ return mouse;
+ }
+
+ @Override
+ public Queue getQueue()
+ {
+ return queue;
+ }
+
+ @Override
+ public boolean isGrabbed()
+ {
+ return grabbed;
+ }
+
+ @Override
+ public boolean isHidden()
+ {
+ return hidden;
+ }
+
+ @Override
+ public void setPressInterval(float pressInterval)
+ {
+ this.pressInterval = pressInterval;
+ }
+
+ @Override
+ public float getPressInterval()
+ {
+ return pressInterval;
+ }
+
+ @Override
+ public void setPressDelay(float pressDelay)
+ {
+ this.pressDelay = pressDelay;
+ }
+
+ @Override
+ public float getPressDelay()
+ {
+ return pressDelay;
+ }
+
+}
diff --git a/src/com/axe/input/ControllerEngine.java b/src/com/axe/input/ControllerEngine.java
new file mode 100644
index 0000000..d7aed41
--- /dev/null
+++ b/src/com/axe/input/ControllerEngine.java
@@ -0,0 +1,5 @@
+package com.axe.input;
+
+public interface ControllerEngine {
+
+}
diff --git a/src/com/axe/input/InputState.java b/src/com/axe/input/InputState.java
new file mode 100644
index 0000000..4e7474d
--- /dev/null
+++ b/src/com/axe/input/InputState.java
@@ -0,0 +1,74 @@
+package com.axe.input;
+
+import com.axe.window.Window;
+
+public class InputState
+{
+
+ public Window window;
+ public final int input;
+ public boolean down;
+ public int frames;
+ public long time;
+ public float seconds;
+ public int presses;
+ public boolean press;
+ public long changeTime;
+
+ public InputState(int input)
+ {
+ this.input = input;
+ }
+
+ public boolean isDown()
+ {
+ return down && frames == 0;
+ }
+
+ public boolean isUp()
+ {
+ return !down && frames == 0;
+ }
+
+ public boolean isPress()
+ {
+ return press;
+ }
+
+ public boolean isChange()
+ {
+ return frames == 0;
+ }
+
+ public void setDown(boolean isDown, long inputTime, Window inputWindow)
+ {
+ if (down != isDown)
+ {
+ frames = 0;
+ time = 0;
+ seconds = 0;
+ down = isDown;
+ press = isDown;
+ presses = isDown ? 1 : 0;
+ changeTime = inputTime;
+ }
+
+ window = inputWindow;
+ }
+
+ public void tick(long currentTime, float delay, float interval)
+ {
+ time = (currentTime - changeTime);
+ seconds = time * 0.001f;
+ press = false;
+
+ if (down)
+ {
+ int currentPresses = (int)Math.max(0, (seconds - delay) / interval) + 1;
+
+ press = (currentPresses != presses);
+ presses = currentPresses;
+ }
+ }
+
+}
diff --git a/src/com/axe/input/InputStateAll.java b/src/com/axe/input/InputStateAll.java
new file mode 100644
index 0000000..0eb0838
--- /dev/null
+++ b/src/com/axe/input/InputStateAll.java
@@ -0,0 +1,39 @@
+package com.axe.input;
+
+public class InputStateAll extends InputState
+{
+
+ public InputState[] states;
+
+ public InputStateAll(InputState ... states)
+ {
+ super( states[0].input );
+
+ this.states = states;
+ }
+
+ public void update()
+ {
+ down = true;
+ frames = Integer.MAX_VALUE;
+ time = Long.MAX_VALUE;
+ seconds = Float.MAX_VALUE;
+ presses = Integer.MAX_VALUE;
+ press = true;
+ changeTime = 0;
+
+ for (int i = 0; i < states.length; i++)
+ {
+ InputState s = states[ i ];
+
+ down = down && s.down;
+ frames = Math.min( frames, s.frames );
+ time = Math.min( time, s.time );
+ seconds = Math.min( seconds, s.seconds );
+ press = press && s.press;
+ presses = Math.min( presses, s.presses );
+ changeTime = Math.max( changeTime, s.changeTime );
+ }
+ }
+
+}
diff --git a/src/com/axe/input/InputStateAny.java b/src/com/axe/input/InputStateAny.java
new file mode 100644
index 0000000..599bfd8
--- /dev/null
+++ b/src/com/axe/input/InputStateAny.java
@@ -0,0 +1,39 @@
+package com.axe.input;
+
+public class InputStateAny extends InputState
+{
+
+ public InputState[] states;
+
+ public InputStateAny(InputState ... states)
+ {
+ super( states[0].input );
+
+ this.states = states;
+ }
+
+ public void update()
+ {
+ down = false;
+ frames = 0;
+ time = 0;
+ seconds = 0;
+ presses = 0;
+ press = false;
+ changeTime = Long.MAX_VALUE;
+
+ for (int i = 0; i < states.length; i++)
+ {
+ InputState s = states[ i ];
+
+ down = down || s.down;
+ frames = Math.max( frames, s.frames );
+ time = Math.max( time, s.time );
+ seconds = Math.max( seconds, s.seconds );
+ press = press || s.press;
+ presses = Math.max( presses, s.presses );
+ changeTime = Math.min( changeTime, s.changeTime );
+ }
+ }
+
+}
diff --git a/src/com/axe/input/Key.java b/src/com/axe/input/Key.java
new file mode 100644
index 0000000..cd6b3a6
--- /dev/null
+++ b/src/com/axe/input/Key.java
@@ -0,0 +1,131 @@
+package com.axe.input;
+
+public enum Key
+{
+
+ NONE,
+ ESCAPE,
+ N1,
+ N2,
+ N3,
+ N4,
+ N5,
+ N6,
+ N7,
+ N8,
+ N9,
+ N0,
+ MINUS,
+ EQUALS,
+ BACK,
+ TAB,
+ Q,
+ W,
+ E,
+ R,
+ T,
+ Y,
+ U,
+ I,
+ O,
+ P,
+ LEFT_BRACKET, // LBRACKET
+ RIGHT_BRACKET, // RBRACKET
+ RETURN,
+ LEFT_CONTROL, // LCONTROL
+ A,
+ S,
+ D,
+ F,
+ G,
+ H,
+ J,
+ K,
+ L,
+ SEMICOLON,
+ APOSTROPHE,
+ GRAVE,
+ LEFT_SHIFT, // LSHIFT
+ BACKSLASH,
+ Z,
+ X,
+ C,
+ V,
+ B,
+ N,
+ M,
+ COMMA,
+ PERIOD,
+ SLASH,
+ RIGHT_SHIFT, // RSHIFT
+ MULTIPLY,
+ LEFT_ALT, // LMENU
+ SPACE,
+ CAPITAL,
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ NUMLOCK,
+ SCROLL,
+ NUMPAD7,
+ NUMPAD8,
+ NUMPAD9,
+ SUBTRACT,
+ NUMPAD4,
+ NUMPAD5,
+ NUMPAD6,
+ ADD,
+ NUMPAD1,
+ NUMPAD2,
+ NUMPAD3,
+ NUMPAD0,
+ DECIMAL,
+ F11,
+ F12,
+ F13,
+ F14,
+ F15,
+ KANA,
+ CONVERT,
+ NOCONVERT,
+ YEN,
+ NUMPADEQUALS,
+ CIRCUMFLEX, // ^
+ AT, // +shift
+ COLON, // +shift
+ UNDERLINE, // +shift
+ KANJI,
+ STOP,
+ AX,
+ UNLABELED,
+ NUMPADENTER,
+ RIGHT_CONTROL,
+ NUMPADCOMMA,
+ DIVIDE,
+ SYSRQ,
+ RIGHT_ALT, // RMENU
+ PAUSE,
+ HOME,
+ UP,
+ PAGE_UP, // PRIOR
+ LEFT,
+ RIGHT,
+ END,
+ DOWN,
+ PAGE_DOWN, // NEXT
+ INSERT,
+ DELETE,
+ LEFT_COMMAND, // LMETA, WINDOWS, LCOMMAND
+ RIGHT_COMMAND, // RMETA, WINDOWS, RCOMMAND
+ APPS,
+ POWER,
+ SLEEP
+
+}
\ No newline at end of file
diff --git a/src/com/axe/input/KeyEngine.java b/src/com/axe/input/KeyEngine.java
new file mode 100644
index 0000000..1100f87
--- /dev/null
+++ b/src/com/axe/input/KeyEngine.java
@@ -0,0 +1,32 @@
+package com.axe.input;
+
+import java.util.Queue;
+
+public interface KeyEngine
+{
+ public static final float DEFAULT_PRESS_DELAY = 0.5f;
+ public static final float DEFAULT_PRESS_INTERVAL = 0.1f;
+
+ public KeyState getKey(Key key);
+
+ public InputState getShift();
+
+ public InputState getControl();
+
+ public InputState getMeta();
+
+ public InputState getCommand();
+
+ public InputState getAlt();
+
+ public Queue getQueue();
+
+ public void setPressInterval(float pressInterval);
+
+ public float getPressInterval();
+
+ public void setPressDelay(float pressDelay);
+
+ public float getPressDelay();
+
+}
\ No newline at end of file
diff --git a/src/com/axe/input/KeyState.java b/src/com/axe/input/KeyState.java
new file mode 100644
index 0000000..87c478d
--- /dev/null
+++ b/src/com/axe/input/KeyState.java
@@ -0,0 +1,23 @@
+package com.axe.input;
+
+public class KeyState extends InputState
+{
+
+ public Key key;
+ public char character;
+
+ public KeyState(int input)
+ {
+ super(input);
+
+ this.key = Key.values()[ input ];
+ }
+
+ public KeyState(Key key)
+ {
+ super( key.ordinal() );
+
+ this.key = key;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/axe/input/MouseButtonState.java b/src/com/axe/input/MouseButtonState.java
new file mode 100644
index 0000000..54d6c22
--- /dev/null
+++ b/src/com/axe/input/MouseButtonState.java
@@ -0,0 +1,14 @@
+package com.axe.input;
+
+public class MouseButtonState extends InputState
+{
+
+ public int x;
+ public int y;
+
+ public MouseButtonState(int input)
+ {
+ super( input );
+ }
+
+}
diff --git a/src/com/axe/input/MouseEngine.java b/src/com/axe/input/MouseEngine.java
new file mode 100644
index 0000000..39a2c7f
--- /dev/null
+++ b/src/com/axe/input/MouseEngine.java
@@ -0,0 +1,37 @@
+package com.axe.input;
+
+import java.util.Queue;
+
+public interface MouseEngine
+{
+
+ public static final float DEFAULT_PRESS_DELAY = 0.5f;
+ public static final float DEFAULT_PRESS_INTERVAL = 0.1f;
+
+ public static final int LEFT = 0;
+ public static final int RIGHT = 1;
+ public static final int MIDDLE = 2;
+
+ public InputState getButton(int button);
+
+ public MouseState getMouse();
+
+ public Queue getQueue();
+
+ public void setGrabbed(boolean grabbed);
+
+ public boolean isGrabbed();
+
+ public void setHidden(boolean hidden);
+
+ public boolean isHidden();
+
+ public void setPressInterval(float pressInterval);
+
+ public float getPressInterval();
+
+ public void setPressDelay(float pressDelay);
+
+ public float getPressDelay();
+
+}
\ No newline at end of file
diff --git a/src/com/axe/input/MouseState.java b/src/com/axe/input/MouseState.java
new file mode 100644
index 0000000..2890b5d
--- /dev/null
+++ b/src/com/axe/input/MouseState.java
@@ -0,0 +1,57 @@
+package com.axe.input;
+
+import com.axe.math.Vec2i;
+
+public class MouseState
+{
+
+ public int x, y, dx, dy, sdx, sdy, wheel, wheelSign;
+
+ public boolean inside, insideChange;
+
+ public final Vec2i position = new Vec2i();
+ public final Vec2i delta = new Vec2i();
+ public final Vec2i sign = new Vec2i();
+
+ public void reset(int mx, int my)
+ {
+ x = position.x = mx;
+ y = position.y = my;
+ inside = insideChange = false;
+ clear();
+ }
+
+ public void clear()
+ {
+ dx = dy = delta.x = delta.y = 0;
+ sdx = sdy = sign.x = sign.y = 0;
+ wheel = wheelSign = 0;
+ }
+
+ public void accumulatePosition(int mx, int my)
+ {
+ delta.x = dx += (mx - x);
+ delta.y = dy += (my - y);
+
+ position.x = x = mx;
+ position.y = y = my;
+
+ sign.x = sdx = Integer.signum( dx );
+ sign.y = sdy = Integer.signum( dy );
+ }
+
+ public void accumulateScroll(int ticks)
+ {
+ wheel += ticks;
+ wheelSign = Integer.signum( wheel );
+ }
+
+ public void updateInside(int windowWidth, int windowHeight)
+ {
+ boolean currentInside = !(x < 0 || x >= windowWidth || y < 0 || y >= windowHeight);
+
+ insideChange = (currentInside != inside);
+ inside = currentInside;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/axe/integrate/Integrator.java b/src/com/axe/integrate/Integrator.java
new file mode 100755
index 0000000..5bbac15
--- /dev/null
+++ b/src/com/axe/integrate/Integrator.java
@@ -0,0 +1,15 @@
+package com.axe.integrate;
+
+import com.axe.core.Attribute;
+import com.axe.game.GameState;
+
+public interface Integrator>
+{
+
+ public T position();
+
+ public T acceleration();
+
+ public void update(GameState state);
+
+}
diff --git a/src/com/axe/integrate/IntegratorEuler.java b/src/com/axe/integrate/IntegratorEuler.java
new file mode 100755
index 0000000..460960e
--- /dev/null
+++ b/src/com/axe/integrate/IntegratorEuler.java
@@ -0,0 +1,40 @@
+package com.axe.integrate;
+
+import com.axe.core.Attribute;
+import com.axe.game.GameState;
+
+
+public class IntegratorEuler> implements Integrator
+{
+
+ public T position;
+ public T velocity;
+ public T acceleration;
+
+ public IntegratorEuler(T position, T velocity, T acceleration)
+ {
+ this.position = position;
+ this.velocity = velocity;
+ this.acceleration = acceleration;
+ }
+
+ @Override
+ public void update( GameState state )
+ {
+ velocity.adds( acceleration, state.seconds );
+ position.adds( velocity, state.seconds );
+ }
+
+ @Override
+ public T position()
+ {
+ return position;
+ }
+
+ @Override
+ public T acceleration()
+ {
+ return acceleration;
+ }
+
+}
diff --git a/src/com/axe/integrate/IntegratorRungeKutta.java b/src/com/axe/integrate/IntegratorRungeKutta.java
new file mode 100755
index 0000000..95709c3
--- /dev/null
+++ b/src/com/axe/integrate/IntegratorRungeKutta.java
@@ -0,0 +1,126 @@
+package com.axe.integrate;
+
+import com.axe.core.Attribute;
+import com.axe.game.GameState;
+
+
+public class IntegratorRungeKutta> implements Integrator
+{
+
+ public static final int DEFAULT_ITERATIONS = 4;
+
+ public T position;
+ public T acceleration;
+ public int iterations;
+ public Derivative d0;
+ public Derivative d1;
+ public Derivative d2;
+ public Derivative d3;
+
+ public IntegratorRungeKutta(T position, T acceleration)
+ {
+ this( position, acceleration, DEFAULT_ITERATIONS );
+ }
+
+ public IntegratorRungeKutta(T position, T acceleration, int iterations)
+ {
+ this.position = position;
+ this.acceleration = acceleration;
+ this.d0 = new Derivative( position );
+ this.d1 = new Derivative( position );
+ this.d2 = new Derivative( position );
+ this.d3 = new Derivative( position );
+ }
+
+ @Override
+ public void update( GameState state )
+ {
+ // float delta = 1f / iterations;
+
+ for (int i = 0; i < iterations; i++)
+ {
+ /*
+ a = evaluate( state, t, 0.0f, Derivative() );
+ b = evaluate( state, t, dt*0.5f, a );
+ c = evaluate( state, t, dt*0.5f, b );
+ d = evaluate( state, t, dt, c );
+
+ float dxdt = 1.0f / 6.0f *
+ ( a.dx + 2.0f*(b.dx + c.dx) + d.dx );
+
+ float dvdt = 1.0f / 6.0f *
+ ( a.dv + 2.0f*(b.dv + c.dv) + d.dv );
+
+ state.x = state.x + dxdt * dt;
+ state.v = state.v + dvdt * dt;
+ */
+ }
+
+ }
+
+
+ // TODO implementations specific.
+ public T acceleration(T out, State state, float t)
+ {
+ // Spring Example
+ int springConstant = 10;
+ int springDamping = 1;
+
+ out.set( state.x );
+ out.scale( -springConstant );
+ out.adds( state.v, -springDamping );
+
+ return out;
+ }
+
+ public Derivative evaluate(Derivative out, State initial, float t, float dt, Derivative d)
+ {
+ State state = new State( initial.v );
+
+ state.x.set( initial.x );
+ state.x.adds( d.dx, dt );
+
+ state.v.set( initial.v );
+ state.v.adds( d.dv, dt );
+
+ out.dx = state.v;
+ out.dv = acceleration( initial.v.clone(), state, t + dt );
+
+ return out;
+ }
+
+ @Override
+ public T position()
+ {
+ return position;
+ }
+
+ @Override
+ public T acceleration()
+ {
+ return acceleration;
+ }
+
+ public class State
+ {
+ public T x, v;
+
+ public State(T factory)
+ {
+ this.x = factory.clone();
+ this.v = factory.clone();
+ }
+ }
+
+ public class Derivative
+ {
+ public T dx, dv;
+
+ public Derivative(T factory)
+ {
+ this.dx = factory.clone();
+ this.dv = factory.clone();
+ }
+ }
+
+}
diff --git a/src/com/axe/integrate/IntegratorVerlet.java b/src/com/axe/integrate/IntegratorVerlet.java
new file mode 100755
index 0000000..bce073e
--- /dev/null
+++ b/src/com/axe/integrate/IntegratorVerlet.java
@@ -0,0 +1,45 @@
+package com.axe.integrate;
+
+import com.axe.core.Attribute;
+import com.axe.game.GameState;
+
+
+public class IntegratorVerlet> implements Integrator
+{
+
+ public T position;
+ public T lastPosition;
+ public T acceleration;
+ private T temp;
+
+ public IntegratorVerlet(T position, T acceleration)
+ {
+ this.position = position;
+ this.lastPosition = position.clone();
+ this.acceleration = acceleration;
+ this.temp = position.clone();
+ }
+
+ @Override
+ public void update( GameState state )
+ {
+ temp.set( position );
+ position.scale( 2.0f );
+ position.sub( lastPosition );
+ position.adds( acceleration, state.seconds * state.seconds );
+ lastPosition.set( temp );
+ }
+
+ @Override
+ public T position()
+ {
+ return position;
+ }
+
+ @Override
+ public T acceleration()
+ {
+ return acceleration;
+ }
+
+}
diff --git a/src/com/axe/io/DataBuffer.java b/src/com/axe/io/DataBuffer.java
new file mode 100755
index 0000000..0734542
--- /dev/null
+++ b/src/com/axe/io/DataBuffer.java
@@ -0,0 +1,119 @@
+package com.axe.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+
+public class DataBuffer
+{
+
+ private int write;
+ private int read;
+ private int resize;
+ private byte[] bytes;
+
+ public final OutputStream out;
+ public final InputStream in;
+
+ public DataBuffer(int initialCapacity, int resizeAmount)
+ {
+ this.bytes = new byte[initialCapacity];
+ this.resize = resizeAmount;
+ this.out = new Output();
+ this.in = new Input();
+ }
+
+ private class Output extends OutputStream
+ {
+ private void ensureSize(int s)
+ {
+ if (write + s >= bytes.length)
+ {
+ int minimumSize = write + s;
+ int desiredSize = bytes.length + resize;
+ int nextSize = Math.max( minimumSize, desiredSize );
+
+ bytes = Arrays.copyOf( bytes, nextSize );
+ }
+ }
+
+ @Override
+ public void write( int b ) throws IOException
+ {
+ ensureSize( 1 );
+
+ bytes[write++] = (byte)b;
+ }
+
+ @Override
+ public void write(byte[] b, int offset, int length)
+ {
+ ensureSize( length );
+
+ System.arraycopy( b, offset, bytes, write, length );
+
+ write += length;
+ }
+ }
+
+ private class Input extends InputStream
+ {
+ private int mark = -1;
+
+ @Override
+ public int read() throws IOException
+ {
+ return read < write ? bytes[read++] : -1;
+ }
+
+ @Override
+ public int available()
+ {
+ return (write - read);
+ }
+
+ @Override
+ public void mark(int m)
+ {
+ mark = m;
+ }
+
+ @Override
+ public void reset()
+ {
+ read = mark;
+ mark = -1;
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ @Override
+ public long skip(long bytes)
+ {
+ long skipped = Math.min( bytes, available() );
+
+ read += skipped;
+
+ return skipped;
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length)
+ {
+ int bytesRead = Math.min( available(), length );
+
+ System.arraycopy( bytes, read, b, offset, bytesRead );
+
+ read += bytesRead;
+
+ return bytesRead == 0 ? -1 : bytesRead;
+ }
+ }
+
+}
diff --git a/src/com/axe/io/DataBundle.java b/src/com/axe/io/DataBundle.java
new file mode 100755
index 0000000..bd9f17c
--- /dev/null
+++ b/src/com/axe/io/DataBundle.java
@@ -0,0 +1,88 @@
+package com.axe.io;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+public class DataBundle implements DataModel
+{
+
+ private DataFormat format;
+ private String name;
+ private Map modelMap = new HashMap();
+
+ public DataBundle( InputModel input )
+ {
+ read( input );
+ }
+
+ @Override
+ public void read( InputModel input )
+ {
+ format = input.getFormat();
+ name = input.getName();
+ modelMap.clear();
+
+ for (InputModel child : input)
+ {
+ String name = child.getName();
+ String type = child.readString( "data-type" );
+ Class> clazz = DataRegistry.getClass( type );
+
+ DataModel model = instantiate( clazz );
+ model.read( child );
+
+ modelMap.put( name, model );
+ }
+ }
+
+ @Override
+ public void write( OutputModel output )
+ {
+ for ( Entry entry : modelMap.entrySet() )
+ {
+ DataModel model = entry.getValue();
+ String name = entry.getKey();
+ String type = DataRegistry.getClassName( model.getClass() );
+
+ OutputModel out = output.writeModel( name, model );
+ out.write( "data-type", type );
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T instantiate( Class> clazz ) throws DataException
+ {
+ try
+ {
+ return (T)clazz.newInstance();
+ }
+ catch (Exception ex)
+ {
+ throw new DataException( ex );
+ }
+ }
+
+ public DataFormat getFormat()
+ {
+ return format;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void add(String name, DataModel model)
+ {
+ modelMap.put( name, model );
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get( String name )
+ {
+ return (T)modelMap.get( name );
+ }
+
+}
diff --git a/src/com/axe/io/DataException.java b/src/com/axe/io/DataException.java
new file mode 100755
index 0000000..aca8a8f
--- /dev/null
+++ b/src/com/axe/io/DataException.java
@@ -0,0 +1,22 @@
+package com.axe.io;
+
+public class DataException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ public DataException(String message)
+ {
+ super( message );
+ }
+
+ public DataException(Exception cause)
+ {
+ super( cause );
+ }
+
+ public DataException(String format, Object ... args)
+ {
+ super( String.format(format, args) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/axe/io/DataFormat.java b/src/com/axe/io/DataFormat.java
new file mode 100755
index 0000000..89d383a
--- /dev/null
+++ b/src/com/axe/io/DataFormat.java
@@ -0,0 +1,44 @@
+
+package com.axe.io;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+
+public interface DataFormat
+{
+
+ public OutputModel newOutput( String name );
+
+ public OutputModel newOutput( String name, DataModel model );
+
+ public OutputModel newOutput( String name, int scope );
+
+ public OutputModel newOutput( String name, int scope, DataModel model );
+
+ public OutputModel write( Writer writer, String name, DataModel model ) throws Exception;
+
+ public OutputModel write( File file, String name, DataModel model ) throws Exception;
+
+ public OutputModel write( OutputStream stream, String name, DataModel model ) throws Exception;
+
+ public InputModel read( InputStream stream ) throws Exception;
+
+ public InputModel read( Reader reader ) throws Exception;
+
+ public InputModel read( File file ) throws Exception;
+
+ public InputModel read( String string ) throws Exception;
+
+ public T read( InputStream stream, T model ) throws Exception;
+
+ public T read( Reader reader, T model ) throws Exception;
+
+ public T read( File file, T model ) throws Exception;
+
+ public T read( String string, T model ) throws Exception;
+
+}
diff --git a/src/com/axe/io/DataModel.java b/src/com/axe/io/DataModel.java
new file mode 100755
index 0000000..44ea44f
--- /dev/null
+++ b/src/com/axe/io/DataModel.java
@@ -0,0 +1,8 @@
+package com.axe.io;
+
+
+public interface DataModel
+{
+ public void read(InputModel input);
+ public void write(OutputModel output);
+}
diff --git a/src/com/axe/io/DataRegistry.java b/src/com/axe/io/DataRegistry.java
new file mode 100755
index 0000000..b41dcfa
--- /dev/null
+++ b/src/com/axe/io/DataRegistry.java
@@ -0,0 +1,299 @@
+package com.axe.io;
+
+import java.util.Map;
+
+import com.axe.Axe;
+import com.axe.color.Color;
+import com.axe.color.Colors;
+import com.axe.easing.Easings;
+import com.axe.gfx.Blend;
+import com.axe.gfx.Coord;
+import com.axe.math.Bound2f;
+import com.axe.math.Bound2i;
+import com.axe.math.Bound3f;
+import com.axe.math.Bound3i;
+import com.axe.math.Rangef;
+import com.axe.math.Rangei;
+import com.axe.math.Rect2i;
+import com.axe.math.Scalarf;
+import com.axe.math.Scalari;
+import com.axe.math.Vec2f;
+import com.axe.math.Vec2i;
+import com.axe.math.Vec3f;
+import com.axe.math.Vec3i;
+import com.axe.noise.PerlinNoise;
+import com.axe.noise.SimplexNoise;
+import com.axe.path.AdditivePath;
+import com.axe.path.BezierPath;
+import com.axe.path.ComboPath;
+import com.axe.path.CompiledPath;
+import com.axe.path.CubicPath;
+import com.axe.path.DurationPath;
+import com.axe.path.EasedPath;
+import com.axe.path.IntegralPath;
+import com.axe.path.JumpPath;
+import com.axe.path.LinearPath;
+import com.axe.path.PointPath;
+import com.axe.path.QuadraticPath;
+import com.axe.path.ScaledPath;
+import com.axe.path.SubPath;
+import com.axe.path.TimedPath;
+import com.axe.path.Tween;
+import com.axe.path.UniformPath;
+import com.axe.tile.Tile;
+
+public class DataRegistry
+{
+
+ public static final RegistryMap objects = new RegistryMap();
+ public static final RegistryMap> classes = new RegistryMap>();
+
+ public static void register(String name, Class> clazz)
+ {
+ classes.put( name, clazz );
+ }
+
+ public static void registerClasses(Map> classMap)
+ {
+ classes.putAll( classMap );
+ }
+
+ public static void register(String name, Object object)
+ {
+ objects.put( name, object );
+ }
+
+ public static void registerObjects(Map objectMap)
+ {
+ objects.putAll( objectMap );
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Class getClass(String name)
+ {
+ return (Class)classes.getForward( name );
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getInstance(String className, boolean throwRuntimeException)
+ {
+ try
+ {
+ return (T)classes.getForward( className ).newInstance();
+ }
+ catch (Exception e)
+ {
+ if ( throwRuntimeException )
+ {
+ throw new RuntimeException( e );
+ }
+
+ Axe.logger.log( null, e );
+
+ return null;
+ }
+ }
+
+ public static String getClassName(Class> clazz)
+ {
+ return classes.getBackward( clazz );
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T get(String name)
+ {
+ return (T)objects.getForward( name );
+ }
+
+ public static String getName(Object value)
+ {
+ return objects.getBackward( value );
+ }
+
+ static
+ {
+ // Paths
+ register( "path-bezier", BezierPath.class );
+ register( "path-combo", ComboPath.class );
+ register( "path-compiled", CompiledPath.class );
+ register( "path-cubic", CubicPath.class );
+ register( "path-duration", DurationPath.class );
+ register( "path-eased", EasedPath.class );
+ register( "path-integral", IntegralPath.class );
+ register( "path-jump", JumpPath.class );
+ register( "path-linear", LinearPath.class );
+ register( "path-point", PointPath.class );
+ register( "path-quadratic", QuadraticPath.class );
+ register( "path-sub", SubPath.class );
+ register( "path-timed", TimedPath.class );
+ register( "path-tween", Tween.class );
+ register( "path-uniform", UniformPath.class );
+ register( "path-scaled", ScaledPath.class );
+ register( "path-additive", AdditivePath.class );
+
+ /*
+ // Particle Influences 2d
+ register( "influence2d-acceleration", InfluenceAcceleration.class );
+ register( "influence2d-align", InfluenceAlign.class );
+ register( "influence2d-alpha", InfluenceAlpha.class );
+ register( "influence2d-angle", InfluenceAngle.class );
+ register( "influence2d-color", InfluenceColor.class );
+ register( "influence2d-constraint", InfluenceConstraint.class );
+ register( "influence2d-damping", InfluenceDamping.class );
+ register( "influence2d-scale", InfluenceScale.class );
+ register( "influence2d-size", InfluenceSize.class );
+ register( "influence2d-tile", InfluenceTile.class );
+ register( "influence2d-velocity", InfluenceVelocity.class );
+
+ // Particle Initializers 2d
+ register( "initialize2d-acceleration", InitializeAcceleration.class );
+ register( "initialize2d-acceleration-scalar", InitializeAccelerationScalar.class );
+ register( "initialize2d-angle", InitializeAngle.class );
+ register( "initialize2d-angle-acceleration", InitializeAngleAcceleration.class );
+ register( "initialize2d-angle-velocity", InitializeAngleVelocity.class );
+ register( "initialize2d-color", InitializeColor.class );
+ register( "initialize2d-scale", InitializeScale.class );
+ register( "initialize2d-scale-acceleration", InitializeScaleAcceleration.class );
+ register( "initialize2d-scale-velocity", InitializeScaleVelocity.class );
+ register( "initialize2d-size", InitializeSize.class );
+ register( "initialize2d-tile", InitializeTile.class );
+
+ // Particle Velocity 2d
+ register( "velocity2d-default", VelocityDefault.class );
+ register( "velocity2d-directional", VelocityDirectional.class );
+ register( "velocity2d-ortho", VelocityOrtho.class );
+ register( "velocity2d-outward", VelocityOutward.class );
+ register( "velocity2d-towards", VelocityTowards.class );
+
+ // Particle Volume 2d
+ register( "volume2d-bounds", VolumeBounds.class );
+ register( "volume2d-default", VolumeDefault.class );
+ register( "volume2d-ellipse", VolumeEllipse.class );
+ register( "volume2d-path", VolumePath.class );
+ register( "volume2d-pinwheel", VolumePinwheel.class );
+
+ // Particle Factory 2d
+ register( "particle-factory2d-angle", AngleParticle.factory );
+ register( "particle-factory2d-Base", BaseParticle.factory );
+ register( "particle-factory2d-color", ColorParticle.factory );
+ register( "particle-factory2d-colortile", ColorTileParticle.factory );
+ register( "particle-factory2d-full", FullParticle.factory );
+ register( "particle-factory2d-physics", PhysicsParticle.factory );
+ register( "particle-factory2d-tile", TileParticle.factory );
+ register( "particle-factory2d-twin", TwinParticle.factory );
+
+ // Particle Renderer 2d
+ register( "particle-renderer2d-angle", AngleParticle.VIEW );
+ register( "particle-renderer2d-Base", BaseParticle.VIEW );
+ register( "particle-renderer2d-color", ColorParticle.VIEW );
+ register( "particle-renderer2d-colortile", ColorTileParticle.VIEW );
+ register( "particle-renderer2d-full", FullParticle.VIEW );
+ register( "particle-renderer2d-physics", PhysicsParticle.VIEW );
+ register( "particle-renderer2d-tile", TileParticle.VIEW );
+ register( "particle-renderer2d-twin", TwinParticle.VIEW );
+
+ // Particle Influences 3d
+ register( "influence3d-acceleration", com.axe3d.efx.influence.InfluenceAcceleration.class );
+ register( "influence3d-alpha", com.axe3d.efx.influence.InfluenceAlpha.class );
+ register( "influence3d-angle", com.axe3d.efx.influence.InfluenceAngle.class );
+ register( "influence3d-color", com.axe3d.efx.influence.InfluenceColor.class );
+ register( "influence3d-constraint", com.axe3d.efx.influence.InfluenceConstraint.class );
+ register( "influence3d-damping", com.axe3d.efx.influence.InfluenceDamping.class );
+ register( "influence3d-scale", com.axe3d.efx.influence.InfluenceScale.class );
+ register( "influence3d-size", com.axe3d.efx.influence.InfluenceSize.class );
+ register( "influence3d-tile", com.axe3d.efx.influence.InfluenceTile.class );
+ register( "influence3d-velocity", com.axe3d.efx.influence.InfluenceVelocity.class );
+
+ // Particle Initializers 3d
+ register( "initialize3d-acceleration", com.axe3d.efx.initializer.InitializeAcceleration.class );
+ register( "initialize3d-acceleration-scalar", com.axe3d.efx.initializer.InitializeAccelerationScalar.class );
+ register( "initialize3d-angle", com.axe3d.efx.initializer.InitializeAngle.class );
+ register( "initialize3d-angle-acceleration", com.axe3d.efx.initializer.InitializeAngleAcceleration.class );
+ register( "initialize3d-angle-velocity", com.axe3d.efx.initializer.InitializeAngleVelocity.class );
+ register( "initialize3d-color", com.axe3d.efx.initializer.InitializeColor.class );
+ register( "initialize3d-scale", com.axe3d.efx.initializer.InitializeScale.class );
+ register( "initialize3d-scale-acceleration", com.axe3d.efx.initializer.InitializeScaleAcceleration.class );
+ register( "initialize3d-scale-velocity", com.axe3d.efx.initializer.InitializeScaleVelocity.class );
+ register( "initialize3d-size", com.axe3d.efx.initializer.InitializeSize.class );
+ register( "initialize3d-tile", com.axe3d.efx.initializer.InitializeTile.class );
+
+ // Particle Velocity 3d
+ register( "velocity3d-default", com.axe3d.efx.velocity.VelocityDefault.class );
+ register( "velocity3d-directional", com.axe3d.efx.velocity.VelocityDirectional.class );
+ register( "velocity3d-ortho", com.axe3d.efx.velocity.VelocityOrtho.class );
+ register( "velocity3d-outward", com.axe3d.efx.velocity.VelocityOutward.class );
+ register( "velocity3d-towards", com.axe3d.efx.velocity.VelocityTowards.class );
+
+ // Particle Volume 3d
+ register( "volume3d-bounds", com.axe3d.efx.volume.VolumeBounds.class );
+ register( "volume3d-default", com.axe3d.efx.volume.VolumeDefault.class );
+ register( "volume3d-ellipse", com.axe3d.efx.volume.VolumeEllipse.class );
+ register( "volume3d-path", com.axe3d.efx.volume.VolumePath.class );
+
+ // Particle Factory 3d
+ register( "particle-factory3d-angle", com.axe3d.efx.particle.AngleParticle.factory );
+ register( "particle-factory3d-Base", com.axe3d.efx.particle.BaseParticle.factory );
+ register( "particle-factory3d-color", com.axe3d.efx.particle.ColorParticle.factory );
+ register( "particle-factory3d-colortile", com.axe3d.efx.particle.ColorTileParticle.factory );
+ register( "particle-factory3d-full", com.axe3d.efx.particle.FullParticle.factory );
+ register( "particle-factory3d-physics", com.axe3d.efx.particle.PhysicsParticle.factory );
+ register( "particle-factory3d-tile", com.axe3d.efx.particle.TileParticle.factory );
+ register( "particle-factory3d-twin", com.axe3d.efx.particle.TwinParticle.factory );
+
+ // Particle Renderer 3d
+ register( "particle-renderer3d-angle", com.axe3d.efx.particle.AngleParticle.VIEW );
+ register( "particle-renderer3d-Base", com.axe3d.efx.particle.BaseParticle.VIEW );
+ register( "particle-renderer3d-color", com.axe3d.efx.particle.ColorParticle.VIEW );
+ register( "particle-renderer3d-colortile", com.axe3d.efx.particle.ColorTileParticle.VIEW );
+ register( "particle-renderer3d-full", com.axe3d.efx.particle.FullParticle.VIEW );
+ register( "particle-renderer3d-physics", com.axe3d.efx.particle.PhysicsParticle.VIEW );
+ register( "particle-renderer3d-tile", com.axe3d.efx.particle.TileParticle.VIEW );
+ register( "particle-renderer3d-twin", com.axe3d.efx.particle.TwinParticle.VIEW );
+ */
+
+ // Noise
+ DataRegistry.register( "noise-perlin", PerlinNoise.class );
+ DataRegistry.register( "noise-simplex", SimplexNoise.class );
+
+ // Attributes
+ register( "color", Color.class );
+ register( "coord", Coord.class );
+ register( "tile", Tile.class );
+ register( "scalarf", Scalarf.class );
+ register( "scalari", Scalari.class );
+ register( "bound2f", Bound2f.class );
+ register( "bound2i", Bound2i.class );
+ register( "bound3f", Bound3f.class );
+ register( "bound3i", Bound3i.class );
+ // register( "camera2", Camera2.class );
+ // register( "camera3", Camera3.class );
+ register( "rect2f", Bound2i.class );
+ register( "rect2i", Rect2i.class );
+ register( "vec2f", Vec2f.class );
+ register( "vec2i", Vec2i.class );
+ register( "vec3f", Vec3f.class );
+ register( "vec3i", Vec3i.class );
+ register( "rangef", Rangef.class );
+ register( "rangei", Rangei.class );
+
+ // Colors
+ registerObjects( Colors.ColorMap );
+
+ // Easing Types
+ registerObjects( Easings.TypeMap );
+
+ // Easing Functions
+ registerObjects( Easings.MethodMap );
+
+ // Blends
+ register( "Add", Blend.Add );
+ register( "AlphaAdd", Blend.AlphaAdd );
+ register( "Alpha", Blend.Alpha );
+ register( "Color", Blend.Color );
+ register( "Minus", Blend.Minus );
+ register( "PremultAlpha", Blend.PremultAlpha );
+ register( "Modulate", Blend.Modulate );
+ register( "Xor", Blend.Xor );
+ register( "None", Blend.None );
+ }
+}
diff --git a/src/com/axe/io/DataUtility.java b/src/com/axe/io/DataUtility.java
new file mode 100755
index 0000000..c020715
--- /dev/null
+++ b/src/com/axe/io/DataUtility.java
@@ -0,0 +1,509 @@
+package com.axe.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class DataUtility
+{
+
+ private static DataFormat defaultFormat = null;
+
+ public static void setDefaultFormat( DataFormat format )
+ {
+ defaultFormat = format;
+ }
+
+ public static DataFormat getDefaultFormat()
+ {
+ return defaultFormat;
+ }
+
+ public static final int BYTE_SHIFT = 7;
+ public static final int BYTE_MASK = 0x7F;
+ public static final int BYTE_MORE = 0x80;
+
+ private static final int BYTES_BYTE = 1;
+ private static final int BYTES_INT = 4;
+ private static final int BYTES_LONG = 8;
+ private static final int[] VALUE_BYTES = {
+ /*0*/ 0,
+ /*1*/ 1 << (0 * 7),
+ /*2*/ 1 << (1 * 7),
+ /*3*/ 1 << (2 * 7),
+ /*4*/ 1 << (3 * 7),
+ /*5*/ 1 << (4 * 7),
+ /*6*/ 1 << (5 * 7),
+ /*7*/ 1 << (6 * 7),
+ /*8*/ 1 << (7 * 7),
+ };
+
+ public static int readInt( InputStream in ) throws IOException
+ {
+ int x = 0;
+ int b = 0;
+ int shift = 0;
+
+ do
+ {
+ b = in.read();
+
+ if ( b == -1 )
+ {
+ return x;
+ }
+
+ x |= (b & BYTE_MASK) << shift;
+ shift += BYTE_SHIFT;
+ }
+ while ( (b & BYTE_MORE) == BYTE_MORE );
+
+ return x;
+ }
+
+ public static int writeInt( OutputStream out, int value ) throws IOException
+ {
+ int bytes = 0;
+
+ do
+ {
+ out.write( (value & BYTE_MASK) | (value > BYTE_MASK ? BYTE_MORE : 0) );
+ value >>= BYTE_SHIFT;
+ bytes++;
+ } while ( value > 0 );
+
+ return bytes;
+ }
+
+ public static long readLong( InputStream in ) throws IOException
+ {
+ long x = 0;
+ int b = 0;
+ long shift = 0;
+
+ do
+ {
+ b = in.read();
+
+ if ( b == -1 )
+ {
+ return x;
+ }
+
+ x |= (b & BYTE_MASK) << shift;
+ shift += BYTE_SHIFT;
+ }
+ while ( (b & BYTE_MORE) == BYTE_MORE );
+
+ return x;
+ }
+
+ public static int writeLong( OutputStream out, long value ) throws IOException
+ {
+ int bytes = 0;
+
+ do
+ {
+ out.write( (int)((value & BYTE_MASK) | (value > BYTE_MASK ? BYTE_MORE : 0)) );
+ value >>= BYTE_SHIFT;
+ bytes++;
+ } while ( value > 0 );
+
+ return bytes;
+ }
+
+ public static int getInt( ByteBuffer in )
+ {
+ int x = 0;
+ int b = 0;
+ int shift = 0;
+
+ do
+ {
+ b = in.get() & 0xFF;
+ x |= (b & BYTE_MASK) << shift;
+ shift += BYTE_SHIFT;
+ }
+ while ( (b & BYTE_MORE) == BYTE_MORE );
+
+ return x;
+ }
+
+ public static int putInt( ByteBuffer out, int value )
+ {
+ int bytes = 0;
+
+ do
+ {
+ out.put( (byte)((value & BYTE_MASK) | (value > BYTE_MASK ? BYTE_MORE : 0)) );
+ value >>= BYTE_SHIFT;
+ bytes++;
+ } while ( value > 0 );
+
+ return bytes;
+ }
+
+ public static long getLong( ByteBuffer in )
+ {
+ long x = 0;
+ int b = 0;
+ long shift = 0;
+
+ do
+ {
+ b = in.get() & 0xFF;
+ x |= (b & BYTE_MASK) << shift;
+ shift += BYTE_SHIFT;
+ }
+ while ( (b & BYTE_MORE) == BYTE_MORE );
+
+ return x;
+ }
+
+ public static int putLong( ByteBuffer out, long value )
+ {
+ int bytes = 0;
+
+ do
+ {
+ out.put( (byte)((value & BYTE_MASK) | (value > BYTE_MASK ? BYTE_MORE : 0)) );
+ value >>= BYTE_SHIFT;
+ bytes++;
+ }
+ while ( value > 0 );
+
+ return bytes;
+ }
+
+ public static int sizeOf( int value )
+ {
+ for (int i = BYTES_INT; i > BYTES_BYTE; i--)
+ {
+ if ( value >= VALUE_BYTES[i] )
+ {
+ return i;
+ }
+ }
+
+ return BYTES_BYTE;
+ }
+
+ public static int sizeOf( long value )
+ {
+ for (int i = BYTES_LONG; i > BYTES_BYTE; i--)
+ {
+ if ( value >= VALUE_BYTES[i] )
+ {
+ return i;
+ }
+ }
+
+ return BYTES_BYTE;
+ }
+
+ public static I convertFromOutput( OutputModel out, I in )
+ {
+ // out.copyTo( in );
+
+ return in;
+ }
+
+ public static O convertFromInput( InputModel in, O out )
+ {
+ in.copyTo( out );
+
+ return out;
+ }
+
+ public static T clone(T model, T out)
+ {
+ try
+ {
+ DataFormat format = getDefaultFormat();
+ DataBuffer buffer = new DataBuffer( 4096, 2048 );
+
+ OutputModel clone = format.newOutput( "clone" );
+ model.write( clone );
+ clone.output( buffer.out );
+
+ InputModel cloned = format.read( buffer.in );
+ out.read( cloned );
+
+ return out;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException( e );
+ }
+ }
+
+ public static OutputModel convertFromInput( InputModel in, DataFormat format )
+ {
+ OutputModel out = format.newOutput( in.getName() );
+
+ in.copyTo( out );
+
+ return out;
+ }
+
+ public static void readFile( File file, ByteBuffer in ) throws Exception
+ {
+ RandomAccessFile stream = new RandomAccessFile( file, "r" );
+
+ try
+ {
+ in.clear();
+
+ stream.getChannel().read( in );
+
+ in.flip();
+ }
+ finally
+ {
+ stream.close();
+ }
+ }
+
+ public static void writeFile( File file, ByteBuffer out ) throws Exception
+ {
+ RandomAccessFile stream = new RandomAccessFile( file, "rw" );
+
+ try
+ {
+ FileChannel channel = stream.getChannel();
+
+ int pos = out.position();
+ out.flip();
+
+ channel.write( out );
+
+ out.limit( out.capacity() );
+ out.position( pos );
+ }
+ finally
+ {
+ stream.close();
+ }
+ }
+
+ public static ByteBuffer resize( ByteBuffer buffer, int expectedCapacity )
+ {
+ ByteBuffer result = ( buffer != null ? buffer : ByteBuffer.allocateDirect( expectedCapacity ) );
+
+ if ( result.capacity() < expectedCapacity )
+ {
+ result = ByteBuffer.allocateDirect( expectedCapacity );
+ result.put( buffer );
+ result.clear();
+ }
+
+ return result;
+ }
+
+ public static ByteBuffer read( File file ) throws IOException
+ {
+ FileInputStream fis = new FileInputStream( file );
+
+ return read( fis.getChannel().size(), fis, true );
+ }
+
+ public static ByteBuffer read( long size, InputStream input, boolean close ) throws IOException
+ {
+ ByteBuffer buffer = ByteBuffer.allocateDirect( (int)size );
+ byte[] data = new byte[ 4096 ];
+ int read = 0;
+
+ while ( (read = input.read( data ) ) > 0 )
+ {
+ if ( buffer.remaining() < read )
+ {
+ return null;
+ }
+
+ buffer.put( data, 0, read );
+ }
+
+ buffer.clear();
+
+ if ( close )
+ {
+ input.close();
+ }
+
+ return buffer;
+ }
+
+ public static int transfer( InputStream from, OutputStream to, int chunkSize ) throws IOException
+ {
+ byte[] data = new byte[ chunkSize ];
+ int totalRead = 0;
+ int read = 0;
+
+ while ( (read = from.read( data )) > 0 )
+ {
+ to.write( data, 0, read );
+ totalRead += read;
+ }
+
+ return totalRead;
+ }
+
+ public static OutputStream toOutputStream(final ByteBuffer out)
+ {
+ if (out == null)
+ {
+ return null;
+ }
+
+ return new OutputStream()
+ {
+ @Override
+ public void write( int b ) throws IOException
+ {
+ out.put( (byte)b );
+ }
+
+ @Override
+ public void write(byte[] b, int offset, int length)
+ {
+ out.put( b, offset, length );
+ }
+ };
+ }
+
+ public static InputStream syphon(final InputStream in, final OutputStream out)
+ {
+ if (in == null)
+ {
+ return null;
+ }
+
+ return new InputStream()
+ {
+ @Override
+ public int read() throws IOException
+ {
+ int b = in.read();
+
+ if (b != -1)
+ {
+ out.write( b );
+ }
+
+ return b;
+ }
+
+ @Override
+ public int available() throws IOException
+ {
+ return in.available();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ in.close();
+ out.close();
+ }
+
+ @Override
+ public long skip(long bytes) throws IOException
+ {
+ return in.skip( bytes );
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length) throws IOException
+ {
+ int actualLength = in.read( b, offset, length );
+
+ if (actualLength != -1)
+ {
+ out.write( b, offset, actualLength );
+ }
+
+ return actualLength;
+ }
+ };
+ }
+
+ public static InputStream toInputStream(final ByteBuffer in)
+ {
+ if (in == null)
+ {
+ return null;
+ }
+
+ return new InputStream()
+ {
+ public int mark = -1;
+
+ @Override
+ public int read() throws IOException
+ {
+ return in.hasRemaining() ? in.get() & 0xFF : -1;
+ }
+
+ @Override
+ public int available()
+ {
+ return in.remaining();
+ }
+
+ @Override
+ public void mark(int m)
+ {
+ mark = m;
+ }
+
+ @Override
+ public void reset()
+ {
+ in.position( mark );
+ mark = -1;
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ @Override
+ public void close()
+ {
+ in.position( 0 );
+ }
+
+ @Override
+ public long skip(long bytes)
+ {
+ long skipped = Math.min( bytes, in.remaining() );
+
+ in.position( in.position() + (int)skipped );
+
+ return skipped;
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length)
+ {
+ int read = Math.min( in.remaining(), length );
+
+ in.get( b, offset, read );
+
+ return read == 0 ? -1 : read;
+ }
+ };
+ }
+
+}
diff --git a/src/com/axe/io/DualInputModel.java b/src/com/axe/io/DualInputModel.java
new file mode 100755
index 0000000..31ec555
--- /dev/null
+++ b/src/com/axe/io/DualInputModel.java
@@ -0,0 +1,139 @@
+package com.axe.io;
+
+import java.util.Iterator;
+
+import com.axe.io.base.BaseInputModel;
+
+public class DualInputModel extends BaseInputModel
+{
+
+ private final InputModel first;
+ private final InputModel second;
+ private final DualIterator iterator;
+
+ public DualInputModel( DataFormat format, String name, InputModel first, InputModel second )
+ {
+ super( format, name );
+
+ this.first = first;
+ this.second = second;
+ this.iterator = new DualIterator();
+ }
+
+ @Override
+ public void copyTo( OutputModel out )
+ {
+ second.copyTo( out );
+ first.copyTo( out );
+ }
+
+ @Override
+ public boolean hasAttribute( String name )
+ {
+ return first.hasAttribute( name ) || second.hasAttribute( name );
+ }
+
+ @Override
+ public boolean hasChild( String name )
+ {
+ return first.hasChild( name ) || second.hasChild( name );
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ return iterator.take();
+ }
+
+ @Override
+ protected String getAttribute( String name )
+ {
+ if ( first.hasAttribute( name ) )
+ {
+ return first.readString( name );
+ }
+
+ return second.readString( name );
+ }
+
+ @Override
+ public InputModel readModel( String name )
+ {
+ InputModel model = first.readModel( name );
+
+ if ( model == null )
+ {
+ model = second.readModel( name );
+ }
+
+ return model;
+ }
+
+ @Override
+ public T readModel( String name, String attributeName, boolean requires ) throws DataException
+ {
+ T result = first.readModel( name, attributeName, false );
+
+ if ( result == null )
+ {
+ result = second.readModel( name, attributeName, requires );
+ }
+
+ return result;
+ }
+
+
+ private class DualIterator implements Iterator
+ {
+ public Iterator s, f;
+ public boolean nextSecond = true;
+
+ public DualIterator()
+ {
+ s = second.iterator();
+ f = first.iterator();
+ }
+
+ public Iterator take()
+ {
+ if ( hasNext() )
+ {
+ return new DualIterator();
+ }
+
+ s = second.iterator();
+ f = first.iterator();
+
+ nextSecond = s.hasNext();
+
+ return this;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return s.hasNext() || f.hasNext();
+ }
+
+ @Override
+ public InputModel next()
+ {
+ return ( ( nextSecond = s.hasNext() ) ? s.next() : f.next() );
+ }
+
+ @Override
+ public void remove()
+ {
+ if ( nextSecond )
+ {
+ s.remove();
+ }
+ else
+ {
+ f.remove();
+ }
+ }
+
+ }
+
+}
diff --git a/src/com/axe/io/InputModel.java b/src/com/axe/io/InputModel.java
new file mode 100755
index 0000000..59b203b
--- /dev/null
+++ b/src/com/axe/io/InputModel.java
@@ -0,0 +1,84 @@
+package com.axe.io;
+
+import java.util.List;
+
+import com.axe.math.calc.Calculator;
+
+public interface InputModel extends Iterable
+{
+ public String getName();
+ public DataFormat getFormat();
+
+ public void copyTo( OutputModel out );
+
+ public InputModel[] getChildren( String name );
+
+ public boolean hasAttribute(String name);
+ public boolean hasChild( String name );
+
+ // Attributes
+
+ public double readDouble(String name) throws DataException;
+ public double readDouble(String name, Double defaultValue) throws DataException;
+ public float readFloat(String name) throws DataException;
+ public float readFloat(String name, Float defaultValue) throws DataException;
+ public byte readByte(String name) throws DataException;
+ public byte readByte(String name, Byte defaultValue) throws DataException;
+ public byte readByte(String name, Byte defaultValue, int radix) throws DataException;
+ public short readShort(String name) throws DataException;
+ public short readShort(String name, Short defaultValue) throws DataException;
+ public short readShort(String name, Short defaultValue, int radix) throws DataException;
+ public int readInt(String name) throws DataException;
+ public int readInt(String name, Integer defaultValue) throws DataException;
+ public int readInt(String name, Integer defaultValue, int radix) throws DataException;
+ public long readLong(String name) throws DataException;
+ public long readLong(String name, Long defaultValue) throws DataException;
+ public long readLong(String name, Long defaultValue, int radix) throws DataException;
+ public boolean readBoolean(String name) throws DataException;
+ public boolean readBoolean(String name, Boolean defaultValue) throws DataException;
+ public char readChar(String name) throws DataException;
+ public char readChar(String name, Character defaultValue) throws DataException;
+ public String readString(String name) throws DataException;
+ public String readString(String name, String defaultValue) throws DataException;
+ public String readNullableString(String name) throws DataException;
+ public Class readClass(String name) throws DataException;
+ public Class readClass(String name, Class defaultClass) throws DataException;
+ public T readInstance(String name) throws DataException;
+ public > E readEnum(String name, Class enumType) throws DataException;
+ public > E readEnum(String name, Class enumType, E enumConstant) throws DataException;
+ public T[] readDelimited(String name, char delimiter, Class itemType) throws DataException;
+
+ // Children
+
+ public T[] readModelArray(String name, Class itemType) throws DataException;
+ public T[] readModelArray(String name, String attributeName) throws DataException;
+ public InputModel[] readModelArray(String name) throws DataException;
+
+ public T[] readModelArrayQualified(String name, Class itemType, String className) throws DataException;
+ public