Posted by
bananafish on
Dec 23, 2012; 4:16pm
URL: https://forum.jogamp.org/ShaderCode-throws-Unknown-shader-type-36313-with-GEOMETRY-SHADER-tp4027631p4027634.html
Below is the java code for a test case and an image of the expected output.
Loads a low-resolution image of bananas from wikimedia commons,
uploads it as a GL texture, sets up vertex,geometry,and fragment
shaders then uses immediate mode (for simplicity) to display the
image as two triangles.
To choose between using ShaderCode or raw calls for setting up
shaders, flip the boolean value of GeomShaderBananaGL.USE_SHADER_CODE_CLASS .

EDIT0: Removed unneeded UTF loader code. Added layout hints to shaders. Added boolean switch to toggle geometry shader.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.charset.Charset;
import javax.imageio.ImageIO;
import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL2;
import javax.media.opengl.GL3;
import javax.media.opengl.GL4;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.glsl.ShaderState;
/**
* JOGL Geometry ShaderCode test case.
* Loads a low-resolution image of bananas from wikimedia commons,
* uploads it as a GL texture, sets up vertex,geometry,and fragment
* shaders then uses immediate mode (for simplicity) to display the
* image as two triangles. This code should not be regarded
* as an academic example, since using immediate mode with a
* geometry shader is really pushing it.
*
* If the geometry shader functions properly, the banana image will be
* flipped both horizontally and vertically.
* If the geometry shader is bypassed, the banana image
* will be in the correct orientation.
*
* To choose between using ShaderCode or raw calls for setting up
* shaders, flip the boolean value of GeomShaderBananaGL.USE_SHADER_CODE_CLASS .
*
* Tests OK with Radeon HD5570, FGLRX on Xubuntu 12.10 x64
*
* @author Chuck Ritola December 2012
*
*/
public class GeomShaderBananaGL extends JFrame implements GLEventListener
{
GLProfile glp = GLProfile.get(GLProfile.GL2GL3);
GLCapabilities capabilities = new GLCapabilities(glp);
GLCanvas canvas = new GLCanvas(capabilities);
GLU glu = new GLU();
final FPSAnimator animator = new FPSAnimator(canvas,30);
int testTextureID=0;
ShaderState shaderState=new ShaderState();
ShaderProgram texturedShaderProgram;
///////////////////////////////////////////////////////////////////////////
/////////////// USE THIS TO SWITCH SHADER LOAD METHODS ////////////////////
///////////////////////////////////////////////////////////////////////////
private static final boolean USE_SHADER_CODE_CLASS=false;
///////////////////////////////////////////////////////////////////////////
/////////////// USE THIS TO ENABLE/DISABLE GEOMETRY SHADER ////////////////
///////////////////////////////////////////////////////////////////////////
private static final boolean USE_GEOM_SHADER=true;
//SHADER CODE
private static final String vertexShaderSource =
"#version 410\n" +
"\n" +
"//OUT\n" +
"layout (location=0) out smooth vec2 fragTexCoord;\n" +
"\n" +
"void main()\n" +
"{\n" +
"fragTexCoord=gl_MultiTexCoord0;\n" +
"gl_Position=gl_Vertex;"+
"}// end main()";
private static final String fragShaderSource=
"#version 410\n" +
"\n" +
"layout (location=0) in smooth vec2 fragTexCoord;\n" +
"uniform sampler2D textureMap;\n" +
"\n" +
"void main()\n" +
"{\n" +
" gl_FragColor = texture2D(textureMap,fragTexCoord);\n" +
"}//end main()";
private static final String geomShaderSource=
"#version 410\n" +
"\n" +
"//OUTPUT\n" +
"layout (triangle_strip, max_vertices=3) out;\n" +
"layout (location=0) out smooth vec2 VfragTexCoord;" +
"\n" +
"// INPUT\n" +
"layout (triangles, invocations=1) in;\n" +
"layout (location=0) in smooth vec2 fragTexCoord[3];" +
"\n" +
"void main()\n" +
"{\n" +
"int i;\n" +
"for(i=0; i< gl_VerticesIn; i++)\n" +
" {\n" +
" gl_Position = vec4(gl_PositionIn[i].xyz*-1,1);\n" + //This line flips the coordinates.
" VfragTexCoord = fragTexCoord[i];" +
" EmitVertex();\n" +
" }//end for(vertices)\n" +
"EndPrimitive();\n" +
"}";
public GeomShaderBananaGL()
{// Bread n' butter window setup stuff.
super("JOGL Geometry Shader Banana Test");
setSize(800,600);
setBackground(Color.black);
add(canvas);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.addGLEventListener(this);
animator.start();
}
public static void main(String[] args)
{
System.out.println
(" JOGL Geometry ShaderCode test case.\n" +
" Loads a low-resolution image of bananas from wikimedia commons,\n" +
" uploads it as a GL texture, sets up vertex,geometry,and fragment\n" +
" shaders then uses immediate mode (for simplicity) to display the\n" +
" image as two triangles.\n" +
" \n" +
" If the geometry shader functions properly, the banana image will be\n" +
" flipped both horizontally and vertically. \n" +
" If the geometry shader is bypassed,\n" +
" the banana image will be in the correct orientation.");
new GeomShaderBananaGL();
}
@Override
public void display(GLAutoDrawable drawable)
{
GL2 gl = drawable.getGL().getGL2();
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glDepthFunc(GL2.GL_LESS);
gl.glDepthFunc(GL2.GL_ALWAYS);
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_COLOR_BUFFER_BIT);
//Draw the image as a pseudo-quad using two triangles
gl.glBindTexture(GL2.GL_TEXTURE_2D, testTextureID);
gl.glBegin(GL2.GL_TRIANGLES);
gl.glColor3d(1, 1, 1);
gl.glTexCoord2d(0, 1);gl.glVertex2d(-1, 1); //Top left
gl.glTexCoord2d(0, 0);gl.glVertex2d(-1, -1); //Bottom left
gl.glTexCoord2d(1, 0);gl.glVertex2d(1, -1); //Bottom right
gl.glTexCoord2d(0, 1);gl.glVertex2d(-1, 1); //Top left
gl.glTexCoord2d(1, 1);gl.glVertex2d(1, 1); //Top right
gl.glTexCoord2d(1, 0);gl.glVertex2d(1, -1); //Bottom right
gl.glEnd();
gl.glFlush();
}//end display()
@Override
public void dispose(GLAutoDrawable drawable)
{}
@Override
public void init(GLAutoDrawable drawable)
{
GL2 gl = drawable.getGL().getGL2();
canvas.setGL(new DebugGL2(gl));
if(USE_SHADER_CODE_CLASS)
initUsingShaderCode(gl);
else
initUsingRawMethod(gl);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glClearColor(0f, 0f, 0f, 0f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
testTextureID = createTestTexture(gl);
}
private void initUsingRawMethod(GL2 gl)
{
int vs = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
int fs = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
int gs = gl.glCreateShader(GL3.GL_GEOMETRY_SHADER);
int prg = gl.glCreateProgram();
genShader(gl,vs,vertexShaderSource);
genShader(gl,fs,fragShaderSource);
if(USE_GEOM_SHADER)genShader(gl,gs,geomShaderSource);
gl.glAttachShader(prg, vs);
gl.glAttachShader(prg, fs);
if(USE_GEOM_SHADER)gl.glAttachShader(prg, gs);
gl.glLinkProgram(prg);
gl.glUseProgram(prg);
gl.glValidateProgram(prg);
IntBuffer statBuf = IntBuffer.allocate(1);
gl.glGetProgramiv(prg, GL2.GL_VALIDATE_STATUS, statBuf);
if(statBuf.get(0)==GL2.GL_FALSE)
{
statBuf.clear();
gl.glGetProgramiv(prg, GL2.GL_INFO_LOG_LENGTH, statBuf);
ByteBuffer log = ByteBuffer.allocate(statBuf.get(0));
gl.glGetProgramInfoLog(prg, statBuf.get(0), null, log);
System.out.println(Charset.forName("US-ASCII").decode(log)
.toString());
System.exit(1);
}
}//end initUsingRawMethod(...)
private void genShader(GL2 gl, int shaderID, String source)
{
gl.glShaderSource(shaderID, 1, new String[]{source}, (IntBuffer)null);
gl.glCompileShader(shaderID);
printStatusInfo(gl, shaderID);
}//end genShader
private void printStatusInfo(GL2 gl, int shaderID)
{
IntBuffer statBuf = IntBuffer.allocate(1);
gl.glGetShaderiv(shaderID, GL4.GL_COMPILE_STATUS, statBuf);
if(statBuf.get(0)==GL4.GL_FALSE)
{
statBuf.clear();
gl.glGetShaderiv(shaderID, GL4.GL_INFO_LOG_LENGTH, statBuf);
ByteBuffer log = ByteBuffer.allocate(statBuf.get(0));
gl.glGetShaderInfoLog(shaderID, statBuf.get(0), null, log);
System.out.println(Charset.forName("US-ASCII").decode(log)
.toString());
System.exit(1);
}
}//end printStatusInfo(...)
private void initUsingShaderCode(GL2 gl)
{
try
{
ShaderCode fs = new ShaderCode(GL2.GL_FRAGMENT_SHADER,1,new String[][]{new String[]{fragShaderSource}});
fs.compile(gl);
ShaderCode vs = new ShaderCode(GL2.GL_VERTEX_SHADER,1,new String[][]{new String[]{vertexShaderSource}});
vs.compile(gl);
ShaderCode gs;
if(USE_GEOM_SHADER)gs = new ShaderCode(GL3.GL_GEOMETRY_SHADER,1,new String[][]{new String[]{geomShaderSource}});
if(USE_GEOM_SHADER)gs.compile(gl);
texturedShaderProgram = new ShaderProgram();
texturedShaderProgram.add(fs);
texturedShaderProgram.add(vs);
if(USE_GEOM_SHADER)texturedShaderProgram.add(gs);
texturedShaderProgram.link(gl, System.out);
shaderState.attachShaderProgram(gl, texturedShaderProgram, true);
shaderState.useProgram(gl, true);
}
catch(Exception e){e.printStackTrace();System.exit(1);}
}
/**
* Loads a picture of bananas from wikimedia and uploads it to the GPU as a 128x128 texture
* @param gl
* @return OpenGL texture ID of the bananas.
*/
private int createTestTexture(GL2 gl)
{
IntBuffer indexBuffer = IntBuffer.allocate(1);
gl.glGenTextures(1, indexBuffer);
int textureID = indexBuffer.get();
BufferedImage img=null;
try {img= ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Bananas_white_background.jpg/320px-Bananas_white_background.jpg"));}
catch(Exception e){e.printStackTrace();System.exit(1);}
double scalarU = img.getWidth()/128.;
double scalarV = img.getHeight()/128.;
ByteBuffer textureBuffer = ByteBuffer.allocateDirect(3*128*128);// RGB * W * H
for(int y=127; y>0; y--)//OpenGL textures are bottom-up
{
for(int x=0; x<128; x++)
{
final Color c = new Color(img.getRGB((int)(x*scalarU),(int)(y*scalarV)));//Scale and load from int
//Write component-by-component to RGB buffer
textureBuffer.put((byte)c.getRed());
textureBuffer.put((byte)c.getGreen());
textureBuffer.put((byte)c.getBlue());
}//end for(u)
}//end for(v)
textureBuffer.rewind();
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER,
GL2.GL_LINEAR);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER,
GL2.GL_LINEAR);
gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB,
128,128,
0, GL2.GL_RGB, GL2.GL_UNSIGNED_BYTE, textureBuffer);
return textureID;
}//end createTestTexture(...)
@Override
public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3,
int arg4)
{}
}//end Test