import java.nio.*; // Native IO buffers: LWJGL uses these to efficiently exchange data with system memory import org.lwjgl.opengl.*; import org.lwjgl.opengl.glu.GLU; import org.lwjgl.opengl.glu.Sphere; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.glu.*; /** * GLART_sphere_texture_material.java * * Whenever you enable lighting, a material is implicitly enabled as well. Light * requires material to reflect off, and OpenGL provides a default material (a * gray color with no reflection). You can set material properties to adjust * the surface quality of your textured shapes. * * OpenGL renders lighting effects first, then texture, and this may dull the * reflected highlights (specular), particularly affecting glossy materials. * Use glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SEPARATE_SPECULAR_COLOR) * to have OpenGL render reflections after (on top of) the texture. (note: this is a 1.2 * feature). */ public class simple { private boolean done = false; private final String windowTitle = "Sphere with Texture and Material"; private DisplayMode displayMode; float rotation = 0; // color of overall scene lighting float ambient[] = { 0f, 0f, 0f, 1f }; // color of light source float lightDiffuse[] = { .8f, .8f, .75f, 1f }; // direct light float lightSpecular[] = { .9f, .9f, .85f, 1f }; // highlight float lightAmbient[] = { .2f, .2f, .0f, 1f }; // scattered light // light position: if last value is 0, then this describes light direction. // If 1, then light position. float lightPosition[] = { -4f, 4f, 6, 1f }; // color of material float mtlDiffuse[] = { .398f, .398f, .398f, 1f }; // white/green float mtlAmbient[] = { .08f, .08f, .08f, 1f }; // light gray greenish float mtlSpecular[] = { .8f, .8f, .8f, 1f }; // almost white: very reflective float mtlEmissive[] = {.15f, .2f, .15f, 1f}; // glow color float mtlShininess = 127f; // 0=no shine, 127=max shine // Material object will hold color values GLMaterial material = new GLMaterial(); // texture handle (a number that refers to an allocated texture) int graniteTextureHandle = 0; int woodTextureHandle = 1; int marbleTextureHandle=2; //Main function just creates and runs the application. public static void main(String args[]) { simple app = new simple(); app.run(); } //Initialize the app, then sit in a render loop until done==true. public void run() { try { init(); while (!done) { mainloop(); render(); Display.update(); } cleanup(); } catch (Exception e) { e.printStackTrace(); System.exit(0); } } //Initialize the environment:@throws Exception private void init() throws Exception { initDisplay(); initGL(); //////////////////////////////////// // Create sphere texture // Load the image as RGBA pixels //GLImage textureImg = new GLImage("images/marble.jpg"); GLImage textureImg = new GLImage("images/granite.jpg"); GLImage textureImg2 = new GLImage("images/wood.jpg"); GLImage textureImg4 = new GLImage("images/lightmarble.jpg"); // Allocate and configure a texture based on the image graniteTextureHandle = makeTexture(textureImg); woodTextureHandle = makeTexture(textureImg2); marbleTextureHandle = makeTexture(textureImg4); } //Create an OpenGL display, in this case a fullscreen window private void initDisplay() throws Exception { // set to full screen, no chrome Display.setFullscreen(false); // get all possible display resolutions DisplayMode d[] = Display.getAvailableDisplayModes(); // find a resolution we like for (int i = 0; i < d.length; i++) { if (d[i].getWidth() == 800 && d[i].getHeight() == 600 && d[i].getBitsPerPixel() == 32) { displayMode = d[i]; break; } } // set the display to the resolution we picked Display.setDisplayMode(displayMode); Display.setTitle(windowTitle); // create the window Display.create(); } //Initialize OpenGL private void initGL() { // Select the Projection Matrix (controls perspective) GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); // Reset The Projection Matrix // Define perspective GLU.gluPerspective( 45.0f, // Field Of View (float)displayMode.getWidth() / (float)displayMode.getHeight(), // aspect ratio 0.1f, // near Z clipping plane 100.0f); // far Z clipping plane // Where is the 'eye' GLU.gluLookAt( -1f, 0f, 4f, // eye position 0f, 0f, 0f, // target to look at 0f, 1f, 0f); // which way is up // Select The Modelview Matrix (controls model orientation) GL11.glMatrixMode(GL11.GL_MODELVIEW); // make sure OpenGL correctly layers objects GL11.glEnable(GL11.GL_DEPTH_TEST); // OpenGL won't draw backward facing triangles ("back faces") GL11.glEnable(GL11.GL_CULL_FACE); // turn lighting on (does not create a light) GL11.glEnable(GL11.GL_LIGHTING); // Create a light // diffuse is the color of direct light from this light source // specular is the hightlight color // ambient is the color of scattered light from this source // position is where the light is, or it's direction setLight( GL11.GL_LIGHT1, lightDiffuse, lightAmbient, lightSpecular, lightPosition ); // no overall scene lighting setAmbientLight(ambient); // change the current material settings material.setSurfaceColorLit(mtlDiffuse); material.setSurfaceColorShadow(mtlAmbient); material.setReflectionColor(mtlSpecular); material.setShininess(mtlShininess); material.setGlowColor(mtlEmissive); // activate this material material.apply(); // set the background color GL11.glClearColor(.2f, .2f, .23f, 1); // blending GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // Force normals to length 1 GL11.glEnable(GL11.GL_NORMALIZE); // Draw specular highlghts on top of textures GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SEPARATE_SPECULAR_COLOR ); } //Handle keyboard input. Just check for escape key or user //clicking to close the window. private void mainloop() { if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) { // Escape is pressed done = true; } if(Display.isCloseRequested()) { // Window is closed done = true; } } //Render the scene. private void render() { rotation += .33f; // Clear screen and depth buffer GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // reset the coordinate system to center of screen GL11.glLoadIdentity(); GL11.glRotatef(rotation, 0,1,0); GL11.glTranslated(0f,.25f, 0f); GL11.glPushMatrix(); { // draw sphere in front GL11.glPushMatrix(); { GL11.glTranslated(0f, -.25f, 0f); GL11.glScaled(.15f, .75f, .5f); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D,graniteTextureHandle); renderSphere(); GL11.glDisable(GL11.GL_TEXTURE_2D); } GL11.glPopMatrix(); GL11.glPushMatrix(); { GL11.glTranslated(0f, .75f, 0f); GL11.glScaled(.5f, .25f, .5f); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D,marbleTextureHandle); renderSphere(); GL11.glDisable(GL11.GL_TEXTURE_2D); } GL11.glPopMatrix(); GL11.glPushMatrix(); { GL11.glTranslated(0f, -1.25f, 0f); GL11.glScaled(.75f, .25f, .75f); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D,woodTextureHandle); renderCube(); GL11.glDisable(GL11.GL_TEXTURE_2D); } GL11.glPopMatrix(); } GL11.glPopMatrix(); } //Cleanup all the resources. private void cleanup() { Display.destroy(); } /** * Simple way to setup a light. Uses same color for direct light (diffuse), * reflected highlight (specular) and scattered light (ambient). Ambient * color is darkened to 1/4 of the light color. * @param GLLightHandle * @param color * @param position */ public static void setLight(int GLLightHandle, float[] color, float[] position ) { float[] ambientLight = {color[0]/4f, color[1]/4f, color[2]/4f, color[3]/4f}; FloatBuffer lightColor = allocFloats(color); FloatBuffer ambientColor = allocFloats(ambientLight); FloatBuffer ltPosition = allocFloats(position); GL11.glLight(GLLightHandle, GL11.GL_DIFFUSE, lightColor); // color of the direct illumination GL11.glLight(GLLightHandle, GL11.GL_SPECULAR, lightColor); // color of the highlight (same as direct light) GL11.glLight(GLLightHandle, GL11.GL_AMBIENT, ambientColor); // color of the scattered light (darker) GL11.glLight(GLLightHandle, GL11.GL_POSITION, ltPosition); GL11.glEnable(GLLightHandle); // Enable the light (GL_LIGHT1 - 7) } /** * Set the color of a 'positional' light (a light that has a specific * position within the scene).
*
* Params:
* an OpenGL light number (GL11.GL_LIGHT1),
* 'Diffuse': color of direct light from this source,
* 'Ambient': color of scattered light from this source
* 'Specular': color of this light reflected off a surface,
* position.
*/ public static void setLight( int GLLightHandle, float[] diffuseLightColor, float[] ambientLightColor, float[] specularLightColor, float[] position ) { FloatBuffer ltDiffuse = allocFloats(diffuseLightColor); FloatBuffer ltAmbient = allocFloats(ambientLightColor); FloatBuffer ltSpecular = allocFloats(specularLightColor); FloatBuffer ltPosition = allocFloats(position); GL11.glLight(GLLightHandle, GL11.GL_DIFFUSE, ltDiffuse); // color of the direct illumination GL11.glLight(GLLightHandle, GL11.GL_AMBIENT, ltAmbient); // color of the reflected light GL11.glLight(GLLightHandle, GL11.GL_SPECULAR, ltSpecular); // color of the highlight (same as direct light) GL11.glLight(GLLightHandle, GL11.GL_POSITION, ltPosition); GL11.glEnable(GLLightHandle); // Enable the light (GL_LIGHT1 - 7) //GL11.glLightf(GLLightHandle, GL11.GL_QUADRATIC_ATTENUATION, .005F); // how light beam drops off } /** * Set the color of the Global Ambient Light. Affects all objects in * scene regardless of their placement. */ public static void setAmbientLight(float[] ambientLightColor) { FloatBuffer ltAmbient = allocFloats(ambientLightColor); GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, ltAmbient); } public static final int SIZE_FLOAT = 4; public static FloatBuffer allocFloats(int howmany) { return ByteBuffer.allocateDirect(howmany * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); } public static FloatBuffer allocFloats(float[] floatarray) { FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(floatarray).flip(); return fb; } /** * call the LWJGL Sphere class to create sphere geometry, * with normals */ public static void renderSphere() { Sphere s = new Sphere(); // an LWJGL class for drawing sphere s.setOrientation(GLU.GLU_OUTSIDE); // normals point outwards s.setTextureFlag(true); // generate texture coords s.draw(1, 48, 48); // run GL commands to draw sphere } public static void renderCube() { GL11.glBegin(GL11.GL_QUADS); // Front Face GL11.glNormal3f( 0.0f, 0.0f, 1.0f); GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left // Back Face GL11.glNormal3f( 0.0f, 0.0f, -1.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Left // Top Face GL11.glNormal3f( 0.0f, 1.0f, 0.0f); GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right // Bottom Face GL11.glNormal3f( 0.0f, -1.0f, 0.0f); GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Top Left GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right // Right face GL11.glNormal3f( 1.0f, 0.0f, 0.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Right GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left // Left Face GL11.glNormal3f( -1.0f, 0.0f, 0.0f); GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left GL11.glEnd(); } /** * Create a texture from the given image. */ public static int makeTexture(GLImage textureImg) { if ( textureImg == null ) { return 0; } else { return makeTexture(textureImg.pixelBuffer, textureImg.w, textureImg.h); } } /** * Create a texture from the given pixels in RGBA format. Set the texture * to repeat in both directions and use LINEAR for magnification. * @return the texture handle */ public static int makeTexture(ByteBuffer pixels, int w, int h) { // get a new empty texture int textureHandle = allocateTexture(); // 'select' the new texture by it's handle GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle); // set texture parameters GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); //GL11.GL_NEAREST); // Create the texture from pixels GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, w, h, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels); return textureHandle; } /** * Allocate a texture (glGenTextures) and return the handle to it. */ public static int allocateTexture() { IntBuffer textureHandle = allocInts(1); GL11.glGenTextures(textureHandle); return textureHandle.get(0); } public static final int SIZE_INT = 4; public static IntBuffer allocInts(int howmany) { return ByteBuffer.allocateDirect(howmany * SIZE_INT).order(ByteOrder.nativeOrder()).asIntBuffer(); } }