/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2012 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.render;
import java.net.URI;
import java.nio.FloatBuffer;
import java.util.HashMap;
import com.jogamp.opengl.GL2GL3;
import com.jaamsim.math.Ray;
public class OverlayTexture implements OverlayRenderable {
// Position and size, specified in pixels, origin at the bottom left
private int _x, _y;
private int _width, _height;
private URI _imageURI;
private boolean _isTransparent;
private boolean _isCompressed;
static private boolean staticInit = false;
static private int vertBuff;
static private int texCoordBuff;
static private HashMap<Integer, Integer> VAOMap = new HashMap<>();
static private int progHandle;
static private int offsetVar;
static private int sizeVar;
static private int texVar;
static private int hasTexVar;
private boolean _alignRight, _alignBottom;
private VisibilityInfo _visInfo;
public OverlayTexture(int x, int y, int width, int height, URI imageURI, boolean transparent, boolean compressed,
boolean alignRight, boolean alignBottom, VisibilityInfo visInfo) {
_x = x; _y = y;
_width = width; _height = height;
_imageURI = imageURI;
_isTransparent = transparent; _isCompressed = compressed;
_alignRight = alignRight; _alignBottom = alignBottom;
_visInfo = visInfo;
}
private static void initStaticBuffers(Renderer r) {
GL2GL3 gl = r.getGL();
int[] buffs = new int[2];
gl.glGenBuffers(2, buffs, 0);
vertBuff = buffs[0];
texCoordBuff = buffs[1];
FloatBuffer verts = FloatBuffer.allocate(6*3); // 2 triangles * 3 coordinates
verts.put(0.0f); verts.put(0.0f); verts.put(0.0f);
verts.put(1.0f); verts.put(0.0f); verts.put(0.0f);
verts.put(1.0f); verts.put(1.0f); verts.put(0.0f);
verts.put(0.0f); verts.put(0.0f); verts.put(0.0f);
verts.put(1.0f); verts.put(1.0f); verts.put(0.0f);
verts.put(0.0f); verts.put(1.0f); verts.put(0.0f);
verts.flip();
gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, vertBuff);
gl.glBufferData(GL2GL3.GL_ARRAY_BUFFER, 6*3*4, verts, GL2GL3.GL_STATIC_DRAW);
FloatBuffer texCoords = FloatBuffer.allocate(6*2); // 2 triangles * 2 coordinates
texCoords.put(0.0f); texCoords.put(0.0f);
texCoords.put(1.0f); texCoords.put(0.0f);
texCoords.put(1.0f); texCoords.put(1.0f);
texCoords.put(0.0f); texCoords.put(0.0f);
texCoords.put(1.0f); texCoords.put(1.0f);
texCoords.put(0.0f); texCoords.put(1.0f);
texCoords.flip();
gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, texCoordBuff);
gl.glBufferData(GL2GL3.GL_ARRAY_BUFFER, 6*2*4, texCoords, GL2GL3.GL_STATIC_DRAW);
// Initialize the shader variables
progHandle = r.getShader(Renderer.ShaderHandle.OVERLAY_FLAT).getProgramHandle();
texVar = gl.glGetUniformLocation(progHandle, "tex");
hasTexVar = gl.glGetUniformLocation(progHandle, "useTex");
sizeVar = gl.glGetUniformLocation(progHandle, "size");
offsetVar = gl.glGetUniformLocation(progHandle, "offset");
staticInit = true;
}
private void setupVAO(int contextID, Renderer renderer) {
GL2GL3 gl = renderer.getGL();
int vao = renderer.generateVAO(contextID, gl);
VAOMap.put(contextID, vao);
gl.glBindVertexArray(vao);
// Position
int posVar = gl.glGetAttribLocation(progHandle, "position");
gl.glEnableVertexAttribArray(posVar);
gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, vertBuff);
gl.glVertexAttribPointer(posVar, 3, GL2GL3.GL_FLOAT, false, 0, 0);
// TexCoords
int texCoordVar = gl.glGetAttribLocation(progHandle, "texCoordVert");
gl.glEnableVertexAttribArray(texCoordVar);
gl.glBindBuffer(GL2GL3.GL_ARRAY_BUFFER, texCoordBuff);
gl.glVertexAttribPointer(texCoordVar, 2, GL2GL3.GL_FLOAT, false, 0, 0);
gl.glBindVertexArray(0);
}
@Override
public void render(int contextID, Renderer renderer,
double windowWidth, double windowHeight, Camera cam, Ray pickRay) {
if (!staticInit) {
initStaticBuffers(renderer);
}
double x = _x;
double y = _y;
if (_alignRight) {
x = windowWidth - _x - _width;
}
if (!_alignBottom) {
y = windowHeight - _y - _height;
}
GL2GL3 gl = renderer.getGL();
int textureID = renderer.getTexCache().getTexID(gl, _imageURI, _isTransparent, _isCompressed, false);
if (textureID == TexCache.LOADING_TEX_ID) {
return; // This texture is not ready yet
}
if (!VAOMap.containsKey(contextID)) {
setupVAO(contextID, renderer);
}
int vao = VAOMap.get(contextID);
gl.glBindVertexArray(vao);
gl.glUseProgram(progHandle);
gl.glUniform1i(hasTexVar, 1);
gl.glActiveTexture(GL2GL3.GL_TEXTURE0);
gl.glBindTexture(GL2GL3.GL_TEXTURE_2D, textureID);
gl.glTexParameteri(GL2GL3.GL_TEXTURE_2D, GL2GL3.GL_TEXTURE_WRAP_S, GL2GL3.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL2GL3.GL_TEXTURE_2D, GL2GL3.GL_TEXTURE_WRAP_T, GL2GL3.GL_CLAMP_TO_EDGE);
gl.glUniform1i(texVar, 0);
if (_isTransparent) {
gl.glEnable(GL2GL3.GL_BLEND);
gl.glBlendEquationSeparate(GL2GL3.GL_FUNC_ADD, GL2GL3.GL_MAX);
gl.glBlendFuncSeparate(GL2GL3.GL_SRC_ALPHA, GL2GL3.GL_ONE_MINUS_SRC_ALPHA, GL2GL3.GL_ONE, GL2GL3.GL_ONE);
}
// Set the size and scale in normalized (-1, 1) coordinates
double normX = x / (0.5 * windowWidth) - 1;
double normY = y / (0.5 * windowHeight) - 1;
double normWidth = _width / (0.5 * windowWidth);
double normHeight = _height / (0.5 * windowHeight);
gl.glUniform2f(offsetVar, (float)normX, (float)normY);
gl.glUniform2f(sizeVar, (float)normWidth, (float)normHeight);
// Draw
gl.glDisable(GL2GL3.GL_CULL_FACE);
gl.glDrawArrays(GL2GL3.GL_TRIANGLES, 0, 6);
gl.glEnable(GL2GL3.GL_CULL_FACE);
if (_isTransparent) {
gl.glDisable(GL2GL3.GL_BLEND);
}
}
@Override
public boolean renderForView(int viewID, Camera cam) {
return _visInfo.isVisible(viewID);
}
}