/* * 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.logic; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Maps; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.terasology.assets.management.AssetManager; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.lifecycleEvents.BeforeDeactivateComponent; import org.terasology.entitySystem.entity.lifecycleEvents.OnActivatedComponent; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.RenderSystem; import org.terasology.math.MatrixUtils; import org.terasology.math.Region3i; import org.terasology.math.geom.Matrix4f; import org.terasology.math.geom.Quat4f; import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.rendering.assets.material.Material; import org.terasology.rendering.world.WorldRenderer; import java.nio.FloatBuffer; import java.util.LinkedHashMap; import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; import static org.lwjgl.opengl.GL11.glBegin; import static org.lwjgl.opengl.GL11.glDisable; import static org.lwjgl.opengl.GL11.glEnable; import static org.lwjgl.opengl.GL11.glEnd; import static org.lwjgl.opengl.GL11.glLineWidth; import static org.lwjgl.opengl.GL11.glVertex3f; /** * Renderes region outlines for all entities with {@link RegionOutlineComponent}s. */ @RegisterSystem(RegisterMode.CLIENT) public class RegionOutlineRenderer extends BaseComponentSystem implements RenderSystem { @In private AssetManager assetManager; @In private WorldRenderer worldRenderer; @In private EntityManager entityManager; private Material material; private LinkedHashMap<EntityRef, RegionOutlineComponent> entityToRegionOutlineMap = Maps.newLinkedHashMap(); @Override public void initialise() { Preconditions.checkArgument(!Strings.isNullOrEmpty("engine:white")); this.material = assetManager.getAsset("engine:white", Material.class).get(); } @ReceiveEvent public void onRegionOutlineComponentActivation(OnActivatedComponent event, EntityRef entity, RegionOutlineComponent component) { entityToRegionOutlineMap.put(entity, component); } @ReceiveEvent public void onRegionOutlineComponentDeactivation(BeforeDeactivateComponent event, EntityRef entity, RegionOutlineComponent component) { entityToRegionOutlineMap.remove(entity); } @Override public void renderOverlay() { if (entityToRegionOutlineMap.isEmpty()) { return; // skip everything if there is nothing to do to avoid possibly costly draw mode changes } glDisable(GL_DEPTH_TEST); glLineWidth(2); Vector3f cameraPosition = worldRenderer.getActiveCamera().getPosition(); FloatBuffer tempMatrixBuffer44 = BufferUtils.createFloatBuffer(16); FloatBuffer tempMatrixBuffer33 = BufferUtils.createFloatBuffer(12); material.setFloat("sunlight", 1.0f, true); material.setFloat("blockLight", 1.0f, true); material.setMatrix4("projectionMatrix", worldRenderer.getActiveCamera().getProjectionMatrix()); Vector3f worldPos = new Vector3f(); Vector3f worldPositionCameraSpace = new Vector3f(); worldPositionCameraSpace.sub(worldPos, cameraPosition); Matrix4f matrixCameraSpace = new Matrix4f(new Quat4f(0, 0, 0, 1), worldPositionCameraSpace, 1.0f); Matrix4f modelViewMatrix = MatrixUtils.calcModelViewMatrix(worldRenderer.getActiveCamera().getViewMatrix(), matrixCameraSpace); MatrixUtils.matrixToFloatBuffer(modelViewMatrix, tempMatrixBuffer44); material.setMatrix4("worldViewMatrix", tempMatrixBuffer44, true); MatrixUtils.matrixToFloatBuffer(MatrixUtils.calcNormalMatrix(modelViewMatrix), tempMatrixBuffer33); material.setMatrix3("normalMatrix", tempMatrixBuffer33, true); for (RegionOutlineComponent regionOutline: entityToRegionOutlineMap.values()) { material.setFloat3("colorOffset", regionOutline.color.rf(), regionOutline.color.gf(), regionOutline.color.bf(), true); drawRegionOutline(regionOutline); } glEnable(GL_DEPTH_TEST); } private void drawRegionOutline(RegionOutlineComponent regionComponent) { if (regionComponent.corner1 == null || regionComponent.corner2 == null) { return; } Region3i region = Region3i.createBounded(regionComponent.corner1, regionComponent.corner2); Vector3f min = new Vector3f(region.minX() - 0.5f, region.minY() - 0.5f, region.minZ() - 0.5f); Vector3f max = new Vector3f(region.maxX() + 0.5f, region.maxY() + 0.5f, region.maxZ() + 0.5f); // 4 lines along x axis: glBegin(GL11.GL_LINES); glVertex3f(min.x(), min.y(), min.z()); glVertex3f(max.x(), min.y(), min.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(min.x(), max.y(), min.z()); glVertex3f(max.x(), max.y(), min.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(min.x(), min.y(), max.z()); glVertex3f(max.x(), min.y(), max.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(min.x(), max.y(), max.z()); glVertex3f(max.x(), max.y(), max.z()); glEnd(); // 4 lines along y axis glBegin(GL11.GL_LINES); glVertex3f(min.x(), min.y(), min.z()); glVertex3f(min.x(), max.y(), min.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(max.x(), min.y(), min.z()); glVertex3f(max.x(), max.y(), min.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(min.x(), min.y(), max.z()); glVertex3f(min.x(), max.y(), max.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(max.x(), min.y(), max.z()); glVertex3f(max.x(), max.y(), max.z()); glEnd(); // 4 lines along z axis: glBegin(GL11.GL_LINES); glVertex3f(min.x(), min.y(), min.z()); glVertex3f(min.x(), min.y(), max.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(max.x(), min.y(), min.z()); glVertex3f(max.x(), min.y(), max.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(min.x(), max.y(), min.z()); glVertex3f(min.x(), max.y(), max.z()); glEnd(); glBegin(GL11.GL_LINES); glVertex3f(max.x(), max.y(), min.z()); glVertex3f(max.x(), max.y(), max.z()); glEnd(); } @Override public void renderOpaque() { } @Override public void renderAlphaBlend() { } @Override public void renderFirstPerson() { } @Override public void renderShadows() { } }