Commit 8aebf8a7 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '298-new-module-for-shader-creation' into 'master'

Refactored creating shaders, introduced new module Shaders

Closes #298

See merge request grp-fidentis/analyst2!323
parents 6d68768a 64379b9f
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
                        <publicPackage>cz.fidentis.analyst.engines.cut</publicPackage>
                        <publicPackage>cz.fidentis.analyst.engines.point2surface</publicPackage>
                        <publicPackage>cz.fidentis.analyst.engines.glyphs</publicPackage>
                        <publicPackage>cz.fidentis.analyst.engines.shaders</publicPackage>
                        <publicPackage>com.jogamp.*</publicPackage>
                        <publicPackage>org.ejml.simple.*</publicPackage>
                    </publicPackages>
                </configuration>
@@ -100,6 +102,23 @@
            <version>${version.org.junit.jupiter}</version>
            <scope>test</scope>
        </dependency>

        <!-- JOGL -->
        <dependency>
            <groupId>org.jogamp.jogl</groupId>
            <artifactId>jogl-all-main</artifactId>
            <version>${version.org.jogamp}</version>
        </dependency>
        <dependency>
            <groupId>org.jogamp.jogl</groupId>
            <artifactId>nativewindow-main</artifactId>
            <version>${version.org.jogamp}</version>
        </dependency>
        <dependency>
            <groupId>org.jogamp.gluegen</groupId>
            <artifactId>gluegen-rt-main</artifactId>
            <version>${version.org.jogamp}</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+26 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.shaders;

/**
 * A GLSL program, which links multiple shaders together, for example vertex shader and a fragment shader.
 *
 * @author Ondrej Simecek
 * @author Radek Oslejsek
 * @author Pavol Kycina
 */
public interface Program {

    /**
     * Returns internal ID of the program in the OpenGL context.
     * @return an internal ID of the program in the OpenGL context
     */
    int getProgramId();

    /**
     * Returns precomputed OpenGL uniform location.
     *
     * @param key Name of the precomputed uniform location (see the {@code uniformLocations} param of
     *            the program constructor).
     * @return Precomputed uniform location or -1.
     */
    int getUniformLocation(String key);
}
+100 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.rendering.shaders;
package cz.fidentis.analyst.engines.shaders;

import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLException;
import cz.fidentis.analyst.engines.shaders.impl.ProgramImpl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

import static com.jogamp.opengl.GL.GL_FALSE;
import static com.jogamp.opengl.GL2ES2.*;
import static com.jogamp.opengl.GL2ES2.GL_COMPILE_STATUS;
import static com.jogamp.opengl.GL2ES2.GL_INFO_LOG_LENGTH;

/**
 * A GLSL program, which links a vertex shader and a fragment shader together.
 * Stateless services for compiling vertex and fragment shaders and composing them into GLSL programs.
 *
 * @author Ondrej Simecek
 * @author Radek Oslejsek
 * @author Pavol Kycina
 */
public abstract class Program {

    private final int programId;

    private final int vertexShaderId;

    private final int fragmentShaderId;
public interface ProgramServices {

    /**
     *  Links existing shaders into a program.
     * Compiles GLSL code from GLSL file on specified URL.
     *
     * @param gl OpenGL context
     *  @param vertexShaderId IDs of the (already compiled) vertex shader
     *  @param fragmentShaderId IDs of the (already compiled) fragment shader
     *  @throws GLException if the program initiation fails
     * @param shaderType Shader type to create, i.e., {@code GL_VERTEX_SHADER} or {@code GL_FRAGMENT_SHADER}
     * @param url URL to the shader file, the file must be in UTF-8 encoding
     * @return shader's ID in the provided OpenGL context
     * @throws IOException when cannot be read from the file
     */
    public Program(GL2 gl, int vertexShaderId, int fragmentShaderId) {
        this.vertexShaderId = vertexShaderId;
        this.fragmentShaderId = fragmentShaderId;

        programId = gl.glCreateProgram();
        gl.glAttachShader(programId, vertexShaderId);
        gl.glAttachShader(programId, fragmentShaderId);
        gl.glLinkProgram(programId);

        // check program status
        int[] linkStatus = new int[1];
        gl.glGetProgramiv(programId, GL_LINK_STATUS, linkStatus, 0);

        if (GL_FALSE == linkStatus[0]) {
            int[] infoLogLength = new int[1];
            gl.glGetProgramiv(programId, GL_INFO_LOG_LENGTH, infoLogLength, 0);

            byte[] infoLogBytes = new byte[infoLogLength[0]];
            gl.glGetProgramInfoLog(programId, infoLogLength[0], infoLogLength, 0, infoLogBytes, 0);

            throw new GLException(new String(infoLogBytes, 0, infoLogLength[0]));
        }
    static int compileShader(GL2 gl, int shaderType, URL url) throws IOException {
        URLConnection connection = url.openConnection();
        String sourceCode = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
        return compileShaderCode(gl, shaderType, sourceCode);
    }

    /**
     * Returns internal ID of the program in the OpenGL context.
     * @return an internal ID of the program in the OpenGL context
     */
    public int getProgramId() {
        return programId;
    }

    public int getVertexShaderId() {
        return vertexShaderId;
    }

    public int getFragmentShaderId() {
        return fragmentShaderId;
    }

    /**
     * A utility method which loads and compiles GLSL code of a vertex or fragment shader
     * A utility method which compiles given GLSL code
     *
     * @param gl OpenGL context
     * @param shaderType Shader type to create, i.e., {@code GL_VERTEX_SHADER} or {@code GL_FRAGMENT_SHADER}
     * @param glslFile Relative path to the file with shader's code
     * @param shaderSourceCode Shader's source code in GLSL
     * @return shader's ID in the provided OpenGL context
     * @throws IOException If there is an error reading GLSL file with shader's code
     * @throws GLException if the shader initiation fails
     */
    public static int compileShader(GL2 gl, int shaderType, String glslFile) throws IOException, GLException {
        // read source code
        String shaderCode;
        try (InputStreamReader ios = new InputStreamReader(ShadersManager.class.getClassLoader().getResourceAsStream(glslFile))) {
            shaderCode = new BufferedReader(ios).lines().collect(Collectors.joining("\n"));
        }

    static int compileShaderCode(GL2 gl, int shaderType, String shaderSourceCode) {
        // compile shader
        int shaderId = gl.glCreateShader(shaderType);
        gl.glShaderSource(shaderId, 1, new String[]{shaderCode}, new int[]{shaderCode.length()}, 0);

        gl.glShaderSource(shaderId, 1, new String[]{shaderSourceCode}, new int[]{shaderSourceCode.length()}, 0);
        gl.glCompileShader(shaderId);

        // check shader status
@@ -111,4 +70,31 @@ public abstract class Program {

        return shaderId;
    }

    /**
     * Creates new GLSL program from compiled shaders.
     *
     * @param gl OpenGL context.
     * @param vertexShader ID of compiled vertex shader in the OpenGL context
     * @param fragmentShader ID of compiled fragment shader in the OpenGL context
     * @return Program which has all provided shaders attached to it.
     * @throws GLException if the program initiation fails
     */
    static Program createProgram(GL2 gl, int vertexShader, int fragmentShader) {
        return new ProgramImpl(gl, vertexShader, fragmentShader);
    }
    /**
     * Creates new GLSL program from compiled shader.
     *
     * @param gl OpenGL context
     * @param vertexShader ID of compiled vertex shader in the OpenGL context
     * @param fragmentShader ID of compiled fragment shader in the OpenGL context
     * @param uniformLocations Keys of uniform locations to be computed from the OpenGL context and stored.
     * @return Program which has all provided shaders attached to it.
     * @throws GLException if the program initiation fails
     */
    static Program createProgram(GL2 gl, int vertexShader, int fragmentShader, Collection<String> uniformLocations) {
        return new ProgramImpl(gl,vertexShader, fragmentShader, uniformLocations);
    }

}
+82 −0
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.shaders.impl;

import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLException;
import cz.fidentis.analyst.engines.shaders.Program;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static com.jogamp.opengl.GL.GL_FALSE;
import static com.jogamp.opengl.GL2ES2.*;

/**
 * A GLSL program implementation, which links multiple shaders together,
 * for example vertex shader and a fragment shader.
 *
 * @author Ondrej Simecek
 * @author Radek Oslejsek
 * @author Pavol Kycina
 */
public class ProgramImpl implements Program {

    private final Map<String, Integer> uniformLocations = new HashMap<>();

    private final int programId;

    /**
     * Links existing shaders into a program.
     *
     * @param gl OpenGL context
     * @param vertexShader ID of compiled vertex shader in the OpenGL context
     * @param fragmentShader ID of compiled fragment shader in the OpenGL context
     * @param uniformLocations Keys of uniform locations to be computed from the OpenGL context and stored.
     * @throws GLException if the program initiation fails
     */
    public ProgramImpl(GL2 gl, int vertexShader, int fragmentShader, Collection<String> uniformLocations) {
        this(gl, vertexShader, fragmentShader);
        uniformLocations.forEach(key -> this.uniformLocations.put(key,gl.glGetUniformLocation(programId, key)));
    }

    /**
     * Links existing shaders into a program.
     *
     * @param gl OpenGL context
     * @param vertexShader ID of compiled vertex shader in the OpenGL context
     * @param fragmentShader ID of compiled fragment shader in the OpenGL context
     * @throws GLException if the program initiation fails
     */
    public ProgramImpl(GL2 gl, int vertexShader, int fragmentShader) {
        programId = gl.glCreateProgram();

        gl.glAttachShader(programId, vertexShader);
        gl.glAttachShader(programId, fragmentShader);

        gl.glLinkProgram(programId);

        // check program status
        int[] linkStatus = new int[1];
        gl.glGetProgramiv(programId, GL_LINK_STATUS, linkStatus, 0);

        if (GL_FALSE == linkStatus[0]) {
            int[] infoLogLength = new int[1];
            gl.glGetProgramiv(programId, GL_INFO_LOG_LENGTH, infoLogLength, 0);

            byte[] infoLogBytes = new byte[infoLogLength[0]];
            gl.glGetProgramInfoLog(programId, infoLogLength[0], infoLogLength, 0, infoLogBytes, 0);

            throw new GLException(new String(infoLogBytes, 0, infoLogLength[0]));
        }
    }

    @Override
    public int getProgramId() {
        return programId;
    }

    @Override
    public int getUniformLocation(String key) {
        return uniformLocations.getOrDefault(key, -1);
    }
}
+4 −0
Original line number Diff line number Diff line
/**
 * Services for GLSL shaders and programs dealing with geometry (often meshes).
 */
package cz.fidentis.analyst.engines.shaders;
Loading