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();
}
}