Initial commit.

master
Ondřej Hruška 10 years ago
commit f9100f0f0a
  1. 36
      .classpath
  2. 5
      .gitignore
  3. 17
      .project
  4. 11
      .settings/org.eclipse.jdt.core.prefs
  5. BIN
      lib/OpenAL32.dll
  6. BIN
      lib/OpenAL64.dll
  7. BIN
      lib/jinput-dx8.dll
  8. BIN
      lib/jinput-dx8_64.dll
  9. BIN
      lib/jinput-raw.dll
  10. BIN
      lib/jinput-raw_64.dll
  11. BIN
      lib/jinput.jar
  12. BIN
      lib/jogg-0.0.7.jar
  13. BIN
      lib/jorbis-0.0.15.jar
  14. BIN
      lib/libjinput-linux.so
  15. BIN
      lib/libjinput-linux64.so
  16. BIN
      lib/libjinput-osx.jnilib
  17. BIN
      lib/liblwjgl.jnilib
  18. BIN
      lib/liblwjgl.so
  19. BIN
      lib/liblwjgl64.so
  20. BIN
      lib/libopenal.so
  21. BIN
      lib/libopenal64.so
  22. BIN
      lib/lwjgl-source-2.8.4.zip
  23. BIN
      lib/lwjgl.dll
  24. BIN
      lib/lwjgl.jar
  25. BIN
      lib/lwjgl64.dll
  26. BIN
      lib/lwjgl_util.jar
  27. BIN
      lib/slick-util-src.zip
  28. BIN
      lib/slick-util.jar
  29. 11
      res/models/turtle.mtl
  30. 3558
      res/models/turtle.obj
  31. BIN
      res/models/turtle.png
  32. BIN
      res/models/turtle.wings
  33. BIN
      res/models/turtle.xcf
  34. 11
      res/models/turtle2.mtl
  35. 3558
      res/models/turtle2.obj
  36. BIN
      res/models/turtle2.wings
  37. 86
      src/com/mykaruga/models/Models.java
  38. 67
      src/com/mykaruga/models/wavefront/loader/Face.java
  39. 37
      src/com/mykaruga/models/wavefront/loader/LineParserFactory.java
  40. 50
      src/com/mykaruga/models/wavefront/loader/Material.java
  41. 33
      src/com/mykaruga/models/wavefront/loader/NormalParser.java
  42. 300
      src/com/mykaruga/models/wavefront/loader/RenderModel.java
  43. 35
      src/com/mykaruga/models/wavefront/loader/TextureCoordinate.java
  44. 45
      src/com/mykaruga/models/wavefront/loader/Vertex.java
  45. 15
      src/com/mykaruga/models/wavefront/parser/CommentParser.java
  46. 19
      src/com/mykaruga/models/wavefront/parser/DefaultParser.java
  47. 19
      src/com/mykaruga/models/wavefront/parser/LineParser.java
  48. 41
      src/com/mykaruga/models/wavefront/parser/mtl/KdMapParser.java
  49. 35
      src/com/mykaruga/models/wavefront/parser/mtl/KdParser.java
  50. 74
      src/com/mykaruga/models/wavefront/parser/mtl/MaterialFileParser.java
  51. 27
      src/com/mykaruga/models/wavefront/parser/mtl/MaterialParser.java
  52. 24
      src/com/mykaruga/models/wavefront/parser/mtl/MtlLineParserFactory.java
  53. 98
      src/com/mykaruga/models/wavefront/parser/obj/FaceParser.java
  54. 21
      src/com/mykaruga/models/wavefront/parser/obj/FreeFormParser.java
  55. 27
      src/com/mykaruga/models/wavefront/parser/obj/MaterialParser.java
  56. 29
      src/com/mykaruga/models/wavefront/parser/obj/ObjLineParserFactory.java
  57. 37
      src/com/mykaruga/models/wavefront/parser/obj/TextureCooParser.java
  58. 34
      src/com/mykaruga/models/wavefront/parser/obj/VertexParser.java
  59. 152
      src/com/porcupine/color/HSV.java
  60. 336
      src/com/porcupine/color/RGB.java
  61. 729
      src/com/porcupine/coord/Coord.java
  62. 159
      src/com/porcupine/coord/CoordI.java
  63. 639
      src/com/porcupine/coord/Rect.java
  64. 283
      src/com/porcupine/coord/Vec.java
  65. 64
      src/com/porcupine/ion/AbstractIonList.java
  66. 75
      src/com/porcupine/ion/AbstractIonMap.java
  67. 261
      src/com/porcupine/ion/Ion.java
  68. 144
      src/com/porcupine/ion/IonList.java
  69. 143
      src/com/porcupine/ion/IonMap.java
  70. 57
      src/com/porcupine/ion/IonMarks.java
  71. 41
      src/com/porcupine/ion/Ionizable.java
  72. 16
      src/com/porcupine/ion/IonizableOptional.java
  73. 208
      src/com/porcupine/ion/StreamUtils.java
  74. 804
      src/com/porcupine/math/Calc.java
  75. 91
      src/com/porcupine/math/Polar.java
  76. 95
      src/com/porcupine/math/PolarDeg.java
  77. 174
      src/com/porcupine/math/Range.java
  78. 52
      src/com/porcupine/mutable/AbstractMutable.java
  79. 28
      src/com/porcupine/mutable/MBoolean.java
  80. 28
      src/com/porcupine/mutable/MDouble.java
  81. 29
      src/com/porcupine/mutable/MFloat.java
  82. 28
      src/com/porcupine/mutable/MInt.java
  83. 28
      src/com/porcupine/mutable/MString.java
  84. 132
      src/com/porcupine/struct/Struct2.java
  85. 172
      src/com/porcupine/struct/Struct3.java
  86. 213
      src/com/porcupine/struct/Struct4.java
  87. 256
      src/com/porcupine/struct/Struct5.java
  88. 295
      src/com/porcupine/struct/Struct6.java
  89. 336
      src/com/porcupine/struct/Struct7.java
  90. 377
      src/com/porcupine/struct/Struct8.java
  91. 54
      src/com/porcupine/time/FpsMeter.java
  92. 130
      src/com/porcupine/time/Timer.java
  93. 36
      src/com/porcupine/util/FileSuffixFilter.java
  94. 182
      src/com/porcupine/util/FileUtils.java
  95. 1062
      src/com/porcupine/util/PropertyManager.java
  96. 104
      src/com/porcupine/util/StringUtils.java
  97. 51
      src/com/porcupine/util/VarargsParser.java
  98. 368
      src/net/spritegen/App.java
  99. 57
      src/net/spritegen/Constants.java
  100. 90
      src/net/spritegen/SetupLoader.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry exported="true" kind="lib" path="lib/jinput.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="lib/jogg-0.0.7.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="lib/jorbis-0.0.15.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="lib/lwjgl_util.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="lib/lwjgl.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="lib/slick-util.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="SpriteGen/lib"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>

5
.gitignore vendored

@ -0,0 +1,5 @@
/bin/
/target/
*.log
.attach_pid*
*~

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SpriteGen</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,11 @@
# Exported from Wings 3D 1.4.1
newmtl turtle_auv
Ns 100.0
d 1.0
illum 2
Kd 1.0 1.0 1.0
Ka 1.0 1.0 1.0
Ks 1.0 1.0 1.0
Ke 0.0 0.0 0.0
map_Kd turtle.png

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Binary file not shown.

@ -0,0 +1,11 @@
# Exported from Wings 3D 1.4.1
newmtl turtle_auv
Ns 100.0
d 1.0
illum 2
Kd 1.0 1.0 1.0
Ka 1.0 1.0 1.0
Ks 1.0 1.0 1.0
Ke 0.0 0.0 0.0
map_Kd turtle.png

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -0,0 +1,86 @@
package com.mykaruga.models;
import static org.lwjgl.opengl.GL11.*;
import java.io.File;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import net.spritegen.App;
import net.spritegen.Constants;
import net.spritegen.textures.TextureManager;
import net.spritegen.util.Utils;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.porcupine.math.Calc;
import com.porcupine.math.Calc.Buffers;
public class Models {
public static RenderModel turtle;
public static void load() {
turtle = new RenderModel(App.modelFile.getAbsolutePath());
}
private static int beginList = -1;
private static int endList = -1;
public static void renderBegin() {
if (beginList == -1) {
beginList = glGenLists(1);
glNewList(beginList, GL_COMPILE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
float spec = (float) App.cfg.mat_specular;
float amb = (float) App.cfg.mat_ambient;
float diff = (float) App.cfg.mat_diffuse;
FloatBuffer buff = Calc.Buffers.alloc(4);
Calc.Buffers.fill(buff, amb, amb, amb, 1.0f);
glMaterial(GL_FRONT, GL_AMBIENT, Buffers.mkFillBuff(amb, amb, amb, 1f));
buff.clear();
Calc.Buffers.fill(buff, spec, spec, spec, 1.0f);
glLight(GL_LIGHT0, GL_SPECULAR, buff);
glMaterial(GL_FRONT, GL_SPECULAR, Buffers.mkFillBuff(spec, spec, spec, 1f));
buff.clear();
Calc.Buffers.fill(buff, diff, diff, diff, 1.0f);
glLight(GL_LIGHT0, GL_DIFFUSE, buff);
glMaterial(GL_FRONT, GL_DIFFUSE, Buffers.mkFillBuff(diff, diff, diff, 1f));
glMaterialf(GL_FRONT, GL_SHININESS, 8);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glColor4d(1, 1, 1, 1);
glEndList();
}
glCallList(beginList);
}
public static void renderEnd() {
if (endList == -1) {
endList = glGenLists(1);
glNewList(endList, GL_COMPILE);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_CULL_FACE);
TextureManager.unbind();
glDisable(GL_TEXTURE_2D);
glEndList();
}
glCallList(endList);
}
}

@ -0,0 +1,67 @@
package com.mykaruga.models.wavefront.loader;
public class Face {
public static final int GL_TRIANGLES = 3;
public static final int GL_QUADS = 4;
private Vertex[] vertices;
private Vertex[] normals;
private TextureCoordinate[] textures;
private Material material;
private int type;
public Face copy() {
Face f = new Face();
f.setVertices(vertices);
f.setNormals(normals);
f.setTextures(textures);
f.setMaterial(material);
return f;
}
public Vertex[] getVertices() {
return vertices;
}
public void setVertices(Vertex[] vertices) {
this.vertices = vertices;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Vertex[] getNormals() {
return normals;
}
public void setNormals(Vertex[] normals) {
this.normals = normals;
}
public TextureCoordinate[] getTextures() {
return textures;
}
public void setTextures(TextureCoordinate[] textures) {
this.textures = textures;
}
public Material getMaterial() {
return material;
}
public void setMaterial(Material material) {
this.material = material;
}
}

@ -0,0 +1,37 @@
package com.mykaruga.models.wavefront.loader;
import java.util.Hashtable;
import com.mykaruga.models.wavefront.parser.DefaultParser;
import com.mykaruga.models.wavefront.parser.LineParser;
public abstract class LineParserFactory {
protected Hashtable<String, LineParser> parsers = new Hashtable<String, LineParser>();
protected RenderModel object = null;
public LineParser getLineParser(String line) {
if (line == null) return null;
line = line.replaceAll(" ", " ");
line = line.replaceAll(" ", "");
String[] lineWords = line.split(" ");
if (lineWords.length < 1) return new DefaultParser();
String lineType = lineWords[0];
LineParser parser = parsers.get(lineType);
if (parser == null) {
parser = new DefaultParser();
}
parser.setWords(lineWords);
return parser;
}
}

@ -0,0 +1,50 @@
package com.mykaruga.models.wavefront.loader;
import org.newdawn.slick.opengl.Texture;
public class Material {
private Texture texture;
private Vertex Kd;
private String name;
public Material(String name) {
this.name = name;
}
public Material(Material other) {
//this.texture = other.texture;
this.Kd = other.Kd;
this.name = other.name;
}
public Texture getTexture() {
return texture;
}
public Material setTexture(Texture texture) {
this.texture = texture;
return this;
}
public Vertex getKd() {
return Kd;
}
public void setKa(Vertex kd) {
Kd = kd;
}
@Override
public String toString() {
return "MAT." + name;
}
public String getName() {
return name;
}
}

@ -0,0 +1,33 @@
package com.mykaruga.models.wavefront.loader;
import com.mykaruga.models.wavefront.parser.LineParser;
public class NormalParser extends LineParser {
Vertex vertex = null;
public NormalParser() {}
@Override
public void parse() {
vertex = new Vertex();
try {
vertex.setX(Float.parseFloat(words[1]));
vertex.setY(Float.parseFloat(words[2]));
vertex.setZ(Float.parseFloat(words[3]));
} catch (Exception e) {
throw new RuntimeException("NormalParser Error");
}
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
wavefrontObject.getNormals().add(vertex);
}
}

@ -0,0 +1,300 @@
package com.mykaruga.models.wavefront.loader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map.Entry;
import net.spritegen.textures.TextureManager;
import net.spritegen.util.Log;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.util.ResourceLoader;
import com.mykaruga.models.wavefront.parser.LineParser;
import com.mykaruga.models.wavefront.parser.obj.ObjLineParserFactory;
/**
* OBJ 3D object loaded and pre-rendered.
*
* @author Fabien Sanglard
*/
public class RenderModel {
private static final boolean DEBUG = true;
public String replTexture = null;
private ArrayList<Vertex> vertices = new ArrayList<Vertex>();
private ArrayList<Vertex> normals = new ArrayList<Vertex>();
private ArrayList<TextureCoordinate> textures = new ArrayList<TextureCoordinate>();
private ArrayList<Face> faces = new ArrayList<Face>();
private ObjLineParserFactory parserFactory;
private Hashtable<String, Material> materials = new Hashtable<String, Material>();
// This variable is used for both parsing and rendition
private Material currentMaterial;
private String contextfolder = "";
public double radius = 0;
/**
* Load object with alternate texture.
*
* @param fileName
* @param textureName
*/
public RenderModel(String fileName, String textureName) {
this.replTexture = textureName;
int lastSlashIndex = fileName.lastIndexOf('/');
if (lastSlashIndex != -1) this.contextfolder = fileName.substring(0, lastSlashIndex + 1);
lastSlashIndex = fileName.lastIndexOf('\\');
if (lastSlashIndex != -1) this.contextfolder = fileName.substring(0, lastSlashIndex + 1);
parse(fileName);
calculateRadius();
}
// /**
// * Load object with alternate texture.
// *
// * @param fileName
// * @param textureName
// */
// public RenderModel(RenderModel other, String textureName) {
// this.vertices = other.vertices;
// this.normals = other.normals;
// this.textures = other.textures;
// this.contextfolder = other.contextfolder;
// this.radius = other.radius;
//
// String pathToTextureBinary = getContextfolder() + textureName;
// Texture texture = TextureManager.load(pathToTextureBinary);
// for (Entry<String, Material> e : other.materials.entrySet()) {
// materials.put(e.getKey(), new Material(e.getValue()).setTexture(texture));
// }
// for (Face f : other.faces) {
// Face f2;
// faces.add(f2 = f.copy());
// f2.setMaterial(materials.get(f2.getMaterial().getName()));
// }
//
// }
public RenderModel(String fileName) {
int lastSlashIndex = fileName.lastIndexOf('/');
if (lastSlashIndex != -1) this.contextfolder = fileName.substring(0, lastSlashIndex + 1);
lastSlashIndex = fileName.lastIndexOf('\\');
if (lastSlashIndex != -1) this.contextfolder = fileName.substring(0, lastSlashIndex + 1);
parse(fileName);
calculateRadius();
}
private void calculateRadius() {
double currentNorm = 0;
for (Vertex vertex : vertices) {
currentNorm = vertex.norm();
if (currentNorm > radius) radius = currentNorm;
}
}
public String getContextfolder() {
return contextfolder;
}
public void parse(String fileName) {
parserFactory = new ObjLineParserFactory(this);
InputStream fileInput = ResourceLoader.getResourceAsStream(fileName);
if (fileInput == null) {
// Could not find the file in the jar.
try {
File file = new File(fileName);
if (file.exists()) fileInput = new FileInputStream(file);
} catch (Exception e2) {
e2.printStackTrace();
}
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(fileInput));
String currentLine = null;
while ((currentLine = in.readLine()) != null)
parseLine(currentLine);
in.close();
} catch (Exception e) {
Log.e("Error reading file " + fileName, e);
throw new RuntimeException(e);
}
//
// Log.finest("Loaded OBJ from file " + fileName);
// Log.finest(getVertices().size() + " vertices.");
// Log.finest(getNormals().size() + " normals.");
// Log.finest(getTextures().size() + " textures coordinates.");
// Log.finest(getFaces().size() + " faces.");
}
private int lineCounter = 0;
private void parseLine(String currentLine) {
if ("".equals(currentLine)) return;
LineParser parser = parserFactory.getLineParser(currentLine);
try {
parser.parse();
parser.incoporateResults(this);
} catch (Throwable t) {
Log.e("ERROR at line " + lineCounter + " : " + currentLine, t);
System.exit(1);
}
lineCounter++;
}
public int displayListId = 0;
public void render() {
if (displayListId != 0) {
GL11.glCallList(displayListId);
return;
}
displayListId = GL11.glGenLists(1);
GL11.glNewList(displayListId, GL11.GL_COMPILE);
Face face = null;
Material material = new Material("__non_existant");
for (int i = 0; i < getFaces().size(); i++) {
face = getFaces().get(i);
if (!material.equals(face.getMaterial())) {
// Set texture and setColor
material = face.getMaterial();
if (material == null) {
Log.w("No material in model!");
} else if (material.getTexture() != null) {
GL11.glBindTexture(GL11.GL_TEXTURE_2D, material.getTexture().getTextureID());
} else
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
if (material != null && material.getKd() != null)
GL11.glColor3f(material.getKd().getX(), material.getKd().getY(), material.getKd().getZ());
}
if (face.getType() == Face.GL_TRIANGLES) {
GL11.glBegin(GL11.GL_TRIANGLES);
} else if (face.getType() == Face.GL_QUADS) {
GL11.glBegin(GL11.GL_QUADS);
} else {
GL11.glBegin(GL11.GL_POLYGON);
}
Vertex vertex = null;
Vertex normal = null;
TextureCoordinate textureCoo = null;
for (int j = 0; j < face.getVertices().length; j++) {
vertex = face.getVertices()[j];
if (j < face.getNormals().length && face.getNormals()[j] != null) {
normal = face.getNormals()[j];
GL11.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
}
if (j < face.getTextures().length && face.getTextures()[j] != null) {
textureCoo = face.getTextures()[j];
GL11.glTexCoord2f(textureCoo.getU(), textureCoo.getV());
//GL11.glTexCoord2f(textureCoo.getV(),textureCoo.getU());
}
GL11.glVertex3f(vertex.getX(), vertex.getY(), vertex.getZ());
}
GL11.glEnd();
}
GL11.glEndList();
}
public void setMaterials(Hashtable<String, Material> materials) {
this.materials = materials;
}
public void setTextures(ArrayList<TextureCoordinate> textures) {
this.textures = textures;
}
public ArrayList<TextureCoordinate> getTextures() {
return textures;
}
public void setVertices(ArrayList<Vertex> vertices) {
this.vertices = vertices;
}
public ArrayList<Vertex> getVertices() {
return vertices;
}
public void setFaces(ArrayList<Face> faces) {
this.faces = faces;
}
public ArrayList<Face> getFaces() {
return faces;
}
public void setNormals(ArrayList<Vertex> normals) {
this.normals = normals;
}
public ArrayList<Vertex> getNormals() {
return normals;
}
public Hashtable<String, Material> getMaterials() {
return this.materials;
}
public Material getCurrentMaterial() {
return currentMaterial;
}
public void setCurrentMaterial(Material currentMaterial) {
this.currentMaterial = currentMaterial;
}
}

@ -0,0 +1,35 @@
package com.mykaruga.models.wavefront.loader;
public class TextureCoordinate {
private float u;
private float v;
private float w;
public float getU() {
return u;
}
public void setU(float u) {
this.u = u;
}
public float getV() {
return v;
}
public void setV(float v) {
this.v = v;
}
public float getW() {
return w;
}
public void setW(float w) {
this.w = w;
}
}

@ -0,0 +1,45 @@
package com.mykaruga.models.wavefront.loader;
public class Vertex {
private float x;
private float y;
private float z;
public Vertex(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vertex() {}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getZ() {
return z;
}
public void setZ(float z) {
this.z = z;
}
public double norm() {
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
}
}

@ -0,0 +1,15 @@
package com.mykaruga.models.wavefront.parser;
import com.mykaruga.models.wavefront.loader.RenderModel;
public class CommentParser extends LineParser {
@Override
public void incoporateResults(RenderModel wavefrontObject) {}
@Override
public void parse() {}
}

@ -0,0 +1,19 @@
package com.mykaruga.models.wavefront.parser;
import com.mykaruga.models.wavefront.loader.RenderModel;
public class DefaultParser extends LineParser {
public DefaultParser() {}
@Override
public void parse() {
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {}
}

@ -0,0 +1,19 @@
package com.mykaruga.models.wavefront.parser;
import com.mykaruga.models.wavefront.loader.RenderModel;
public abstract class LineParser {
protected String[] words = null;
public void setWords(String[] words) {
this.words = words;
}
public abstract void parse();
public abstract void incoporateResults(RenderModel wavefrontObject);
}

@ -0,0 +1,41 @@
package com.mykaruga.models.wavefront.parser.mtl;
import net.spritegen.textures.TextureManager;
import org.newdawn.slick.opengl.Texture;
import com.mykaruga.models.wavefront.loader.Material;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.LineParser;
public class KdMapParser extends LineParser {
private Texture texture = null;
private RenderModel object = null;
private String textureFileName = null;
public KdMapParser(RenderModel object) {
this.object = object;
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
if (texture != null) {
Material currentMaterial = wavefrontObject.getCurrentMaterial();
currentMaterial.setTexture(texture);
}
}
@Override
public void parse() {
String textureFileName = words[words.length - 1];
String pathToTextureBinary = object.getContextfolder() + (object.replTexture == null ? textureFileName : object.replTexture);
// load texture, if already loaded, use the same instance.
texture = TextureManager.load(pathToTextureBinary);
}
}

@ -0,0 +1,35 @@
package com.mykaruga.models.wavefront.parser.mtl;
import com.mykaruga.models.wavefront.loader.Material;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.loader.Vertex;
import com.mykaruga.models.wavefront.parser.LineParser;
public class KdParser extends LineParser {
Vertex kd = null;
@Override
public void incoporateResults(RenderModel wavefrontObject) {
Material currentMaterial = wavefrontObject.getCurrentMaterial();
currentMaterial.setKa(kd);
}
@Override
public void parse() {
kd = new Vertex();
try {
kd.setX(Float.parseFloat(words[1]));
kd.setY(Float.parseFloat(words[2]));
kd.setZ(Float.parseFloat(words[3]));
} catch (Exception e) {
throw new RuntimeException("VertexParser Error");
}
}
}

@ -0,0 +1,74 @@
package com.mykaruga.models.wavefront.parser.mtl;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Hashtable;
import org.newdawn.slick.util.ResourceLoader;
import com.mykaruga.models.wavefront.loader.Material;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.LineParser;
public class MaterialFileParser extends LineParser {
Hashtable<String, Material> materials = new Hashtable<String, Material>();
private RenderModel object;
private MtlLineParserFactory parserFactory = null;
public MaterialFileParser(RenderModel object) {
this.object = object;
this.parserFactory = new MtlLineParserFactory(object);
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
// Material are directly added by the parser, no need to do anything here...
}
@Override
public void parse() {
String filename = words[1];
String pathToMTL = object.getContextfolder() + filename;
InputStream fileInput = ResourceLoader.getResourceAsStream(pathToMTL);
if (fileInput == null) {
// Could not find the file in the jar.
try {
File file = new File(pathToMTL);
if (file.exists()) fileInput = new FileInputStream(file);
} catch (Exception e2) {
e2.printStackTrace();
}
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(fileInput));
String currentLine = null;
while ((currentLine = in.readLine()) != null) {
LineParser parser = parserFactory.getLineParser(currentLine);
parser.parse();
parser.incoporateResults(object);
}
if (in != null) in.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error parsing " + pathToMTL);
}
}
}

@ -0,0 +1,27 @@
package com.mykaruga.models.wavefront.parser.mtl;
import com.mykaruga.models.wavefront.loader.Material;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.LineParser;
public class MaterialParser extends LineParser {
String materialName = "";
@Override
public void incoporateResults(RenderModel wavefrontObject) {
Material newMaterial = new Material(materialName);
wavefrontObject.getMaterials().put(materialName, newMaterial);
wavefrontObject.setCurrentMaterial(newMaterial);
}
@Override
public void parse() {
materialName = words[1];
}
}

@ -0,0 +1,24 @@
package com.mykaruga.models.wavefront.parser.mtl;
import com.mykaruga.models.wavefront.loader.LineParserFactory;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.CommentParser;
public class MtlLineParserFactory extends LineParserFactory {
public MtlLineParserFactory(RenderModel object) {
this.object = object;
parsers.put("newmtl", new MaterialParser());
parsers.put("Kd", new KdParser());
parsers.put("map_Kd", new KdMapParser(object));
parsers.put("#", new CommentParser());
}
}

@ -0,0 +1,98 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.Face;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.loader.TextureCoordinate;
import com.mykaruga.models.wavefront.loader.Vertex;
import com.mykaruga.models.wavefront.parser.LineParser;
public class FaceParser extends LineParser {
private Face face;
private Vertex[] vertices;
private Vertex[] normals;
private TextureCoordinate[] textures;
private RenderModel object = null;
public FaceParser(RenderModel object) {
this.object = object;
}
@Override
public void parse() {
face = new Face();
normals = new Vertex[words.length - 1];
textures = new TextureCoordinate[words.length - 1];
switch (words.length) {
case 4:
parseTriangles();
break;
case 5:
parseQuad();
break;
default:
parsePolygon();
}
}
private void parseTriangles() {
face.setType(Face.GL_TRIANGLES);
parseLine(3);
}
private void parsePolygon() {
face.setType(words.length - 1);
parseLine(words.length - 1);
}
private void parseLine(int vertexCount) {
String[] rawFaces = null;
int currentValue;
vertices = new Vertex[vertexCount];
for (int i = 1; i <= vertexCount; i++) {
rawFaces = words[i].split("/");
// v
currentValue = Integer.parseInt(rawFaces[0]);
vertices[i - 1] = object.getVertices().get(currentValue - 1); // -1 because references starts at 1
if (rawFaces.length == 1) continue;
if (!"".equals(rawFaces[1]) && rawFaces.length == 3) {
currentValue = Integer.parseInt(rawFaces[1]);
if (currentValue <= object.getTextures().size()) // This is to compensate the fact that if no texture is in the obj file, sometimes '1' is put instead of 'blank' (we find coord1/1/coord3 instead of coord1//coord3 or coord1/coord3)
textures[i - 1] = object.getTextures().get(currentValue - 1); // -1 because references starts at 1
}
currentValue = Integer.parseInt(rawFaces[rawFaces.length - 1]);
normals[i - 1] = object.getNormals().get(currentValue - 1); // -1 because references starts at 1
}
}
private void parseQuad() {
face.setType(Face.GL_QUADS);
parseLine(4);
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
face.setNormals(this.normals);
face.setVertices(this.vertices);
face.setTextures(this.textures);
if (wavefrontObject.getCurrentMaterial() != null) {
face.setMaterial(wavefrontObject.getCurrentMaterial());
}
wavefrontObject.getFaces().add(face);
}
static int faceC = 0;
}

@ -0,0 +1,21 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.LineParser;
public class FreeFormParser extends LineParser {
public FreeFormParser() {}
@Override
public void parse() {
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {}
}

@ -0,0 +1,27 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.Material;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.LineParser;
public class MaterialParser extends LineParser {
String materialName = "";
@Override
public void parse() {
materialName = words[1];
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
Material newMaterial = wavefrontObject.getMaterials().get(materialName);
wavefrontObject.setCurrentMaterial(newMaterial);
}
}

@ -0,0 +1,29 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.LineParserFactory;
import com.mykaruga.models.wavefront.loader.NormalParser;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.parser.CommentParser;
import com.mykaruga.models.wavefront.parser.mtl.MaterialFileParser;
public class ObjLineParserFactory extends LineParserFactory {
public ObjLineParserFactory(RenderModel object) {
this.object = object;
parsers.put("v", new VertexParser());
parsers.put("vn", new NormalParser());
parsers.put("vp", new FreeFormParser());
parsers.put("vt", new TextureCooParser());
parsers.put("f", new FaceParser(object));
parsers.put("#", new CommentParser());
parsers.put("mtllib", new MaterialFileParser(object));
parsers.put("usemtl", new MaterialParser());
}
}

@ -0,0 +1,37 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.loader.TextureCoordinate;
import com.mykaruga.models.wavefront.parser.LineParser;
public class TextureCooParser extends LineParser {
private TextureCoordinate coordinate = null;
public TextureCooParser() {}
@Override
public void parse() {
coordinate = new TextureCoordinate();
try {
if (words.length >= 2) coordinate.setU(Float.parseFloat(words[1]));
if (words.length >= 3) coordinate.setV(1 - Float.parseFloat(words[2])); // OBJ origin is at upper left, OpenGL origin is at lower left.
if (words.length >= 4) coordinate.setW(Float.parseFloat(words[3]));
} catch (Exception e) {
throw new RuntimeException("TextureParser Error");
}
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
wavefrontObject.getTextures().add(coordinate);
}
}

@ -0,0 +1,34 @@
package com.mykaruga.models.wavefront.parser.obj;
import com.mykaruga.models.wavefront.loader.RenderModel;
import com.mykaruga.models.wavefront.loader.Vertex;
import com.mykaruga.models.wavefront.parser.LineParser;
public class VertexParser extends LineParser {
Vertex vertex = null;
public VertexParser() {}
@Override
public void parse() {
vertex = new Vertex();
try {
vertex.setX(Float.parseFloat(words[1]));
vertex.setY(Float.parseFloat(words[2]));
vertex.setZ(Float.parseFloat(words[3]));
} catch (Exception e) {
throw new RuntimeException("VertexParser Error");
}
}
@Override
public void incoporateResults(RenderModel wavefrontObject) {
wavefrontObject.getVertices().add(vertex);
}
}

@ -0,0 +1,152 @@
package com.porcupine.color;
import java.awt.Color;
import com.porcupine.math.Calc;
/**
* HSV color
*
* @author MightyPork
*/
public class HSV {
/** H */
public double h;
/** S */
public double s;
/** V */
public double v;
/**
* Create black color 0,0,0
*/
public HSV() {}
/**
* Color from HSV 0-1
*
* @param h
* @param s
* @param v
*/
public HSV(Number h, Number s, Number v) {
this.h = h.doubleValue();
this.s = s.doubleValue();
this.v = v.doubleValue();
norm();
}
/**
* @return hue 0-1
*/
public double h() {
return h;
}
/**
* @return saturation 0-1
*/
public double s() {
return s;
}
/**
* @return value/brightness 0-1
*/
public double v() {
return v;
}
/**
* Set color to other color
*
* @param copied copied color
* @return this
*/
public HSV setTo(HSV copied) {
h = copied.h;
s = copied.s;
v = copied.v;
norm();
return this;
}
/**
* Set to H,S,V 0-1
*
* @param h hue
* @param s saturation
* @param v value
* @return this
*/
public HSV setTo(Number h, Number s, Number v) {
this.h = h.doubleValue();
this.s = s.doubleValue();
this.v = v.doubleValue();
norm();
return this;
}
/**
* Fix numbers out of range 0-1
*/
public void norm() {
h = Calc.clampd(h, 0, 1);
s = Calc.clampd(s, 0, 1);
v = Calc.clampd(v, 0, 1);
}
/**
* Convert to RGB
*
* @return RGB representation
*/
public RGB toRGB() {
norm();
int rgb = Color.HSBtoRGB((float) h, (float) s, (float) v);
return RGB.fromHex(rgb);
}
/**
* Make from RGB
*
* @param color RGB
* @return HSV
*/
public static HSV fromRGB(RGB color) {
return color.toHSV();
}
@Override
public String toString() {
return "HSV[" + h + ";" + s + ";" + v + "]";
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof HSV)) return false;
return ((HSV) obj).h == h && ((HSV) obj).s == s && ((HSV) obj).v == v;
}
@Override
public int hashCode() {
return Double.valueOf(h).hashCode() ^ Double.valueOf(s).hashCode() ^ Double.valueOf(v).hashCode();
}
/**
* Get a copy
*
* @return copy
*/
public HSV copy() {
return new HSV().setTo(this);
}
}

@ -0,0 +1,336 @@
package com.porcupine.color;
import java.awt.Color;
import com.porcupine.math.Calc;
/**
* RGB color
*
* @author MightyPork
*/
public class RGB {
/** White */
public static final RGB WHITE = new RGB(1, 1, 1);
/** Black */
public static final RGB BLACK = new RGB(0, 0, 0);
/** Red */
public static final RGB RED = new RGB(1, 0, 0);
/** Lime green */
public static final RGB GREEN = new RGB(0, 1, 0);
/** Blue */
public static final RGB BLUE = new RGB(0, 0, 1);
/** Yellow */
public static final RGB YELLOW = new RGB(1, 1, 0);
/** Purple */
public static final RGB PURPLE = new RGB(1, 0, 1);
/** Cyan */
public static final RGB CYAN = new RGB(0, 1, 1);
/** orange */
public static final RGB ORANGE = new RGB(1, 0.6, 0);
/** no color (alpha=0) */
public static final RGB TRANSPARENT = new RGB(0, 0, 0, 0);
/** R */
public double r;
/** G */
public double g;
/** B */
public double b;
/** ALPHA */
public double a = 1;
/**
* Create black color 0,0,0
*/
public RGB() {}
/**
* Get copy with custom alpha
*
* @param alpha alpha to set
* @return copy w/ alpha
*/
public RGB setAlpha(double alpha) {
return copy().setAlpha_ip(alpha);
}
/**
* set alpha IP
*
* @param alpha alpha to set
* @return this
*/
public RGB setAlpha_ip(double alpha) {
a = alpha;
norm();
return this;
}
/**
* Get copy.
*
* @return copy
*/
public RGB copy() {
return new RGB(r, g, b, a);
}
/**
* Get copy with alpha multiplied by custom value
*
* @param alpha alpha to set
* @return copy w/ alpha
*/
public RGB mulAlpha(double alpha) {
return copy().mulAlpha_ip(alpha);
}
/**
* Multiply alpha by given number
*
* @param alpha alpha multiplier
* @return this
*/
public RGB mulAlpha_ip(double alpha) {
a *= alpha;
norm();
return this;
}
/**
* Color from RGB 0-1
*
* @param r red
* @param g green
* @param b blue
*/
public RGB(Number r, Number g, Number b) {
this.r = r.doubleValue();
this.g = g.doubleValue();
this.b = b.doubleValue();
norm();
}
/**
* Color from RGB 0-1
*
* @param r red
* @param g green
* @param b blue
* @param a alpha
*/
public RGB(Number r, Number g, Number b, Number a) {
this.r = r.doubleValue();
this.g = g.doubleValue();
this.b = b.doubleValue();
this.a = a.doubleValue();
norm();
}
/**
* Color from hex 0xRRGGBB
*
* @param hex hex integer
*/
public RGB(int hex) {
setTo(RGB.fromHex(hex));
norm();
}
/**
* Color from hex 0xRRGGBB
*
* @param hex hex integer
* @param alpha alpha color
*/
public RGB(int hex, double alpha) {
setTo(RGB.fromHex(hex));
a = alpha;
norm();
}
/**
* Color from other RGB and alpha channel
*
* @param color other RGB color
* @param alpha new alpha channel
*/
public RGB(RGB color, double alpha) {
setTo(color);
setAlpha_ip(alpha);
}
/**
* @return red channel 0-1
*/
public double r() {
return r;
}
/**
* @return green channel 0-1
*/
public double g() {
return g;
}
/**
* @return blue channel 0-1
*/
public double b() {
return b;
}
/**
* @return alpha 0-1
*/
public double a() {
return a;
}
/**
* Set color to other color
*
* @param copied copied color
* @return this
*/
public RGB setTo(RGB copied) {
r = copied.r;
g = copied.g;
b = copied.b;
a = copied.a;
norm();
return this;
}
/**
* Set to represent hex color
*
* @param hex hex integer RRGGBB
* @return this
*/
public RGB setTo(int hex) {
setTo(RGB.fromHex(hex));
norm();
return this;
}
/**
* Set to R,G,B 0-1
*
* @param r red
* @param g green
* @param b blue
* @param a alpha
* @return this
*/
public RGB setTo(Number r, Number g, Number b, Number a) {
this.r = r.doubleValue();
this.g = g.doubleValue();
this.b = b.doubleValue();
this.a = a.doubleValue();
norm();
return this;
}
/**
* Set to R,G,B 0-1
*
* @param r red
* @param g green
* @param b blue
* @return this
*/
public RGB setTo(Number r, Number g, Number b) {
this.r = r.doubleValue();
this.g = g.doubleValue();
this.b = b.doubleValue();
this.a = 1;
norm();
return this;
}
/**
* Fix numbers out of range 0-1
*
* @return this
*/
public RGB norm() {
r = Calc.clampd(r, 0, 1);
g = Calc.clampd(g, 0, 1);
b = Calc.clampd(b, 0, 1);
a = Calc.clampd(a, 0, 1);
return this;
}
/**
* Get hex value 0xRRGGBB
*
* @return hex value RRGGBB
*/
public int getHex() {
int ri = (int) Math.round(r * 255);
int gi = (int) Math.round(g * 255);
int bi = (int) Math.round(b * 255);
return (ri << 16) | (gi << 8) | bi;
}
/**
* Convert to HSV
*
* @return HSV representation
*/
public HSV toHSV() {
float[] hsv = { 0, 0, 0 };
Color.RGBtoHSB((int) (r * 255), (int) (g * 255), (int) (b * 255), hsv);
return new HSV(hsv[0], hsv[1], hsv[2]);
}
/**
* Create color from hex 0xRRGGBB
*
* @param hex hex RRGGBB
* @return the new color
*/
public static RGB fromHex(int hex) {
int bi = hex & 0xff;
int gi = (hex >> 8) & 0xff;
int ri = (hex >> 16) & 0xff;
return new RGB(ri / 255D, gi / 255D, bi / 255D);
}
/**
* Make from HSV
*
* @param color HSV color
* @return RGB
*/
public static RGB fromHSV(HSV color) {
return color.toRGB();
}
@Override
public String toString() {
return "RGB[" + r + ";" + g + ";" + b + ";" + a + "]";
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof RGB)) return false;
return ((RGB) obj).r == r && ((RGB) obj).g == g && ((RGB) obj).b == b && ((RGB) obj).a == a;
}
@Override
public int hashCode() {
return Double.valueOf(r).hashCode() ^ Double.valueOf(g).hashCode() ^ Double.valueOf(b).hashCode() ^ Double.valueOf(a).hashCode();
}
}

@ -0,0 +1,729 @@
package com.porcupine.coord;
import java.util.Random;
import com.porcupine.math.Calc;
/**
* Coordinate class, object with three or two double coordinates.<br>
*
* @author MightyPork
*/
public class Coord {
/** Zero Coord */
public static final Coord ZERO = new Coord(0, 0);
/** Coord [1;1;1] */
public static final Coord ONE = new Coord(1, 1, 1);
/** RNG */
protected static Random rand = new Random();
/** X coordinate */
public double x = 0;
/** Y coordinate */
public double y = 0;
/** Z coordinate */
public double z = 0;
/**
* Create zero coord
*/
public Coord() {}
/**
* Create 2D coord
*
* @param x x coordinate
* @param y y coordinate
*/
public Coord(Number x, Number y) {
setTo(x, y);
}
/**
* Create 3D coord
*
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
*/
public Coord(Number x, Number y, Number z) {
setTo(x, y, z);
}
/**
* Create coord as a copy of another
*
* @param copied copied coord
*/
public Coord(Coord copied) {
this.x = copied.x;
this.y = copied.y;
this.z = copied.z;
}
/**
* Convert X and Y coordinates of this coord to a new CoordI.
*
* @return the new CoordI
*/
public CoordI toCoordI() {
return new CoordI((int) Math.round(x), (int) Math.round(y));
}
/**
* Generate random coord (gaussian)
*
* @param max max distance from 0
* @return new coord
*/
public static Coord random(double max) {
return new Coord(Calc.clampd(rand.nextGaussian() * max, -max * 2, max * 2), Calc.clampd(rand.nextGaussian() * max, -max * 2, max * 2),
Calc.clampd(rand.nextGaussian() * max, -max * 2, max * 2));
}
/**
* Generate random coord (min-max)
*
* @param min min offset
* @param max max offset
* @return new coord
*/
public static Coord random(double min, double max) {
return new Coord((rand.nextBoolean() ? -1 : 1) * (min + rand.nextDouble() * (max - min)), (rand.nextBoolean() ? -1 : 1)
* (min + rand.nextDouble() * (max - min)), (rand.nextBoolean() ? -1 : 1) * (min + rand.nextDouble() * (max - min)));
}
/**
* offset randomly in place
*
* @param max max +- offset
* @return this
*/
public Coord random_offset_ip(double max) {
return add(random(max));
}
/**
* offset randomly in place
*
* @param min min offset
* @param max max offset
* @return this
*/
public Coord random_offset_ip(double min, double max) {
add(random(min, max));
return this;
}
/**
* Set to max values of this and other coord
*
* @param other other coord
*/
public void setMax(Coord other) {
x = Math.max(x, other.x);
y = Math.max(y, other.y);
z = Math.max(z, other.z);
}
/**
* Set to min values of this and other coord
*
* @param other other coord
*/
public void setMin(Coord other) {
x = Math.min(x, other.x);
y = Math.min(y, other.y);
z = Math.min(z, other.z);
}
/**
* offset randomly
*
* @param max max +- offset
* @return offset coord
*/
public Coord random_offset(double max) {
Coord r = random(1);
Vec v = new Vec(r);
v.norm_ip(0.00001 + rand.nextDouble() * max);
return copy().add_ip(v);
}
/**
* offset randomly
*
* @param min min offset
* @param max max offset
* @return offset coord
*/
public Coord random_offset(double min, double max) {
return copy().add_ip(random(min, max));
}
/**
* @return X as double
*/
public double x() {
return x;
}
/**
* @return Y as double
*/
public double y() {
return y;
}
/**
* @return Z as double
*/
public double z() {
return z;
}
/**
* @return X as double
*/
public double xd() {
return x;
}
/**
* @return Y as double
*/
public double yd() {
return y;
}
/**
* @return Z as double
*/
public double zd() {
return z;
}
/**
* @return X as double
*/
public float xf() {
return (float) x;
}
/**
* @return Y as double
*/
public float yf() {
return (float) y;
}
/**
* @return Z as double
*/
public float zf() {
return (float) z;
}
/**
* @return X as double
*/
public int xi() {
return (int) Math.round(x);
}
/**
* @return Y as double
*/
public int yi() {
return (int) Math.round(y);
}
/**
* @return Z as double
*/
public int zi() {
return (int) Math.round(z);
}
/**
* Set 3D coordinates to
*
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
* @return this
*/
public Coord setTo(Number x, Number y, Number z) {
this.x = x.doubleValue();
this.y = y.doubleValue();
this.z = z.doubleValue();
return this;
}
/**
* Set 2D coordinates to
*
* @param x x coordinate
* @param y y coordinate
* @return this
*/
public Coord setTo(Number x, Number y) {
setTo(x, y, 0);
return this;
}
/**
* Set coordinates to match other coord
*
* @param copied coord whose coordinates are used
* @return this
*/
public Coord setTo(Coord copied) {
setTo(copied.x, copied.y, copied.z);
return this;
}
/**
* Set X coordinate in place
*
* @param x x coordinate
* @return this
*/
public Coord setX_ip(Number x) {
this.x = x.doubleValue();
return this;
}
/**
* Set Y coordinate in place
*
* @param y y coordinate
* @return this
*/
public Coord setY_ip(Number y) {
this.y = y.doubleValue();
return this;
}
/**
* Set Z coordinate in place
*
* @param z z coordinate
* @return this
*/
public Coord setZ_ip(Number z) {
this.z = z.doubleValue();
return this;
}
/**
* Set X coordinate in a copy
*
* @param x x coordinate
* @return copy with set coordinate
*/
public Coord setX(Number x) {
return copy().setX_ip(x);
}
/**
* Set Y coordinate in a copy
*
* @param y y coordinate
* @return copy with set coordinate
*/
public Coord setY(Number y) {
return copy().setY_ip(y);
}
/**
* Set Z coordinate in a copy
*
* @param z z coordinate
* @return copy with set coordinate
*/
public Coord setZ(Number z) {
return copy().setZ_ip(z);
}
/**
* Get a copy subtracted by 3D coordinate
*
* @param x x offset
* @param y y offset
* @param z z offset
* @return the offset copy
*/
public Coord sub(Number x, Number y, Number z) {
return copy().sub_ip(x, y, z);
}
/**
* Get a copy subtracted by 2D coordinate
*
* @param x x offset
* @param y y offset
* @return the offset copy
*/
public Coord sub(Number x, Number y) {
return copy().sub_ip(x, y);
}
/**
* Get a copy subtracted by vector
*
* @param vec offset
* @return the offset copy
*/
public Coord sub(Coord vec) {
return copy().sub_ip(vec);
}
/**
* Offset by 3D coordinate in place
*
* @param x x offset
* @param y y offset
* @param z z offset
* @return this
*/
public Coord sub_ip(Number x, Number y, Number z) {
this.x -= x.doubleValue();
this.y -= y.doubleValue();
this.z -= z.doubleValue();
return this;
}
/**
* Offset by 2D coordinate in place
*
* @param x x offset
* @param y y offset
* @return this
*/
public Coord sub_ip(Number x, Number y) {
this.x -= x.doubleValue();
this.y -= y.doubleValue();
return this;
}
/**
* Offset by vector in place
*
* @param vec offset
* @return this
*/
public Coord sub_ip(Coord vec) {
this.x -= vec.x;
this.y -= vec.y;
this.z -= vec.z;
return this;
}
/**
* Get a copy offset by 3D coordinate
*
* @param x x offset
* @param y y offset
* @param z z offset
* @return the offset copy
*/
public Coord add(Number x, Number y, Number z) {
return copy().add_ip(x, y, z);
}
/**
* Get a copy offset by 2D coordinate
*
* @param x x offset
* @param y y offset
* @return the offset copy
*/
public Coord add(Number x, Number y) {
return copy().add_ip(x, y);
}
/**
* Get a copy offset by vector
*
* @param vec offset
* @return the offset copy
*/
public Coord add(Coord vec) {
return copy().add_ip(vec);
}
/**
* Offset by 3D coordinate in place
*
* @param x x offset
* @param y y offset
* @param z z offset
* @return this
*/
public Coord add_ip(Number x, Number y, Number z) {
this.x += x.doubleValue();
this.y += y.doubleValue();
this.z += z.doubleValue();
return this;
}
/**
* Offset by 2D coordinate in place
*
* @param x x offset
* @param y y offset
* @return this
*/
public Coord add_ip(Number x, Number y) {
this.x += x.doubleValue();
this.y += y.doubleValue();
return this;
}
/**
* Offset by vector in place
*
* @param vec offset
* @return this
*/
public Coord add_ip(Coord vec) {
this.x += vec.x;
this.y += vec.y;
this.z += vec.z;
return this;
}
/**
* @return copy of this vector
*/
public Coord copy() {
return new Coord(x, y, z);
}
/**
* Get distance to other point
*
* @param point other point
* @return distance in units
*/
public double distTo(Coord point) {
return Math.sqrt((point.x - x) * (point.x - x) + (point.y - y) * (point.y - y) + (point.z - z) * (point.z - z));
}
/**
* Create vector from this point to other point
*
* @param point second point
* @return vector
*/
public Vec vecTo(Coord point) {
return (Vec) (new Vec(point)).add(new Vec(this).neg());
}
/**
* Get distance to other point
*
* @param a point a
* @param b point b
* @return distance in units
*/
public static double dist(Coord a, Coord b) {
return a.distTo(b);
}
/**
* Get middle of line to other point
*
* @param other other point
* @return middle
*/
public Coord midTo(Coord other) {
return add(vecTo(other).scale(0.5));
}
private Coord last;
private Vec offs;
/**
* Store current value as LAST
*/
public void pushLast() {
if (last == null) last = new Coord();
if (offs == null) offs = new Vec();
last.setTo(this);
}
/**
* Apply coordinates change for delta time
*/
public void update() {
if (last == null) last = new Coord();
if (offs == null) offs = new Vec();
offs = last.vecTo(this);
}
/**
* Get coordinate at delta time since LAST
*
* @param delta delta time 0-1
* @return delta pos
*/
public Coord getDelta(double delta) {
if (last == null) last = new Coord();
if (offs == null) offs = new Vec();
return new Coord(this.add(offs.scale(delta)));
}
@Override
public String toString() {
return "[ " + x + " ; " + y + " ; " + z + " ]";
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!obj.getClass().isAssignableFrom(Vec.class)) return false;
Vec other = (Vec) obj;
return x == other.x && y == other.y && z == other.z;
}
@Override
public int hashCode() {
return Double.valueOf(x).hashCode() ^ Double.valueOf(y).hashCode() ^ Double.valueOf(z).hashCode();
}
/**
* Multiply by number
*
* @param d number
* @return multiplied copy
*/
public Coord mul(double d) {
return copy().mul_ip(d);
}
/**
* Multiply by number in place
*
* @param d multiplier
* @return this
*/
public Coord mul_ip(double d) {
x *= d;
y *= d;
z *= d;
return this;
}
/**
* Multiply coords by number
*
* @param xd x multiplier
* @param yd y multiplier
* @param zd z multiplier
* @return multiplied copy
*/
public Coord mul(double xd, double yd, double zd) {
return copy().mul_ip(xd, yd, zd);
}
/**
* Multiply coords by number in place
*
* @param xd x multiplier
* @param yd y multiplier
* @param zd z multiplier
* @return this
*/
public Coord mul_ip(double xd, double yd, double zd) {
x *= xd;
y *= yd;
z *= zd;
return this;
}
/**
* Divide by number in place
*
* @param d number to divide by
* @return this
*/
public Coord div_ip(double d) {
if (d == 0) return this;
x /= d;
y /= d;
z /= d;
return this;
}
/**
* Get copy divided by number
*
* @param d number to divide by
* @return divided copy
*/
public Coord div(double d) {
return copy().div_ip(d);
}
/**
* Round in place
*
* @return this
*/
public Coord round_ip() {
x = Math.round(x);
y = Math.round(y);
z = Math.round(z);
return this;
}
/**
* Get a copy with rounded coords
*
* @return rounded copy
*/
public Coord round() {
return copy().round_ip();
}
/**
* Check if this rectangle in inside a rectangular zone
*
* @param min min coord
* @param max max coord
* @return is inside
*/
public boolean isInRect(Coord min, Coord max) {
return (x >= min.x && x <= max.x) && (y >= min.y && y <= max.y) && (z >= min.z && z <= max.z);
}
/**
* Check if this rectangle in inside a rectangular zone
*
* @param rect checked rect.
* @return is inside
*/
public boolean isInRect(Rect rect) {
return isInRect(rect.min, rect.max);
}
/**
* Get size
*
* @return size
*/
public double size() {
return new Vec(this).size();
}
}

@ -0,0 +1,159 @@
package com.porcupine.coord;
/**
* Simple integer coordinate class<br>
* Unlike Coord, this is suitable for using in array indices etc.
*
* @author MightyPork
*/
public class CoordI {
/** X coordinate */
public int x = 0;
/** Y coordinate */
public int y = 0;
/**
* Integer 2D Coord
*
* @param x x coord
* @param y y coord
*/
public CoordI(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Create CoordI as copy of other
*
* @param other coord to copy
*/
public CoordI(CoordI other) {
setTo(other);
}
/**
* Get copy
*
* @return copy
*/
public CoordI copy() {
return new CoordI(x, y);
}
/**
* Set coords to
*
* @param x x coord to set
* @param y y coord to set
*/
public void setTo(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Set to coords from other coord
*
* @param other source coord
*/
public void setTo(CoordI other) {
this.x = other.x;
this.y = other.y;
}
/**
* Convert to double Coord
*
* @return coord with X and y from this CoordI
*/
public Coord toCoord() {
return new Coord(x, y);
}
@Override
public String toString() {
return "[ " + x + " ; " + y + " ]";
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj instanceof CoordI) return ((CoordI) obj).x == x && ((CoordI) obj).y == y;
return false;
}
@Override
public int hashCode() {
return x ^ y;
}
/**
* Add other coordI coordinates in place
*
* @param move coordI to add
* @return this
*/
public CoordI add_ip(CoordI move) {
x += move.x;
y += move.y;
return this;
}
/**
* Subtract other coordI coordinates in place
*
* @param move coordI to subtract
* @return this
*/
public CoordI sub_ip(CoordI move) {
x -= move.x;
y -= move.y;
return this;
}
/**
* Middle of this and other coordinate, rounded to CoordI - integers
*
* @param other other coordI
* @return middle CoordI
*/
public CoordI midTo(CoordI other) {
return new CoordI((x + other.x) / 2, (y + other.y) / 2);
}
/**
* Subtract x,y in a copy
*
* @param x x to subtract
* @param y y to subtract
* @return copy subtracted
*/
public CoordI sub(int x, int y) {
return copy().sub_ip(new CoordI(x, y));
}
/**
* Subtract other coordI coordinates in a copy
*
* @param other coordI to subtract
* @return copy subtracted
*/
public CoordI sub(CoordI other) {
return copy().sub_ip(other);
}
/**
* Add other coordI coordinates in a copy
*
* @param other coordI to add
* @return copy modified
*/
public CoordI add(CoordI other) {
return copy().add_ip(other);
}
}

@ -0,0 +1,639 @@
package com.porcupine.coord;
import com.porcupine.math.Calc;
/**
* Rectangle determined by two coordinates - min and max.
*
* @author MightyPork
*/
public class Rect {
/** Rect [0, 0, 1, 1] */
public static final Rect ONE = new Rect(0, 0, 1, 1);
/** Rect all zeros */
public static final Rect ZERO = new Rect(0, 0, 0, 0);
/** Highest coordinates xy */
protected Coord max = new Coord();
/** Lowest coordinates xy */
protected Coord min = new Coord();
/**
* New Rect [0, 0, 0, 0]
*/
public Rect() {
this(0, 0, 0, 0);
}
/**
* New rect of two coords
*
* @param c1 coord 1
* @param c2 coord 2
*/
public Rect(Coord c1, Coord c2) {
this(c1.x, c1.y, c2.x, c2.y);
}
/**
* New Rect
*
* @param x1 lower x
* @param y1 lower y
* @param x2 upper x
* @param y2 upper y
*/
public Rect(double x1, double y1, double x2, double y2) {
setTo(x1, y1, x2, y2);
}
/**
* Make rect from min coord and size
*
* @param x1 min x
* @param y1 min y
* @param width size x
* @param height size y
* @return the new rect
*/
public static Rect fromSize(int x1, int y1, int width, int height) {
return new Rect(x1, y1, x1 + width, y1 + height);
}
/**
* Make rect from min coord and size
*
* @param min min coord
* @param width size x
* @param height size y
* @return the new rect
*/
public static Rect fromSize(Coord min, int width, int height) {
return new Rect(min, min.add(width, height));
}
/**
* New rect as a copy of other rect
*
* @param r other rect
*/
public Rect(Rect r) {
this(r.min.x, r.min.y, r.max.x, r.max.y);
}
/**
* Rect [0, 0, x, y]
*
* @param x width
* @param y height
*/
public Rect(int x, int y) {
this(0, 0, x, y);
}
/**
* Rect [0, 0, size.x, size.y]
*
* @param size size coord
*/
public Rect(Coord size) {
this(0, 0, size.x, size.y);
}
/**
* Add X and Y to all coordinates in a copy
*
* @param x x to add
* @param y y to add
* @return copy changed
*/
public Rect add(double x, double y) {
return add(new Vec(x, y));
}
/**
* Get offset copy (add)
*
* @param move offset vector
* @return offset copy
*/
public Rect add(Vec move) {
return copy().add_ip(move);
}
/**
* Add X and Y to all coordinates in place
*
* @param x x to add
* @param y y to add
* @return this
*/
public Rect add_ip(double x, double y) {
return add_ip(new Vec(x, y));
}
/**
* Offset in place (add)
*
* @param move offset vector
* @return this
*/
public Rect add_ip(Vec move) {
min.add_ip(move);
max.add_ip(move);
return this;
}
/**
* Get a copy
*
* @return copy
*/
public Rect copy() {
return new Rect(this);
}
/**
* Divide in copy
*
* @param factor divisor
* @return offset copy
*/
public Rect div(double factor) {
return copy().div_ip(factor);
}
/**
* Divide coord in place
*
* @param factor divisor
* @return this
*/
public Rect div_ip(double factor) {
min.div_ip(factor);
max.div_ip(factor);
return this;
}
/**
* Get rect center
*
* @return center
*/
public Coord getCenter() {
return min.midTo(max);
}
/**
* Get center of the lower edge.
*
* @return center
*/
public Coord getCenterDown() {
return new Coord((max.x + min.x) / 2, min.y);
}
/**
* Get center of the left edge.
*
* @return center
*/
public Coord getCenterLeft() {
return new Coord(min.x, (max.y + min.y) / 2);
}
/**
* Get center of the right edge.
*
* @return center
*/
public Coord getCenterRight() {
return new Coord(max.x, (max.y + min.y) / 2);
}
/**
* Get center of the top edge.
*
* @return center
*/
public Coord getCenterTop() {
return new Coord((max.x + min.x) / 2, max.y);
}
/**
* Get left top
*
* @return center
*/
public Coord getLeftTop() {
return new Coord(min.x, max.y);
}
/**
* Get left bottom
*
* @return center
*/
public Coord getLeftBottom() {
return new Coord(min.x, min.y);
}
/**
* Get right top
*
* @return center
*/
public Coord getRightTop() {
return new Coord(max.x, max.y);
}
/**
* Get right bottom
*
* @return center
*/
public Coord getRightBottom() {
return new Coord(max.x, min.y);
}
/**
* @return highjest coordinates xy
*/
public Coord getMax() {
return max;
}
/**
* @return lowest coordinates xy
*/
public Coord getMin() {
return min;
}
/**
* Get size (width, height) as (x,y)
*
* @return coord of width,height
*/
public Coord getSize() {
return new Coord(Math.abs(min.x - max.x), Math.abs(min.y - max.y));
}
/**
* Check if point is inside this rectangle
*
* @param point point to test
* @return is inside
*/
public boolean isInside(Coord point) {
return Calc.inRange(point.x, min.x, max.x) && Calc.inRange(point.y, min.y, max.y);
}
/**
* Multiply in copy
*
* @param factor multiplier
* @return offset copy
*/
public Rect mul(double factor) {
return copy().mul_ip(factor);
}
/**
* Multiply coord in place
*
* @param factor multiplier
* @return this
*/
public Rect mul_ip(double factor) {
min.mul_ip(factor);
max.mul_ip(factor);
return this;
}
/**
* Set to [0,0,coord.x,coord.y]
*
* @param coord size coord
*/
public void setTo(Coord coord) {
setTo(0, 0, coord.x, coord.y);
}
/**
* Set to coordinates
*
* @param x1 lower x
* @param y1 lower y
* @param x2 upper x
* @param y2 upper y
*/
public void setTo(double x1, double y1, double x2, double y2) {
min.x = Calc.min(x1, x2);
min.y = Calc.min(y1, y2);
max.x = Calc.max(x1, x2);
max.y = Calc.max(y1, y2);
}
/**
* Set to other rect's coordinates
*
* @param r other rect
*/
public void setTo(Rect r) {
min.setTo(r.min);
max.setTo(r.max);
}
/**
* Subtract X and Y from all coordinates in a copy
*
* @param x x to subtract
* @param y y to subtract
* @return copy changed
*/
public Rect sub(double x, double y) {
return sub(new Vec(x, y));
}
/**
* Get offset copy (subtract)
*
* @param move offset vector
* @return offset copy
*/
public Rect sub(Vec move) {
return copy().sub_ip(move);
}
/**
* Subtract X and Y from all coordinates in place
*
* @param x x to subtract
* @param y y to subtract
* @return this
*/
public Rect sub_ip(double x, double y) {
return sub_ip(new Vec(x, y));
}
/**
* Offset in place (subtract)
*
* @param move offset vector
* @return this
*/
public Rect sub_ip(Vec move) {
min.sub_ip(move);
max.sub_ip(move);
return this;
}
/**
* Grow to sides in place
*
* @param grow grow size (added to each side)
* @return this
*/
public Rect grow_ip(Coord grow) {
min.sub_ip(grow);
max.add_ip(grow);
return this;
}
/**
* Grow to sides in copy
*
* @param grow grow size (added to each side)
* @return grown copy
*/
public Rect grow(Coord grow) {
return copy().grow_ip(grow);
}
/**
* Grow up in place
*
* @param add added pixels
* @return this
*/
public Rect growUp_ip(double add) {
max.add_ip(0, add);
return this;
}
/**
* Grow up in copy
*
* @param add added pixels
* @return grown copy
*/
public Rect growUp(double add) {
return copy().growUp_ip(add);
}
/**
* Grow down in place
*
* @param down added pixels
* @return this
*/
public Rect growDown_ip(double down) {
min.sub_ip(0, down);
return this;
}
/**
* Grow down in copy
*
* @param down added pixels
* @return grown copy
*/
public Rect growDown(double down) {
return copy().growDown_ip(down);
}
/**
* Grow to left in place
*
* @param left added pixels
* @return this
*/
public Rect growLeft_ip(double left) {
min.sub_ip(left, 0);
return this;
}
/**
* Grow to left in copy
*
* @param left added pixels
* @return grown copy
*/
public Rect growLeft(double left) {
return copy().growLeft_ip(left);
}
/**
* Grow to right in place
*
* @param right added pixels
* @return this
*/
public Rect growRight_ip(double right) {
max.add_ip(right, 0);
return this;
}
/**
* Grow to right in copy
*
* @param right added pixels
* @return grown copy
*/
public Rect growRight(double right) {
return copy().growRight_ip(right);
}
/**
* Grow to sides in place
*
* @param x x to add
* @param y y to add
* @return this
*/
public Rect grow_ip(double x, double y) {
min.sub_ip(x, y);
max.add_ip(x, y);
return this;
}
/**
* Grow to sides in copy
*
* @param x x to add
* @param y y to add
* @return grown copy
*/
public Rect grow(double x, double y) {
return copy().grow_ip(x, y);
}
/**
* Get copy with the same center and width=0
*
* @return line
*/
public Rect getAxisV() {
return new Rect(getCenterDown(), getCenterTop());
}
/**
* Get copy with the same center and height=0
*
* @return line
*/
public Rect getAxisH() {
return new Rect(getCenterLeft(), getCenterRight());
}
/**
* Get top edge rect
*
* @return line
*/
public Rect getEdgeTop() {
return new Rect(getLeftTop(), getRightTop());
}
/**
* Get bottom edge rect
*
* @return line
*/
public Rect getEdgeBottom() {
return new Rect(getLeftBottom(), getRightBottom());
}
/**
* Get left edge rect
*
* @return line
*/
public Rect getEdgeLeft() {
return new Rect(getLeftBottom(), getLeftTop());
}
/**
* Get right edge rect
*
* @return line
*/
public Rect getEdgeRight() {
return new Rect(getRightBottom(), getRightTop());
}
@Override
public String toString() {
return "rect{ " + min + " - " + max + " }";
}
/**
* @return lower x
*/
public double x1() {
return min.x;
}
/**
* @return upper x
*/
public double x2() {
return max.x;
}
/**
* @return lower y
*/
public double y1() {
return min.y;
}
/**
* @return upper y
*/
public double y2() {
return max.y;
}
/**
* Round coords in copy
*
* @return copy, rounded
*/
public Rect round() {
return new Rect(min.round(), max.round());
}
/**
* Round this in place
*
* @return this
*/
public Rect round_ip() {
min.round_ip();
max.round_ip();
return this;
}
}

@ -0,0 +1,283 @@
package com.porcupine.coord;
/**
* Vector in 2D/3D space.
*
* @author MightyPork
*/
public class Vec extends Coord {
/** Zero vector */
@SuppressWarnings("hiding")
public static final Vec ZERO = new Vec(0, 0, 0);
/** Vec [1;1;1] */
@SuppressWarnings("hiding")
public static final Vec ONE = new Vec(1, 1, 1);
/**
* Create zero vector
*/
public Vec() {
super();
}
/**
* Create 2D vector
*
* @param x x coordinate
* @param y y coordinate
*/
public Vec(Number x, Number y) {
super(x, y);
}
/**
* Create 3D vector
*
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
*/
public Vec(Number x, Number y, Number z) {
super(x, y, z);
}
/**
* Create vector as a copy of another
*
* @param copied copied vector
*/
public Vec(Coord copied) {
super(copied);
}
/**
* Negate all coordinates (* -1)
*
* @return negated coordinate
*/
public Vec neg() {
return copy().neg_ip();
}
/**
* Negate all coordinates (* -1), in place
*
* @return this
*/
public Vec neg_ip() {
scale_ip(-1);
return this;
}
/**
* Multiply all coordinates by factor; scalar multiplication
*
* @param factor multiplier
* @return copy multiplied
*/
public Vec scale(double factor) {
return copy().scale_ip(factor);
}
/**
* Multiply all coordinates by factor, in place
*
* @param factor multiplier
* @return this
*/
public Vec scale_ip(double factor) {
return (Vec) mul_ip(factor);
}
/**
* Multiply by other vector, vector multiplication
*
* @param vec other vector
* @return copy multiplied
*/
public Vec cross(Vec vec) {
return copy().cross_ip(vec);
}
/**
* Multiply by other vector, vector multiplication; in place
*
* @param vec other vector
* @return this
*/
public Vec cross_ip(Vec vec) {
setTo(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x);
return this;
}
/**
* Get dot product
*
* @param vec other vector
* @return dot product
*/
public double dot(Vec vec) {
return x * vec.x + y * vec.y + z * vec.z;
}
/**
* Get vector size
*
* @return vector size in units
*/
@Override
public double size() {
return Math.sqrt(x * x + y * y + z * z);
}
/**
* Scale vector to given size
*
* @param size size we need
* @return scaled vector
*/
public Vec norm(double size) {
return copy().norm_ip(size);
}
/**
* Scale vector to given size, in place
*
* @param size size we need
* @return scaled vector
*/
public Vec norm_ip(double size) {
if (size() == 0) {
z = -1;
}
if (size == 0) {
setTo(0, 0, 0);
return this;
}
double k = size / size();
scale_ip(k);
return this;
}
// STATIC
/**
* Get vector size
*
* @param vec vector to get size of
* @return size in units
*/
public static double size(Vec vec) {
return vec.size();
}
/**
* Get dot product of two vectors
*
* @param a 1st vector
* @param b 2nd vector
* @return dot product
*/
public static double dot(Vec a, Vec b) {
return a.dot(b);
}
/**
* Get cross product of two vectors
*
* @param a 1st vector
* @param b 2nd vector
* @return cross product
*/
public static Vec cross(Vec a, Vec b) {
return a.cross(b);
}
/**
* Scale vector
*
* @param a vector
* @param scale
* @return scaled copy
*/
public static Vec scale(Vec a, double scale) {
return a.scale(scale);
}
@Override
public Vec copy() {
return new Vec(this);
}
/**
* Generate random coord (gaussian)
*
* @param max max distance from 0
* @return new coord
*/
public static Vec random(double max) {
return new Vec(Coord.random(max));
}
/**
* Generate random coord (min-max)
*
* @param max max distance from 0
* @return new coord
*/
public static Vec random(double min, double max) {
return new Vec(Coord.random(min, max));
}
/**
* offset randomly in place
*
* @param max max +- offset
* @return this
*/
@Override
public Vec random_offset_ip(double max) {
return (Vec) super.random_offset_ip(max);
}
/**
* offset randomly in place
*
* @param min min offset
* @param max max offset
* @return this
*/
@Override
public Vec random_offset_ip(double min, double max) {
return (Vec) super.random_offset_ip(min, max);
}
/**
* offset randomly
*
* @param max max +- offset
* @return offset coord
*/
@Override
public Vec random_offset(double max) {
return (Vec) super.random_offset(max);
}
/**
* offset randomly
*
* @param min min offset
* @param max max offset
* @return offset coord
*/
@Override
public Vec random_offset(double min, double max) {
return (Vec) super.random_offset(min, max);
}
}

@ -0,0 +1,64 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
/**
* Ionizable Arraylist
*
* @author MightyPork
* @param <T>
*/
public abstract class AbstractIonList<T> extends ArrayList<T> implements Ionizable {
@Override
public void ionRead(InputStream in) throws IOException {
while (true) {
byte b = StreamUtils.readByte(in);
if (b == IonMarks.ENTRY) {
T value = (T) Ion.readObject(in);
add(value);
} else if (b == IonMarks.END) {
break;
} else {
throw new RuntimeException("Unexpected mark in AbstractIonList: " + Integer.toHexString(b));
}
}
ionReadCustomData(in);
}
@Override
public void ionWrite(OutputStream out) throws IOException {
for (T entry : this) {
if (entry instanceof IonizableOptional && !((IonizableOptional) entry).ionShouldSave()) continue;
StreamUtils.writeByte(out, IonMarks.ENTRY);
Ion.writeObject(out, entry);
}
StreamUtils.writeByte(out, IonMarks.END);
ionWriteCustomData(out);
}
/**
* Read custom data of this AbstractIonList implementation
*
* @param in input stream
*/
public void ionReadCustomData(InputStream in) {}
/**
* Write custom data of this AbstractIonList implementation
*
* @param out output stream
*/
public void ionWriteCustomData(OutputStream out) {}
@Override
public abstract byte ionMark();
}

@ -0,0 +1,75 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
/**
* Ionizable HashMap
*
* @author MightyPork
* @param <V>
*/
public abstract class AbstractIonMap<V> extends LinkedHashMap<String, V> implements Ionizable {
@Override
public V get(Object key) {
return super.get(key);
}
@Override
public V put(String key, V value) {
return super.put(key, value);
}
@Override
public void ionRead(InputStream in) throws IOException {
while (true) {
byte b = StreamUtils.readByte(in);
if (b == IonMarks.ENTRY) {
String key = StreamUtils.readStringBytes(in);
V value = (V) Ion.readObject(in);
put(key, value);
} else if (b == IonMarks.END) {
break;
} else {
throw new RuntimeException("Unexpected mark in IonMap: " + Integer.toHexString(b));
}
}
ionReadCustomData(in);
}
@Override
public void ionWrite(OutputStream out) throws IOException {
for (java.util.Map.Entry<String, V> entry : entrySet()) {
StreamUtils.writeByte(out, IonMarks.ENTRY);
StreamUtils.writeStringBytes(out, entry.getKey());
Ion.writeObject(out, entry.getValue());
}
StreamUtils.writeByte(out, IonMarks.END);
ionWriteCustomData(out);
}
/**
* Read custom data of this AbstractIonMap implementation
*
* @param in input stream
*/
public void ionReadCustomData(InputStream in) {}
/**
* Write custom data of this AbstractIonMap implementation
*
* @param out output stream
*/
public void ionWriteCustomData(OutputStream out) {}
@Override
public byte ionMark() {
return IonMarks.MAP;
}
}

@ -0,0 +1,261 @@
package com.porcupine.ion;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import com.porcupine.math.Calc;
/**
* Universal data storage system
*
* @author MightyPork
*/
public class Ion {
/** Ionizables<Mark, Class> */
private static Map<Byte, Class<?>> customIonizables = new HashMap<Byte, Class<?>>();
// register default ionizables
static {
registerIonizable(IonMarks.MAP, IonMap.class);
registerIonizable(IonMarks.LIST, IonList.class);
}
/**
* Register new Ionizable for direct reconstructing.
*
* @param mark byte mark to be used, see {@link IonMarks} for reference.
* @param objClass class of the registered Ionizable
*/
public static void registerIonizable(byte mark, Class<?> objClass) {
if (customIonizables.containsKey(mark)) {
throw new RuntimeException("IonMark " + mark + " is already used @ " + objClass.getSimpleName());
}
customIonizables.put(mark, objClass);
}
/**
* Load Ion object from file.
*
* @param file file path
* @return the loaded object
*/
public static Object fromFile(String file) {
return fromFile(new File(file));
}
/**
* Load Ion object from file.
*
* @param file file
* @return the loaded object
*/
public static Object fromFile(File file) {
try {
InputStream in = new FileInputStream(file);
Object obj = fromStream(in);
in.close();
return obj;
} catch (FileNotFoundException e) {
System.err.println("Could not find ION file " + file);
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Load Ion object from stream.
*
* @param in input stream
* @return the loaded object
*/
public static Object fromStream(InputStream in) {
try {
return readObject(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Store Ion object to file.
*
* @param path file path
* @param obj object to store
*/
public static void toFile(String path, Object obj) {
toFile(new File(path), obj);
}
/**
* Store Ion object to file.
*
* @param path file path
* @param obj object to store
*/
public static void toFile(File path, Object obj) {
try {
String f = path.toString();
File dir = new File(f.substring(0, f.lastIndexOf(File.separator)));
dir.mkdirs();
OutputStream out = new FileOutputStream(path);
toStream(out, obj);
out.flush();
out.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Store Ion object to output stream.
*
* @param out output stream *
* @param obj object to store
*/
public static void toStream(OutputStream out, Object obj) {
try {
writeObject(out, obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Read single ionizable or primitive object from input stream
*
* @param in input stream
* @return the loaded object
*/
public static Object readObject(InputStream in) {
try {
int bi = in.read();
if (bi == -1) throw new RuntimeException("Unexpected end of stream.");
byte b = (byte) bi;
if (customIonizables.containsKey(b)) {
Ionizable ion = ((Ionizable) customIonizables.get(b).newInstance());
ion.ionRead(in);
return ion;
}
switch (b) {
case IonMarks.BOOLEAN:
return StreamUtils.readBoolean(in);
case IonMarks.BYTE:
return StreamUtils.readByte(in);
case IonMarks.CHAR:
return StreamUtils.readChar(in);
case IonMarks.SHORT:
return StreamUtils.readShort(in);
case IonMarks.INT:
return StreamUtils.readInt(in);
case IonMarks.LONG:
return StreamUtils.readLong(in);
case IonMarks.FLOAT:
return StreamUtils.readFloat(in);
case IonMarks.DOUBLE:
return StreamUtils.readDouble(in);
case IonMarks.STRING:
String s = StreamUtils.readString(in);
return s;
default:
throw new RuntimeException("Invalid Ion mark " + Integer.toHexString(bi));
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
/**
* Write single ionizable or primitive object to output stream
*
* @param out output stream
* @param obj stored object
*/
public static void writeObject(OutputStream out, Object obj) {
try {
if (obj instanceof Ionizable) {
out.write(((Ionizable) obj).ionMark());
((Ionizable) obj).ionWrite(out);
return;
}
if (obj instanceof Boolean) {
out.write(IonMarks.BOOLEAN);
StreamUtils.writeBoolean(out, (Boolean) obj);
return;
}
if (obj instanceof Byte) {
out.write(IonMarks.BYTE);
StreamUtils.writeByte(out, (Byte) obj);
return;
}
if (obj instanceof Character) {
out.write(IonMarks.CHAR);
StreamUtils.writeChar(out, (Character) obj);
return;
}
if (obj instanceof Short) {
out.write(IonMarks.SHORT);
StreamUtils.writeShort(out, (Short) obj);
return;
}
if (obj instanceof Integer) {
out.write(IonMarks.INT);
StreamUtils.writeInt(out, (Integer) obj);
return;
}
if (obj instanceof Long) {
out.write(IonMarks.LONG);
StreamUtils.writeLong(out, (Long) obj);
return;
}
if (obj instanceof Float) {
out.write(IonMarks.FLOAT);
StreamUtils.writeFloat(out, (Float) obj);
return;
}
if (obj instanceof Double) {
out.write(IonMarks.DOUBLE);
StreamUtils.writeDouble(out, (Double) obj);
return;
}
if (obj instanceof String) {
out.write(IonMarks.STRING);
StreamUtils.writeString(out, (String) obj);
return;
}
throw new RuntimeException(Calc.className(obj) + " can't be stored to Ion storage.");
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}

@ -0,0 +1,144 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
/**
* Ionizable Arraylist
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class IonList extends ArrayList<Object> implements Ionizable {
public boolean getBoolean(int index) {
return (Boolean) get(index);
}
public boolean getBool(int index) {
return (Boolean) get(index);
}
public byte getByte(int index) {
return (Byte) get(index);
}
public char getChar(int index) {
return (Character) get(index);
}
public char getCharacter(int index) {
return (Character) get(index);
}
public short getShort(int index) {
return (Short) get(index);
}
public int getInteger(int index) {
return (Integer) get(index);
}
public int getInt(int index) {
return (Integer) get(index);
}
public long getLong(int index) {
return (Long) get(index);
}
public float getFloat(int index) {
return (Float) get(index);
}
public double getDouble(int index) {
return (Double) get(index);
}
public String getString(int index) {
return (String) get(index);
}
@Override
public Object get(int index) {
return super.get(index);
}
public void addBoolean(boolean num) {
add(num);
}
public void addBool(boolean num) {
add(num);
}
public void addByte(int num) {
add((byte) num);
}
public void addChar(char num) {
add(num);
}
public void addShort(int num) {
add((short) num);
}
public void addInteger(int num) {
add(num);
}
public void addInt(int num) {
add(num);
}
public void addLong(long num) {
add(num);
}
public void addFloat(double num) {
add((float) num);
}
public void addDouble(double num) {
add(num);
}
public void addString(String num) {
add(num);
}
@Override
public void ionRead(InputStream in) throws IOException {
while (true) {
byte b = StreamUtils.readByte(in);
if (b == IonMarks.ENTRY) {
Object value = Ion.readObject(in);
add(value);
} else if (b == IonMarks.END) {
break;
} else {
throw new RuntimeException("Unexpected mark in IonList: " + Integer.toHexString(b));
}
}
}
@Override
public void ionWrite(OutputStream out) throws IOException {
for (Object entry : this) {
StreamUtils.writeByte(out, IonMarks.ENTRY);
Ion.writeObject(out, entry);
}
StreamUtils.writeByte(out, IonMarks.END);
}
@Override
public byte ionMark() {
return IonMarks.LIST;
}
}

@ -0,0 +1,143 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
/**
* Ionizable HashMap
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class IonMap extends LinkedHashMap<String, Object> implements Ionizable {
public boolean getBoolean(String key) {
return (Boolean) get(key);
}
public boolean getBool(String key) {
return (Boolean) get(key);
}
public byte getByte(String key) {
return (Byte) get(key);
}
public char getChar(String key) {
return (Character) get(key);
}
public short getShort(String key) {
return (Short) get(key);
}
public int getInt(String key) {
return (Integer) get(key);
}
public long getLong(String key) {
return (Long) get(key);
}
public float getFloat(String key) {
return (Float) get(key);
}
public double getDouble(String key) {
return (Double) get(key);
}
public String getString(String key) {
return (String) get(key);
}
@Override
public Object get(Object arg0) {
return super.get(arg0);
}
public void putBoolean(String key, boolean num) {
put(key, num);
}
public void putBool(String key, boolean num) {
put(key, num);
}
public void putByte(String key, int num) {
put(key, (byte) num);
}
public void putChar(String key, char num) {
put(key, num);
}
public void putCharacter(String key, char num) {
put(key, num);
}
public void putShort(String key, int num) {
put(key, num);
}
public void putInt(String key, int num) {
put(key, num);
}
public void putInteger(String key, int num) {
put(key, num);
}
public void putLong(String key, long num) {
put(key, num);
}
public void putFloat(String key, double num) {
put(key, (float) num);
}
public void putDouble(String key, double num) {
put(key, num);
}
public void putString(String key, String num) {
put(key, num);
}
@Override
public void ionRead(InputStream in) throws IOException {
while (true) {
byte b = StreamUtils.readByte(in);
if (b == IonMarks.ENTRY) {
String key = StreamUtils.readStringBytes(in);
Object value = Ion.readObject(in);
put(key, value);
} else if (b == IonMarks.END) {
break;
} else {
throw new RuntimeException("Unexpected mark in IonMap: " + Integer.toHexString(b));
}
}
}
@Override
public void ionWrite(OutputStream out) throws IOException {
for (Entry<String, Object> entry : entrySet()) {
StreamUtils.writeByte(out, IonMarks.ENTRY);
StreamUtils.writeStringBytes(out, entry.getKey());
Ion.writeObject(out, entry.getValue());
}
StreamUtils.writeByte(out, IonMarks.END);
}
@Override
public byte ionMark() {
return IonMarks.MAP;
}
}

@ -0,0 +1,57 @@
package com.porcupine.ion;
/**
* Byte marks used to structure data in Ion files.
*
* @author MightyPork
*/
public class IonMarks {
/** Null value */
public static final byte NULL = 0;
/** Boolean value */
public static final byte BOOLEAN = 1;
/** Byte value */
public static final byte BYTE = 2;
/** Character value */
public static final byte CHAR = 3;
/** Short value */
public static final byte SHORT = 4;
/** Integer value */
public static final byte INT = 5;
/** Long value */
public static final byte LONG = 6;
/** Float value */
public static final byte FLOAT = 7;
/** Double value */
public static final byte DOUBLE = 8;
/** String value */
public static final byte STRING = 9;
/** List value (begin) - contains entries, ends with END */
public static final byte LIST = 10;
/** Map value (begin) - contains entries, ends with END */
public static final byte MAP = 11;
/**
* List / Map entry<br>
* In list directly followed by entry value. In map followed by (string) key
* and the entry value.
*/
public static final byte ENTRY = 12;
/** End of List / Map */
public static final byte END = 13;
}

@ -0,0 +1,41 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Object that can be saved to and loaded from Ion file.<br>
* All classes implementing Ionizable must be registered to {@link Ion} using
* Ion.registerIonizable(obj.class).
*
* @author MightyPork
*/
public interface Ionizable {
/**
* Load data from the input stream. Mark has already been read, begin
* reading right after it.
*
* @param in input stream
* @throws IOException at IO error
*/
public void ionRead(InputStream in) throws IOException;
/**
* Store data to output stream. mark has already been written, begin right
* after it.
*
* @param out Output stream
* @throws IOException at IO error
*/
public void ionWrite(OutputStream out) throws IOException;
/**
* Get Ion mark byte.
*
* @return Ion mark byte.
*/
public byte ionMark();
}

@ -0,0 +1,16 @@
package com.porcupine.ion;
/**
* Optional ionizable
*
* @author MightyPork
*/
public interface IonizableOptional extends Ionizable {
/**
* Get if this ionizable should be saved to a list
*
* @return should save
*/
public boolean ionShouldSave();
}

@ -0,0 +1,208 @@
package com.porcupine.ion;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* Utilities to store and load objects to streams.
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class StreamUtils {
private static ByteBuffer bi = ByteBuffer.allocate(Integer.SIZE / 8);
private static ByteBuffer bd = ByteBuffer.allocate(Double.SIZE / 8);
private static ByteBuffer bf = ByteBuffer.allocate(Float.SIZE / 8);
private static ByteBuffer bc = ByteBuffer.allocate(Character.SIZE / 8);
private static ByteBuffer bl = ByteBuffer.allocate(Long.SIZE / 8);
private static ByteBuffer bs = ByteBuffer.allocate(Short.SIZE / 8);
private static byte[] ai = new byte[Integer.SIZE / 8];
private static byte[] ad = new byte[Double.SIZE / 8];
private static byte[] af = new byte[Float.SIZE / 8];
private static byte[] ac = new byte[Character.SIZE / 8];
private static byte[] al = new byte[Long.SIZE / 8];
private static byte[] as = new byte[Short.SIZE / 8];
// CONVERSIONS
private static byte[] convBool(boolean bool) {
return new byte[] { (byte) (bool ? 1 : 0) };
}
private static byte[] convByte(byte num) {
return new byte[] { num };
}
private static byte[] convChar(char num) {
bc.clear();
bc.putChar(num);
return bc.array();
}
private static byte[] convShort(short num) {
bs.clear();
bs.putShort(num);
return bs.array();
}
private static byte[] convInt(int num) {
bi.clear();
bi.putInt(num);
return bi.array();
}
private static byte[] convLong(long num) {
bl.clear();
bl.putLong(num);
return bl.array();
}
private static byte[] convFloat(float num) {
bf.clear();
bf.putFloat(num);
return bf.array();
}
private static byte[] convDouble(double num) {
bd.clear();
bd.putDouble(num);
return bd.array();
}
private static byte[] convString(String str) {
char[] chars = str.toCharArray();
ByteBuffer bstr = ByteBuffer.allocate((Character.SIZE / 8) * chars.length + (Character.SIZE / 8));
for (char c : chars) {
bstr.putChar(c);
}
bstr.putChar((char) 0);
return bstr.array();
}
private static byte[] convString_b(String str) {
char[] chars = str.toCharArray();
ByteBuffer bstr = ByteBuffer.allocate((Byte.SIZE / 8) * chars.length + 1);
for (char c : chars) {
bstr.put((byte) c);
}
bstr.put((byte) 0);
return bstr.array();
}
public static void writeBoolean(OutputStream out, boolean num) throws IOException {
out.write(convBool(num));
}
public static void writeByte(OutputStream out, byte num) throws IOException {
out.write(convByte(num));
}
public static void writeChar(OutputStream out, char num) throws IOException {
out.write(convChar(num));
}
public static void writeShort(OutputStream out, short num) throws IOException {
out.write(convShort(num));
}
public static void writeInt(OutputStream out, int num) throws IOException {
out.write(convInt(num));
}
public static void writeLong(OutputStream out, long num) throws IOException {
out.write(convLong(num));
}
public static void writeFloat(OutputStream out, float num) throws IOException {
out.write(convFloat(num));
}
public static void writeDouble(OutputStream out, double num) throws IOException {
out.write(convDouble(num));
}
public static void writeString(OutputStream out, String str) throws IOException {
out.write(convString(str));
}
public static void writeStringBytes(OutputStream out, String str) throws IOException {
out.write(convString_b(str));
}
// READING
public static boolean readBoolean(InputStream in) throws IOException {
return in.read() > 0;
}
public static byte readByte(InputStream in) throws IOException {
return (byte) in.read();
}
public static char readChar(InputStream in) throws IOException {
in.read(ac, 0, ac.length);
ByteBuffer buf = ByteBuffer.wrap(ac);
return buf.getChar();
}
public static short readShort(InputStream in) throws IOException {
in.read(as, 0, as.length);
ByteBuffer buf = ByteBuffer.wrap(as);
return buf.getShort();
}
public static long readLong(InputStream in) throws IOException {
in.read(al, 0, al.length);
ByteBuffer buf = ByteBuffer.wrap(al);
return buf.getLong();
}
public static int readInt(InputStream in) throws IOException {
in.read(ai, 0, ai.length);
ByteBuffer buf = ByteBuffer.wrap(ai);
return buf.getInt();
}
public static float readFloat(InputStream in) throws IOException {
in.read(af, 0, af.length);
ByteBuffer buf = ByteBuffer.wrap(af);
return buf.getFloat();
}
public static double readDouble(InputStream in) throws IOException {
in.read(ad, 0, ad.length);
ByteBuffer buf = ByteBuffer.wrap(ad);
return buf.getDouble();
}
public static String readString(InputStream in) throws IOException {
String s = "";
char c;
while ((c = readChar(in)) > 0) {
s += c;
}
return s;
}
public static String readStringBytes(InputStream in) throws IOException {
String s = "";
byte b;
while ((b = readByte(in)) > 0) {
s += (char) b;
}
return s;
}
}

@ -0,0 +1,804 @@
package com.porcupine.math;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.lwjgl.BufferUtils;
import com.porcupine.coord.Coord;
import com.porcupine.coord.Vec;
/**
* Math helper
*
* @author MightyPork
*/
public class Calc {
/** Square root of two */
public static final double SQ2 = 1.41421356237;
/**
* Get distance from 2D line to 2D point [X,Y]
*
* @param lineDirVec line directional vector
* @param linePoint point of line
* @param point point coordinate
* @return distance
*/
public static double linePointDist(Vec lineDirVec, Coord linePoint, Coord point) {
// line point L[lx,ly]
double lx = linePoint.x;
double ly = linePoint.y;
// line equation ax+by+c=0
double a = -lineDirVec.y;
double b = lineDirVec.x;
double c = -a * lx - b * ly;
// checked point P[x,y]
double x = point.x;
double y = point.y;
// distance
return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
}
/**
* Get distance from 2D line to 2D point [X,Z]
*
* @param lineDirVec line directional vector
* @param linePoint point of line
* @param point point coordinate
* @return distance
*/
public static double linePointDistXZ(Vec lineDirVec, Coord linePoint, Coord point) {
return linePointDist(new Vec(lineDirVec.x, lineDirVec.z), new Coord(linePoint.x, linePoint.z), new Coord(point.x, point.z));
}
/**
* Get longest side of a right-angled triangle
*
* @param a side a (opposite)
* @param b side b (adjacent)
* @return longest side (hypotenuse)
*/
public static double pythC(double a, double b) {
return Math.sqrt(square(a) + square(b));
}
/**
* Get adjacent side of a right-angled triangle
*
* @param a side a (opposite)
* @param c side c (hypotenuse)
* @return side b (adjacent)
*/
public static double pythB(double a, double c) {
return Math.sqrt(square(c) - square(a));
}
/**
* Get opposite side of a right-angled triangle
*
* @param b side b (adjacent)
* @param c side c (hypotenuse)
* @return side a (opposite)
*/
public static double pythA(double b, double c) {
return Math.sqrt(square(c) - square(b));
}
private static class Angles {
public static double delta(double alpha, double beta, double a360) {
while (Math.abs(alpha - beta) > a360 / 2D) {
alpha = norm(alpha + a360 / 2D, a360);
beta = norm(beta + a360 / 2D, a360);
}
return beta - alpha;
}
public static double norm(double angle, double a360) {
while (angle < 0)
angle += a360;
while (angle > a360)
angle -= a360;
return angle;
}
}
/**
* Calc subclass with buffer utils.
*
* @author MightyPork
*/
public static class Buffers {
/**
* Create java.nio.FloatBuffer of given floats, and flip it.
*
* @param obj floats or float array
* @return float buffer
*/
public static FloatBuffer mkFillBuff(float... obj) {
return (FloatBuffer) BufferUtils.createFloatBuffer(obj.length).put(obj).flip();
}
/**
* Fill java.nio.FloatBuffer with floats or float array
*
* @param buff
* @param obj
*/
public static void fill(FloatBuffer buff, float... obj) {
buff.put(obj);
buff.flip();
}
/**
* Create new java.nio.FloatBuffer of given length
*
* @param count elements
* @return the new java.nio.FloatBuffer
*/
public static FloatBuffer alloc(int count) {
return BufferUtils.createFloatBuffer(count);
}
}
/**
* Angle calculations for degrees.
*
* @author MightyPork
*/
public static class Deg {
/** 180° in degrees */
public static final double a180 = 180;
/** 270° in degrees */
public static final double a270 = 270;
/** 360° in degrees */
public static final double a360 = 360;
/** 45° in degrees */
public static final double a45 = 45;
/** 90° in degrees */
public static final double a90 = 90;
/**
* Subtract two angles alpha - beta
*
* @param alpha first angle
* @param beta second angle
* @return (alpha - beta) in degrees
*/
public static double delta(double alpha, double beta) {
return Angles.delta(alpha, beta, a360);
}
/**
* Difference of two angles (absolute value of delta)
*
* @param alpha first angle
* @param beta second angle
* @return difference in radians
*/
public static double diff(double alpha, double beta) {
return Math.abs(Angles.delta(alpha, beta, a360));
}
/**
* Cosinus in degrees
*
* @param deg angle in degrees
* @return cosinus
*/
public static double cos(double deg) {
return Math.cos(toRad(deg));
}
/**
* Sinus in degrees
*
* @param deg angle in degrees
* @return sinus
*/
public static double sin(double deg) {
return Math.sin(toRad(deg));
}
/**
* Tangents in degrees
*
* @param deg angle in degrees
* @return tangents
*/
public static double tan(double deg) {
return Math.tan(toRad(deg));
}
/**
* Angle normalized to 0-360 range
*
* @param angle angle to normalize
* @return normalized angle
*/
public static double norm(double angle) {
return Angles.norm(angle, a360);
}
/**
* Convert to radians
*
* @param deg degrees
* @return radians
*/
public static double toRad(double deg) {
return Math.toRadians(deg);
}
/**
* Round angle to 0,45,90,135...
*
* @param deg angle in deg. to round
* @param x rounding increment (45 - round to 0,45,90...)
* @return rounded
*/
public static int roundX(double deg, double x) {
double half = x / 2d;
deg += half;
deg = norm(deg);
int times = (int) Math.floor(deg / x);
double a = times * x;
if (a == 360) a = 0;
return (int) Math.round(a);
}
/**
* Round angle to 0,45,90,135...
*
* @param deg angle in deg. to round
* @return rounded
*/
public static int round45(double deg) {
return roundX(deg, 45);
}
/**
* Round angle to 0,90,180,270
*
* @param deg angle in deg. to round
* @return rounded
*/
public static int round90(double deg) {
return roundX(deg, 90);
}
/**
* Round angle to 0,15,30,45,60,75,90...
*
* @param deg angle in deg to round
* @return rounded
*/
public static int round15(double deg) {
return roundX(deg, 15);
}
}
/**
* Angle calculations for radians.
*
* @author MightyPork
*/
public static class Rad {
/** 180° in radians */
public static final double a180 = Math.PI;
/** 270° in radians */
public static final double a270 = Math.PI * 1.5D;
/** 360° in radians */
public static final double a360 = Math.PI * 2D;
/** 45° in radians */
public static final double a45 = Math.PI / 4D;
/** 90° in radians */
public static final double a90 = Math.PI / 2D;
/**
* Subtract two angles alpha - beta
*
* @param alpha first angle
* @param beta second angle
* @return (alpha - beta) in radians
*/
public static double delta(double alpha, double beta) {
return Angles.delta(alpha, beta, a360);
}
/**
* Difference of two angles (absolute value of delta)
*
* @param alpha first angle
* @param beta second angle
* @return difference in radians
*/
public static double diff(double alpha, double beta) {
return Math.abs(Angles.delta(alpha, beta, a360));
}
/**
* Cos
*
* @param rad angle in rads
* @return cos
*/
public static double cos(double rad) {
return Math.cos(rad);
}
/**
* Sin
*
* @param rad angle in rads
* @return sin
*/
public static double sin(double rad) {
return Math.sin(rad);
}
/**
* Tan
*
* @param rad angle in rads
* @return tan
*/
public static double tan(double rad) {
return Math.tan(rad);
}
/**
* Angle normalized to 0-2*PI range
*
* @param angle angle to normalize
* @return normalized angle
*/
public static double norm(double angle) {
return Angles.norm(angle, a360);
}
/**
* Convert to degrees
*
* @param rad radians
* @return degrees
*/
public static double toDeg(double rad) {
return Math.toDegrees(rad);
}
}
private static Random rand = new Random();
/**
* Get volume of a sphere
*
* @param radius sphere radius
* @return volume in cubic units
*/
public static double sphereGetVolume(double radius) {
return (4D / 3D) * Math.PI * cube(radius);
}
/**
* Get radius of a sphere
*
* @param volume sphere volume
* @return radius in units
*/
public static double sphereGetRadius(double volume) {
return Math.cbrt((3D * volume) / (4 * Math.PI));
}
/**
* Get surface of a circle
*
* @param radius circle radius
* @return volume in square units
*/
public static double circleGetSurface(double radius) {
return Math.PI * square(radius);
}
/**
* Get radius of a circle
*
* @param surface circle volume
* @return radius in units
*/
public static double circleGetRadius(double surface) {
return Math.sqrt(surface / Math.PI);
}
/**
* Check if objects are equal (for equals function)
*
* @param a
* @param b
* @return are equal
*/
public static boolean areObjectsEqual(Object a, Object b) {
return a == null ? b == null : a.equals(b);
}
/**
* Private clamping helper.
*
* @param number number to be clamped
* @param min min value
* @param max max value
* @return clamped double
*/
private static double clamp_double(Number number, Number min, Number max) {
double n = number.doubleValue();
double mind = min.doubleValue();
double maxd = max.doubleValue();
if (n > maxd) n = maxd;
if (n < mind) n = mind;
return n;
}
/**
* Private clamping helper.
*
* @param number number to be clamped
* @param min min value
* @return clamped double
*/
private static double clamp_double(Number number, Number min) {
double n = number.doubleValue();
double mind = min.doubleValue();
if (n < mind) n = mind;
return n;
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* DOUBLE version
*
* @param number clamped number
* @param min minimal allowed value
* @param max maximal allowed value
* @return result
*/
public static double clampd(Number number, Number min, Number max) {
return clamp_double(number, min, max);
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* FLOAT version
*
* @param number clamped number
* @param min minimal allowed value
* @param max maximal allowed value
* @return result
*/
public static float clampf(Number number, Number min, Number max) {
return (float) clamp_double(number, min, max);
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* INTEGER version
*
* @param number clamped number
* @param min minimal allowed value
* @param max maximal allowed value
* @return result
*/
public static int clampi(Number number, Number min, Number max) {
return (int) Math.round(clamp_double(number, min, max));
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* INTEGER version
*
* @param number clamped number
* @param range range
* @return result
*/
public static int clampi(Number number, Range range) {
return (int) Math.round(clamp_double(number, range.getMin(), range.getMax()));
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* DOUBLE version
*
* @param number clamped number
* @param range range
* @return result
*/
public static double clampd(Number number, Range range) {
return clamp_double(number, range.getMin(), range.getMax());
}
/**
* Clamp number to min and max bounds, inclusive.<br>
* FLOAT version
*
* @param number clamped number
* @param range range
* @return result
*/
public static float clampf(Number number, Range range) {
return (float) clamp_double(number, range.getMin(), range.getMax());
}
/**
* Clamp number to min and infinite bounds, inclusive.<br>
* DOUBLE version
*
* @param number clamped number
* @param min minimal allowed value
* @return result
*/
public static double clampd(Number number, Number min) {
return clamp_double(number, min);
}
/**
* Clamp number to min and infinite bounds, inclusive.<br>
* FLOAT version
*
* @param number clamped number
* @param min minimal allowed value
* @return result
*/
public static float clampf(Number number, Number min) {
return (float) clamp_double(number, min);
}
/**
* Clamp number to min and infinite bounds, inclusive.<br>
* INTEGER version
*
* @param number clamped number
* @param min minimal allowed value
* @return result
*/
public static int clampi(Number number, Number min) {
return (int) Math.round(clamp_double(number, min));
}
/**
* Get class simple name
*
* @param obj object
* @return simple name
*/
public static String className(Object obj) {
if (obj == null) return "NULL";
return obj.getClass().getSimpleName();
}
/**
* Cube a double
*
* @param a squared double
* @return square
*/
public static double cube(double a) {
return a * a * a;
}
/**
* Convert double to string, remove the mess at the end.
*
* @param d double
* @return string
*/
public static String doubleToString(double d) {
String s = Double.toString(d);
s = s.replaceAll("([0-9]+\\.[0-9]+)00+[0-9]+", "$1");
s = s.replaceAll("0+$", "");
s = s.replaceAll("\\.$", "");
return s;
}
/**
* Convert float to string, remove the mess at the end.
*
* @param f float
* @return string
*/
public static String floatToString(float f) {
String s = Float.toString(f);
s = s.replaceAll("([0-9]+\\.[0-9]+)00+[0-9]+", "$1");
s = s.replaceAll("0+$", "");
s = s.replaceAll("\\.$", "");
return s;
}
/**
* Check if number is in range
*
* @param number checked
* @param left lower end
* @param right upper end
* @return is in range
*/
public static boolean inRange(double number, double left, double right) {
return number >= left && number <= right;
}
/**
* Get number from A to B at delta time (tween A to B)
*
* @param last last number
* @param now new number
* @param dtime delta time
* @return current number to render
*/
public static double interpolate(double last, double now, double dtime) {
return last + (now - last) * dtime;
}
/**
* Get angle [degrees] from A to B at delta time (tween A to B)
*
* @param last last angle
* @param now new angle
* @param delta delta time
* @return current angle to render
*/
public static double interpolateDeg(double last, double now, double delta) {
return Deg.norm(last + Deg.delta(now, last) * delta);
}
/**
* Get highest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static double max(double... numbers) {
double highest = numbers[0];
for (double num : numbers) {
if (num > highest) highest = num;
}
return highest;
}
/**
* Get highest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static float max(float... numbers) {
float highest = numbers[0];
for (float num : numbers) {
if (num > highest) highest = num;
}
return highest;
}
/**
* Get highest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static int max(int... numbers) {
int highest = numbers[0];
for (int num : numbers) {
if (num > highest) highest = num;
}
return highest;
}
/**
* Get lowest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static double min(double... numbers) {
double lowest = numbers[0];
for (double num : numbers) {
if (num < lowest) lowest = num;
}
return lowest;
}
/**
* Get lowest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static float min(float... numbers) {
float lowest = numbers[0];
for (float num : numbers) {
if (num < lowest) lowest = num;
}
return lowest;
}
/**
* Get lowest number of a list
*
* @param numbers numbers
* @return lowest
*/
public static int min(int... numbers) {
int lowest = numbers[0];
for (int num : numbers) {
if (num < lowest) lowest = num;
}
return lowest;
}
/**
* Split comma separated list of integers.
*
* @param list String containing the list.
* @return array of integers or null.
*/
public static List<Integer> parseIntList(String list) {
if (list == null) {
return null;
}
String[] parts = list.split(",");
ArrayList<Integer> intList = new ArrayList<Integer>();
for (String part : parts) {
try {
intList.add(Integer.parseInt(part));
} catch (NumberFormatException e) {}
}
return intList;
}
/**
* Pick random element from a given list.
*
* @param list list of choices
* @return picked element
*/
public static Object pick(List<?> list) {
if (list.size() == 0) return null;
return list.get(rand.nextInt(list.size()));
}
/**
* Square a double
*
* @param a squared double
* @return square
*/
public static double square(double a) {
return a * a;
}
/**
* Signum.
*
* @param number
* @return sign, -1,0,1
*/
public static int sgn(double number) {
return number > 0 ? 1 : number < 0 ? -1 : 0;
}
}

@ -0,0 +1,91 @@
package com.porcupine.math;
import com.porcupine.coord.Coord;
/**
* Polar coordinate
*
* @author MightyPork
*/
public class Polar {
/** angle in radians */
public double angle = 0;
/** distance in units */
public double distance = 0;
/**
* @param angle angle in radians
* @param distance distance from origin
*/
public Polar(double angle, double distance) {
this.angle = angle;
this.distance = distance;
}
/**
* Make polar from coord
*
* @param coord coord
* @return polar
*/
public static Polar fromCoord(Coord coord) {
return new Polar(Math.atan2(coord.y, coord.x), Math.sqrt(Calc.square(coord.x) + Calc.square(coord.y)));
}
/**
* Make polar from coords
*
* @param x x coord
* @param y y coord
* @return polar
*/
public static Polar fromCoord(double x, double y) {
return Polar.fromCoord(new Coord(x, y));
}
/**
* Make polar from coords
*
* @param x x coord
* @param z z coord
* @return polar
*/
public static Polar fromCoordXZ(double x, double z) {
return Polar.fromCoordXZ(new Coord(x, 0, z));
}
/**
* Get coord from polar
*
* @return coord
*/
public Coord toCoord() {
return new Coord(distance * Math.cos(angle), distance * Math.sin(angle));
}
/**
* Get X,0,Y coord from polar
*
* @return coord
*/
public Coord toCoordXZ() {
return new Coord(distance * Math.cos(angle), 0, distance * Math.sin(angle));
}
@Override
public String toString() {
return "Polar(theta=" + angle + ", r=" + distance + ")";
}
/**
* Build polar from X,Z instead of X,Y
*
* @param coord cpprd with X,Z
* @return polar
*/
public static Polar fromCoordXZ(Coord coord) {
return fromCoord(coord.x, coord.z);
}
}

@ -0,0 +1,95 @@
package com.porcupine.math;
import com.porcupine.coord.Coord;
import com.porcupine.math.Calc.Deg;
import com.porcupine.math.Calc.Rad;
/**
* Polar coordinate in degrees
*
* @author MightyPork
*/
public class PolarDeg {
/** angle in degrees */
public double angle = 0;
/** distance in units */
public double distance = 0;
/**
* Polar coordinate in degrees
*
* @param angle angle in degrees
* @param distance distance from origin
*/
public PolarDeg(double angle, double distance) {
this.angle = angle;
this.distance = distance;
}
/**
* Make polar from coord
*
* @param coord coord
* @return polar
*/
public static PolarDeg fromCoord(Coord coord) {
return new PolarDeg(Rad.toDeg(Math.atan2(coord.y, coord.x)), Math.sqrt(Calc.square(coord.x) + Calc.square(coord.y)));
}
/**
* Make polar from coords
*
* @param x x coord
* @param y y coord
* @return polar
*/
public static PolarDeg fromCoord(double x, double y) {
return PolarDeg.fromCoord(new Coord(x, y));
}
/**
* Make polar from coords
*
* @param x x coord
* @param z y coord
* @return polar
*/
public static PolarDeg fromCoordXZ(double x, double z) {
return PolarDeg.fromCoordXZ(new Coord(x, 0, z));
}
/**
* Get coord from polar
*
* @return coord
*/
public Coord toCoord() {
return new Coord(distance * Math.cos(Deg.toRad(angle)), distance * Math.sin(Deg.toRad(angle)));
}
/**
* Get X,0,Y coord from polar
*
* @return coord
*/
public Coord toCoordXZ() {
return new Coord(distance * Math.cos(Deg.toRad(angle)), 0, distance * Math.sin(Deg.toRad(angle)));
}
@Override
public String toString() {
return "Polar(theta=" + angle + ", r=" + distance + ")";
}
/**
* Build polar from X,Z instead of X,Y
*
* @param coord cpprd with X,Z
* @return polar
*/
public static PolarDeg fromCoordXZ(Coord coord) {
return fromCoord(coord.x, coord.z);
}
}

@ -0,0 +1,174 @@
package com.porcupine.math;
import java.util.Random;
/**
* Numeric range, able to generate random numbers and give min/max values.
*
* @author MightyPork
*/
public class Range {
private double min = 0;
private double max = 1;
private static Random rand = new Random();
/**
* Implicit range constructor 0-1
*/
public Range() {}
/**
* Create new range
*
* @param min min number
* @param max max number
*/
public Range(double min, double max) {
if (min > max) {
double t = min;
min = max;
max = t;
}
this.min = min;
this.max = max;
}
/**
* Create new range
*
* @param minmax min = max number
*/
public Range(double minmax) {
this.min = minmax;
this.max = minmax;
}
/**
* Get random integer from range
*
* @return random int
*/
public int randInt() {
return (int) (Math.round(min) + rand.nextInt((int) (Math.round(max) - Math.round(min)) + 1));
}
/**
* Get random double from this range
*
* @return random double
*/
public double randDouble() {
return min + rand.nextDouble() * (max - min);
}
/**
* Get min
*
* @return min number
*/
public double getMin() {
return min;
}
/**
* Get max
*
* @return max number
*/
public double getMax() {
return max;
}
/**
* Get min
*
* @return min number
*/
public int getMinI() {
return (int) min;
}
/**
* Get max
*
* @return max number
*/
public int getMaxI() {
return (int) max;
}
/**
* Set min
*
* @param min min value
*/
public void setMin(double min) {
this.min = min;
}
/**
* Set max
*
* @param max max value
*/
public void setMax(double max) {
this.max = max;
}
@Override
public String toString() {
return "Range(" + min + ";" + max + ")";
}
/**
* Get identical copy
*
* @return copy
*/
public Range copy() {
return new Range(min, max);
}
/**
* Set to value of other range
*
* @param other copied range
*/
public void setTo(Range other) {
if (other == null) return;
min = other.min;
max = other.max;
if (min > max) {
double t = min;
min = max;
max = t;
}
}
/**
* Set to min-max values
*
* @param min min value
* @param max max value
*/
public void setTo(double min, double max) {
if (min > max) {
double t = min;
min = max;
max = t;
}
this.min = min;
this.max = max;
}
}

@ -0,0 +1,52 @@
package com.porcupine.mutable;
/**
* Mutable object
*
* @author MightyPork
* @param <T> type
*/
public abstract class AbstractMutable<T> {
/** The wrapped value */
public T o = getDefault();
/**
* Implicint constructor
*/
public AbstractMutable() {}
/**
* new mutable object
*
* @param o value
*/
public AbstractMutable(T o) {
this.o = o;
}
/**
* Get the wrapped value
*
* @return value
*/
public T get() {
return o;
}
/**
* Set value
*
* @param o new value to set
*/
public void set(T o) {
this.o = o;
}
/**
* Get default value
*
* @return default value
*/
protected abstract T getDefault();
}

@ -0,0 +1,28 @@
package com.porcupine.mutable;
/**
* Mutable boolean
*
* @author MightyPork
*/
public class MBoolean extends AbstractMutable<Boolean> {
/**
* Mutable boolean
*
* @param o value
*/
public MBoolean(Boolean o) {
super(o);
}
/**
* Imp.c.
*/
public MBoolean() {}
@Override
protected Boolean getDefault() {
return false;
}
}

@ -0,0 +1,28 @@
package com.porcupine.mutable;
/**
* Mutable double
*
* @author MightyPork
*/
public class MDouble extends AbstractMutable<Double> {
/**
* Mutable double
*
* @param o value
*/
public MDouble(Double o) {
super(o);
}
/**
* Imp.c.
*/
public MDouble() {}
@Override
protected Double getDefault() {
return 0d;
}
}

@ -0,0 +1,29 @@
package com.porcupine.mutable;
/**
* Mutable float
*
* @author MightyPork
*/
public class MFloat extends AbstractMutable<Float> {
/**
* Mutable float
*
* @param o value
*/
public MFloat(Float o) {
super(o);
}
/**
* Imp.c.
*/
public MFloat() {}
@Override
protected Float getDefault() {
return 0f;
}
}

@ -0,0 +1,28 @@
package com.porcupine.mutable;
/**
* Mutable integer
*
* @author MightyPork
*/
public class MInt extends AbstractMutable<Integer> {
/**
* Mutable int
*
* @param o value
*/
public MInt(Integer o) {
super(o);
}
/**
* Imp.c.
*/
public MInt() {}
@Override
protected Integer getDefault() {
return 0;
}
}

@ -0,0 +1,28 @@
package com.porcupine.mutable;
/**
* Mutable string
*
* @author MightyPork
*/
public class MString extends AbstractMutable<String> {
/**
* Mutable string
*
* @param o value
*/
public MString(String o) {
super(o);
}
/**
* Imp.c.
*/
public MString() {}
@Override
protected String getDefault() {
return "";
}
}

@ -0,0 +1,132 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 2 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
*/
public class Struct2<T1, T2> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* Make structure of 2 objects
*
* @param objA 1st object
* @param objB 2nd object
*/
public Struct2(T1 objA, T2 objB) {
a = objA;
b = objB;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct2<?, ?> t = (Struct2<?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "}";
}
}

@ -0,0 +1,172 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 3 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
*/
public class Struct3<T1, T2, T3> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* Make structure of 3 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
*/
public Struct3(T1 objA, T2 objB, T3 objC) {
a = objA;
b = objB;
c = objC;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct3<?, ?, ?> t = (Struct3<?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "}";
}
}

@ -0,0 +1,213 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 4 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
* @param <T4> 4th object class
*/
public class Struct4<T1, T2, T3, T4> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* 4th object
*/
public T4 d;
/**
* Make structure of 4 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
* @param objD 4th object
*/
public Struct4(T1 objA, T2 objB, T3 objC, T4 objD) {
a = objA;
b = objB;
c = objC;
d = objD;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 4th object
*/
public T4 getD() {
return d;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* @return 4th object
*/
public T4 get4() {
return d;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void setD(T4 obj) {
d = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void set4(T4 obj) {
d = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct4<?, ?, ?, ?> t = (Struct4<?, ?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c) && Calc.areObjectsEqual(d, t.d);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
hash += (d == null ? 0 : d.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "," + d + "}";
}
}

@ -0,0 +1,256 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 5 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
* @param <T4> 4th object class
* @param <T5> 5th object class
*/
public class Struct5<T1, T2, T3, T4, T5> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* 4th object
*/
public T4 d;
/**
* 5th object
*/
public T5 e;
/**
* Make structure of 4 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
* @param objD 4th object
* @param objE 5th object
*/
public Struct5(T1 objA, T2 objB, T3 objC, T4 objD, T5 objE) {
a = objA;
b = objB;
c = objC;
d = objD;
e = objE;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 4th object
*/
public T4 getD() {
return d;
}
/**
* @return 5th object
*/
public T5 getE() {
return e;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* @return 4th object
*/
public T4 get4() {
return d;
}
/**
* @return 5th object
*/
public T5 get5() {
return e;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void setD(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void setE(T5 obj) {
e = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void set4(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void set5(T5 obj) {
e = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct5<?, ?, ?, ?, ?> t = (Struct5<?, ?, ?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c) && Calc.areObjectsEqual(d, t.d)
&& Calc.areObjectsEqual(e, t.e);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
hash += (d == null ? 0 : d.hashCode());
hash += (e == null ? 0 : e.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "," + d + "," + e + "}";
}
}

@ -0,0 +1,295 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 6 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
* @param <T4> 4th object class
* @param <T5> 5th object class
* @param <T6> 6th object class
*/
public class Struct6<T1, T2, T3, T4, T5, T6> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* 4th object
*/
public T4 d;
/**
* 5th object
*/
public T5 e;
/**
* 6th object
*/
public T6 f;
/**
* Make structure of 4 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
* @param objD 4th object
* @param objE 5th object
* @param objF 6th object
*/
public Struct6(T1 objA, T2 objB, T3 objC, T4 objD, T5 objE, T6 objF) {
a = objA;
b = objB;
c = objC;
d = objD;
e = objE;
f = objF;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 4th object
*/
public T4 getD() {
return d;
}
/**
* @return 5th object
*/
public T5 getE() {
return e;
}
/**
* @return 6th object
*/
public T6 getF() {
return f;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* @return 4th object
*/
public T4 get4() {
return d;
}
/**
* @return 5th object
*/
public T5 get5() {
return e;
}
/**
* @return 6th object
*/
public T6 get6() {
return f;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void setD(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void setE(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void setF(T6 obj) {
f = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void set4(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void set5(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void set6(T6 obj) {
f = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct6<?, ?, ?, ?, ?, ?> t = (Struct6<?, ?, ?, ?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c) && Calc.areObjectsEqual(d, t.d)
&& Calc.areObjectsEqual(e, t.e) && Calc.areObjectsEqual(f, t.f);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
hash += (d == null ? 0 : d.hashCode());
hash += (e == null ? 0 : e.hashCode());
hash += (f == null ? 0 : f.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "," + d + "," + e + "," + f + "}";
}
}

@ -0,0 +1,336 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 7 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
* @param <T4> 4th object class
* @param <T5> 5th object class
* @param <T6> 6th object class
* @param <T7> 7th object class
*/
public class Struct7<T1, T2, T3, T4, T5, T6, T7> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* 4th object
*/
public T4 d;
/**
* 5th object
*/
public T5 e;
/**
* 6th object
*/
public T6 f;
/**
* 7th object
*/
public T7 g;
/**
* Make structure of 4 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
* @param objD 4th object
* @param objE 5th object
* @param objF 6th object
* @param objG 7th object
*/
public Struct7(T1 objA, T2 objB, T3 objC, T4 objD, T5 objE, T6 objF, T7 objG) {
a = objA;
b = objB;
c = objC;
d = objD;
e = objE;
f = objF;
g = objG;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 4th object
*/
public T4 getD() {
return d;
}
/**
* @return 5th object
*/
public T5 getE() {
return e;
}
/**
* @return 6th object
*/
public T6 getF() {
return f;
}
/**
* @return 7th object
*/
public T7 getG() {
return g;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* @return 4th object
*/
public T4 get4() {
return d;
}
/**
* @return 5th object
*/
public T5 get5() {
return e;
}
/**
* @return 6th object
*/
public T6 get6() {
return f;
}
/**
* @return 7th object
*/
public T7 get7() {
return g;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void setD(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void setE(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void setF(T6 obj) {
f = obj;
}
/**
* Set 7th object
*
* @param obj 6th object
*/
public void setG(T7 obj) {
g = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void set4(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void set5(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void set6(T6 obj) {
f = obj;
}
/**
* Set 7th object
*
* @param obj 6th object
*/
public void set7(T7 obj) {
g = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct7<?, ?, ?, ?, ?, ?, ?> t = (Struct7<?, ?, ?, ?, ?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c) && Calc.areObjectsEqual(d, t.d)
&& Calc.areObjectsEqual(e, t.e) && Calc.areObjectsEqual(f, t.f) && Calc.areObjectsEqual(g, t.g);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
hash += (d == null ? 0 : d.hashCode());
hash += (e == null ? 0 : e.hashCode());
hash += (f == null ? 0 : f.hashCode());
hash += (g == null ? 0 : g.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "," + d + "," + e + "," + f + "," + g + "}";
}
}

@ -0,0 +1,377 @@
package com.porcupine.struct;
import com.porcupine.math.Calc;
/**
* Structure of 7 objects.
*
* @author MightyPork
* @copy (c) 2012
* @param <T1> 1st object class
* @param <T2> 2nd object class
* @param <T3> 3rd object class
* @param <T4> 4th object class
* @param <T5> 5th object class
* @param <T6> 6th object class
* @param <T7> 7th object class
* @param <T8> 8th object class
*/
public class Struct8<T1, T2, T3, T4, T5, T6, T7, T8> {
/**
* 1st object
*/
public T1 a;
/**
* 2nd object
*/
public T2 b;
/**
* 3rd object
*/
public T3 c;
/**
* 4th object
*/
public T4 d;
/**
* 5th object
*/
public T5 e;
/**
* 6th object
*/
public T6 f;
/**
* 7th object
*/
public T7 g;
/**
* 8th object
*/
public T8 h;
/**
* Make structure of 4 objects
*
* @param objA 1st object
* @param objB 2nd object
* @param objC 3rd object
* @param objD 4th object
* @param objE 5th object
* @param objF 6th object
* @param objG 7th object
* @param objH 8th object
*/
public Struct8(T1 objA, T2 objB, T3 objC, T4 objD, T5 objE, T6 objF, T7 objG, T8 objH) {
a = objA;
b = objB;
c = objC;
d = objD;
e = objE;
f = objF;
g = objG;
h = objH;
}
/**
* @return 1st object
*/
public T1 getA() {
return a;
}
/**
* @return 2nd object
*/
public T2 getB() {
return b;
}
/**
* @return 3rd object
*/
public T3 getC() {
return c;
}
/**
* @return 4th object
*/
public T4 getD() {
return d;
}
/**
* @return 5th object
*/
public T5 getE() {
return e;
}
/**
* @return 6th object
*/
public T6 getF() {
return f;
}
/**
* @return 7th object
*/
public T7 getG() {
return g;
}
/**
* @return 8th object
*/
public T8 getH() {
return h;
}
/**
* @return 1st object
*/
public T1 get1() {
return a;
}
/**
* @return 2nd object
*/
public T2 get2() {
return b;
}
/**
* @return 3rd object
*/
public T3 get3() {
return c;
}
/**
* @return 4th object
*/
public T4 get4() {
return d;
}
/**
* @return 5th object
*/
public T5 get5() {
return e;
}
/**
* @return 6th object
*/
public T6 get6() {
return f;
}
/**
* @return 7th object
*/
public T7 get7() {
return g;
}
/**
* @return 8th object
*/
public T8 get8() {
return h;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void setA(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void setB(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void setC(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void setD(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void setE(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void setF(T6 obj) {
f = obj;
}
/**
* Set 7th object
*
* @param obj 6th object
*/
public void setG(T7 obj) {
g = obj;
}
/**
* Set 8th object
*
* @param obj 6th object
*/
public void setH(T8 obj) {
h = obj;
}
/**
* Set 1st object
*
* @param obj 1st object
*/
public void set1(T1 obj) {
a = obj;
}
/**
* Set 2nd object
*
* @param obj 2nd object
*/
public void set2(T2 obj) {
b = obj;
}
/**
* Set 3rd object
*
* @param obj 3rd object
*/
public void set3(T3 obj) {
c = obj;
}
/**
* Set 4th object
*
* @param obj 4th object
*/
public void set4(T4 obj) {
d = obj;
}
/**
* Set 5th object
*
* @param obj 5th object
*/
public void set5(T5 obj) {
e = obj;
}
/**
* Set 6th object
*
* @param obj 6th object
*/
public void set6(T6 obj) {
f = obj;
}
/**
* Set 7th object
*
* @param obj 6th object
*/
public void set7(T7 obj) {
g = obj;
}
/**
* Set 8th object
*
* @param obj 6th object
*/
public void set8(T8 obj) {
h = obj;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
Struct8<?, ?, ?, ?, ?, ?, ?, ?> t = (Struct8<?, ?, ?, ?, ?, ?, ?, ?>) obj;
return Calc.areObjectsEqual(a, t.a) && Calc.areObjectsEqual(b, t.b) && Calc.areObjectsEqual(c, t.c) && Calc.areObjectsEqual(d, t.d)
&& Calc.areObjectsEqual(e, t.e) && Calc.areObjectsEqual(f, t.f) && Calc.areObjectsEqual(g, t.g) && Calc.areObjectsEqual(h, t.h);
}
@Override
public int hashCode() {
int hash = 0;
hash += (a == null ? 0 : a.hashCode());
hash += (b == null ? 0 : b.hashCode());
hash += (c == null ? 0 : c.hashCode());
hash += (d == null ? 0 : d.hashCode());
hash += (e == null ? 0 : e.hashCode());
hash += (f == null ? 0 : f.hashCode());
hash += (g == null ? 0 : g.hashCode());
hash += (h == null ? 0 : h.hashCode());
return hash;
}
@Override
public String toString() {
return "STRUCT {" + a + "," + b + "," + c + "," + d + "," + e + "," + f + "," + g + "," + h + "}";
}
}

@ -0,0 +1,54 @@
package com.porcupine.time;
/**
* Class for counting FPS in games.<br>
* This class can be used also as a simple frequency meter - output is in Hz.
*
* @author MightyPork
*/
public class FpsMeter {
private long frames = 0;
private long drops = 0;
private long lastTimeMillis = System.currentTimeMillis();
private long lastSecFPS = 0;
private long lastSecDrop = 0;
/**
* @return current second's FPS
*/
public long getFPS() {
return lastSecFPS;
}
/**
* Notification that frame was rendered
*/
public void frame() {
if (System.currentTimeMillis() - lastTimeMillis > 1000) {
lastSecFPS = frames;
lastSecDrop = drops;
frames = 0;
drops = 0;
lastTimeMillis = System.currentTimeMillis();
}
frames++;
}
/**
* Notification that some frames have been dropped
*
* @param dropped dropped frames
*/
public void drop(int dropped) {
drops += dropped;
}
/**
* @return current second's dropped frames
*/
public long getDropped() {
return lastSecDrop;
}
}

@ -0,0 +1,130 @@
package com.porcupine.time;
import com.porcupine.math.Calc;
/**
* Precise game timer
*/
public class Timer {
/**
* Ticks elapsed since last updateTimer().<br>
* Used to count how many frames to skip.
*/
public int ticksMissed;
/** Speed multiplier. */
public float timerSpeedMultiplier;
/**
* How much of the next tick has already elapsed.
*/
public float renderDeltaTime;
/**
* How many update ticks are to be run since last time
*
* @return update ticks needed
*/
public int getTicksMissed() {
return ticksMissed;
}
/**
* Get render delta time, 0-1
*
* @return delta time
*/
public double getDeltaTime() {
return renderDeltaTime;
}
/**
* @return speed multiplier
*/
public double getSpeed() {
return timerSpeedMultiplier;
}
/**
* Set speed multiplier
*
* @param speed new speed multiplier
*/
public void setSpeed(double speed) {
timerSpeedMultiplier = (float) speed;
}
private float ticksPerSecond;
private double lastUpdateSecs;
private long lastUpdateMillis;
private long lastSyncMillis;
private long syncCounter;
private double timeSyncAdjustment;
/**
* init timer
*
* @param ticksPerSecond logic update ticks per second
*/
public Timer(float ticksPerSecond) {
timerSpeedMultiplier = 1.0F;
renderDeltaTime = 0.0F;
timeSyncAdjustment = 1.0D;
this.ticksPerSecond = ticksPerSecond;
lastUpdateMillis = System.currentTimeMillis();
lastSyncMillis = System.nanoTime() / 1000000;
}
/**
* Updates all fields of the Timer using the current time
*/
public void update() {
long l = System.currentTimeMillis();
long deltaMillis = l - lastUpdateMillis;
long millis = System.nanoTime() / 1000000;
double secs = millis / 1000D;
if (deltaMillis > 1000L) {
lastUpdateSecs = secs;
} else if (deltaMillis < 0L) {
lastUpdateSecs = secs;
} else {
syncCounter += deltaMillis;
if (syncCounter > 1000L) {
long d1 = millis - lastSyncMillis;
double d2 = (double) syncCounter / (double) d1;
timeSyncAdjustment += (d2 - timeSyncAdjustment) * 0.2D;
lastSyncMillis = millis;
syncCounter = 0L;
}
if (syncCounter < 0L) {
lastSyncMillis = millis;
}
}
lastUpdateMillis = l;
double delta = (secs - lastUpdateSecs) * timeSyncAdjustment;
lastUpdateSecs = secs;
delta = Calc.clampd(delta, 0, 1);
renderDeltaTime += delta * timerSpeedMultiplier * ticksPerSecond;
ticksMissed = (int) renderDeltaTime;
renderDeltaTime -= ticksMissed;
ticksMissed = Calc.clampi(ticksMissed, 0, 10);
}
}

@ -0,0 +1,36 @@
package com.porcupine.util;
import java.io.File;
import java.io.FileFilter;
/**
* File filter for certain suffixes
*
* @author MightyPork
*/
public class FileSuffixFilter implements FileFilter {
/** Array of allowed suffixes */
private String[] suffixes = null;
/**
* Suffix filter
*
* @param suffixes var-args allowed suffixes, case insensitive
*/
public FileSuffixFilter(String... suffixes) {
this.suffixes = suffixes;
}
@Override
public boolean accept(File pathname) {
//System.out.println(pathname);
for (String suffix : suffixes) {
return pathname.isFile() && pathname.getName().toLowerCase().trim().endsWith(suffix.toLowerCase().trim());
}
return false;
}
}

@ -0,0 +1,182 @@
package com.porcupine.util;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.spritegen.util.Log;
/**
* Utilities for filesystem
*
* @author MightyPork
*/
public class FileUtils {
private enum EnumOS {
linux, solaris, windows, macos, unknown;
}
/**
* get working directory path ending with slash
*
* @param dirname name of the directory, dot will be added automatically
* @return File path to the folder
*/
public static File getAppDir(String dirname) {
String s = System.getProperty("user.home", ".");
File file;
switch (getOs()) {
case linux:
case solaris:
file = new File(s, "." + dirname + '/');
break;
case windows:
String s1 = System.getenv("APPDATA");
if (s1 != null) {
file = new File(s1, "." + dirname + '/');
} else {
file = new File(s, "." + dirname + '/');
}
break;
case macos:
file = new File(s, "Library/Application Support/" + dirname);
break;
default:
file = new File(s, dirname + "/");
break;
}
if (!file.exists() && !file.mkdirs()) {
throw new RuntimeException((new StringBuilder()).append("The working directory could not be created: ").append(file).toString());
} else {
return file;
}
}
private static EnumOS getOs() {
String s = System.getProperty("os.name").toLowerCase();
if (s.contains("win")) {
return EnumOS.windows;
}
if (s.contains("mac")) {
return EnumOS.macos;
}
if (s.contains("solaris")) {
return EnumOS.solaris;
}
if (s.contains("sunos")) {
return EnumOS.solaris;
}
if (s.contains("linux")) {
return EnumOS.linux;
}
if (s.contains("unix")) {
return EnumOS.linux;
} else {
return EnumOS.unknown;
}
}
/**
* Get files in a folder (create folder if needed)
*
* @param dir folder
* @param filter file filter
* @return list of files
*/
public static List<File> listFolder(File dir, FileFilter filter) {
try {
dir.mkdir();
} catch (RuntimeException e) {
Log.e("Error creating folder " + dir, e);
}
List<File> list = new ArrayList<File>();
try {
for (File f : dir.listFiles(filter)) {
list.add(f);
}
} catch (Exception e) {
Log.e("Error listing folder " + dir, e);
}
return list;
}
/**
* Get files in a folder (create folder if needed)
*
* @param dir folder
* @return list of files
*/
public static List<File> listFolder(File dir) {
return listFolder(dir, null);
}
/**
* Remove extension.
*
* @param file file
* @return filename without extension
*/
public static String removeExtension(File file) {
return removeExtension(file.getName());
}
/**
* Remove extension.
*
* @param filename
* @return filename without extension
*/
public static String removeExtension(String filename) {
String[] parts = filename.split("[.]");
String out = "";
for (int i = 0; i < parts.length - 1; i++) {
out += parts[i];
}
return out;
}
/**
* Read entire file to a string.
*
* @param file file
* @return file contents
* @throws IOException
*/
public static String fileToString(File file) throws IOException {
String result = null;
DataInputStream in = null;
byte[] buffer = new byte[(int) file.length()];
in = new DataInputStream(new FileInputStream(file));
in.readFully(buffer);
result = new String(buffer);
in.close();
return result;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,104 @@
package com.porcupine.util;
/**
* General purpose string utilities
*
* @author MightyPork
*/
public class StringUtils {
/**
* Get if string is in array
*
* @param needle checked string
* @param case_sensitive case sensitive comparision
* @param haystack array of possible values
* @return is in array
*/
public static boolean isInArray(String needle, boolean case_sensitive, String... haystack) {
if (case_sensitive) {
for (String s : haystack) {
if (needle.equals(s)) return true;
}
return false;
} else {
for (String s : haystack) {
if (needle.equalsIgnoreCase(s)) return true;
}
return false;
}
}
/**
* Repeat a string
*
* @param repeated string
* @param count
* @return output
*/
public static String repeat(String repeated, int count) {
String s = "";
for (int i = 0; i < count; i++)
s += repeated;
return s;
}
/**
* convert string to a same-length sequence of # marks
*
* @param password password
* @return encoded
*/
public static String passwordify(String password) {
return passwordify(password, "#");
}
/**
* convert string to a same-length sequence of chars
*
* @param password password
* @param replacing character used in output
* @return encoded
*/
public static String passwordify(String password, String replacing) {
return repeat(replacing, password.length());
}
/**
* Get ordinal version of numbers (1 = 1st, 5 = 5th etc.)
*
* @param number number
* @return ordinal, string
*/
public static String numberToOrdinal(int number) {
if (number % 100 < 4 || number % 100 > 13) {
if (number % 10 == 1) return number + "st";
if (number % 10 == 2) return number + "nd";
if (number % 10 == 3) return number + "rd";
}
return number + "th";
}
/**
* Format number with thousands separated by a dot.
*
* @param number number
* @return string 12.004.225
*/
public static String formatInt(long number) {
String num = number + "";
String out = "";
String dot = ".";
int cnt = 1;
for (int i = num.length() - 1; i >= 0; i--) {
out = num.charAt(i) + out;
if (cnt % 3 == 0 && i > 0) out = dot + out;
cnt++;
}
return out;
}
}

@ -0,0 +1,51 @@
package com.porcupine.util;
import java.util.LinkedHashMap;
/**
* Varargs parser<br>
* Converts an array of repeated "key, value" pairs to a LinkedHashMap.<br>
* example:
*
* <pre>
* Object[] array = { &quot;one&quot;, 1, &quot;two&quot;, 4, &quot;three&quot;, 9, &quot;four&quot;, 16 };
* Map&lt;String, Integer&gt; args = new VarargsParser&lt;String, Integer&gt;().parse(array);
* </pre>
*
* @author MightyPork
* @param <K> Type for Map keys
* @param <V> Type for Map values
*/
public class VarargsParser<K, V> {
/**
* Parse array of vararg key, value pairs to a LinkedHashMap.
*
* @param args varargs
* @return LinkedHashMap
* @throws ClassCastException in case of incompatible type in the array
* @throws IllegalArgumentException in case of invalid array length (odd)
*/
@SuppressWarnings("unchecked")
public LinkedHashMap<K, V> parse(Object... args) throws ClassCastException, IllegalArgumentException {
LinkedHashMap<K, V> attrs = new LinkedHashMap<K, V>();
if (args.length % 2 != 0) {
throw new IllegalArgumentException("Odd number of elements in varargs map!");
}
K key = null;
for (Object o : args) {
if (key == null) {
if (o == null) throw new RuntimeException("Key cannot be NULL in varargs map.");
key = (K) o;
} else {
attrs.put(key, (V) o);
key = null;
}
}
return attrs;
}
}

@ -0,0 +1,368 @@
package net.spritegen;
import static org.lwjgl.opengl.GL11.*;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.swing.*;
import net.spritegen.gui.Screen;
import net.spritegen.gui.ScreenSprites;
import net.spritegen.util.Log;
import net.spritegen.util.Utils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import com.porcupine.coord.Coord;
import com.porcupine.time.FpsMeter;
import com.porcupine.time.Timer;
import com.porcupine.util.FileUtils;
/**
* SECTOR main class
*
* @author MightyPork
*/
public class App {
/** instance */
public static App inst;
/** current screen */
public static Screen screen = null;
public static String[] args;
/**
* @param args
*/
public static void main(String[] args) {
App.args = args;
inst = new App();
try {
inst.start();
} catch (Throwable t) {
showCrashReport(t);
}
}
/**
* Show crash report dialog with error stack trace.
*
* @param error
*/
public static void showCrashReport(Throwable error) {
Log.e(error);
try {
inst.deinit();
} catch (Throwable t) {}
JFrame f = new JFrame("SpriteGen has crashed!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BoxLayout(f.getContentPane(), BoxLayout.Y_AXIS));
StringWriter sw = new StringWriter();
error.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
String errorLogAsString = "Not found.";
String wholeLogAsString = "Not found.";
try {
wholeLogAsString = FileUtils.fileToString(Utils.getGameSubfolder(Constants.FILE_LOG));
} catch (Exception e) {
e.printStackTrace();
}
try {
errorLogAsString = FileUtils.fileToString(Utils.getGameSubfolder(Constants.FILE_LOG_E));
} catch (Exception e) {
e.printStackTrace();
}
String txt = "";
txt = "";
txt += "SPRITE-GEN HAS CRASHED!\n";
txt += "\n";
txt += "Please report it to MightyPork:\n";
txt += "\tE-mail: ondra@ondrovo.com\n";
txt += "\tTwitter: #MightyPork (post log via pastebin.com)\n";
txt += "\n";
txt += "\n";
txt += "\n";
txt += "### STACK TRACE ###\n";
txt += "\n";
txt += exceptionAsString + "\n";
txt += "\n";
txt += "\n";
txt += "### ERROR LOG ###\n";
txt += "\n";
txt += errorLogAsString + "\n";
txt += "\n";
txt += "\n";
txt += "### FULL LOG ###\n";
txt += "\n";
txt += wholeLogAsString + "\n";
// Create Scrolling Text Area in Swing
JTextArea ta = new JTextArea(txt, 20, 70);
ta.setFont(new Font("Courier", 0, 16));
ta.setMargin(new Insets(10, 10, 10, 10));
ta.setEditable(false);
ta.setLineWrap(false);
JScrollPane sbrText = new JScrollPane(ta);
sbrText.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10), BorderFactory.createEtchedBorder()));
sbrText.setWheelScrollingEnabled(true);
sbrText.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sbrText.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
// Create Quit Button
JButton btnQuit = new JButton("Quit");
btnQuit.setAlignmentX(Component.CENTER_ALIGNMENT);
btnQuit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPane.add(btnQuit);
f.getContentPane().add(sbrText);
f.getContentPane().add(buttonPane);
// Close when the close button is clicked
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display Frame
f.pack(); // Adjusts frame to size of components
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation((dim.width - f.getWidth()) / 2, (dim.height - f.getHeight()) / 2);
f.setVisible(true);
while (true) {}
}
public static File modelFile;
public static File modelDir;
public static SetupLoader cfg;
private void deinit() {
Display.destroy();
Mouse.destroy();
Keyboard.destroy();
AL.destroy();
}
/**
* Quit to OS
*/
public void exit() {
deinit();
System.exit(0);
}
/**
* Get current screen
*
* @return screen
*/
public Screen getScreen() {
return screen;
}
/**
* Get screen size
*
* @return size
*/
public Coord getSize() {
return new Coord(Display.getWidth(), Display.getHeight());
}
// INIT
private void init() throws LWJGLException {
Log.setPrintToStdout(true);
if (args.length == 0) {
System.out.println("Args: folder/model.obj\n" +
"SpriteGen operates in .spritegen folder.\n" +
"There is a folder \".spritegen/models\", which contains subfolders with your models.\n" +
"\n" +
"Spritesheet settings are found in \"models/modelDir/config.ini\". This file will\n" +
"be generated while creating first spritesheet from that folder.\n" +
"\n" +
"Output PNG image will be saved in \"models/modelDir/out\".\n" +
"\n" +
"Example usage: java -jar spritegen.jar turtle/turtle.obj");
}
File dir = Utils.getGameSubfolder("models");
dir.mkdirs();
if (args.length == 0) {
exit();
return;
}
modelFile = Utils.getGameSubfolder("models/" + args[0]);
modelDir = modelFile.getParentFile();
File out = new File(modelDir,"out");
out.mkdirs();
cfg = new SetupLoader(modelDir);
Log.i("Output image size: " + cfg.img_size + "x" + cfg.img_size);
// init display
Display.setDisplayMode(new DisplayMode(ScreenSprites.FRAME_SIZE, ScreenSprites.FRAME_SIZE));
Display.setResizable(false);
Display.setVSyncEnabled(true);
Display.setTitle(Constants.TITLEBAR);
int samples = cfg.samples;
while (true) {
try {
Display.create(new PixelFormat().withSamples(samples).withAlphaBits(4));
Log.i("Created display with " + samples + "x multisampling.");
break;
} catch (LWJGLException e) {
Log.w("Failed to create display with " + samples + "x multisampling, trying " + samples / 2 + "x.");
if (samples >= 2) {
samples /= 2;
} else if (samples == 1) {
samples = 0;
} else if (samples == 0) {
Log.e("Could not create display.", e);
exit();
}
}
}
Mouse.create();
Keyboard.create();
Keyboard.enableRepeatEvents(false);
StaticInitializer.initOnStartup();
}
private void start() throws LWJGLException {
Log.enable(true);
Log.setPrintToStdout(true);
init();
mainLoop();
deinit();
}
// INIT END
// UPDATE LOOP
/** fps meter */
public FpsMeter fpsMeter;
/** timer */
public Timer timer;
private int timerAfterResize = 0;
private void mainLoop() {
screen = new ScreenSprites();
screen.init();
timer = new Timer(Constants.FPS_UPDATE);
fpsMeter = new FpsMeter();
while (!Display.isCloseRequested()) {
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int j = timer.ticksMissed;
if (j > 1) fpsMeter.drop(j - 1);
timer.update();
for (int i = 0; i < j; i++) {
screen.update();
}
fpsMeter.frame();
float delta = timer.renderDeltaTime;
screen.render(delta);
Display.update();
try {
Display.sync(Constants.FPS_RENDER);
} catch (Throwable t) {
Log.e("Your graphics card driver does not support fullscreen properly.", t);
}
}
}
// UPDATE LOOP END
/**
* Replace screen
*
* @param newScreen new screen
*/
public void replaceScreen(Screen newScreen) {
screen = newScreen;
screen.init();
}
/**
* Replace screen, don't init it
*
* @param newScreen new screen
*/
public void replaceScreenNoInit(Screen newScreen) {
screen = newScreen;
}
}

@ -0,0 +1,57 @@
package net.spritegen;
import net.spritegen.gui.ScreenSprites;
import com.porcupine.coord.Coord;
/**
* Sector constants
*
* @author MightyPork
*/
@SuppressWarnings("javadoc")
public class Constants {
// STRINGS
public static final String TITLEBAR = "SpriteGen";
// FILES+DIRS
public static final String APP_DIR = "spritegen";
public static final String FILE_LOG = "Runtime.log";
public static final String FILE_LOG_E = "Error.log";
// TIMING
public static final int FPS_UPDATE = 55;
public static final double SPEED_MUL = 100D / FPS_UPDATE;
public static final int FPS_RENDER = 200; // max
// // INITIAL WINDOW SIZE (later loaded from config file)
// public static final int WINDOW_SIZE_X = ScreenSprites.FRAME_SIZE; //1024; FIXME
// public static final int WINDOW_SIZE_Y = ScreenSprites.FRAME_SIZE; //768; FIXME
//
// // LIGHT
// public static final float LIGHT_AMBIENT = 1F;
// public static final float LIGHT_SPECULAR = 0.5F;
// public static final float LIGHT_DIFFUSE = 1F;
// public static final Coord LIGHT_POS = new Coord(0, 3, 3);
// public static final float LIGHT_ATTR = 1;
//
// public static final float SCENE_MAT_AMBIENT = 1F;
// public static final float SCENE_MAT_SPECULAR = 1F;
// public static final float SCENE_MAT_DIFFUSE = 1F;
// CAMERA & SCENE
public static final Coord CAM_POS = new Coord(0, 0, 5);
public static final Coord CAM_LOOKAT = new Coord(0, 0, 0);
public static final float CAM_ANGLE = 45;
public static final double CAM_NEAR = 0.1;
public static final double FOG_START = 80;
public static final double CAM_FAR = 100;
}

@ -0,0 +1,90 @@
package net.spritegen;
import java.io.File;
import net.spritegen.util.Utils;
import com.porcupine.coord.Coord;
import com.porcupine.util.PropertyManager;
public class SetupLoader {
public PropertyManager cfg;
public int img_size;
public int samples;
public double render_wobble_y;
public double render_wobble_z;
public double render_rotate_x;
public double renmder_move_y;
public double render_move_x;
public double render_scale;
public Coord light_pos;
public double light_attr;
public double light_diffuse;
public double light_specular;
public double light_ambient;
public double mat_diffuse;
public double mat_specular;
public double mat_ambient;
public SetupLoader(File dir) {
dir.mkdirs();
File file = new File(dir,"config.ini");
cfg = new PropertyManager(file.getAbsolutePath(), "Spritesheet setup file");
cfg.putInteger("output.size", 512, "Output image size");
cfg.putDouble("render.walk.wobble_x_angle_max", 6, "Maximal wobble angle for walking (rotate around Y)");
cfg.putDouble("render.walk.wobble_z_angle_max", 0, "Maximal wobble angle for walking (rotate around Z)");
cfg.putDouble("render.rotate_x", 60, "Rotate around X axis to get 2D or 2.5D perspective");
cfg.putDouble("render.move_y", 0, "Y offset (for centering)");
cfg.putDouble("render.move_x", 0, "X move (for centering)");
cfg.putDouble("render.scale", 1, "Render scale");
cfg.putInteger("render.multisampling", 4, "Multisampling (smoothing) level, values: 0,1,2,4,8");
cfg.putDouble("render.material.ambient", 1, "Material property: ambient");
cfg.putDouble("render.material.specular", 1, "Material property: specular");
cfg.putDouble("render.material.diffuse", 1, "Material property: diffuse");
cfg.putDouble("render.light.ambient", 1, "Light property: ambient");
cfg.putDouble("render.light.specular", 1, "Light property: specular");
cfg.putDouble("render.light.diffuse", 1, "Light property: diffuse");
cfg.putDouble("render.light.attribute", 1, "Light property: attribute");
cfg.putDouble("render.light.x", 0, "Light pos: X");
cfg.putDouble("render.light.y", 3, "Light pos: Y");
cfg.putDouble("render.light.z", 3, "Light pos: Z");
cfg.apply();
img_size = cfg.getInt("output.size");
render_wobble_y = cfg.getDouble("render.walk.wobble_x_angle_max");
render_wobble_z = cfg.getDouble("render.walk.wobble_z_angle_max");
render_rotate_x = cfg.getDouble("render.rotate_x");
renmder_move_y = cfg.getDouble("render.move_y");
render_move_x = cfg.getDouble("render.move_x");
render_scale = cfg.getDouble("render.scale");
samples = cfg.getInt("render.multisampling");
mat_ambient = cfg.getDouble("render.material.ambient");
mat_specular = cfg.getDouble("render.material.specular");
mat_diffuse = cfg.getDouble("render.material.diffuse");
light_ambient = cfg.getDouble("render.light.ambient");
light_specular = cfg.getDouble("render.light.specular");
light_diffuse = cfg.getDouble("render.light.diffuse");
light_attr = cfg.getDouble("render.light.attribute");
light_pos = new Coord(cfg.getDouble("render.light.x"),
cfg.getDouble("render.light.y"),
cfg.getDouble("render.light.z"));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save