From 778b6554c96663eb77f7690a0f161e3985e0d59d Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Tue, 26 Nov 2013 03:38:18 +0100 Subject: first commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 11 +++ COPYING | 22 +++++ Makefile | 12 +++ src/v/D3.java | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/v/VMaths.java | 225 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 550 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 Makefile create mode 100644 src/v/D3.java create mode 100644 src/v/VMaths.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c243105 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +_/ +bin/ +obj/ +\#*\# +*~ +*.bak +*.swo +*.swp +*.class +*.jar + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..c5c21e8 --- /dev/null +++ b/COPYING @@ -0,0 +1,22 @@ +Copyright (c) 2013, Mattias Andrée +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7e724d6 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +JAVAC = javac + +.PHONY: all +all: + @mkdir -p bin + $(JAVAC) -cp src -s src -d bin src/v/D3.java + + +.PHONY: clean +clean: + -rm -r bin + diff --git a/src/v/D3.java b/src/v/D3.java new file mode 100644 index 0000000..0ba9815 --- /dev/null +++ b/src/v/D3.java @@ -0,0 +1,280 @@ +/** + * Copyright (c) 2013, Mattias Andrée + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package v; + +import javax.swing.*; +import java.awt.event.*; +import java.awt.*; +import java.util.*; + +import static v.VMaths.*; + + +public class D3 +{ + static final float DEGREES_PER_SECOND = 50f / 1000f; + static final float[][] UNIT = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + + static float[] xs = new float[8]; + static float[] ys = new float[8]; + static float[] zs = new float[8]; + + static float[] normal_xs = {0f, 0f, 1f, -1f, 0f, 0f}; + static float[] normal_ys = {1f, 0f, 0f, 0f, 0f, -1f}; + static float[] normal_zs = {0f, 1f, 0f, 0f, -1f, 0f}; + + static float[] rotation = {1f, 0f, 0f}; + static float rotation_speed = 0f; + + static int rx = 0; + static int ry = 0; + static int rxy = 0; + + public static void main(String... args) throws InterruptedException + { + for (int i = 0; i < 8; i++) + { + xs[i] = ((i & 1) != 0 ? 1f : 0f) - 0.5f; + ys[i] = ((i & 2) != 0 ? 1f : 0f) - 0.5f; + zs[i] = ((i & 4) != 0 ? 1f : 0f) - 0.5f; + } + + final JFrame window = new JFrame(); + final JPanel panel; + window.pack(); + window.setLayout(new BorderLayout()); + window.add(panel = new JPanel() + { + { + this.setBackground(Color.BLACK); + } + + @Override + public void paint(Graphics g) + { + super.paint(g); + + /* */ + int[] z = new int[6]; + for (int i = 0; i < 6; i++) + { + int v = (int)(normal_zs[i] * 1000f); + z[i] = (v << 8) | i; + } + + Arrays.sort(z); + + for (int i = 0; i < 6; i++) + { + int side = z[i] & 7; + switch (side) + { + case 0: draw(188, 188, 188, 0, 1, 5, 4, g, normal_zs[0]); break; + case 1: draw(188, 0, 0, 0, 1, 3, 2, g, normal_zs[1]); break; + case 2: draw( 0, 188, 0, 0, 2, 6, 4, g, normal_zs[2]); break; + case 3: draw( 0, 0, 188, 1, 3, 7, 5, g, normal_zs[3]); break; + case 4: draw(188, 128, 0, 4, 5, 7, 6, g, normal_zs[4]); break; + case 5: draw(188, 188, 0, 2, 3, 7, 6, g, normal_zs[5]); break; + } + } + /* */ + + /* */ + draw(new Color(255, 0, 0), 0, 1, g); + draw(new Color( 0, 0, 255), 0, 2, g); + draw(new Color(210, 0, 210), 0, 4, g); + draw(new Color(255, 255, 0), 1, 3, g); + draw(new Color(210, 128, 0), 1, 5, g); + draw(new Color( 0, 255, 0), 2, 3, g); + draw(new Color( 0, 210, 210), 2, 6, g); + draw(new Color(188, 210, 0), 3, 7, g); + draw(new Color(188, 0, 0), 4, 5, g); + draw(new Color( 0, 0, 188), 4, 6, g); + draw(new Color(188, 188, 0), 5, 7, g); + draw(new Color( 0, 188, 0), 6, 7, g); + /* */ + } + + private void draw(int R, int G, int B, int a, int b, int c, int d, Graphics g, float normal_z) + { + int A = (int)(255f * normal_z); + if (A > 0) + { + A = A / 2 + 128; + + if (A > 255) + A = 255; + g.setColor(new Color(R, G, B, A)); + g.fillPolygon(new int[] {Px(a), Px(b), Px(c), Px(d)}, + new int[] {Py(a), Py(b), Py(c), Py(d)}, 4); + } + } + + private void draw(Color colour, int i, int j, Graphics g) + { + g.setColor(colour); + g.drawLine(Px(i), Py(i), Px(j), Py(j)); + } + + static final float SCREEN_Z = 50f; + static final float MODEL_Z = 55f; + static final float VIEWER_Z = 50f; + static final float VIEWER_X = 0f; + static final float VIEWER_Y = 0f; + static final float CAMERA_Z = 10f; + static final float CAMERA_X = 0f; + static final float CAMERA_Y = 0f; + + private int Px(int i) + { + /* Orthogonal projection */ + //float z = SCREEN_Z / (zs[i] + MODEL_Z); + //return (int)(xs[i] * z * 300f + 400f); + + /* Perspective projection */ + float model_z = zs[i] + MODEL_Z; + float model_x = xs[i]; + float p = VIEWER_Z / (model_z - CAMERA_Z) * (model_x - CAMERA_X) - VIEWER_X; + return (int)(p * 300f + 400f); + } + + private int Py(int i) + { + /* Orthogonal projection */ + //float z = SCREEN_Z / (zs[i] + MODEL_Z); + //return (int)(ys[i] * z * 300f + 300f); + + /* Perspective projection */ + float model_z = zs[i] + MODEL_Z; + float model_y = ys[i]; + float p = VIEWER_Z / (model_z - CAMERA_Z) * (model_y - CAMERA_Y) - VIEWER_Y; + return (int)(p * 300f + 300f); + } + + }); + window.setBackground(Color.BLACK); + final Insets in = window.getInsets(); + window.setSize(new Dimension(in.left + 800 + in.right, in.top + 600 + in.bottom)); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setVisible(true); + + final float SPEED = (float)(Math.sqrt(25.5f / 2f)) * DEGREES_PER_SECOND; + + window.addKeyListener(new KeyListener() + { + public void keyTyped(KeyEvent e) {} + + public void keyReleased(KeyEvent e) + { + switch (e.getKeyCode()) + { + case KeyEvent.VK_D: rx = 0; break; + case KeyEvent.VK_A: rx = 0; break; + case KeyEvent.VK_W: ry = 0; break; + case KeyEvent.VK_S: ry = 0; break; + case KeyEvent.VK_E: rxy = 0; break; + case KeyEvent.VK_Q: rxy = 0; break; + } + } + + public void keyPressed(KeyEvent e) + { + switch (e.getKeyCode()) + { + case KeyEvent.VK_D: rx = +1; break; + case KeyEvent.VK_A: rx = -1; break; + case KeyEvent.VK_W: ry = +1; break; + case KeyEvent.VK_S: ry = -1; break; + case KeyEvent.VK_E: rxy = +1; break; + case KeyEvent.VK_Q: rxy = -1; break; + + case KeyEvent.VK_R: + rotation_speed = 0; + break; + } + } + }); + + for (;;) + { + Thread.sleep(50); + + if (rx != 0) + { + float[] v = mul(rx * SPEED, createRotation("x")); + v = add(mul(rotation_speed, rotation), v); + rotation_speed = length(v); + rotation = normalise(v); + } + + if (ry != 0) + { + float[] v = mul(ry * SPEED, createRotation("y")); + v = add(mul(rotation_speed, rotation), v); + rotation_speed = length(v); + rotation = normalise(v); + } + + if (rxy != 0) + { + float[] v = mul(rxy * SPEED, createRotation("xy")); + v = add(mul(rotation_speed, rotation), v); + rotation_speed = length(v); + rotation = normalise(v); + } + + if (rotation_speed != 0) + transform(createRotation(rotation, rotation_speed)); + + panel.repaint(); + } + } + + + public static void transform(float[][] m) + { + /* This is not a transformation of the object, but + * rather its projection onto the screen. (This + * program combines the object and the projection.) */ + + for (int i = 0; i < 8; i++) + { + float[] v = mul(m, xs[i], ys[i], zs[i]); + xs[i] = v[0]; + ys[i] = v[1]; + zs[i] = v[2]; + } + + for (int i = 0; i < 6; i++) + { + float[] v = mul(m, normal_xs[i], normal_ys[i], normal_zs[i]); + normal_xs[i] = v[0]; + normal_ys[i] = v[1]; + normal_zs[i] = v[2]; + } + } + +} + diff --git a/src/v/VMaths.java b/src/v/VMaths.java new file mode 100644 index 0000000..9312608 --- /dev/null +++ b/src/v/VMaths.java @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2013, Mattias Andrée + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package v; + +/** + * Orthonormalised vector maths + */ +public class VMaths +{ + + public static float[] createRotation(String side) + { + switch (side.toLowerCase()) + { + case "x": + case "xz": + case "zx": + return new float[] { 0f, -1f, 0f }; + + case "y": + case "yz": + case "zy": + return new float[] { -1f, 0f, 0f }; + + case "xy": + case "yx": + return new float[] { 0f, 0f, +1f }; + } + + return null; + } + + public static float[][] createRotation(String side, float thetaDegrees) + { + switch (side.toLowerCase()) + { + case "x": + case "xz": + case "zx": + return createRotation( 0f, -1f, 0f, thetaDegrees); + + case "y": + case "yz": + case "zy": + return createRotation(-1f, 0f, 0f, thetaDegrees); + + case "xy": + case "yx": + return createRotation( 0f, 0f, +1f, thetaDegrees); + } + + return null; + } + + public static float[][] createRotation(float x, float y, float z, float thetaDegrees) + { + float theta = thetaDegrees * (float)(Math.PI) / 180f; + float[][] m = new float[3][3]; + + float cos = (float)(Math.cos(theta)); + float sin = (float)(Math.sin(theta)); + float _cos = 1f - cos; + + m[0][0] = x * x * _cos + cos; + m[1][0] = x * y * _cos + z * sin; + m[2][0] = x * z * _cos - y * sin; + + m[0][1] = y * x * _cos - z * sin; + m[1][1] = y * y * _cos + cos; + m[2][1] = y * z * _cos + x * sin; + + m[0][2] = z * x * _cos + y * sin; + m[1][2] = z * y * _cos - x * sin; + m[2][2] = z * z * _cos + cos; + + return m; + } + + public static float[][] createRotation(float[] v, float thetaDegrees) + { + return createRotation(v[0], v[1], v[2], thetaDegrees); + } + + public static float[] mul(float[][] m, float[] v) + { + int n, k = v.length; + float[] rc = new float[n = m.length]; + + for (int r = 0; r < n; r++) + for (int i = 0; i < k; i++) + rc[r] += m[r][i] * v[i]; + + return rc; + } + + public static float[] mul(float[][] m, float x, float y, float z) + { + int n; + float[] rc = new float[n = m.length]; + + for (int i = 0; i < n; i++) + rc[i] = m[i][0] * x + + m[i][1] * y + + m[i][2] * z; + + return rc; + } + + public static float[][] mul(float[][] a, float[][] b) + { + int n, m, k = b.length; + float[][] rc = new float[n = a.length][m = b[0].length]; + + for (int r = 0; r < n; r++) + for (int c = 0; c < m; c++) + for (int i = 0; i < k; i++) + rc[r][c] += a[i][r] * b[c][i]; + + return rc; + } + + public static float[][] mul(float a, float[][] b) + { + int n, m; + float[][] rc = new float[n = b.length][m = b[0].length]; + + for (int r = 0; r < n; r++) + for (int c = 0; c < m; c++) + rc[r][c] = a * b[r][c]; + + return rc; + } + + public static float[] mul(float a, float[] b) + { + int n; + float[] rc = new float[n = b.length]; + + for (int r = 0; r < n; r++) + rc[r] = a * b[r]; + + return rc; + } + + public static float[][] add(float[][] a, float[][] b) + { + int n, m; + float[][] rc = new float[n = a.length][m = b[0].length]; + + for (int r = 0; r < n; r++) + for (int c = 0; c < m; c++) + rc[r][c] = a[r][c] + b[r][c]; + + return rc; + } + + public static float[] add(float[] a, float[] b) + { + int n; + float[] rc = new float[n = a.length]; + + for (int r = 0; r < n; r++) + rc[r] = a[r] + b[r]; + + return rc; + } + + public static float length(float[] v) + { + int n = v.length; + float length = 0; + + for (int r = 0; r < n; r++) + length += v[r] * v[r]; + + length = (float)Math.sqrt(length); + + return length; + } + + public static float[] normalise(float[] v) + { + int n; + float[] rc = new float[n = v.length]; + float length = length(v); + + if (length * length == 0f) + { + for (int r = 0; r < n; r++) + rc[r] = 0; + rc[0] = 1; + } + else + for (int r = 0; r < n; r++) + rc[r] = v[r] / length; + + return rc; + } + + + +} + -- cgit v1.2.3-70-g09d2