/* Copyright (c) 2012 Jesper Öqvist <jesper@llbit.se> * * 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 <http://www.gnu.org/licenses/>. */ package se.llbit.chunky.model; import se.llbit.chunky.resources.Texture; import se.llbit.chunky.world.Block; import se.llbit.math.AABB; import se.llbit.math.QuickMath; import se.llbit.math.Ray; /** * A textured block. * * @author Jesper Öqvist <jesper@llbit.se> */ public class TexturedBlockModel { private static final AABB block = new AABB(0, 1, 0, 1, 0, 1); /** * Find intersection between a ray and a block. * The ray origin is updated to the intersection point. * * @param texture array of textures for each side of the block. * Texture 0 is north, 1 is south, 2 is west, * 3 is east, 4 is top, 5 is bottom. * @return <code>true</code> if the ray intersects the block */ public static boolean intersect(Ray ray, Texture[] texture) { ray.t = Double.POSITIVE_INFINITY; if (block.intersect(ray)) { float[] color; if (ray.n.z < 0) { color = texture[0].getColor(ray.u, ray.v); } else if (ray.n.z > 0) { color = texture[1].getColor(ray.u, ray.v); } else if (ray.n.x > 0) { color = texture[2].getColor(ray.u, ray.v); } else if (ray.n.x < 0) { color = texture[3].getColor(ray.u, ray.v); } else if (ray.n.y > 0) { color = texture[4].getColor(ray.u, ray.v); } else { color = texture[5].getColor(ray.u, ray.v); } if (color[3] > Ray.EPSILON) { ray.color.set(color); ray.distance += ray.tNext; ray.o.scaleAdd(ray.tNext, ray.d); return true; } } return false; } /** * Find intersection between ray and block. * * @param ray ray to test * @param texture Texture array * @param index An index array used to index the texture array * @return <code>true</code> if the ray intersected the block */ public static boolean intersect(Ray ray, Texture[] texture, int[] index) { ray.t = Double.POSITIVE_INFINITY; if (block.intersect(ray)) { float[] color; if (ray.n.z < 0) { color = texture[index[0]].getColor(ray.u, ray.v); } else if (ray.n.z > 0) { color = texture[index[1]].getColor(ray.u, ray.v); } else if (ray.n.x > 0) { color = texture[index[2]].getColor(ray.u, ray.v); } else if (ray.n.x < 0) { color = texture[index[3]].getColor(ray.u, ray.v); } else if (ray.n.y > 0) { color = texture[index[4]].getColor(ray.u, ray.v); } else { color = texture[index[5]].getColor(ray.u, ray.v); } if (color[3] > Ray.EPSILON) { ray.color.set(color); ray.distance += ray.tNext; ray.o.scaleAdd(ray.tNext, ray.d); return true; } } return false; } /** * Find intersection between ray and block. * * @param ray ray to test * @param texture Block texture * @return <code>true</code> if the ray intersected the block */ public static boolean intersect(Ray ray, Texture texture) { ray.t = Double.POSITIVE_INFINITY; if (block.intersect(ray)) { float[] color = texture.getColor(ray.u, ray.v); if (color[3] > Ray.EPSILON) { ray.color.set(color); ray.distance += ray.tNext; ray.o.scaleAdd(ray.tNext, ray.d); return true; } } return false; } /** * Find the color of the object at the intersection point. * * @param ray ray to test */ public static void getIntersectionColor(Ray ray) { if (ray.getCurrentMaterial() == Block.AIR) { ray.color.x = 1; ray.color.y = 1; ray.color.z = 1; ray.color.w = 0; return; } getTextureCoordinates(ray); ray.getCurrentMaterial().getTexture(ray.getBlockData()).getColor(ray); } /** * Calculate the UV coordinates for the ray on the intersected block. * * @param ray ray to test */ private static void getTextureCoordinates(Ray ray) { int bx = (int) QuickMath.floor(ray.o.x); int by = (int) QuickMath.floor(ray.o.y); int bz = (int) QuickMath.floor(ray.o.z); if (ray.n.y != 0) { ray.u = ray.o.x - bx; ray.v = ray.o.z - bz; } else if (ray.n.x != 0) { ray.u = ray.o.z - bz; ray.v = ray.o.y - by; } else { ray.u = ray.o.x - bx; ray.v = ray.o.y - by; } if (ray.n.x > 0 || ray.n.z < 0) { ray.u = 1 - ray.u; } } }