All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.math.Quad Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2012-2015 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky 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 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky 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 Chunky.  If not, see .
 */
package se.llbit.math;

import java.util.Collection;

import se.llbit.chunky.world.Material;
import se.llbit.math.primitive.Primitive;
import se.llbit.math.primitive.TexturedTriangle;


/**
 * A quad.
 *
 * @author Jesper Öqvist 
 */
public class Quad {

  protected Vector3 o = new Vector3();
  protected Vector3 xv = new Vector3();
  protected Vector3 yv = new Vector3();
  protected Vector4 uv = new Vector4();

  /**
   * Normal vector
   */
  public Vector3 n = new Vector3();

  protected double d, xvl, yvl;

  /**
   * Create new Quad
   */
  protected Quad(Quad other, Transform t) {
    o.set(other.o);
    o.x -= .5;
    o.y -= .5;
    o.z -= .5;
    t.apply(o);
    o.x += .5;
    o.y += .5;
    o.z += .5;
    xv.set(other.xv);
    yv.set(other.yv);
    n.set(other.n);
    t.applyRotScale(xv);
    t.applyRotScale(yv);
    t.applyRotScale(n);
    xvl = other.xvl;
    yvl = other.yvl;
    d = -n.dot(o);
    uv.set(other.uv);
  }

  /**
   * Create transformed Quad
   */
  public Quad(Quad other, Matrix3 t) {
    o.set(other.o);
    o.x -= .5;
    o.y -= .5;
    o.z -= .5;
    t.transform(o);
    o.x += .5;
    o.y += .5;
    o.z += .5;
    xv.set(other.xv);
    yv.set(other.yv);
    n.set(other.n);
    t.transform(xv);
    t.transform(yv);
    t.transform(n);
    xvl = other.xvl;
    yvl = other.yvl;
    d = -n.dot(o);
    uv.set(other.uv);
  }

  /**
   * Create new quad
   *
   * @param v0 Bottom left vector
   * @param v1 Top right vector
   * @param v2 Bottom right vector
   * @param uv Minimum and maximum U/V texture coordinates
   */
  public Quad(Vector3 v0, Vector3 v1, Vector3 v2, Vector4 uv) {
    o.set(v0);
    xv.sub(v1, v0);
    xvl = 1 / xv.lengthSquared();
    yv.sub(v2, v0);
    yvl = 1 / yv.lengthSquared();
    n.cross(xv, yv);
    n.normalize();
    d = -n.dot(o);
    this.uv.set(uv);
    this.uv.y -= uv.x;
    this.uv.w -= uv.z;
  }

  /**
   * Find intersection between the given ray and this quad
   *
   * @return true if the ray intersects this quad
   */
  public boolean intersect(Ray ray) {
    double u, v;

    double ix = ray.o.x - QuickMath.floor(ray.o.x + ray.d.x * Ray.OFFSET);
    double iy = ray.o.y - QuickMath.floor(ray.o.y + ray.d.y * Ray.OFFSET);
    double iz = ray.o.z - QuickMath.floor(ray.o.z + ray.d.z * Ray.OFFSET);

    // test that the ray is heading toward the plane
    double denom = ray.d.dot(n);
    if (denom < -Ray.EPSILON) {

      // Test for intersection with the plane at origin.
      double t = -(ix * n.x + iy * n.y + iz * n.z + d) / denom;
      if (t > -Ray.EPSILON && t < ray.t) {

        // Plane intersection confirmed.
        // Translate to get hit point relative to the quad origin.
        ix = ix + ray.d.x * t - o.x;
        iy = iy + ray.d.y * t - o.y;
        iz = iz + ray.d.z * t - o.z;
        u = ix * xv.x + iy * xv.y + iz * xv.z;
        u *= xvl;
        v = ix * yv.x + iy * yv.y + iz * yv.z;
        v *= yvl;
        if (u >= 0 && u <= 1 && v >= 0 && v <= 1) {
          ray.u = uv.x + u * uv.y;
          ray.v = uv.z + v * uv.w;
          ray.tNext = t;
          return true;
        }
      }
    }
    return false;
  }

  /**
   * @return Scaled copy of this quad
   */
  public Quad getScaled(double scale) {
    Matrix3 transform = new Matrix3();
    transform.scale(scale);
    return new Quad(this, transform);
  }

  public void addTriangles(Collection primitives, Material material,
      Transform transform) {
    Vector3 c0 = new Vector3(o);
    Vector3 c1 = new Vector3();
    Vector3 c2 = new Vector3();
    Vector3 c3 = new Vector3();
    c1.add(o, xv);
    c2.add(o, yv);
    c3.add(c1, yv);
    transform.apply(c0);
    transform.apply(c1);
    transform.apply(c2);
    transform.apply(c3);
    double u0 = uv.x;
    double u1 = uv.x + uv.y;
    double v0 = uv.z;
    double v1 = uv.z + uv.w;
    primitives.add(new TexturedTriangle(c0, c2, c1, new Vector2(u0, v0), new Vector2(u0, v1),
        new Vector2(u1, v0), material));
    primitives.add(new TexturedTriangle(c1, c2, c3, new Vector2(u1, v0), new Vector2(u0, v1),
        new Vector2(u1, v1), material));
  }

  /**
   * Build a transformed copy of this quad.
   */
  public Quad transform(Transform transform) {
    return new Quad(this, transform);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy