All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.saintandreas.gl.shaders.Program Maven / Gradle / Ivy

The newest version!
package org.saintandreas.gl.shaders;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;

import org.saintandreas.gl.BufferUtils;
import org.saintandreas.gl.OpenGL;
import org.saintandreas.math.Matrix4f;
import org.saintandreas.math.Vector3f;
import org.saintandreas.math.Vector4f;
import org.saintandreas.resources.Resource;
import org.saintandreas.resources.ResourceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Program {

  private static final Logger LOG = LoggerFactory.getLogger(Program.class);

  enum ShaderType {
    VERTEX, GEOMETRY, FRAGMENT
  };

  private final int VERTEX_SHADER = 0;
  private final int GEOMETRY_SHADER = 1;
  private final int FRAGMENT_SHADER = 2;

  public final Map uniforms = new HashMap();
  public final Map attributes = new HashMap();
  private static Program CURRENT_PROGRAM = null;

  private Shader[] shaders = new Shader[3];
  public int program = -1;

  public Program(Resource vs, Resource fs) {
    this(ResourceManager.getProvider().getAsString(vs),
        ResourceManager.getProvider().getAsString(fs));
  }

  public Program(String vssf, String fssf) {
    this(new Shader(GL_VERTEX_SHADER, vssf), null, new Shader(
        GL_FRAGMENT_SHADER, fssf));
  }

  public Program(Shader vs, Shader fs) {
    this(vs, null, fs);
  }

  public Program(Shader vs, Shader gs, Shader fs) {
    shaders[VERTEX_SHADER] = vs;
    shaders[GEOMETRY_SHADER] = gs;
    shaders[FRAGMENT_SHADER] = fs;
  }

  public void destroy() {
    if (program != -1) {
      glDeleteProgram(program);
      program = -1;
    }
  }

  public void link() {
    for (Shader s : shaders) {
      if (null != s && s.shader == -1) {
        s.compile();
      }
    }
    int newProgram = linkProgram(shaders);
    if (program != -1) {
      glDeleteProgram(program);
      program = -1;
    }
    this.uniforms.clear();
    this.attributes.clear();
    program = newProgram;
    if (program == -1) { 
      throw new IllegalStateException("Link failure");
    }
    int count = glGetProgrami(program, GL_ACTIVE_UNIFORMS);
    for (int i = 0; i < count; ++i) {
      String name = glGetActiveUniform(program, i, 256);
      int location = glGetUniformLocation(program, name);
      this.uniforms.put(name, location);
    }

    count = glGetProgrami(program, GL_ACTIVE_ATTRIBUTES);
    for (int i = 0; i < count; ++i) {
      String name = glGetActiveAttrib(program, i, 256);
      int location = glGetAttribLocation(program, name);
      this.attributes.put(name, location);
    }
  }

  public String getLog() {
    return getLog(program);
  }

  public void use() {
    if (program == -1) {
      throw new IllegalStateException("Program is not linked");
    }
    CURRENT_PROGRAM = this;
    glUseProgram(program);
    OpenGL.checkError();
  }

  public static void clear() {
    glUseProgram(0);
    CURRENT_PROGRAM = null;
  }

  protected int getUniformLocation(String string) {
    if (!uniforms.containsKey(string)) {
      return -1;
    }
    return this.uniforms.get(string);
  }

  private void checkCurrent() {
    if (this != CURRENT_PROGRAM) {
      throw new IllegalStateException(
          "Attempting to set uniform on unbound program");
    }
  }

  public void setUniform(final String string, int value) {
    checkCurrent();
    int location = getUniformLocation(string);
    glUniform1i(location, value);
  }

  public void setUniform(final String string, float value) {
    checkCurrent();
    int location = getUniformLocation(string);
    glUniform1f(location, value);
  }

  public void setUniform(final String string, Vector4f value) {
    checkCurrent();
    int location = getUniformLocation(string);
    glUniform4f(location, value.x, value.y, value.z, value.w);
  }

  public void setUniform(final String string, Vector3f value) {
    checkCurrent();
    int location = getUniformLocation(string);
    glUniform3f(location, value.x, value.y, value.z);
  }

  public void setUniformMatrix4(final String name, FloatBuffer fb) {
    checkCurrent();
    int location = getUniformLocation(name);
    glUniformMatrix4(location, false, fb);
  }

  public void setUniformMatrix4(final String name, float[] v) {
    FloatBuffer fb = ByteBuffer.allocateDirect(v.length * 4)
        .order(ByteOrder.nativeOrder()).asFloatBuffer();
    fb.put(v);
    fb.position(0);
    setUniformMatrix4(name, fb);
  }

  public void setUniform(final String name, Matrix4f m) {
    FloatBuffer fb = BufferUtils.getFloatBuffer(16);
    m.fillFloatBuffer(fb, true);
    fb.position(0);
    setUniformMatrix4(name, fb);
  }

  public static String getLog(int program) {
    return glGetProgramInfoLog(program, 8192);
  }

  public static int linkProgram(Shader... shaders) {
    int newProgram = glCreateProgram();
    for (Shader s : shaders) {
      if (null != s) {
        s.attach(newProgram);
      }
    }
    glLinkProgram(newProgram);
    int linkResult = glGetProgrami(newProgram, GL_LINK_STATUS);
    if (GL_TRUE != linkResult) {
      String log = getLog(newProgram);
      LOG.warn("Link failed: " + log);
      glDeleteProgram(newProgram);
      throw new RuntimeException(log);
    }
    return newProgram;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy