org.oscim.renderer.GLUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2016-2019 devemux86
* Copyright 2019 Gustl22
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.renderer;
import org.oscim.backend.GL;
import org.oscim.backend.GLAdapter;
import org.oscim.utils.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.oscim.backend.GLAdapter.gl;
import static org.oscim.backend.GLAdapter.gl30;
/**
* Utility functions
*/
public class GLUtils {
static final Logger log = LoggerFactory.getLogger(GLUtils.class);
/**
* Set int color argb to uniform wxyz.
*/
public static void setColor(int location, int color) {
gl.uniform4f(location,
((color >>> 16) & 0xff) / 255f,
((color >>> 8) & 0xff) / 255f,
((color >>> 0) & 0xff) / 255f,
((color >>> 24) & 0xff) / 255f);
}
public static void setColor(int location, int color, float alpha) {
if (alpha >= 1)
alpha = ((color >>> 24) & 0xff) / 255f;
else if (alpha < 0)
alpha = 0;
else
alpha *= ((color >>> 24) & 0xff) / 255f;
if (alpha == 1) {
gl.uniform4f(location,
((color >>> 16) & 0xff) / 255f,
((color >>> 8) & 0xff) / 255f,
((color >>> 0) & 0xff) / 255f,
alpha);
} else {
gl.uniform4f(location,
((color >>> 16) & 0xff) / 255f * alpha,
((color >>> 8) & 0xff) / 255f * alpha,
((color >>> 0) & 0xff) / 255f * alpha,
alpha);
}
}
public static void setColorBlend(int location, int color1, int color2, float mix) {
float a1 = (((color1 >>> 24) & 0xff) / 255f) * (1 - mix);
float a2 = (((color2 >>> 24) & 0xff) / 255f) * mix;
gl.uniform4f(location,
((((color1 >>> 16) & 0xff) / 255f) * a1
+ (((color2 >>> 16) & 0xff) / 255f) * a2),
((((color1 >>> 8) & 0xff) / 255f) * a1
+ (((color2 >>> 8) & 0xff) / 255f) * a2),
((((color1 >>> 0) & 0xff) / 255f) * a1
+ (((color2 >>> 0) & 0xff) / 255f) * a2),
(a1 + a2));
}
public static void setTextureParameter(int min_filter, int mag_filter, int wrap_s, int wrap_t) {
gl.texParameterf(GL.TEXTURE_2D,
GL.TEXTURE_MIN_FILTER,
min_filter);
gl.texParameterf(GL.TEXTURE_2D,
GL.TEXTURE_MAG_FILTER,
mag_filter);
gl.texParameterf(GL.TEXTURE_2D,
GL.TEXTURE_WRAP_S,
wrap_s); // Set U Wrapping
gl.texParameterf(GL.TEXTURE_2D,
GL.TEXTURE_WRAP_T,
wrap_t); // Set V Wrapping
}
public static int loadTexture(byte[] pixel, int width, int height, int format,
int min_filter, int mag_filter, int wrap_s, int wrap_t) {
int[] textureIds = GLUtils.glGenTextures(1);
GLState.bindTex2D(textureIds[0]);
setTextureParameter(min_filter, mag_filter, wrap_s, wrap_t);
ByteBuffer buf = ByteBuffer.allocateDirect(width * height).order(ByteOrder.nativeOrder());
buf.put(pixel);
buf.position(0);
IntBuffer intBuf = buf.asIntBuffer();
gl.texImage2D(GL.TEXTURE_2D, 0, format, width, height, 0, format,
GL.UNSIGNED_BYTE, intBuf);
GLState.bindTex2D(0);
return textureIds[0];
}
/**
* Check the status of current framebuffer.
* See: https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glCheckFramebufferStatus.xml
*
* @param op the operation which should be debugged
* @return the status code
*/
public static int checkFramebufferStatus(String op) {
int status = gl.checkFramebufferStatus(GL.FRAMEBUFFER);
if (status != GL.FRAMEBUFFER_COMPLETE)
log.error(op + ": \tglFramebuffer " + getFramebufferStatusString(status) + " (" + status + ")");
return status;
}
/**
* @param status the status code of a framebuffer
* @return the status code as string
*/
public static String getFramebufferStatusString(int status) {
switch (status) {
case GL.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
case GL.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
case GL.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
case GL.FRAMEBUFFER_UNSUPPORTED:
return "GL_FRAMEBUFFER_UNSUPPORTED";
case GL.FRAMEBUFFER_COMPLETE:
return "GL_FRAMEBUFFER_COMPLETE";
default:
return String.valueOf(status);
}
}
/**
* Check GL error.
* See: https://www.khronos.org/opengl/wiki/OpenGL_Error
*
* @param op the operation which should be debugged
*/
public static void checkGlError(String op) {
int error; // GL.NO_ERROR
while ((error = gl.getError()) != GL.NO_ERROR) {
log.error(op + ": \tglError " + getGlErrorString(error) + " (" + error + ")");
// throw new RuntimeException(op + ": glError " + error);
}
}
/**
* Check GL error.
* See: https://www.khronos.org/opengl/wiki/OpenGL_Error
*
* @param op the operation which should be debugged
* @param id the error to be found
* @return true if error was found
*/
public static boolean checkGlError(String op, int id) {
boolean hasError = false;
int error; // GL.NO_ERROR
while ((error = gl.getError()) != GL.NO_ERROR) {
log.error(op + ": \tglError " + getGlErrorString(error) + " (" + error + ")");
// throw new RuntimeException(op + ": glError " + error);
if (error == id)
hasError = true;
}
return hasError;
}
/**
* Check GL errors.
* See: https://www.khronos.org/opengl/wiki/OpenGL_Error
*
* @param op the operation which should be debugged
* @return the OpenGL error codes
*/
public static List checkGlErrors(String op) {
List errors = new ArrayList<>();
int error; // GL.NO_ERROR
while ((error = gl.getError()) != GL.NO_ERROR) {
log.error(op + ": \tglError " + getGlErrorString(error) + " (" + error + ")");
// throw new RuntimeException(op + ": glError " + error);
errors.add(error);
}
return errors;
}
/**
* @param error the error code of OpenGL
* @return the error code as string
*/
public static String getGlErrorString(int error) {
switch (error) {
case GL.INVALID_ENUM:
return "GL_INVALID_ENUM";
case GL.INVALID_VALUE:
return "GL_INVALID_VALUE";
case GL.INVALID_OPERATION:
return "GL_INVALID_OPERATION";
case 0x0503: // GL.STACK_OVERFLOW
return "GL_STACK_OVERFLOW";
case 0x0504: // GL.STACK_UNDERFLOW
return "GL_STACK_UNDERFLOW";
case GL.OUT_OF_MEMORY:
return "GL_OUT_OF_MEMORY";
case GL.INVALID_FRAMEBUFFER_OPERATION:
return "GL_INVALID_FRAMEBUFFER_OPERATION";
case 0x0507: // GL.CONTEXT_LOST (with OpenGL 4.5)
return "GL_CONTEXT_LOST";
case 0x8031: // GL.TABLE_TOO_LARGE (deprecated in OpenGL 3.0)
return "GL_TABLE_TOO_LARGE";
case GL.NO_ERROR:
return "GL_NO_ERROR";
default:
return String.valueOf(error);
}
}
public static void setColor(int handle, float[] c, float alpha) {
if (alpha >= 1) {
gl.uniform4f(handle, c[0], c[1], c[2], c[3]);
} else {
if (alpha < 0) {
log.debug("setColor: " + alpha);
alpha = 0;
gl.uniform4f(handle, 0, 0, 0, 0);
}
gl.uniform4f(handle,
c[0] * alpha, c[1] * alpha,
c[2] * alpha, c[3] * alpha);
}
}
public static float[] colorToFloat(int color) {
float[] c = new float[4];
c[3] = (color >> 24 & 0xff) / 255.0f;
c[0] = (color >> 16 & 0xff) / 255.0f;
c[1] = (color >> 8 & 0xff) / 255.0f;
c[2] = (color >> 0 & 0xff) / 255.0f;
return c;
}
// premultiply alpha
public static float[] colorToFloatP(int color) {
float[] c = new float[4];
c[3] = (color >> 24 & 0xff) / 255.0f;
c[0] = (color >> 16 & 0xff) / 255.0f * c[3];
c[1] = (color >> 8 & 0xff) / 255.0f * c[3];
c[2] = (color >> 0 & 0xff) / 255.0f * c[3];
return c;
}
/**
* public-domain function by Darel Rex Finley from
* http://alienryderflex.com/saturation.html
*
* @param color The passed-in RGB values can be on any desired scale, such as
* 0 to 1, or 0 to 255.
* @param change 0.0 creates a black-and-white image. 0.5 reduces the color
* saturation by half. 1.0 causes no change. 2.0 doubles the
* color saturation.
*/
public static void changeSaturation(float color[], float change) {
float r = color[0];
float g = color[1];
float b = color[2];
double p = Math.sqrt(r * r * 0.299f + g * g * 0.587f + b * b * 0.114f);
color[0] = FastMath.clampN((float) (p + (r - p) * change));
color[1] = FastMath.clampN((float) (p + (g - p) * change));
color[2] = FastMath.clampN((float) (p + (b - p) * change));
}
public static void glUniform3fv(int location, int count, float[] val) {
FloatBuffer buf = MapRenderer.getFloatBuffer(count * 3);
buf.put(val);
buf.flip();
gl.uniform3fv(location, count, buf);
}
public static void glUniform4fv(int location, int count, float[] val) {
FloatBuffer buf = MapRenderer.getFloatBuffer(count * 4);
buf.put(val);
buf.flip();
gl.uniform4fv(location, count, buf);
}
public static int[] glGenBuffers(int num) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.position(0);
buf.limit(num);
gl.genBuffers(num, buf);
int[] ret = new int[num];
buf.position(0);
buf.limit(num);
buf.get(ret);
return ret;
}
public static void glDeleteBuffers(int num, int[] ids) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
buf.flip();
gl.deleteBuffers(num, buf);
}
public static int[] glGenFrameBuffers(int num) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.position(0);
buf.limit(num);
gl.genFramebuffers(num, buf);
int[] ret = new int[num];
buf.position(0);
buf.limit(num);
buf.get(ret);
return ret;
}
public static void glDeleteFrameBuffers(int num, int[] ids) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
buf.flip();
gl.deleteFramebuffers(num, buf);
}
public static int[] glGenRenderBuffers(int num) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.position(0);
buf.limit(num);
gl.genRenderbuffers(num, buf);
int[] ret = new int[num];
buf.position(0);
buf.limit(num);
buf.get(ret);
return ret;
}
public static void glDeleteRenderBuffers(int num, int[] ids) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
buf.flip();
gl.deleteRenderbuffers(num, buf);
}
public static int[] glGenTextures(int num) {
if (num <= 0)
return null;
int[] ret = new int[num];
// Workaround for texture memory leaks on desktop
IntBuffer buf;
if (GLAdapter.GDX_DESKTOP_QUIRKS)
buf = ByteBuffer.allocateDirect(num * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
else
buf = MapRenderer.getIntBuffer(num);
if (GLAdapter.GDX_WEBGL_QUIRKS) {
for (int i = 0; i < num; i++) {
gl.genTextures(num, buf);
buf.position(0);
ret[i] = buf.get();
buf.position(0);
}
} else {
gl.genTextures(num, buf);
buf.position(0);
buf.get(ret);
}
return ret;
}
public static void glDeleteTextures(int num, int[] ids) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
buf.flip();
gl.deleteTextures(num, buf);
}
/*========== GL30 ==========*/
/**
* Specifies a list of color buffers to be drawn into.
*
* @param num Specifies the number of buffers in bufs.
* @param glEnum Points to an array of symbolic constants specifying the buffers into which fragment colors or data values will be written.
*/
public static void glDrawBuffers(int num, int[] glEnum) {
IntBuffer buf = MapRenderer.getIntBuffer(num);
buf.put(glEnum, 0, num);
buf.flip();
gl30.drawBuffers(num, buf);
}
}