|
This example shows how to implement bump-mapping visual effect with JOGL.
This is the Java port of the one of the NeHe OpenGL tutorials.
You can get complete IntelliJ IDEA project structure (all source, resources, build script, …) by downloading the source distribution from here.
The original post of the programmer who ported the examples can be found here.
package demos.nehe.lesson22;
/*--. .-"-.
/ o_O / O o \
\_ (__\ \_ v _/
// \\ // \\
(( )) (( ))
¤¤¤¤¤¤¤¤¤¤¤¤¤¤--""---""--¤¤¤¤--""---""--¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
¤ ||| ||| ¤
¤ | | ¤
¤ ¤
¤ Programmer:Abdul Bezrati ¤
¤ Program :Nehe's 22nd lesson port to JOGL ¤
¤ Comments :None ¤
¤ _______ ¤
¤ /` _____ `\;,
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
¤
¤ (__(^===^)__)';, ___ ¤
¤ / ::: \ ,; /^ ^\ ¤
¤ | ::: | ,;' ( Ö Ö ) ¤
¤¤¤'._______.'`¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ --°oOo--(_)--oOo°--¤¤*/
import demos.common.GLDisplay;
/**
* @author Abdul Bezrati
*/
public class Lesson22 {
public static void main(String[] args) {
GLDisplay neheGLDisplay = GLDisplay.createGLDisplay(
"Lesson 22: Bump mapping (extensions)");
Renderer renderer = new Renderer();
InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
neheGLDisplay.addGLEventListener(renderer);
neheGLDisplay.addKeyListener(inputHandler);
neheGLDisplay.start();
}
}
package demos.nehe.lesson22;
import demos.common.GLDisplay;
import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
class InputHandler extends KeyAdapter {
private Renderer renderer;
public InputHandler(Renderer renderer, GLDisplay glDisplay) {
this.renderer = renderer;
glDisplay.registerKeyStrokeForHelp(KeyStroke.getKeyStroke(
KeyEvent.VK_F, 0), "Switch texture filter");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_M, 0), "Toggle multitexturing");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_B, 0), "Toggle bumpmapping");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_E, 0), "Toggle embossed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "Zoom in");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "Zoom out");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
"Decrease X-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
"Increase X-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
"Decrease Y-axis rotation speed");
glDisplay.registerKeyStrokeForHelp(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
"Increase Y-axis rotation speed");
}
public void keyPressed(KeyEvent e) {
processKeyEvent(e, true);
}
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F:
renderer.switchFilter();
break;
case KeyEvent.VK_M:
renderer.toggleMultitexture();
break;
case KeyEvent.VK_B:
renderer.toggleBumps();
break;
case KeyEvent.VK_E:
renderer.toggleEmboss();
break;
default:
processKeyEvent(e, false);
}
}
private void processKeyEvent(KeyEvent e, boolean pressed) {
switch (e.getKeyCode()) {
case KeyEvent.VK_PAGE_UP:
renderer.zoomIn(pressed);
break;
case KeyEvent.VK_PAGE_DOWN:
renderer.zoomOut(pressed);
break;
case KeyEvent.VK_UP:
renderer.decreaseXspeed(pressed);
break;
case KeyEvent.VK_DOWN:
renderer.increaseXspeed(pressed);
break;
case KeyEvent.VK_RIGHT:
renderer.increaseYspeed(pressed);
break;
case KeyEvent.VK_LEFT:
renderer.decreaseYspeed(pressed);
break;
}
}
}
package demos.nehe.lesson22;
import demos.common.TextureReader;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.awt.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import com.sun.opengl.util.BufferUtil;
class Renderer implements GLEventListener {
// Flag Indicating Whether Multitexturing Is Supported
private boolean multitextureSupported;
private boolean multitextureEnabled = true; // Use It If It Is Supported?
private boolean __ARB_ENABLE = true; // Used To Disable ARB Extensions Entirely
private boolean embossEnabled = false; // Emboss Only, No Basetexture?
private boolean bumpsEnabled = true; // Do Bumpmapping?
// Number Of Texel-Pipelines. This Is At Least 1.
private int[] maxTexelUnits = new int[1];
private int[] multiLogo = new int[1]; // Handle For Multitexture-Enabled-Logo
private int[] invbump = new int[3]; // Inverted Bumpmap
private int[] textures = new int[3]; // Storage For 3 Textures
private int[] glLogo = new int[1]; // Handle For OpenGL-Logo
private int filter = 1; // Which Filter To Use
private int[] bump = new int[3]; // Our Bumpmappings
// Position is somewhat in front of screen
private float[] lightPosition = {0.0f, 0.0f, 2.0f};
private float[] lightAmbient = {0.2f, 0.2f, 0.2f}; // Ambient Light is 20% white
private float[] lightDiffuse = {1.0f, 1.0f, 1.0f}; // Diffuse Light is white
// Maximum Emboss-Translate. Increase To Get Higher Immersion
private float MAX_EMBOSS = 8e-3f;
// At A Cost Of Lower Quality (More Artifacts Will Occur!)
private float[] gray = Color.gray.getRGBComponents(null); // Gray Color
// Data Contains The Faces For The Cube In Format 2xTexCoord, 3xVertex;
// Note That The Tesselation Of The Cube Is Only Absolute Minimum.
private float[] data = {0f, 0f, -1f, -1f, 1f, // FRONT FACE
1f, 0f, 1f, -1f, 1f,
1f, 1f, 1f, 1f, 1f,
0f, 1f, -1f, 1f, 1f,
1f, 0f, -1f, -1f, -1f, // BACK FACE
1f, 1f, -1f, 1f, -1f,
0f, 1f, 1f, 1f, -1f,
0f, 0f, 1f, -1f, -1f,
0f, 1f, -1f, 1f, -1f, // Top Face
0f, 0f, -1f, 1f, 1f,
1f, 0f, 1f, 1f, 1f,
1f, 1f, 1f, 1f, -1f,
1f, 1f, -1f, -1f, -1f, // Bottom Face
0f, 1f, 1f, -1f, -1f,
0f, 0f, 1f, -1f, 1f,
1f, 0f, -1f, -1f, 1f,
1f, 0f, 1f, -1f, -1f, // Right Face
1f, 1f, 1f, 1f, -1f,
0f, 1f, 1f, 1f, 1f,
0f, 0f, 1f, -1f, 1f,
0f, 0f, -1f, -1f, -1f, // Left Face
1f, 0f, -1f, -1f, 1f,
1f, 1f, -1f, 1f, 1f,
0f, 1f, -1f, 1f, -1f};
private float yspeed; // Y Rotation Speed
private boolean increaseY;
private boolean decreaseY;
private float xspeed; // X Rotation Speed
private boolean increaseX;
private boolean decreaseX;
private float xrot; // X Rotation
private float yrot; // Y Rotation
private float z = -5; // Depth Into The Screen
private boolean zoomIn;
private boolean zoomOut;
private GLU glu = new GLU();
public void increaseXspeed(boolean increase) {
increaseX = increase;
}
public void decreaseXspeed(boolean decrease) {
decreaseX = decrease;
}
public void increaseYspeed(boolean increase) {
increaseY = increase;
}
public void decreaseYspeed(boolean decrease) {
decreaseY = decrease;
}
public void zoomOut(boolean zoom) {
zoomOut = zoom;
}
public void zoomIn(boolean zoom) {
zoomIn = zoom;
}
public void switchFilter() {
filter = (filter + 1) % 2;
}
public void toggleMultitexture() {
this.multitextureEnabled = !multitextureEnabled && multitextureSupported;
}
public void toggleEmboss() {
this.embossEnabled = !embossEnabled;
}
public void toggleBumps() {
bumpsEnabled = !bumpsEnabled;
}
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glEnable(GL.GL_TEXTURE_2D); // Enable Texture Mapping
gl.glShadeModel(GL.GL_SMOOTH); // Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
gl.glClearDepth(1.0f); // Depth Buffer Setup
gl.glEnable(GL.GL_DEPTH_TEST); // Enables Depth Testing
gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing To Do
// Really Nice Perspective Calculations
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
multitextureSupported = initMultitexture(gl);
try {
loadGLTextures(gl, glu);
} catch (IOException e) {
throw new RuntimeException(e);
}
initLights(gl); // Initialize OpenGL Light
}
// isMultitextureSupported() Checks At Run-Time If Multitexturing Is Supported
private boolean initMultitexture(GL gl) {
String extensions;
extensions = gl.glGetString(GL.GL_EXTENSIONS); // Fetch Extension String
int multiTextureAvailable = extensions.indexOf("GL_ARB_multitexture");
int textureEnvCombineAvailable = extensions.indexOf("GL_ARB_texture_env_combine");
if (multiTextureAvailable != -1 // Is Multitexturing Supported?
&& __ARB_ENABLE // Override-Flag
&& textureEnvCombineAvailable != -1) {
// Is texture_env_combining Supported?
gl.glGetIntegerv(GL.GL_MAX_TEXTURE_UNITS, maxTexelUnits, 0);
return true;
}
multitextureEnabled = false; // We Can't Use It If It Isn't Supported!
return false;
}
// Load PNGs And Convert To Textures
private void loadGLTextures(GL gl, GLU glu) throws IOException {
TextureReader.Texture texture = TextureReader.readTexture(
"demos/data/images/Base.bmp");
gl.glGenTextures(3, textures, 0); // Create Three Textures
// Create Nearest Filtered Texture
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
// ========
// Use GL_RGB8 Instead Of "3" In glTexImage2D. Also Defined By GL: GL_RGBA8 Etc.
// NEW: Now Creating GL_RGBA8 Textures, Alpha Is 1.0f Where Not Specified By Format.
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[1]); // Create Linear Filtered Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[2]); // Create MipMapped Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
GL.GL_LINEAR_MIPMAP_NEAREST);
glu.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, texture.getPixels());
// Load The Bumpmaps
texture = TextureReader.readTexture("demos/data/images/Bump.bmp");
// Scale RGB By 50%, So That We Have Only
gl.glPixelTransferf(GL.GL_RED_SCALE, 0.5f);
gl.glPixelTransferf(GL.GL_GREEN_SCALE, 0.5f); // Half Intenstity
gl.glPixelTransferf(GL.GL_BLUE_SCALE, 0.5f);
gl.glTexParameteri(GL.GL_TEXTURE_2D,
GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP); // No Wrapping, Please!
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);
gl.glTexParameterfv(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_BORDER_COLOR, gray, 0);
gl.glGenTextures(3, bump, 0); // Create Three Textures
gl.glBindTexture(GL.GL_TEXTURE_2D, bump[0]); // Create Nearest Filtered Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glBindTexture(GL.GL_TEXTURE_2D, bump[1]); // Create Linear Filtered Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glBindTexture(GL.GL_TEXTURE_2D, bump[2]); // Create MipMapped Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
GL.GL_LINEAR_MIPMAP_NEAREST);
glu.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
ByteBuffer pixels = texture.getPixels();
for (int i = 0; i < pixels.limit(); i++) // Invert The Bumpmap
pixels.put(i, (byte) (255 - pixels.get(i)));
pixels.flip();
gl.glGenTextures(3, invbump, 0); // Create Three Textures
gl.glBindTexture(GL.GL_TEXTURE_2D, invbump[0]); // Create Nearest Filtered Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glBindTexture(GL.GL_TEXTURE_2D, invbump[1]); // Create Linear Filtered Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glBindTexture(GL.GL_TEXTURE_2D, invbump[2]); // Create MipMapped Texture
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
GL.GL_LINEAR_MIPMAP_NEAREST);
glu.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGB8, texture.getWidth(),
texture.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
texture.getPixels());
gl.glPixelTransferf(GL.GL_RED_SCALE, 1.0f); // Scale RGB Back To 100% Again
gl.glPixelTransferf(GL.GL_GREEN_SCALE, 1.0f);
gl.glPixelTransferf(GL.GL_BLUE_SCALE, 1.0f);
// Load The Logo-Pngs
texture = TextureReader.readTexture("demos/data/images/OpenGL_Alpha.bmp", true);
// Create Memory For RGBA8-Texture
ByteBuffer alpha = BufferUtil.newByteBuffer(texture.getPixels().limit());
// Pick Only Red Value As Alpha!
for (int a = 0; a < alpha.capacity(); a += 4)
alpha.put(a + 3, texture.getPixels().get(a));
texture = TextureReader.readTexture("demos/data/images/OpenGL.bmp", true);
for (int a = 0; a < texture.getPixels().limit(); a += 4) {
alpha.put(a, texture.getPixels().get(a)); // R
alpha.put(a + 1, texture.getPixels().get(a + 1)); // G
alpha.put(a + 2, texture.getPixels().get(a + 2)); // B
}
alpha.position(0);
alpha.limit(alpha.capacity());
gl.glGenTextures(1, glLogo, 0); // Create One Textures
// Create Linear Filtered RGBA8-Texture
gl.glBindTexture(GL.GL_TEXTURE_2D, glLogo[0]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8, texture.getWidth(),
texture.getHeight(), 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, alpha);
texture = TextureReader.readTexture("demos/data/images/Multi_On_Alpha.bmp",
true);// Load The "Extension Enabled"-Logo
// Create Memory For RGBA8-Texture
alpha = BufferUtil.newByteBuffer(texture.getPixels().limit());
// Pick Only Red Value As Alpha!
for (int a = 0; a < alpha.capacity(); a += 4)
alpha.put(a + 3, texture.getPixels().get(a));
texture = TextureReader.readTexture("demos/data/images/Multi_On.bmp", true);
for (int a = 0; a < texture.getPixels().limit(); a += 4) {
alpha.put(a, texture.getPixels().get(a)); // R
alpha.put(a + 1, texture.getPixels().get(a + 1)); //& | |