/* * JaamSim Discrete Event Simulation * Copyright (C) 2014 Ausenco Engineering Canada Inc. * * 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 com.jaamsim.font; import java.util.HashMap; import com.jogamp.opengl.GL2GL3; import com.jaamsim.math.Color4d; import com.jaamsim.math.Mat4d; import com.jaamsim.math.Ray; import com.jaamsim.math.Vec3d; import com.jaamsim.math.Vec4d; import com.jaamsim.render.Camera; import com.jaamsim.render.OverlayRenderable; import com.jaamsim.render.RenderUtils; import com.jaamsim.render.Renderer; import com.jaamsim.render.Shader; import com.jaamsim.render.VisibilityInfo; public class BillboardString implements OverlayRenderable { private final TessFont _font; private final String _contents; private final float[] _color; private final double _height; private final Vec3d _pos; private final double _xOffset, _yOffset; private final VisibilityInfo _visInfo; private final Mat4d tempViewMat = new Mat4d(); private final Vec4d tempPos = new Vec4d(); private static HashMap<Integer, Integer> VAOMap = new HashMap<>(); public BillboardString(TessFont font, String contents, Color4d color, double height, Vec3d pos, double xOffset, double yOffset, VisibilityInfo visInfo) { _font = font; _contents = contents; _color = color.toFloats(); _height = height; _xOffset = xOffset; _yOffset = yOffset; _pos = pos; _visInfo = visInfo; } /** * Note: render() and renderForView() are mutually non-reentrant due to shared temporaries. This should be fine * because neither should ever be called by any thread other than the render thread. */ @Override public void render(int contextID, Renderer renderer, double windowWidth, double windowHeight, Camera cam, Ray pickRay) { GL2GL3 gl = renderer.getGL(); if (!VAOMap.containsKey(contextID)) { setupVAO(contextID, renderer); } int vao = VAOMap.get(contextID); gl.glBindVertexArray(vao); // Render the string Shader s = renderer.getShader(Renderer.ShaderHandle.OVERLAY_FONT); s.useShader(gl); int prog = s.getProgramHandle(); // Work out the billboard position cam.getViewMat4d(tempViewMat); // Build up the projection*view matrix tempViewMat.mult4(cam.getProjMat4d(), tempViewMat); tempPos.x = _pos.x; tempPos.y = _pos.y; tempPos.z = _pos.z; tempPos.w = 1.0; tempPos.mult4(tempViewMat, tempPos); tempPos.x /= tempPos.w; tempPos.y /= tempPos.w; // TempPos x and y are now in normalized coordinate space (after the projection) int colorVar = gl.glGetUniformLocation(prog, "color"); gl.glUniform4fv(colorVar, 1, _color, 0); int posVar = gl.glGetAttribLocation(prog, "position"); gl.glEnableVertexAttribArray(posVar); gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, _font.getGLBuffer(gl)); gl.glVertexAttribPointer(posVar, 2, GL2GL3.GL_FLOAT, false, 0, 0); gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, 0); int offsetVar = gl.glGetUniformLocation(prog, "offset"); float scaleY = (float)(2 * _height / (windowHeight * _font.getNominalHeight())); float scaleX = scaleY * (float)(windowHeight/windowWidth); int scaleVar = gl.glGetUniformLocation(prog, "scale"); gl.glUniform2f(scaleVar, scaleX, scaleY); float offsetX = (float)tempPos.x; float offsetY = (float)tempPos.y; offsetX += _xOffset*2.0/windowWidth; offsetY += _yOffset*2.0/windowHeight; gl.glDisable(GL2GL3.GL_CULL_FACE); for (int cp : RenderUtils.stringToCodePoints(_contents)) { TessChar tc = _font.getTessChar(cp); if (tc == null) { assert(false); continue; } gl.glUniform2f(offsetVar, offsetX, offsetY); gl.glDrawArrays(GL2GL3.GL_TRIANGLES, tc.getStartIndex(), tc.getNumVerts()); offsetX += tc.getAdvance()*scaleX; } gl.glEnable(GL2GL3.GL_CULL_FACE); } private void setupVAO(int contextID, Renderer renderer) { GL2GL3 gl = renderer.getGL(); int vao = renderer.generateVAO(contextID, gl); VAOMap.put(contextID, vao); } @Override public boolean renderForView(int viewID, Camera cam) { // Check the view if (!_visInfo.isVisible(viewID)) { return false; } // Render if the billboard is in front of the camera cam.getViewMat4d(tempViewMat); // tempPos is now the billboard in normalized coordinate space tempPos.multAndTrans3(tempViewMat, _pos); return tempPos.z < 0; } }