Java tutorial
/******************************************************************************* * Copyright (c) 2013 Philip Collin. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * Philip Collin - initial API and implementation ******************************************************************************/ package com.lyeeedar.Roguelike3D.Graphics.Lights; import java.io.Serializable; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector3; import com.lyeeedar.Utils.Bag; public class LightManager implements Serializable { /** * */ private static final long serialVersionUID = 1441486882161209270L; public static final int maxLights = 10; public enum LightQuality { FORWARD_VERTEX, DEFERRED }; public static LightQuality getLightQuality(String quality) { for (LightQuality lq : LightQuality.values()) { if (quality.equalsIgnoreCase("" + lq)) return lq; } return null; } public LightQuality quality; public final Bag<PointLight> dynamicPointLights = new Bag<PointLight>(maxLights); public final Bag<PointLight> staticPointLights = new Bag<PointLight>(maxLights); private transient float[] positions; private transient float[] colors; private transient float[] attenuations; private transient float[] powers; private transient int i; public int maxLightsPerModel; public final Color ambientLight = new Color(); public final Vector3 ambientDir = new Vector3(); public LightManager(int maxLightsPerModel, LightQuality lightQuality) { quality = lightQuality; this.maxLightsPerModel = maxLightsPerModel; fixReferences(); } public void setAmbient(float r, float g, float b, float x, float y, float z) { ambientLight.set(r, g, b, 1.0f); ambientDir.set(x, y, z); } public void setAmbient(Color colour, Vector3 dir) { ambientLight.set(colour); ambientDir.set(dir); } public void fixReferences() { if (maxLightsPerModel == 0) return; colors = new float[3 * maxLightsPerModel]; positions = new float[3 * maxLightsPerModel]; attenuations = new float[maxLightsPerModel]; powers = new float[maxLightsPerModel]; for (PointLight p : staticPointLights) p.fixReferences(); for (PointLight p : dynamicPointLights) p.fixReferences(); } public PointLight getDynamicLight(String UID) { for (PointLight p : dynamicPointLights) { if (p.UID.equals(UID)) return p; } System.err.println("Light not found!"); return null; } public PointLight getStaticLight(String UID) { for (PointLight p : staticPointLights) { if (p.UID.equals(UID)) return p; } System.err.println("Light not found!"); return null; } public void addDynamicLight(PointLight light) { dynamicPointLights.add(light); } public void addStaticLight(PointLight light) { staticPointLights.add(light); } public void removeDynamicLight(String UID) { for (int i = 0; i < dynamicPointLights.size; i++) { if (dynamicPointLights.get(i).UID.equals(UID)) { dynamicPointLights.remove(i); return; } } } public void removeStaticLight(String UID) { for (int i = 0; i < staticPointLights.size; i++) { if (staticPointLights.get(i).UID.equals(UID)) { staticPointLights.remove(i); return; } } } public void clearAllLights() { dynamicPointLights.clear(); staticPointLights.clear(); } public void updateLightNum(int val) { if (val < 1) val = 1; maxLightsPerModel = val; colors = new float[3 * maxLightsPerModel]; positions = new float[3 * maxLightsPerModel]; attenuations = new float[maxLightsPerModel]; powers = new float[maxLightsPerModel]; } public void calculateDynamicLights(float x, float y, float z) { if (maxLightsPerModel == 0) return; final int maxSize = dynamicPointLights.size; if (maxSize > maxLightsPerModel) { for (i = 0; i < maxSize; i++) { final PointLight light = dynamicPointLights.get(i); light.priority = (int) (PointLight.PRIORITY_DISCRETE_STEPS * light.position.dst(x, y, z)); } dynamicPointLights.sort(); } // fill the light arrays final int size = maxLightsPerModel > maxSize ? maxSize : maxLightsPerModel; for (i = 0; i < size; i++) { final PointLight light = dynamicPointLights.get(i); final Vector3 pos = light.position; positions[3 * i + 0] = pos.x; positions[3 * i + 1] = pos.y; positions[3 * i + 2] = pos.z; final Color col = light.getColour(); colors[3 * i + 0] = col.r; colors[3 * i + 1] = col.g; colors[3 * i + 2] = col.b; attenuations[i] = light.attenuation; powers[i] = light.power; } } public void applyDynamicLights(ShaderProgram shader) { if (maxLightsPerModel == 0) return; shader.setUniform3fv("u_light_positions", positions, 0, maxLightsPerModel * 3); shader.setUniform3fv("u_light_colours", colors, 0, maxLightsPerModel * 3); shader.setUniform1fv("u_light_attenuations", attenuations, 0, maxLightsPerModel); shader.setUniform1fv("u_light_powers", powers, 0, maxLightsPerModel); } public void applyAmbient(ShaderProgram shader) { shader.setUniformf("u_colour", ambientLight.r, ambientLight.g, ambientLight.b); } public Color calculateLightAtPoint(Vector3 position, Vector3 normal, boolean bakeStatics) { Color h_ambient = ambientLight.cpy().mul(0.5f); Color light_agg_col = h_ambient.add(calculateLight(ambientDir, h_ambient.cpy(), 0, 1, normal)); if (!bakeStatics) return light_agg_col; for (PointLight pl : staticPointLights) { Vector3 l_vector = pl.position.cpy().sub(position); light_agg_col.add(calculateLight(l_vector, pl.getColour().cpy(), pl.attenuation, pl.power, normal)); } return light_agg_col; } private Color calculateLight(Vector3 l_vector, Color l_colour, float l_attenuation, float l_power, Vector3 n_dir) { float distance = l_vector.len(); Vector3 l_dir = l_vector.cpy().div(distance); float NdotL = n_dir.dot(l_dir); float intensity = MathUtils.clamp(NdotL, 0.0f, 1.0f); float attenuation = 1.0f; if (l_attenuation != 0) attenuation /= (l_attenuation * distance + l_attenuation / 10 * distance * distance); return l_colour.mul(intensity).mul(l_power).mul(attenuation); } public Color getAmbient() { return ambientLight; } }