/* * Copyright 2016 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.rendering.dag.stateChanges; import org.terasology.assets.ResourceUrn; import org.terasology.rendering.assets.material.Material; import org.terasology.rendering.dag.RenderPipelineTask; import org.terasology.rendering.dag.StateChange; import java.util.Objects; import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL13.GL_TEXTURE0; import static org.lwjgl.opengl.GL13.glActiveTexture; import static org.terasology.rendering.dag.AbstractNode.getMaterial; /** * This StateChange generates the tasks that set and reset input textures. * * Input textures are assigned to a texture unit and this is then communicated to the shader. * This StateChange and the underlying task only handles textures of type GL_TEXTURE_2D. */ public class SetInputTexture implements StateChange { private final int textureSlot; private final int textureId; private final ResourceUrn materialURN; private final String materialParameter; private SetInputTexture defaultInstance; private SetInputTextureTask task; /** * Constructs an instance of SetInputTexture initialized with the given objects. * * See SetInputTextureTask for more information on how the constructor's parameters are used. * * @param textureSlot a 0-based integer. Notice that textureUnit = GL_TEXTURE0 + textureSlot. See OpenGL spects for maximum allowed values. * @param textureId an integer representing the opengl name of a texture. This is usually the return value of glGenTexture(). * @param materialURN a ResourceURN object uniquely identifying a Material asset. * @param materialParameter a String representing the variable within the shader holding the texture. */ public SetInputTexture(int textureSlot, int textureId, ResourceUrn materialURN, String materialParameter) { this.textureSlot = textureSlot; this.textureId = textureId; this.materialURN = materialURN; this.materialParameter = materialParameter; } private SetInputTexture(int textureSlot, ResourceUrn materialURN, String materialParameter) { this.textureSlot = textureSlot; this.textureId = 0; this.materialURN = materialURN; this.materialParameter = materialParameter; defaultInstance = this; } /** * Generates a SetInputTextureTask with the information provided on construction and returns it. * * @return a SetInputTextureTask instance. */ @Override public RenderPipelineTask generateTask() { if (task == null) { task = new SetInputTextureTask(textureSlot, textureId, materialURN, materialParameter); } return task; } @Override public int hashCode() { return Objects.hash(textureSlot, textureId, materialURN, materialParameter); } @Override public boolean equals(Object other) { return (other instanceof SetInputTexture) && this.textureSlot == ((SetInputTexture) other).textureSlot && this.textureId == ((SetInputTexture) other).textureId && this.materialURN.equals(((SetInputTexture) other).materialURN) && this.materialParameter.equals(((SetInputTexture) other).materialParameter); } /** * Returns a StateChange instance useful to disconnect the given texture from its assigned texture slot. * Also disconnects the texture from the shader program. * * @return the default instance for the particular slot/material/parameter combination held by this * SetInputTexture object, cast as a StateChange instance. */ @Override public StateChange getDefaultInstance() { if (defaultInstance == null) { defaultInstance = new SetInputTexture(textureSlot, materialURN, materialParameter); } return defaultInstance; } @Override public boolean isTheDefaultInstance() { return this.equals(defaultInstance); } /** * Instances of this class bind a texture to a texture unit. The integer identifying * the texture unit is then passed to a shader program using the material/parameter * pair provided on construction. See the source of the execute() method for the * nitty gritty details. * * WARNING: RenderPipelineTasks are not meant for direct instantiation and manipulation. * Modules or other parts of the engine should take advantage of them through classes * inheriting from StateChange. */ private class SetInputTextureTask implements RenderPipelineTask { private final int textureSlot; private final int textureId; private final Material material; private final String materialParameter; private SetInputTextureTask(int textureSlot, int textureId, ResourceUrn materialURN, String materialParameter) { this.textureSlot = textureSlot; this.textureId = textureId; this.material = getMaterial(materialURN); this.materialParameter = materialParameter; } @Override public void execute() { glActiveTexture(GL_TEXTURE0 + textureSlot); glBindTexture(GL_TEXTURE_2D, textureId); material.setInt(materialParameter, textureSlot, true); } @Override public String toString() { return String.format("%30s: slot %s, texture %s, material %s, parameter %s", this.getClass().getSimpleName(), textureSlot, textureId, material.getUrn().toString(), materialParameter); } } }