[Fencommits] libvob: Porting the paper implementation.
Matti J. Katila
majukati at cc.jyu.fi
Mon Apr 3 20:05:09 EEST 2006
Mon Apr 3 19:36:32 EEST 2006 Matti J. Katila <majukati at cc.jyu.fi>
* Porting the paper implementation.
diff -rN -u libvob-old/org/nongnu/libvob/gl/impl/lwjgl/texture/FNoiseTex.java libvob-new/org/nongnu/libvob/gl/impl/lwjgl/texture/FNoiseTex.java
--- libvob-old/org/nongnu/libvob/gl/impl/lwjgl/texture/FNoiseTex.java 1970-01-01 02:00:00.000000000 +0200
+++ libvob-new/org/nongnu/libvob/gl/impl/lwjgl/texture/FNoiseTex.java 2006-04-03 19:39:39.000000000 +0300
@@ -0,0 +1,198 @@
+package org.nongnu.libvob.gl.impl.lwjgl.texture;
+
+import java.nio.FloatBuffer;
+import java.security.SecureRandom;
+
+import org.lwjgl.BufferUtils;
+
+// may be fourier noise...
+public class FNoiseTex extends NamedTexture {
+ /*
+ fnoise.texture
+ *
+ * Copyright (c) 2003, Janne Kujala and Tuomas J. Lukka
+ *
+ * This file is part of Gzz.
+ *
+ * Gzz is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Gzz is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General
+ * Public License along with Gzz; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ */
+ /*
+ * Written by Janne Kujala and Tuomas J. Lukka
+ */
+
+// -*-C++-*-
+ // what?!
+// #define a b
+
+ public FNoiseTex() {}
+
+ static SecureRandom rand = new SecureRandom();
+
+ static double drand() {
+ return rand.nextDouble();
+ }
+
+ /* Add a fourier noise to the data.
+ */
+ static void fourier_noise(int width, int height, int depth, int components, FloatBuffer data,
+ float freq, float df) {
+ fourier_noise(width, height, depth, components, data, freq, df, 1.0f);
+ }
+ static void fourier_noise(int width, int height, int depth, int components, FloatBuffer data,
+ float freq, float df, float aniso) {
+ System.out.println("fn: "+components);
+
+ int nf = (int)(2 * (freq + df) * aniso);
+
+ float xsin[][][] = new float[2][nf][width];
+ xsin[0] = new float[nf][width];
+ for (int i=0; i<nf; i++)
+ xsin[0][i] = new float[width];
+ xsin[1] = new float[nf][width];
+ for (int i=0; i<nf; i++)
+ xsin[1][i] = new float[width];
+ for(int i=0; i<width; i++)
+ for(int f = 0; f < nf; f++) {
+ xsin[0][f][i] = (float) Math.sin(i/(float)width * f * Math.PI * 2);
+ xsin[1][f][i] = (float) Math.cos(i/(float)width * f * Math.PI * 2);
+ }
+
+ float ysin[][][] = new float[2][nf][height];
+ ysin[0] = new float[nf][height];
+ for (int i=0; i<nf; i++)
+ ysin[0][i] = new float[height];
+ ysin[1] = new float[nf][height];
+ for (int i=0; i<nf; i++)
+ ysin[1][i] = new float[height];
+ for(int j=0; j<width; j++)
+ for(int f = 0; f < nf; f++) {
+ ysin[0][f][j] = (float) Math.sin(j/(float)height * f * Math.PI * 2);
+ ysin[1][f][j] = (float) Math.cos(j/(float)height * f * Math.PI * 2);
+ }
+
+ float sumsq[] = new float[components];
+ for(int i=0; i<components; i++) sumsq[i] = 0;
+
+ if(depth < 2) {
+ // 2D
+ for(int xf = 0; xf < nf; xf++) {
+ for(int yf = 0; yf < nf; yf++) {
+
+ double f = Math.sqrt(xf*xf + yf*yf*(aniso*aniso));
+ if(f < freq-df || f > freq+df) continue;
+
+ for(int xsc = 0; xsc < 2; xsc++) {
+ for(int ysc = 0; ysc < 2; ysc++) {
+ float coeff[] = new float[components];
+ for(int co = 0; co < components; co++) {
+ coeff[co] = (float) (drand()-0.5);
+ sumsq[co] += coeff[co] * coeff[co];
+ }
+ int ind = 0;
+ for (int j = 0; j < height; j++) {
+ for (int i = 0; i < width; i++) {
+ for(int co = 0; co < components; co++) {
+ data.put(ind, data.get(ind) + (xsin[xsc][xf][i] * ysin[ysc][yf][j] * coeff[co]));
+ ind++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ int ind = 0;
+
+ for(int co = 0; co < components; co++)
+ sumsq[co] = (float) Math.sqrt(sumsq[co]);
+
+ for (int j = 0; j < height; j++) {
+ for (int i = 0; i < width; i++) {
+ for(int co = 0; co < components; co++) {
+ data.put(ind, data.get(ind) / sumsq[co]);
+ ind++;
+ }
+ }
+ }
+
+ } else {
+ // float zsin[width][nf];
+ // 3D
+ }
+ }
+
+ double identity(double x) { return x; }
+
+ public void render(TextureParam params, int width, int height, int depth, int components, FloatBuffer data) {
+ float bias = params.get("bias", 0);
+ float scale = params.get("scale", 1f);
+ float freq = params.get("freq", 5f);
+ float aniso = params.get("aniso", 1.0f);
+ float df = params.get("df", 2f);
+ long seed = params.getLong("seed", 0);
+ float turb = params.get("turb", 0);
+ float fbm = params.get("fbm", 0);
+ float freq2 = params.get("freq2", 20f);
+
+ //double (*func)(double) = identity;
+ if (turb >0) {
+ fbm = 1;
+ }
+
+ if (seed > 0) rand.setSeed(seed); //srandom((long)seed);
+
+ int d = (depth==0 ? 1 : depth);
+ int n = width*height*d*components;
+
+ for(int i = 0; i<n; i++)
+ data.put(i, 0);
+
+
+ if (fbm > 0) {
+ FloatBuffer tmp = BufferUtils.createFloatBuffer(n);
+
+ for (float f = freq; f <= freq2; f += f) {
+ for(int i = 0; i<n; i++)
+ tmp.put(i, 0);
+ fourier_noise(width,height,d,components,tmp, f, df, aniso);
+
+ float m = (float) (1.0 / (Math.log(f)/Math.log(2) + 1));
+
+ for(int i = 0; i<n; i++)
+ if (turb > 0)
+ data.put(i, data.get(i) + m * Math.abs(tmp.get(i)));
+ else
+ data.put(i, data.get(i) + m * tmp.get(i));
+ }
+
+ for(int i = 0; i<n; i++)
+ tmp.put(i, 0);
+
+ } else {
+
+ fourier_noise(width,height,d,components,data, freq, df, aniso);
+ }
+
+ for(int i = 0; i<n; i++) {
+ data.put(i, data.get(i) * scale);
+ data.put(i, data.get(i) + bias);
+ }
+ }
+
+
+}
diff -rN -u libvob-old/org/nongnu/libvob/gl/impl/lwjgl/trans/linear/OrthoTransform.java libvob-new/org/nongnu/libvob/gl/impl/lwjgl/trans/linear/OrthoTransform.java
--- libvob-old/org/nongnu/libvob/gl/impl/lwjgl/trans/linear/OrthoTransform.java 1970-01-01 02:00:00.000000000 +0200
+++ libvob-new/org/nongnu/libvob/gl/impl/lwjgl/trans/linear/OrthoTransform.java 2006-04-03 19:39:39.000000000 +0300
@@ -0,0 +1,101 @@
+package org.nongnu.libvob.gl.impl.lwjgl.trans.linear;
+
+import java.io.PrintStream;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.util.vector.Vector2f;
+import org.lwjgl.util.vector.Vector3f;
+import org.nongnu.libvob.gl.impl.lwjgl.Coorder;
+import org.nongnu.libvob.gl.impl.lwjgl.Transform;
+
+public class OrthoTransform implements Transform {
+
+ private Coorder coorder;
+ private int TYPE;
+ private Transform parent;
+ private float z,x,y,xs,ys;
+
+ public void setYourself(Coorder base, int index, int[] inds, float[] floats) {
+ this.coorder = base;
+ this.TYPE = inds[index];
+
+ int floatInd = inds[index+2];
+ int parentCS = inds[index+1];
+ parent = base.getTransform(parentCS);
+ z = floats[floatInd];
+ x = floats[floatInd+1];
+ y = floats[floatInd+2];
+ xs = floats[floatInd+3];
+ ys = floats[floatInd+4];
+ }
+
+ public boolean shouldBeDrawn() {
+ return true;
+ }
+
+ public Vector3f transform(Vector3f p) {
+ p = parent.transform(p);
+ p.x += x;
+ p.y += y;
+ p.z += z;
+ p.x *= xs;
+ p.y *= ys;
+ return p;
+ }
+
+ public Vector2f transform(Vector2f p) {
+ p = parent.transform(p);
+ p.x += x;
+ p.y += y;
+ p.x *= xs;
+ p.y *= ys;
+ return p;
+ }
+
+ public void vertex(Vector3f p) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean isNonlinear() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public float nonlinearity(Vector3f p, float radius) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public boolean canPerformGL() {
+ return parent.canPerformGL();
+ }
+
+ public boolean performGL() {
+ boolean parentPerformed = parent.performGL();
+ GL11.glTranslatef(x,y,z);
+ GL11.glScalef(xs,ys, 1f);
+ return parentPerformed;
+ }
+
+ public Transform getInverse() {
+ OrthoTransform inv = (OrthoTransform) coorder.createTransform(TYPE);
+ inv.x = -x;
+ inv.y = -y;
+ inv.z = -z;
+ inv.xs = 1f/xs;
+ inv.ys = 1f/xs;
+ inv.parent = parent.getInverse();
+ return inv;
+ }
+
+ public void dump(PrintStream out) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Vector2f getSqSize() {
+ return parent.getSqSize();
+ }
+
+}
diff -rN -u libvob-old/org/nongnu/libvob/gl/impl/lwjgl/vobs/paper/PaperQuadVob.java libvob-new/org/nongnu/libvob/gl/impl/lwjgl/vobs/paper/PaperQuadVob.java
--- libvob-old/org/nongnu/libvob/gl/impl/lwjgl/vobs/paper/PaperQuadVob.java 1970-01-01 02:00:00.000000000 +0200
+++ libvob-new/org/nongnu/libvob/gl/impl/lwjgl/vobs/paper/PaperQuadVob.java 2006-04-03 19:39:39.000000000 +0300
@@ -0,0 +1,304 @@
+package org.nongnu.libvob.gl.impl.lwjgl.vobs.paper;
+
+import java.awt.Graphics;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.EXTCompiledVertexArray;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.util.vector.Vector2f;
+import org.lwjgl.util.vector.Vector3f;
+import org.nongnu.libvob.AbstractVob;
+import org.nongnu.libvob.VobScene;
+import org.nongnu.libvob.gl.GL;
+import org.nongnu.libvob.gl.PaperMill;
+import org.nongnu.libvob.gl.Ren;
+import org.nongnu.libvob.gl.Ren.PaperQuad;
+import org.nongnu.libvob.gl.impl.lwjgl.CallGL;
+import org.nongnu.libvob.gl.impl.lwjgl.Transform;
+import org.nongnu.libvob.gl.impl.lwjgl.LWJGLRen.Vob2;
+import org.nongnu.libvob.gl.impl.lwjgl.paper.Paper;
+import org.nongnu.libvob.gl.impl.lwjgl.paper.Paper.Pass;
+
+ /**
+ * PaperQuad is a bit complicated: there are three coordinate
+ * systems here: the window cs, the object cs and the paper cs.
+ * cs1 is object => window,
+ * and cs2 is paper => object, unless PAPERQUAD_CS2_TO_SCREEN is set, when it is
+ * paper => window
+ * Corners give the corners of the quad to render, in object
+ * coordinates.
+ */
+ public class PaperQuadVob extends AbstractVob implements PaperQuad, Vob2 {
+
+ public void render(Graphics g, boolean fast, RenderInfo info1, RenderInfo info2) {
+ }
+ public int putGL(VobScene vs, int cs1, int cs2) {
+ return 1;
+ }
+ static public boolean dbg_paperquad = true;
+ static private void p(String s) { System.out.println("PaperQuad:: "+s); }
+
+ Paper paper;
+ float x0,y0,x1,y1;
+ float scale, dicefactor;
+ int flags;
+
+ float []vertices;
+ int []indices;
+ int dice;
+
+ public PaperQuadVob(PaperMill.Paper paper, float x0, float y0, float x1, float y1, float scale, float dicefactor) {
+ this(paper, x0,y0,x1,y1,scale, dicefactor, GL.hasExtension("GL_NV_vertex_program1_1")? Ren.PAPERQUAD_USE_VERTEX_PROGRAM: 0);
+ }
+ public PaperQuadVob(PaperMill.Paper paper, float x0, float y0, float x1, float y1, float scale, float dicefactor, int flags) {
+ this.paper = (Paper)paper;
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+ this.scale = scale;
+ this.dicefactor = dicefactor;
+ this.flags = flags;
+ }
+
+ public void render(Transform coords1, Transform coords2, int callList) {
+
+ final Transform coords2inv = coords2.getInverse();
+
+ CallGL.checkGlError("start PaperQuad render");
+
+ Vector3f paperorigin, paperx, papery;
+ if((flags & Ren.PAPERQUAD_CS2_TO_SCREEN) != 0) {
+ Transform coords1inv = coords1.getInverse();
+ paperorigin = coords1inv.transform(coords2.transform(new Vector3f(0, 0, 0)));
+ paperx = coords1inv.transform(coords2.transform(new Vector3f(1f, 0, 0))).negate(paperorigin);
+ papery = coords1inv.transform(coords2.transform(new Vector3f(0, 1f, 0))).negate(paperorigin);
+ } else {
+ paperorigin = coords2.transform(new Vector3f(0, 0, 0));
+ paperx = coords2.transform(new Vector3f(1f, 0, 0)).negate(paperorigin);
+ papery = coords2.transform(new Vector3f(0, 1f, 0)).negate(paperorigin);
+ }
+
+
+ Paper.LightParam lightParam = new Paper.LightParam();
+
+ // These are now irrelevant
+ lightParam.orig = paperorigin; // - new Vector3f(0,0,0);
+ lightParam.e0 = (Vector3f) paperx.scale(scale);
+ lightParam.e1 = (Vector3f) papery.scale(scale);
+ lightParam.e2 = (Vector3f) new Vector3f(0,0,paperx.length()).scale(scale);
+
+ lightParam.Light = new Vector3f(-1f,-1f,1f);
+ lightParam.Light_w = 0.0f;
+
+ if (dbg_paperquad) p(lightParam.orig+", "+lightParam.e0+", "+lightParam.e1+", "+lightParam.e2+
+ ", x0: "+x0+", y0: "+y0+", x1: "+x1+", y1: +y1");
+ CallGL.checkGlError("midle of PaperQuad render.");
+
+
+ if((flags & Ren.PAPERQUAD_NONL_MAXLEN) != 0) {
+ Vector2f p1 = coords1.transform(new Vector2f(x0,y0));
+ Vector2f p2 = coords1.transform(new Vector2f(x0,y1));
+ Vector2f p3 = coords1.transform(new Vector2f(x1,y0));
+ Vector2f p4 = coords1.transform(new Vector2f(x1,y1));
+ float dist[] = new float[]{
+ (p2.negate(p1)).length(),
+ (p3.negate(p1)).length(),
+ (p4.negate(p2)).length(),
+ (p4.negate(p3)).length()
+ };
+ float m = Float.MIN_VALUE;
+ for (int i = 0; i < dist.length; i++)
+ if (dist[i] > m) m = dist[i];
+
+ dice = (int)(m / dicefactor) + 2;
+ } else { // old way
+
+ Vector3f ctr = new Vector3f(lerp(x0, x1, 0.5f), lerp(y0, y1, 0.5f), 0);
+ float len = (float) (hypot(x1-x0, y1-y0) / 2);
+ float nonl = coords1.nonlinearity(ctr, len);
+
+ dice = (int)(len * nonl * dicefactor) + 2;
+ }
+ if (dbg_paperquad) p("Dice: "+dice);
+
+ // Cap it at a ridiculous value
+ if( dice > 100) dice = 100;
+ if(dice < 2 ) dice = 2;
+
+
+
+ vertices = new float[dice * dice * 5];
+ indices = new int[(dice) * (2*dice)];
+
+// #define VERTICES3(x, y, z) vertices[((x)*dice + (y))*5 + (z)]
+// #define VERTICES2(x, y) vertices[((x)*dice + (y))*5]
+// #define INDICES2(x, y) indices[(x)*2*dice + (y)]
+// #define INDICES1(x) indices[(x)*2*dice]
+
+ int indps[] = new int[dice-1];
+ int counts[] = new int[dice-1];
+ for(int ix = 0; ix<dice; ix++) {
+ if(ix < dice-1) {
+ counts[ix] = 2*dice;
+ indps[ix] = indexOfINDICES1(ix);
+ }
+ for(int iy = 0; iy<dice; iy++) {
+ if(ix < dice-1) {
+ setINDICES2(ix, 2*iy, dice * ix + iy);
+ setINDICES2(ix, 2*iy+1, dice * (ix+1) + iy);
+ }
+ float x = ix / (dice - 1.0f);
+ float y = iy / (dice - 1.0f);
+ Vector3f p = new Vector3f(lerp(x0, x1, x), lerp(y0, y1, y), 0);
+ Vector3f v = coords1.transform(new Vector3f(p));
+ setVERTICES3(ix, iy, 2, v.x);
+ setVERTICES3(ix, iy, 3, v.y);
+ setVERTICES3(ix, iy, 4, v.z);
+ Vector3f t;
+ if((flags & Ren.PAPERQUAD_CS2_TO_SCREEN) != 0) {
+ t = coords2inv.transform(v);
+ } else {
+ t = coords2inv.transform(p);
+ }
+ setVERTICES3(ix, iy, 0, t.x);
+ setVERTICES3(ix, iy, 1, t.y);
+ if(dbg_paperquad) p("PaperQuad:: vert: " +
+ ix + " " +
+ iy +" : " +
+ VERTICES3(ix, iy, 0) + " " +
+ VERTICES3(ix, iy, 1) + " " +
+ VERTICES3(ix, iy, 2) + " " +
+ VERTICES3(ix, iy, 3) + " " +
+ VERTICES3(ix, iy, 4) + " " +
+ "\n");
+ }
+ }
+
+ if((flags & Ren.PAPERQUAD_USE_VERTEX_PROGRAM) != 0) {
+ GL11.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
+ FloatBuffer v = BufferUtils.createFloatBuffer(vertices.length);
+ v.put(vertices);
+ v.flip();
+ GL11.glInterleavedArrays(GL11.GL_T2F_V3F, 5*4 /* *4 size of byte*/, v);
+ EXTCompiledVertexArray.glLockArraysEXT(0, dice*dice);
+
+ for(int it = 0; it < paper.getPassCount(); ++it) {
+
+ Pass pass = paper.getPass(it);
+
+ if(dbg_paperquad) p("Pass");
+ CallGL.checkGlError("start pass.");
+ pass.setUp_VP(lightParam);
+
+ if(dbg_paperquad) p("Going to multidraw");
+ CallGL.checkGlError("start quad strip.");
+
+
+// glMultiDrawElementsEXT(GL_QUAD_STRIP, counts,
+// GL11.GL_UNSIGNED_INT, (const GLvoid **)indps, dice-1);
+ // http://oss.sgi.com/projects/ogl-sample/registry/EXT/multi_draw_arrays.txt
+ IntBuffer ints = BufferUtils.createIntBuffer(2*dice);
+
+ for (int ix=0; ix<dice-1; ix++) {
+ ints.position(0);
+
+ for(int iy = 0; iy<dice; iy++) {
+ ints.put(dice * ix + iy);
+ ints.put(dice * (ix+1) + iy);
+ }
+ ints.flip();
+ GL11.glDrawElements(GL11.GL_QUAD_STRIP, ints);
+ }
+// throw new Error("argh lwjgl is missing impl.");
+
+ if(dbg_paperquad) p("Teardown");
+ CallGL.checkGlError("tear down.");
+ pass.tearDown_VP();
+
+ CallGL.checkGlError("end pass.");
+ if(dbg_paperquad) p("Pass over");
+ }
+ EXTCompiledVertexArray.glUnlockArraysEXT();
+ GL11.glPopClientAttrib();
+ } else {
+ for(int it = 0; it < paper.getPassCount(); ++it) {
+
+ Pass pass = paper.getPass(it);
+
+ if(dbg_paperquad) p("Pass");
+ CallGL.checkGlError("start pass.");
+ pass.setUp_explicit(lightParam);
+
+ if(dbg_paperquad) p("Going to set texcoords explicit");
+ CallGL.checkGlError("set texcoords explicit.");
+
+ for(int ix = 0; ix<dice-1; ix++) {
+ GL11.glBegin(GL11.GL_QUAD_STRIP);
+ for(int iy = 0; iy<dice; iy++) {
+
+ float tmp[] = new float[]{ VERTICES3(ix, iy, 0), VERTICES3(ix, iy, 1), 0 ,1f };
+ if(dbg_paperquad) p("to texcoords");
+ pass.texcoords_explicit( tmp );
+ if(dbg_paperquad) p("to vertex");
+ int ind = indexOfVERTICES2(ix, iy)+2;
+ GL11.glVertex3f(vertices[ind], vertices[ind+1], vertices[ind+2] );
+
+ float tmp2[] = new float[]{ VERTICES3(ix+1, iy, 0), VERTICES3(ix+1, iy, 1), 0 ,1f };
+ if(dbg_paperquad) p("to texcoords");
+ pass.texcoords_explicit( tmp2 );
+ if(dbg_paperquad) p("to vertex");
+ ind = indexOfVERTICES2(ix, iy)+2;
+ GL11.glVertex3f(vertices[ind], vertices[ind+1], vertices[ind+2] );
+ }
+ if(dbg_paperquad) p("to end");
+ GL11.glEnd();
+ }
+
+
+ if(dbg_paperquad) p("Teardown");
+ CallGL.checkGlError("tear down.");
+ pass.tearDown_explicit();
+
+ CallGL.checkGlError("end pass.");
+ if(dbg_paperquad) p("Pass over");
+ }
+ }
+
+ if(dbg_paperquad) p("Passes over");
+ CallGL.checkGlError("at the end of PaperQuad render.");
+ }
+
+// #define VERTICES3(x, y, z) vertices[((x)*dice + (y))*5 + (z)]
+// #define VERTICES2(x, y) vertices[((x)*dice + (y))*5]
+// #define INDICES2(x, y) indices[(x)*2*dice + (y)]
+// #define INDICES1(x) indices[(x)*2*dice]
+
+ private float VERTICES3(int x, int y, int z) {
+ return vertices[((x)*dice + (y))*5 + (z)];
+ }
+ private void setVERTICES3(int x, int y, int z, float value) {
+ vertices[((x)*dice + (y))*5 + z] = value;
+ }
+ private void setINDICES2(int x, int y, int val) {
+ vertices[((x)*dice + (y))*5] = val;
+ }
+ private int indexOfVERTICES2(int x, int y) {
+ return (x)*2*dice + (y);
+ }
+ private int indexOfINDICES1(int x) {
+ return x*2*dice;
+ }
+ private double hypot(float a, float b) {
+ return Math.sqrt(a*b+b*a);
+ }
+
+ // a ..... b
+ // 0 b ..... a
+ private float lerp(float a, float b, float d) {
+ return a+(b-a)*d;
+ }
+
+ }
\ No newline at end of file
More information about the Fencommits
mailing list