Added support for OpenGL ES.

This commit is contained in:
Ioannis Tsakpinis 2011-05-17 16:53:57 +00:00
parent 8f6dcd3a6d
commit 40cbf3e45f
213 changed files with 19618 additions and 194 deletions

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.test.opengles;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengles.PixelFormat;
import org.lwjgl.opengles.PowerManagementEventException;
import org.lwjgl.util.vector.Vector2f;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.opengles.GLES20.*;
import static org.lwjgl.test.opengles.util.GLMatrix.*;
/**
* Tests switching between windowed and fullscreen
*
* @author Brian Matzon <brian@matzon.dk>
* @version $Revision: 3172 $
* $Id: FullScreenWindowedTest.java 3172 2008-12-28 19:30:43Z elias_naur $
*/
public class FullScreenWindowedTest {
/** Intended deiplay mode */
private DisplayMode mode;
/** our quad moving around */
private Vector2f quadPosition;
/** our quadVelocity */
private Vector2f quadVelocity;
/** angle of quad */
private float angle;
/** degrees to rotate per frame */
private float angleRotation = 1.0f;
/** Max speed of all changable attributes */
private static final float MAX_SPEED = 20.0f;
private static int buffer_id;
private static int indices_buffer_id;
private QuadRenderer renderer;
/** Creates a FullScreenWindowedTest */
public FullScreenWindowedTest() {
}
/** Executes the test */
public void execute() {
initialize();
mainLoop();
cleanup();
Display.destroy();
}
private void switchMode() throws LWJGLException {
mode = findDisplayMode(1024, 600, Display.getDisplayMode().getBitsPerPixel());
try {
Display.setDisplayModeAndFullscreen(mode);
} catch (PowerManagementEventException e) {
e.printStackTrace();
}
}
/** Initializes the test */
private void initialize() {
try {
//find displaymode
switchMode();
// start of in windowed mode
Display.create(new PixelFormat());
glInit();
quadPosition = new Vector2f(100f, 100f);
quadVelocity = new Vector2f(1.0f, 1.0f);
renderer = new QuadRenderer();
} catch (Exception e) {
e.printStackTrace();
}
}
/** Runs the main loop of the "test" */
private void mainLoop() {
while ( !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) && !Display.isCloseRequested() ) {
if ( Display.isVisible() ) {
// check keyboard input
processKeyboard();
// do "game" logic, and render it
logic();
render();
} else {
// no need to render/paint if nothing has changed (ie. window
// dragged over)
if ( Display.isDirty() ) {
render();
}
// don't waste cpu time, sleep more
try {
Thread.sleep(100);
} catch (InterruptedException inte) {
}
}
// Update window
try {
Display.update();
Display.sync(60);
} catch (PowerManagementEventException e) {
e.printStackTrace();
}
}
}
/** Performs the logic */
private void logic() {
angle += angleRotation;
if ( angle > 90.0f ) {
angle = 0.0f;
}
quadPosition.x += quadVelocity.x;
quadPosition.y += quadVelocity.y;
//check colision with vertical border border
if ( quadPosition.x + 50 >= mode.getWidth() || quadPosition.x - 50 <= 0 ) {
quadVelocity.x *= -1;
}
//check collision with horizontal border
if ( quadPosition.y + 50 >= mode.getHeight() || quadPosition.y - 50 <= 0 ) {
quadVelocity.y *= -1;
}
}
private void render() {
//clear background
glClear(GL_COLOR_BUFFER_BIT);
// draw white quad
glPushMatrix();
{
glTranslatef(quadPosition.x, quadPosition.y, 0);
glRotatef(angle, 0.0f, 0.0f, 1.0f);
renderer.setMVPUniform();
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
}
glPopMatrix();
}
/** Processes keyboard input */
private void processKeyboard() {
//check for fullscreen key
if ( Keyboard.isKeyDown(Keyboard.KEY_F) ) {
try {
cleanup();
switchMode();
glInit();
renderer = new QuadRenderer();
} catch (Exception e) {
e.printStackTrace();
}
}
//check for window key
if ( Keyboard.isKeyDown(Keyboard.KEY_W) ) {
try {
cleanup();
mode = new DisplayMode(800, 480);
Display.setDisplayModeAndFullscreen(mode);
glInit();
renderer = new QuadRenderer();
} catch (Exception e) {
e.printStackTrace();
}
}
//check for speed changes
if ( Keyboard.isKeyDown(Keyboard.KEY_UP) ) {
quadVelocity.y += 0.1f;
}
if ( Keyboard.isKeyDown(Keyboard.KEY_DOWN) ) {
quadVelocity.y -= 0.1f;
}
if ( Keyboard.isKeyDown(Keyboard.KEY_RIGHT) ) {
quadVelocity.x += 0.1f;
}
if ( Keyboard.isKeyDown(Keyboard.KEY_LEFT) ) {
quadVelocity.x -= 0.1f;
}
if ( Keyboard.isKeyDown(Keyboard.KEY_ADD) ) {
angleRotation += 0.1f;
}
if ( Keyboard.isKeyDown(Keyboard.KEY_SUBTRACT) ) {
angleRotation -= 0.1f;
}
//throttle
if ( quadVelocity.x < -MAX_SPEED ) {
quadVelocity.x = -MAX_SPEED;
}
if ( quadVelocity.x > MAX_SPEED ) {
quadVelocity.x = MAX_SPEED;
}
if ( quadVelocity.y < -MAX_SPEED ) {
quadVelocity.y = -MAX_SPEED;
}
if ( quadVelocity.y > MAX_SPEED ) {
quadVelocity.y = MAX_SPEED;
}
if ( angleRotation < 0.0f ) {
angleRotation = 0.0f;
}
if ( angleRotation > MAX_SPEED ) {
angleRotation = MAX_SPEED;
}
}
/** Cleans up the test */
private void cleanup() {
renderer.cleanup();
IntBuffer int_buffer = BufferUtils.createIntBuffer(2);
int_buffer.put(0, buffer_id);
int_buffer.put(1, indices_buffer_id);
glDeleteBuffers(int_buffer);
}
/**
* Retrieves a displaymode, if one such is available
*
* @param width Required width
* @param height Required height
* @param bpp Minimum required bits per pixel
*
* @return
*/
private static DisplayMode findDisplayMode(int width, int height, int bpp) throws LWJGLException {
DisplayMode[] modes = Display.getAvailableDisplayModes();
for ( int i = 0; i < modes.length; i++ ) {
if ( modes[i].getWidth() == width && modes[i].getHeight() == height && modes[i].getBitsPerPixel() >= bpp && modes[i].getFrequency() <= 60 ) {
return modes[i];
}
}
return Display.getDesktopDisplayMode();
}
/** Initializes OGL */
private void glInit() {
// Go into orthographic projection mode.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, mode.getWidth(), 0, mode.getHeight(), -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, mode.getWidth(), mode.getHeight());
//set clear color to black
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//sync frame (only works on windows)
Display.setVSyncEnabled(true);
final IntBuffer int_buffer = BufferUtils.createIntBuffer(2);
glGenBuffers(int_buffer);
buffer_id = int_buffer.get(0);
indices_buffer_id = int_buffer.get(1);
glBindBuffer(GL_ARRAY_BUFFER, buffer_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_id);
final FloatBuffer vertices = BufferUtils.createFloatBuffer(2 * 4);
vertices
.put(-50).put(-50)
.put(50).put(-50)
.put(-50).put(50)
.put(50).put(50);
vertices.rewind();
final IntBuffer indices = BufferUtils.createIntBuffer(4);
indices.put(0).put(1).put(2).put(3);
indices.rewind();
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
}
/** Test entry point */
public static void main(String[] args) {
System.out.println("Change between fullscreen and windowed mode, by pressing F and W respectively");
System.out.println("Move quad using arrowkeys, and change rotation using +/-");
FullScreenWindowedTest fswTest = new FullScreenWindowedTest();
fswTest.execute();
System.exit(0);
}
}

View file

@ -0,0 +1,580 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* 3-D gear wheels. Originally by Brian Paul
*/
package org.lwjgl.test.opengles;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengles.*;
import org.lwjgl.test.opengles.util.Geometry;
import org.lwjgl.test.opengles.util.ImmediateModeBuffer;
import org.lwjgl.test.opengles.util.Shader;
import org.lwjgl.test.opengles.util.ShaderProgram;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import java.lang.reflect.Field;
import java.nio.FloatBuffer;
import java.util.StringTokenizer;
import static org.lwjgl.opengles.GLES20.*;
import static org.lwjgl.test.opengles.util.GLLight.*;
import static org.lwjgl.test.opengles.util.GLMatrix.*;
import static org.lwjgl.test.opengles.util.Geometry.*;
/**
* <p>
* This is the OpenGL "standard" Gears demo, originally by Brian Paul
* </p>
*
* @author Brian Matzon <brian@matzon.dk>
* @version $Revision: 3276 $
* $Id: Gears.java 3276 2010-02-21 21:18:17Z matzon $
*/
public class Gears {
private boolean run = true;
private float view_rotx = 20.0f;
private float view_roty = 30.0f;
private float view_rotz = 0.0f;
private Gear gear1;
private Gear gear2;
private Gear gear3;
private float angle = 0.0f;
private Shader vsh;
private Shader fsh;
private ShaderProgram program;
private int LIGHT_POS;
private int MVP;
private int NM;
private int GEAR_COLOR;
private int vPosition;
private int vNormal;
private final Matrix4f p = new Matrix4f();
private final Matrix4f mv = new Matrix4f();
private final Matrix4f mvp = new Matrix4f();
private final FloatBuffer m4fBuffer = BufferUtils.createFloatBuffer(4 * 4);
private final FloatBuffer m3fBuffer = BufferUtils.createFloatBuffer(3 * 3);
public static void main(String[] args) {
new Gears().execute();
System.exit(0);
}
/**
*
*/
private void execute() {
try {
init();
} catch (LWJGLException e) {
e.printStackTrace();
System.out.println("Failed to initialize Gears.");
return;
}
System.out.println("\nGL RENDERER: " + glGetString(GL_RENDERER));
System.out.println("GL VENDOR: " + glGetString(GL_VENDOR));
System.out.println("GL VERSION: " + glGetString(GL_VERSION));
System.out.println("GL_SHADING_LANGUAGE_VERSION: " + glGetString(GL_SHADING_LANGUAGE_VERSION));
System.out.println("GL_EXTENSIONS = " + glGetString(GL_EXTENSIONS));
ContextCapabilities caps = GLContext.getCapabilities();
System.out.println();
// Check extension support
Field[] field = ContextCapabilities.class.getFields();
for ( Field f : field ) {
if ( f.getName().startsWith("GL_") ) {
try {
System.out.println(f.getName() + " - " + f.getBoolean(caps));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
System.out.println();
// Check for extensions that LWJGL does not support
final String extensions = glGetString(GL_EXTENSIONS);
final StringTokenizer tokenizer = new StringTokenizer(extensions);
while ( tokenizer.hasMoreTokens() ) {
final String ext = tokenizer.nextToken();
try {
if ( !caps.getClass().getField(ext).getBoolean(caps) )
System.out.println("-- Extension exposed but functions are missing: " + ext);
} catch (NoSuchFieldException e) {
System.out.println("-- No LWJGL support for extension: " + ext);
} catch (Exception e) {
e.printStackTrace();
}
}
loop();
destroy();
}
/**
*
*/
private void destroy() {
program.destroy();
fsh.destroy();
vsh.destroy();
gear3.destroy();
gear2.destroy();
gear1.destroy();
Display.destroy();
}
/**
*
*/
private void loop() {
long lastFrameTime = Sys.getTime();
long startTime = System.currentTimeMillis() + 5000;
long fps = 0;
while ( run ) {
if ( !Display.isVisible() )
Thread.yield();
else {
// This is the current frame time.
long frameStart = Sys.getTime();
// How many seconds passed since last frame.
final float frameTime = (float)((frameStart - lastFrameTime) / (double)Sys.getTimerResolution());
lastFrameTime = frameStart;
angle += frameTime * 120.0f;
handleInput();
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COVERAGE_BUFFER_BIT_NV);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
glPushMatrix();
glTranslatef(-3.0f, -2.0f, 0.0f);
glRotatef(angle, 0.0f, 0.0f, 1.0f);
gear1.render();
glPopMatrix();
glPushMatrix();
glTranslatef(3.1f, -2.0f, 0.0f);
glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
gear2.render();
glPopMatrix();
glPushMatrix();
glTranslatef(-3.1f, 4.2f, 0.0f);
glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
gear3.render();
glPopMatrix();
glPopMatrix();
try {
Display.update();
//Display.sync(60);
} catch (PowerManagementEventException e) {
e.printStackTrace();
}
if ( startTime > System.currentTimeMillis() ) {
fps++;
} else {
long timeUsed = 5000 + (startTime - System.currentTimeMillis());
startTime = System.currentTimeMillis() + 5000;
System.out.println(fps + " frames in " + (timeUsed / 1000f) + " seconds = " + (fps / (timeUsed / 1000f)));
fps = 0;
}
if ( Display.isCloseRequested() )
break;
}
}
}
private void handleInput() {
if ( Keyboard.getNumKeyboardEvents() != 0 ) {
while ( Keyboard.next() ) {
if ( Keyboard.getEventKeyState() )
continue;
final int key = Keyboard.getEventKey();
switch ( key ) {
case Keyboard.KEY_ESCAPE:
run = false;
break;
}
}
}
while ( Mouse.next() ) ;
}
/**
*
*/
private void init() throws LWJGLException {
final int WIDTH = 640;
final int HEIGHT = 480;
Display.setLocation((Display.getDisplayMode().getWidth() - WIDTH) / 2,
(Display.getDisplayMode().getHeight() - HEIGHT) / 2);
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
} catch (PowerManagementEventException e) {
e.printStackTrace();
}
Display.setTitle("Gears");
Display.create(new PixelFormat());
//glCoverageMaskNV(true);
// setup ogl
glViewport(0, 0, WIDTH, HEIGHT);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
final Vector3f lp = new Vector3f(5.0f, 5.0f, 10.0f);
lp.normalise();
glLight(GL_LIGHT0, GL_POSITION, lp.getX(), lp.getY(), lp.getZ(), 0.0f);
/* make the gears */
gear1 = new Gear(gear(1.0f, 4.0f, 1.0f, 20, 0.7f), new float[] { 0.8f, 0.1f, 0.0f, 1.0f });
gear2 = new Gear(gear(0.5f, 2.0f, 2.0f, 10, 0.7f), new float[] { 0.0f, 0.8f, 0.2f, 1.0f });
gear3 = new Gear(gear(1.3f, 2.0f, 0.5f, 10, 0.7f), new float[] { 0.2f, 0.2f, 1.0f, 1.0f });
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
final float h = (float)300 / (float)300;
glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -40.0f);
vsh = new Shader(GL_VERTEX_SHADER, "uniform highp vec4 LIGHT_POS;\n" +
"uniform highp mat4 MODEL_VIEW_PROJECTION_MATRIX;\n" +
"uniform mediump mat3 NORMAL_MATRIX;\n" +
"uniform lowp vec3 GEAR_COLOR;\n" +
"attribute highp vec3 vPosition;\n" +
"attribute mediump vec3 vNormal;\n" +
"varying lowp vec3 color;\n" +
"void main(void) {\n" +
"\tgl_Position = MODEL_VIEW_PROJECTION_MATRIX * vec4(vPosition, 1.0);\n" +
"\tvec3 normal = NORMAL_MATRIX * vNormal;\n" +
"\tcolor = max(dot(normal, vec3(LIGHT_POS)), 0.0) * GEAR_COLOR + vec3(0.05);\n" +
"}");
fsh = new Shader(GL_FRAGMENT_SHADER, "varying lowp vec3 color;\n" +
"void main(void) {\n" +
"\tgl_FragColor = vec4(color, 1.0);\n" +
"}");
program = new ShaderProgram(vsh, fsh);
program.enable();
LIGHT_POS = program.getUniformLocation("LIGHT_POS");
MVP = program.getUniformLocation("MODEL_VIEW_PROJECTION_MATRIX");
NM = program.getUniformLocation("NORMAL_MATRIX");
GEAR_COLOR = program.getUniformLocation("GEAR_COLOR");
vPosition = program.getAttributeLocation("vPosition");
vNormal = program.getAttributeLocation("vNormal");
glEnableVertexAttribArray(vNormal);
glEnableVertexAttribArray(vPosition);
}
/**
* Draw a gear wheel. You'll probably want to call this function when
* building a display list since we do a lot of trig here.
*
* @param inner_radius radius of hole at center
* @param outer_radius radius at center of teeth
* @param width width of gear
* @param teeth number of teeth
* @param tooth_depth depth of tooth
*/
private static Geometry gear(float inner_radius, float outer_radius, float width, int teeth, float tooth_depth) {
int i;
float r0, r1, r2;
float angle, da;
float u, v, len;
r0 = inner_radius;
r1 = outer_radius - tooth_depth / 2.0f;
r2 = outer_radius + tooth_depth / 2.0f;
da = 2.0f * (float)Math.PI / teeth / 4.0f;
final Geometry gear = new Geometry();
final ImmediateModeBuffer imb = new ImmediateModeBuffer(1024);
int lastDrawIndex = 0;
//glShadeModel(GL_FLAT);
// draw front face
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, teeth * 4 + 2);
for ( i = 0; i <= teeth; i++ ) {
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f);
if ( i < teeth ) {
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle + 3.0f * da), r1 * sin(angle + 3.0f * da), width * 0.5f);
}
}
// draw front sides of teeth
for ( i = 0; i < teeth; i++ ) {
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, 4);
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle + 3.0f * da), r1 * sin(angle + 3.0f * da), width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r2 * cos(angle + 2.0f * da), r2 * sin(angle + 2.0f * da), width * 0.5f);
}
// draw back face
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, (teeth + 1) * 4);
for ( i = 0; i <= teeth; i++ ) {
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f);
}
// draw back sides of teeth
for ( i = 0; i < teeth; i++ ) {
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, 4);
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f);
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5f);
}
// draw outward faces of teeth
// OpenGL ES 2.0 note: This needs to be converted to a triangle
// list with face normals to get the flat look of the original.
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, teeth * 8 + 2);
for ( i = 0; i < teeth; i++ ) {
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(cos(angle), sin(angle), 0.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5f);
imb.glNormal3f(cos(angle), sin(angle), 0.0f);
imb.glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5f);
u = r2 * cos(angle + da) - r1 * cos(angle);
v = r2 * sin(angle + da) - r1 * sin(angle);
len = (float)Math.sqrt(u * u + v * v);
u /= len;
v /= len;
imb.glNormal3f(v, -u, 0.0f);
imb.glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5f);
imb.glNormal3f(v, -u, 0.0f);
imb.glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5f);
imb.glNormal3f(cos(angle), sin(angle), 0.0f);
imb.glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5f);
imb.glNormal3f(cos(angle), sin(angle), 0.0f);
imb.glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5f);
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
imb.glNormal3f(v, -u, 0.0f);
imb.glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5f);
imb.glNormal3f(v, -u, 0.0f);
imb.glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5f);
}
imb.glNormal3f(cos(0), sin(0), 0.0f);
imb.glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5f);
imb.glNormal3f(cos(0), sin(0), 0.0f);
imb.glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5f);
//glShadeModel(GL_SMOOTH);
// draw inside radius cylinder
lastDrawIndex += gear.addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, (teeth + 1) * 2);
for ( i = 0; i <= teeth; i++ ) {
angle = i * 2.0f * (float)Math.PI / teeth;
imb.glNormal3f(-cos(angle), -sin(angle), 0.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5f);
imb.glNormal3f(-cos(angle), -sin(angle), 0.0f);
imb.glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5f);
}
gear.update(imb.getBuffer());
return gear;
}
private class Gear {
private final Geometry geom;
private final float[] color;
Gear(final Geometry geom, final float[] color) {
this.geom = geom;
this.color = color;
}
void render() {
// Set gear color
glUniform3f(GEAR_COLOR, color[0], color[1], color[2]);
// Set Light position
setUniform4f(LIGHT_POS, GL_LIGHT0, GL_POSITION);
// Get Projection and Modelview matrices
glMatrixMode(GL_PROJECTION);
glGetMatrix(p);
glMatrixMode(GL_MODELVIEW);
glGetMatrix(mv);
// Set MVP uniform
Matrix4f.mul(p, mv, mvp);
mvp.store(m4fBuffer);
m4fBuffer.flip();
glUniformMatrix4(MVP, false, m4fBuffer);
// Set normal matrix (upper-left 3x3 of the inverse transpose MV matrix)
mv.invert();
mv.transpose();
mv.store3f(m3fBuffer);
m3fBuffer.flip();
glUniformMatrix3(NM, false, m3fBuffer);
geom.bind();
final int stride = (3 + 3) * 4;
glVertexAttribPointer(vNormal, 3, GL_FLOAT, false, stride, 0);
glVertexAttribPointer(vPosition, 3, GL_FLOAT, false, stride, 3 * 4);
geom.draw();
}
void destroy() {
geom.destroy();
}
}
}

View file

@ -0,0 +1,251 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* $Id: VBOIndexTest.java 2983 2008-04-07 18:36:09Z matzon $
*
* Simple java test program.
*
* @author elias_naur <elias_naur@users.sourceforge.net>
* @version $Revision: 2983 $
*/
package org.lwjgl.test.opengles;
import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengles.GLContext;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.opengles.GLES20.*;
import static org.lwjgl.opengles.OESMapbuffer.*;
import static org.lwjgl.test.opengles.util.GLMatrix.*;
public final class MappedIndexedVBOTest {
static {
try {
//find first display mode that allows us 640*480*16
int mode = -1;
DisplayMode[] modes = Display.getAvailableDisplayModes();
for ( int i = 0; i < modes.length; i++ ) {
if ( modes[i].getWidth() == 640
&& modes[i].getHeight() == 480
&& modes[i].getBitsPerPixel() >= 16 ) {
mode = i;
break;
}
}
if ( mode != -1 ) {
//select above found displaymode
System.out.println("Setting display mode to " + modes[mode]);
Display.setDisplayMode(modes[mode]);
System.out.println("Created display.");
}
} catch (Exception e) {
System.err.println("Failed to create display due to " + e);
}
}
static {
try {
Display.createES();
System.out.println("Created OpenGL.");
if ( !GLContext.getCapabilities().GL_OES_mapbuffer ) {
System.out.println("GL_OES_mapbuffer is not supported, quitting!");
System.exit(0);
}
} catch (Exception e) {
System.err.println("Failed to create OpenGL due to " + e);
System.exit(1);
}
}
/** Is the game finished? */
private static boolean finished;
/** A rotating square! */
private static float angle;
private static int buffer_id;
private static int indices_buffer_id;
private static FloatBuffer vertices;
private static ByteBuffer mapped_buffer;
private static FloatBuffer mapped_float_buffer;
private static IntBuffer indices;
private static ByteBuffer mapped_indices_buffer;
private static IntBuffer mapped_indices_int_buffer;
private static QuadRenderer renderer;
public static void main(String[] arguments) {
try {
init();
while ( !finished ) {
Display.update();
Display.sync(30);
if ( !Display.isVisible() )
Thread.sleep(200);
else if ( Display.isCloseRequested() )
System.exit(0);
mainLoop();
render();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
cleanup();
}
System.exit(0);
}
/** All calculations are done in here */
private static void mainLoop() {
angle += 1f;
if ( angle > 360.0f )
angle = 0.0f;
if ( Mouse.getDX() != 0 || Mouse.getDY() != 0 || Mouse.getDWheel() != 0 )
System.out.println("Mouse moved " + Mouse.getDX() + " " + Mouse.getDY() + " " + Mouse.getDWheel());
for ( int i = 0; i < Mouse.getButtonCount(); i++ )
if ( Mouse.isButtonDown(i) )
System.out.println("Button " + i + " down");
if ( Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) )
finished = true;
for ( int i = 0; i < Keyboard.getNumKeyboardEvents(); i++ ) {
Keyboard.next();
if ( Keyboard.getEventKey() == Keyboard.KEY_ESCAPE && Keyboard.getEventKeyState() )
finished = true;
if ( Keyboard.getEventKey() == Keyboard.KEY_T && Keyboard.getEventKeyState() )
System.out.println("Current time: " + Sys.getTime());
}
}
/** All rendering is done in here */
private static void render() {
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(Display.getDisplayMode().getWidth() / 2, Display.getDisplayMode().getHeight() / 2, 0.0f);
glRotatef(angle, 0, 0, 1.0f);
renderer.setMVPUniform();
ByteBuffer new_mapped_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES, mapped_buffer);
if ( new_mapped_buffer != mapped_buffer ) {
mapped_buffer = new_mapped_buffer;
mapped_float_buffer = new_mapped_buffer.asFloatBuffer();
}
new_mapped_buffer = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES, mapped_indices_buffer);
if ( new_mapped_buffer != mapped_indices_buffer ) {
mapped_indices_buffer = new_mapped_buffer;
mapped_indices_int_buffer = new_mapped_buffer.asIntBuffer();
}
mapped_float_buffer.rewind();
vertices.rewind();
mapped_float_buffer.put(vertices);
mapped_indices_int_buffer.rewind();
indices.rewind();
mapped_indices_int_buffer.put(indices);
if ( glUnmapBufferOES(GL_ARRAY_BUFFER) &&
glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER) ) {
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
}
glPopMatrix();
}
/** Initialize */
private static void init() throws Exception {
System.out.println("Timer resolution: " + Sys.getTimerResolution());
// Go into orthographic projection mode.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getDisplayMode().getWidth(), 0, Display.getDisplayMode().getHeight(), -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight());
final IntBuffer int_buffer = BufferUtils.createIntBuffer(2);
glGenBuffers(int_buffer);
buffer_id = int_buffer.get(0);
indices_buffer_id = int_buffer.get(1);
glBindBuffer(GL_ARRAY_BUFFER, buffer_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_id);
vertices = BufferUtils.createFloatBuffer(2 * 4);
vertices
.put(-50).put(-50)
.put(50).put(-50)
.put(-50).put(50)
.put(50).put(50);
vertices.rewind();
indices = BufferUtils.createIntBuffer(4);
indices.put(0).put(1).put(2).put(3);
indices.rewind();
glBufferData(GL_ARRAY_BUFFER, 2 * 4 * 4, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * 4, GL_STREAM_DRAW);
renderer = new QuadRenderer();
}
/** Cleanup */
private static void cleanup() {
renderer.cleanup();
IntBuffer int_buffer = BufferUtils.createIntBuffer(2);
int_buffer.put(0, buffer_id);
int_buffer.put(1, indices_buffer_id);
glDeleteBuffers(int_buffer);
Display.destroy();
}
}

View file

@ -0,0 +1,70 @@
package org.lwjgl.test.opengles;
import org.lwjgl.BufferUtils;
import org.lwjgl.test.opengles.util.Shader;
import org.lwjgl.test.opengles.util.ShaderProgram;
import org.lwjgl.util.vector.Matrix4f;
import java.nio.FloatBuffer;
import static org.lwjgl.opengles.GLES20.*;
import static org.lwjgl.test.opengles.util.GLMatrix.*;
final class QuadRenderer {
private final Shader vsh;
private final Shader fsh;
private final ShaderProgram program;
private final int uniMVP;
private final Matrix4f p = new Matrix4f();
private final Matrix4f mv = new Matrix4f();
private final Matrix4f mvp = new Matrix4f();
private final FloatBuffer m4fBuffer = BufferUtils.createFloatBuffer(4 * 4);
QuadRenderer() {
vsh = new Shader(GL_VERTEX_SHADER, "uniform highp mat4 MODEL_VIEW_PROJECTION_MATRIX;\n" +
"attribute highp vec2 vPosition;\n" +
"void main(void) {\n" +
"\tgl_Position = MODEL_VIEW_PROJECTION_MATRIX * vec4(vPosition, 0.0, 1.0);\n" +
"}");
fsh = new Shader(GL_FRAGMENT_SHADER, "void main(void) {\n" +
"\tgl_FragColor = vec4(1.0);\n" +
"}");
program = new ShaderProgram(vsh, fsh);
program.enable();
uniMVP = program.getUniformLocation("MODEL_VIEW_PROJECTION_MATRIX");
final int vPosition = program.getAttributeLocation("vPosition");
glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(vPosition);
}
void setMVPUniform() {
// Get Projection and Modelview matrices
glMatrixMode(GL_PROJECTION);
glGetMatrix(p);
glMatrixMode(GL_MODELVIEW);
glGetMatrix(mv);
// Set MVP uniform
Matrix4f.mul(p, mv, mvp);
mvp.store(m4fBuffer);
m4fBuffer.flip();
glUniformMatrix4(uniMVP, false, m4fBuffer);
}
void cleanup() {
program.destroy();
fsh.destroy();
vsh.destroy();
}
}

View file

@ -0,0 +1,99 @@
package org.lwjgl.test.opengles.util;
import java.nio.*;
import static org.lwjgl.opengles.GLES20.*;
import static org.lwjgl.opengles.OESMapbuffer.*;
abstract class BufferObject implements GLObject {
protected final int ID;
protected int target;
protected int usage;
/** The BufferObject data size in bytes. */
private int size;
protected BufferObject(final int type, final int usage) {
this.ID = glGenBuffers();
this.target = type;
this.usage = usage;
}
protected BufferObject(final int type, final int usage, final Buffer buffer) {
this(type, usage);
setData(buffer);
}
protected BufferObject(final int type, final int usage, final int dataSize) {
this(type, usage);
setData(dataSize);
}
public final int getID() {
return ID;
}
public void destroy() {
glDeleteBuffers(ID);
}
public final int getTarget() {
return target;
}
public final int getUsage() {
return usage;
}
public final int getSize() {
return size;
}
public abstract void enable();
public abstract void disable();
public final void setData(final Buffer buffer) {
enable();
if ( buffer instanceof ByteBuffer ) {
glBufferData(target, (ByteBuffer)buffer, usage);
size = buffer.remaining();
} else if ( buffer instanceof ShortBuffer ) {
glBufferData(target, (ShortBuffer)buffer, usage);
size = buffer.remaining() << 1;
} else if ( buffer instanceof IntBuffer ) {
glBufferData(target, (IntBuffer)buffer, usage);
size = buffer.remaining() << 2;
} else if ( buffer instanceof FloatBuffer ) {
glBufferData(target, (FloatBuffer)buffer, usage);
size = buffer.remaining() << 2;
}
disable();
}
public final void setData(final int dataSize) {
enable();
glBufferData(target, dataSize, usage);
size = dataSize;
disable();
}
public final ByteBuffer map(final int access, final ByteBuffer oldBuffer) {
return glMapBufferOES(target, access, oldBuffer);
}
public final ByteBuffer map(final int access, final int length, final ByteBuffer oldBuffer) {
return glMapBufferOES(target, access, length, oldBuffer);
}
public final boolean unmap() {
return glUnmapBufferOES(target);
}
}

View file

@ -0,0 +1,41 @@
package org.lwjgl.test.opengles.util;
import java.nio.Buffer;
import static org.lwjgl.opengles.GLES20.*;
public final class BufferObjectArray extends BufferObject {
private static int boundBOArray;
public BufferObjectArray(final int usage) {
super(GL_ARRAY_BUFFER, usage);
}
public BufferObjectArray(final int usage, final Buffer buffer) {
super(GL_ARRAY_BUFFER, usage, buffer);
}
public BufferObjectArray(final int usage, final int dataSize) {
super(GL_ARRAY_BUFFER, usage, dataSize);
}
public void enable() {
if ( boundBOArray != ID ) {
glBindBuffer(GL_ARRAY_BUFFER, ID);
boundBOArray = ID;
}
}
public void disable() {
boArrayDisable();
}
public static void boArrayDisable() {
if ( boundBOArray != 0 ) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
boundBOArray = 0;
}
}
}

View file

@ -0,0 +1,41 @@
package org.lwjgl.test.opengles.util;
import java.nio.Buffer;
import static org.lwjgl.opengles.GLES20.*;
public final class BufferObjectElement extends BufferObject {
private static int boundBOElementArray;
public BufferObjectElement(final int usage) {
super(GL_ELEMENT_ARRAY_BUFFER, usage);
}
public BufferObjectElement(final int usage, final Buffer buffer) {
super(GL_ELEMENT_ARRAY_BUFFER, usage, buffer);
}
public BufferObjectElement(final int usage, final int dataSize) {
super(GL_ELEMENT_ARRAY_BUFFER, usage, dataSize);
}
public void enable() {
if ( boundBOElementArray != ID ) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ID);
boundBOElementArray = ID;
}
}
public void disable() {
boElementArrayDisable();
}
public static void boElementArrayDisable() {
if ( boundBOElementArray != 0 ) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
boundBOElementArray = 0;
}
}
}

View file

@ -0,0 +1,165 @@
package org.lwjgl.test.opengles.util;
import static org.lwjgl.opengles.GLES20.*;
/** Emulates the light state in fixed-function OpenGL. */
public class GLLight {
public static final int GL_LIGHT0 = 0x4000;
public static final int GL_LIGHT1 = 0x4001;
public static final int GL_LIGHT2 = 0x4002;
public static final int GL_LIGHT3 = 0x4003;
public static final int GL_LIGHT4 = 0x4004;
public static final int GL_LIGHT5 = 0x4005;
public static final int GL_LIGHT6 = 0x4006;
public static final int GL_LIGHT7 = 0x4007;
public static final int GL_AMBIENT = 0x1200;
public static final int GL_DIFFUSE = 0x1201;
public static final int GL_SPECULAR = 0x1202;
public static final int GL_POSITION = 0x1203;
public static final int GL_SPOT_DIRECTION = 0x1204;
public static final int GL_SPOT_EXPONENT = 0x1205;
public static final int GL_SPOT_CUTOFF = 0x1206;
public static final int GL_CONSTANT_ATTENUATION = 0x1207;
public static final int GL_LINEAR_ATTENUATION = 0x1208;
public static final int GL_QUADRATIC_ATTENUATION = 0x1209;
private static final Light[] lights = new Light[8];
static {
for ( int i = 0; i < lights.length; i++ )
lights[i] = new Light();
System.arraycopy(new float[] { 1.0f, 1.0f, 1.0f, 1.0f }, 0, lights[0].diffuse, 0, 4);
System.arraycopy(new float[] { 1.0f, 1.0f, 1.0f, 1.0f }, 0, lights[0].specular, 0, 4);
}
private GLLight() {
}
public static void glLight(final int light, final int pname, final float v) {
if ( light < GL_LIGHT0 || GL_LIGHT7 < light )
throw new IllegalArgumentException("Invalid light specified: " + light);
final Light l = lights[light - GL_LIGHT0];
switch ( pname ) {
case GL_SPOT_EXPONENT:
l.s = v;
break;
case GL_SPOT_CUTOFF:
l.c = v;
break;
case GL_CONSTANT_ATTENUATION:
l.k0 = v;
break;
case GL_LINEAR_ATTENUATION:
l.k1 = v;
break;
case GL_QUADRATIC_ATTENUATION:
l.k2 = v;
break;
default:
throw new IllegalArgumentException("Invalid light parameter specified: " + pname);
}
}
public static void glLight(final int light, final int pname,
final float x, final float y, final float z) {
if ( light < GL_LIGHT0 || GL_LIGHT7 < light )
throw new IllegalArgumentException("Invalid light specified: " + light);
if ( pname != GL_SPOT_DIRECTION )
throw new IllegalArgumentException("Invalid light parameter specified: " + pname);
final float[] param = lights[light - GL_LIGHT0].direction;
param[0] = x;
param[1] = y;
param[2] = z;
}
private static float[] getParam4f(final int light, final int pname) {
if ( light < GL_LIGHT0 || GL_LIGHT7 < light )
throw new IllegalArgumentException("Invalid light specified: " + light);
final Light l = lights[light - GL_LIGHT0];
switch ( pname ) {
case GL_AMBIENT:
return l.ambient;
case GL_DIFFUSE:
return l.diffuse;
case GL_SPECULAR:
return l.specular;
case GL_POSITION:
return l.position;
default:
throw new IllegalArgumentException("Invalid light parameter specified: " + pname);
}
}
public static void glLight(final int light, final int pname,
final float x, final float y, final float z, final float w) {
final float[] param = getParam4f(light, pname);
param[0] = x;
param[1] = y;
param[2] = z;
param[3] = w;
}
public static void setUniform1f(final int location, final int light, final int pname) {
if ( light < GL_LIGHT0 || GL_LIGHT7 < light )
throw new IllegalArgumentException("Invalid light specified: " + light);
final Light l = lights[light - GL_LIGHT0];
switch ( pname ) {
case GL_SPOT_EXPONENT:
glUniform1f(location, l.s);
break;
case GL_SPOT_CUTOFF:
glUniform1f(location, l.c);
break;
case GL_CONSTANT_ATTENUATION:
glUniform1f(location, l.k0);
break;
case GL_LINEAR_ATTENUATION:
glUniform1f(location, l.k1);
break;
case GL_QUADRATIC_ATTENUATION:
glUniform1f(location, l.k2);
break;
default:
throw new IllegalArgumentException("Invalid light parameter specified: " + pname);
}
}
public static void setUniform3f(final int location, final int light, final int pname) {
if ( pname != GL_SPOT_DIRECTION )
throw new IllegalArgumentException("Invalid light parameter specified: " + pname);
final float[] param = lights[light - GL_LIGHT0].direction;
glUniform3f(location, param[0], param[1], param[2]);
}
public static void setUniform4f(final int location, final int light, final int pname) {
final float[] param = getParam4f(light, pname);
glUniform4f(location, param[0], param[1], param[2], param[3]);
}
private static class Light {
float[] ambient = { 0.0f, 0.0f, 0.0f, 1.0f };
float[] diffuse = { 0.0f, 0.0f, 0.0f, 1.0f };
float[] specular = { 0.0f, 0.0f, 0.0f, 1.0f };
float[] position = { 0.0f, 0.0f, 1.0f, 0.0f };
float[] direction = { 0.0f, 0.0f, -1.0f };
float s, c = 180.0f;
float k0 = 1.0f, k1, k2;
}
}

View file

@ -0,0 +1,163 @@
package org.lwjgl.test.opengles.util;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import java.util.Stack;
import static java.lang.Math.*;
/** Emulates the matrix stack in fixed-function OpenGL. */
public final class GLMatrix {
public static final int GL_MODELVIEW = 0x1700;
public static final int GL_PROJECTION = 0x1701;
private static final float PI = (float)Math.PI;
/** The model/view matrix stack. */
private static final Stack<Matrix4f> mvMatrixStack = new Stack<Matrix4f>();
/** The projection matrix stack. */
private static final Stack<Matrix4f> pMatrixStack = new Stack<Matrix4f>();
private static final Matrix4f m4f = new Matrix4f();
private static final Vector3f v3f = new Vector3f();
private static int mode = GL_MODELVIEW;
static {
mvMatrixStack.push(new Matrix4f());
pMatrixStack.push(new Matrix4f());
}
private GLMatrix() {
}
private static Stack<Matrix4f> getCurrentStack() {
switch ( mode ) {
case GL_MODELVIEW:
return mvMatrixStack;
case GL_PROJECTION:
return pMatrixStack;
default:
return null; // Cannot happen
}
}
private static Matrix4f getCurrentMatrix() {
return getCurrentStack().peek();
}
public static void glMatrixMode(final int mode) {
if ( mode != GL_MODELVIEW && mode != GL_PROJECTION )
throw new IllegalArgumentException("Invalid matrix mode specified: " + mode);
GLMatrix.mode = mode;
}
public static void glPushMatrix() {
final Stack<Matrix4f> stack = getCurrentStack();
stack.push(new Matrix4f(stack.peek()));
}
public static void glPopMatrix() {
final Stack<Matrix4f> stack = getCurrentStack();
if ( stack.size() == 1 )
throw new IllegalStateException("The last matrix in the stack cannot be popped.");
getCurrentStack().pop();
}
public static void glLoadIdentity() {
final Matrix4f m = getCurrentMatrix();
m.setIdentity();
}
public static void glLoadMatrix(final Matrix4f s) {
getCurrentMatrix().load(s);
}
public static void glMultMatrix(final Matrix4f m) {
final Matrix4f c = getCurrentMatrix();
Matrix4f.mul(c, m, c);
}
public static void glTranslatef(final float x, final float y, final float z) {
final Matrix4f m = getCurrentMatrix();
v3f.set(x, y, z);
m.translate(v3f);
}
public static void glRotatef(final float angle, final float x, final float y, final float z) {
final Matrix4f m = getCurrentMatrix();
v3f.set(x, y, z);
m.rotate((float)toRadians(angle), v3f);
}
public static void glOrtho(final float l, final float r, final float b, final float t, final float n, final float f) {
final Matrix4f m = m4f;
m.setIdentity();
m.m00 = 2.0f / (r - l);
m.m30 = -(r + l) / (r - l);
m.m11 = 2.0f / (t - b);
m.m31 = -(t + b) / (t - b);
m.m22 = -2.0f / (f - n);
m.m32 = -(f + n) / (f - n);
glMultMatrix(m);
}
public static void glFrustum(final float l, final float r, final float b, final float t, final float n, final float f) {
final Matrix4f m = m4f;
m.setIdentity();
m.m00 = 2.0f * n / (r - l);
m.m20 = (r + l) / (r - l);
m.m11 = 2.0f * n / (t - b);
m.m21 = (t + b) / (t - b);
m.m22 = -(f + n) / (f - n);
m.m32 = -(2.0f * f * n) / (f - n);
m.m23 = -1.0f;
m.m33 = 0.0f;
glMultMatrix(m);
}
public static void gluPerspective(final float fovy, final float aspect, final float zNear, final float zFar) {
final float radians = fovy / 2.0f * PI / 180.0f;
final float deltaZ = zFar - zNear;
final float sine = (float)sin(radians);
if ( (deltaZ == 0) || (sine == 0) || (aspect == 0) ) {
return;
}
final float cotangent = (float)cos(radians) / sine;
final Matrix4f m = m4f;
m.setIdentity();
m.m00 = cotangent / aspect;
m.m11 = cotangent;
m.m22 = -(zFar + zNear) / deltaZ;
m.m23 = -1.0f;
m.m32 = -2 * zNear * zFar / deltaZ;
m.m33 = 0.0f;
glMultMatrix(m);
}
public static void glGetMatrix(final Matrix4f d) {
d.load(getCurrentMatrix());
}
}

View file

@ -0,0 +1,9 @@
package org.lwjgl.test.opengles.util;
public interface GLObject {
int getID();
void destroy();
}

View file

@ -0,0 +1,78 @@
package org.lwjgl.test.opengles.util;
import org.lwjgl.test.opengles.util.BufferObjectArray;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengles.GLES20.*;
public class Geometry {
protected BufferObjectArray bo;
protected final List<DrawCommand> drawCommands = new ArrayList<DrawCommand>(4);
public Geometry() {
}
public Geometry(final FloatBuffer buffer) {
update(buffer);
}
public void update(final FloatBuffer buffer) {
if ( bo != null )
destroy();
bo = new BufferObjectArray(GL_STATIC_DRAW, buffer);
}
public void bind() {
bo.enable();
}
public void draw() {
for ( DrawCommand command : drawCommands )
command.draw();
}
public void destroy() {
bo.destroy();
bo = null;
drawCommands.clear();
}
public int addDrawCommand(final int mode, final int first, final int count) {
drawCommands.add(new DrawCommand(mode, first, count));
return count;
}
public static float sin(final float r) {
return (float)Math.sin(r);
}
public static float cos(final float r) {
return (float)Math.cos(r);
}
protected static class DrawCommand {
private int mode;
private int first;
private int count;
private DrawCommand(final int mode, final int first, final int count) {
this.mode = mode;
this.first = first;
this.count = count;
}
void draw() {
glDrawArrays(mode, first, count);
}
}
}

View file

@ -0,0 +1,58 @@
package org.lwjgl.test.opengles.util;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
/**
* Utility class that emulates immediate mode vertex data submission.
* Can be used to create VBO data.
*/
public final class ImmediateModeBuffer {
private FloatBuffer buffer;
public ImmediateModeBuffer(final int startSize) {
this.buffer = BufferUtils.createFloatBuffer(startSize);
}
private void checkSize(final int count) {
while ( buffer.remaining() < count ) {
final FloatBuffer newBuffer = BufferUtils.createFloatBuffer(buffer.capacity() << 1);
buffer.flip();
newBuffer.put(buffer);
buffer = newBuffer;
}
}
public FloatBuffer getBuffer() {
buffer.flip();
return buffer;
}
public void glVertex2f(final float x, final float y) {
checkSize(2);
buffer.put(x).put(y);
}
public void glVertex3f(final float x, final float y, final float z) {
checkSize(3);
buffer.put(x).put(y).put(z);
}
public void glVertex4f(final float x, final float y, final float z, final float w) {
checkSize(4);
buffer.put(x).put(y).put(z).put(w);
}
public void glNormal3f(final float x, final float y, final float z) {
checkSize(3);
buffer.put(x).put(y).put(z);
}
public void glTexCoord2f(final float s, final float t) {
checkSize(2);
buffer.put(s).put(t);
}
}

View file

@ -0,0 +1,98 @@
package org.lwjgl.test.opengles.util;
import org.lwjgl.BufferUtils;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import static org.lwjgl.opengles.GLES20.*;
public class Shader implements GLObject {
protected static ByteBuffer fileBuffer = BufferUtils.createByteBuffer(1024 * 10);
private int type;
private int ID;
public Shader() {
}
public Shader(final int type, final CharSequence source) {
createFromSource(type, source);
}
public int getID() {
return ID;
}
public int getType() {
return type;
}
public void destroy() {
if ( ID == 0 )
throw new IllegalStateException("The shader has not been created");
glDeleteShader(ID);
ID = 0;
}
public void createFromFile(final int type, final ClassLoader loader, final String file) throws IOException {
final InputStream inputStream = loader.getResourceAsStream(file);
if ( inputStream == null )
throw new IllegalArgumentException("A shader source file could not be found: " + file);
final BufferedInputStream stream = new BufferedInputStream(inputStream);
byte character;
while ( (character = (byte)stream.read()) != -1 )
fileBuffer.put(character);
fileBuffer.flip();
stream.close();
final byte[] array = new byte[fileBuffer.remaining()];
fileBuffer.get(array);
final String source = new String(array);
fileBuffer.clear();
createFromSource(type, source);
}
public void createFromSource(final int type, final CharSequence source) {
if ( ID != 0 )
throw new IllegalStateException("The shader has already been created");
this.type = type;
this.ID = glCreateShader(type);
glShaderSource(ID, source);
glCompileShader(ID);
if ( glGetShader(ID, GL_COMPILE_STATUS) == GL_FALSE ) {
printInfoLog();
destroy();
throw new RuntimeException("A compilation error occured in a shader.");
}
}
public void printInfoLog() {
if ( ID == 0 )
throw new IllegalStateException("The shader has not been created");
final int logLength = glGetShader(ID, GL_INFO_LOG_LENGTH);
if ( logLength <= 1 )
return;
System.out.println("\nInfo Log of Shader Object: " + ID);
System.out.println("--------------------------");
System.out.println(glGetShaderInfoLog(ID, logLength));
}
}

View file

@ -0,0 +1,82 @@
package org.lwjgl.test.opengles.util;
import static org.lwjgl.opengles.GLES20.*;
public class ShaderProgram implements GLObject {
private final int ID;
public ShaderProgram(final Shader... shaders) {
this.ID = glCreateProgram();
for ( Shader shader : shaders )
glAttachShader(ID, shader.getID());
glLinkProgram(ID);
if ( glGetProgram(ID, GL_LINK_STATUS) == GL_FALSE ) {
printInfoLog();
destroy();
throw new RuntimeException("Failed to link a Shader Program: " + ID);
}
}
public void validate() {
glValidateProgram(ID);
final boolean error = glGetProgram(ID, GL_VALIDATE_STATUS) == GL_FALSE;
if ( error ) {
printInfoLog();
throw new RuntimeException("Failed to validate a Shader Program.");
}
}
public int getID() {
return ID;
}
public void destroy() {
glDeleteProgram(ID);
}
public void enable() {
glUseProgram(ID);
}
public static void disable() {
glUseProgram(0);
}
public int getUniformLocation(final String uniform) {
final int location = glGetUniformLocation(ID, uniform);
if ( location == -1 )
throw new IllegalArgumentException("Invalid uniform name specified: " + uniform);
return location;
}
public int getAttributeLocation(final String attrib) {
final int location = glGetAttribLocation(ID, attrib);
if ( location == -1 )
throw new IllegalArgumentException("Invalid attribute name specified: " + attrib);
return location;
}
private void printInfoLog() {
final int logLength = glGetProgram(ID, GL_INFO_LOG_LENGTH);
System.out.println(logLength);
if ( logLength <= 1 )
return;
System.out.println("\nInfo Log of Shader Program: " + ID);
System.out.println("-------------------");
System.out.println(glGetProgramInfoLog(ID, logLength));
System.out.println("-------------------");
}
}

View file

@ -0,0 +1,414 @@
package org.lwjgl.test.opengles.util;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengles.GLES20.*;
/** VBO implementation of GLU Sphere. */
public final class Sphere {
/* QuadricNormal */
public static final int GLU_SMOOTH = 100000;
public static final int GLU_FLAT = 100001;
public static final int GLU_NONE = 100002;
/* QuadricDrawStyle */
public static final int GLU_POINT = 100010;
public static final int GLU_LINE = 100011;
public static final int GLU_FILL = 100012;
public static final int GLU_SILHOUETTE = 100013;
/* QuadricOrientation */
public static final int GLU_OUTSIDE = 100020;
public static final int GLU_INSIDE = 100021;
static final float PI = (float)Math.PI;
private int drawStyle;
private int orientation;
private boolean textureFlag;
private int normals;
private BufferObjectArray bo;
private final List<DrawCommand> drawCommands = new ArrayList<DrawCommand>(4);
public Sphere() {
this(GLU_FILL, GLU_OUTSIDE, false, GLU_SMOOTH);
}
public Sphere(final int drawStyle, final int orientation, final boolean textureFlag, final int normals) {
setDrawStyle(drawStyle);
setOrientation(orientation);
setTextureFlag(textureFlag);
setNormals(normals);
}
public Sphere(final float radius, final int slices, final int stacks) {
this();
updateGeometry(radius, slices, stacks);
}
public Sphere(final float radius, final int slices, final int stacks,
final int drawStyle, final int orientation, final boolean textureFlag, final int normals) {
this(drawStyle, orientation, textureFlag, normals);
updateGeometry(radius, slices, stacks);
}
public void updateGeometry(final float radius, final int slices, final int stacks) {
if ( bo != null )
destroy();
bo = new BufferObjectArray(GL_STATIC_DRAW, createBuffer(radius, slices, stacks));
}
public void bind() {
bo.enable();
}
public void draw() {
for ( DrawCommand command : drawCommands )
command.draw();
}
public void destroy() {
bo.destroy();
bo = null;
drawCommands.clear();
}
/**
* specifies the draw style for quadrics.
* <p/>
* The legal values are as follows:
* <p/>
* GLU.FILL: Quadrics are rendered with polygon primitives. The polygons
* are drawn in a counterclockwise fashion with respect to
* their normals (as defined with glu.quadricOrientation).
* <p/>
* GLU.LINE: Quadrics are rendered as a set of lines.
* <p/>
* GLU.SILHOUETTE: Quadrics are rendered as a set of lines, except that edges
* separating coplanar faces will not be drawn.
* <p/>
* GLU.POINT: Quadrics are rendered as a set of points.
*
* @param drawStyle The drawStyle to set
*/
public void setDrawStyle(int drawStyle) {
switch ( drawStyle ) {
case GLU_FILL:
case GLU_LINE:
case GLU_SILHOUETTE:
case GLU_POINT:
break;
default:
throw new IllegalArgumentException("Invalid draw style specified: " + drawStyle);
}
this.drawStyle = drawStyle;
}
/**
* specifies what kind of normals are desired for quadrics.
* The legal values are as follows:
* <p/>
* GLU.NONE: No normals are generated.
* <p/>
* GLU.FLAT: One normal is generated for every facet of a quadric.
* <p/>
* GLU.SMOOTH: One normal is generated for every vertex of a quadric. This
* is the default.
*
* @param normals The normals to set
*/
public void setNormals(int normals) {
switch ( normals ) {
case GLU_NONE:
case GLU_FLAT:
case GLU_SMOOTH:
break;
default:
throw new IllegalArgumentException("Invalid normal kind specified: " + normals);
}
this.normals = normals;
}
/**
* specifies what kind of orientation is desired for.
* The orientation values are as follows:
* <p/>
* GLU.OUTSIDE: Quadrics are drawn with normals pointing outward.
* <p/>
* GLU.INSIDE: Normals point inward. The default is GLU.OUTSIDE.
* <p/>
* Note that the interpretation of outward and inward depends on the quadric
* being drawn.
*
* @param orientation The orientation to set
*/
public void setOrientation(int orientation) {
if ( orientation != GLU_OUTSIDE && orientation != GLU_INSIDE )
throw new IllegalArgumentException("Invalid orientation specified: " + orientation);
this.orientation = orientation;
}
/**
* specifies if texture coordinates should be generated for
* quadrics rendered with qobj. If the value of textureCoords is true,
* then texture coordinates are generated, and if textureCoords is false,
* they are not.. The default is false.
* <p/>
* The manner in which texture coordinates are generated depends upon the
* specific quadric rendered.
*
* @param textureFlag The textureFlag to set
*/
public void setTextureFlag(boolean textureFlag) {
this.textureFlag = textureFlag;
}
/**
* Returns the drawStyle.
*
* @return int
*/
public int getDrawStyle() {
return drawStyle;
}
/**
* Returns the normals.
*
* @return int
*/
public int getNormals() {
return normals;
}
/**
* Returns the orientation.
*
* @return int
*/
public int getOrientation() {
return orientation;
}
/**
* Returns the textureFlag.
*
* @return boolean
*/
public boolean getTextureFlag() {
return textureFlag;
}
private static float sin(final float r) {
return (float)Math.sin(r);
}
private static float cos(final float r) {
return (float)Math.cos(r);
}
private int addDrawCommand(final int mode, final int first, final int count) {
drawCommands.add(new DrawCommand(mode, first, count));
return count;
}
/**
* draws a sphere of the given radius centered around the origin.
* The sphere is subdivided around the z axis into slices and along the z axis
* into stacks (similar to lines of longitude and latitude).
* <p/>
* If the orientation is set to GLU.OUTSIDE (with glu.quadricOrientation), then
* any normals generated point away from the center of the sphere. Otherwise,
* they point toward the center of the sphere.
* <p/>
* If texturing is turned on (with glu.quadricTexture), then texture
* coordinates are generated so that t ranges from 0.0 at z=-radius to 1.0 at
* z=radius (t increases linearly along longitudinal lines), and s ranges from
* 0.0 at the +y axis, to 0.25 at the +x axis, to 0.5 at the -y axis, to 0.75
* at the -x axis, and back to 1.0 at the +y axis.
*/
public FloatBuffer createBuffer(float radius, int slices, int stacks) {
float rho, theta;
float x, y, z;
float s, t, ds, dt;
int i, j;
final boolean normals = this.normals != GLU_NONE;
final float nsign = this.orientation == GLU_INSIDE ? -1.0f : 1.0f;
final float drho = PI / stacks;
final float dtheta = 2.0f * PI / slices;
final ImmediateModeBuffer imb = new ImmediateModeBuffer(16 * 1024); // TODO: We can calculate this to avoid re-allocs
int lastDrawIndex = 0;
if ( this.drawStyle == GLU_FILL ) {
if ( !this.textureFlag ) {
lastDrawIndex += addDrawCommand(GL_TRIANGLE_FAN, lastDrawIndex, slices + 2);
// draw +Z end as a triangle fan
imb.glNormal3f(0.0f, 0.0f, 1.0f);
imb.glVertex3f(0.0f, 0.0f, nsign * radius);
for ( j = 0; j <= slices; j++ ) {
theta = (j == slices) ? 0.0f : j * dtheta;
x = -sin(theta) * sin(drho);
y = cos(theta) * sin(drho);
z = nsign * cos(drho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
imb.glVertex3f(x * radius, y * radius, z * radius);
}
}
ds = 1.0f / slices;
dt = 1.0f / stacks;
t = 1.0f; // because loop now runs from 0
final int imin, imax;
if ( this.textureFlag ) {
imin = 0;
imax = stacks;
} else {
imin = 1;
imax = stacks - 1;
}
// draw intermediate stacks as quad strips
for ( i = imin; i < imax; i++ ) {
lastDrawIndex += addDrawCommand(GL_TRIANGLE_STRIP, lastDrawIndex, (slices + 1) * 2);
rho = i * drho;
s = 0.0f;
for ( j = 0; j <= slices; j++ ) {
theta = (j == slices) ? 0.0f : j * dtheta;
x = -sin(theta) * sin(rho);
y = cos(theta) * sin(rho);
z = nsign * cos(rho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
if ( textureFlag )
imb.glTexCoord2f(s, t);
imb.glVertex3f(x * radius, y * radius, z * radius);
x = -sin(theta) * sin(rho + drho);
y = cos(theta) * sin(rho + drho);
z = nsign * cos(rho + drho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
if ( textureFlag )
imb.glTexCoord2f(s, t - dt);
s += ds;
imb.glVertex3f(x * radius, y * radius, z * radius);
}
t -= dt;
}
if ( !this.textureFlag ) {
lastDrawIndex += addDrawCommand(GL_TRIANGLE_FAN, lastDrawIndex, slices + 2);
// draw -Z end as a triangle fan
imb.glNormal3f(0.0f, 0.0f, -1.0f);
imb.glVertex3f(0.0f, 0.0f, -radius * nsign);
rho = PI - drho;
s = 1.0f;
for ( j = slices; j >= 0; j-- ) {
theta = (j == slices) ? 0.0f : j * dtheta;
x = -sin(theta) * sin(rho);
y = cos(theta) * sin(rho);
z = nsign * cos(rho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
s -= ds;
imb.glVertex3f(x * radius, y * radius, z * radius);
}
}
} else if ( this.drawStyle == GLU_LINE || this.drawStyle == GLU_SILHOUETTE ) {
// draw stack lines
for ( i = 1; i < stacks; i++ ) { // stack line at i==stacks-1 was missing here
lastDrawIndex += addDrawCommand(GL_LINE_LOOP, lastDrawIndex, slices);
rho = i * drho;
for ( j = 0; j < slices; j++ ) {
theta = j * dtheta;
x = cos(theta) * sin(rho);
y = sin(theta) * sin(rho);
z = cos(rho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
imb.glVertex3f(x * radius, y * radius, z * radius);
}
}
// draw slice lines
for ( j = 0; j < slices; j++ ) {
lastDrawIndex += addDrawCommand(GL_LINE_STRIP, lastDrawIndex, stacks + 1);
theta = j * dtheta;
for ( i = 0; i <= stacks; i++ ) {
rho = i * drho;
x = cos(theta) * sin(rho);
y = sin(theta) * sin(rho);
z = cos(rho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
imb.glVertex3f(x * radius, y * radius, z * radius);
}
}
} else if ( this.drawStyle == GLU_POINT ) {
lastDrawIndex += addDrawCommand(GL_POINTS, lastDrawIndex, 2 + (stacks - 2) * slices);
// top and bottom-most points
if ( normals )
imb.glNormal3f(0.0f, 0.0f, nsign);
imb.glVertex3f(0.0f, 0.0f, radius);
if ( normals )
imb.glNormal3f(0.0f, 0.0f, -nsign);
imb.glVertex3f(0.0f, 0.0f, -radius);
// loop over stacks
for ( i = 1; i < stacks - 1; i++ ) {
rho = i * drho;
for ( j = 0; j < slices; j++ ) {
theta = j * dtheta;
x = cos(theta) * sin(rho);
y = sin(theta) * sin(rho);
z = cos(rho);
if ( normals )
imb.glNormal3f(x * nsign, y * nsign, z * nsign);
imb.glVertex3f(x * radius, y * radius, z * radius);
}
}
}
return imb.getBuffer();
}
private static class DrawCommand {
private int mode;
private int first;
private int count;
private DrawCommand(final int mode, final int first, final int count) {
this.mode = mode;
this.first = first;
this.count = count;
}
void draw() {
glDrawArrays(mode, first, count);
}
}
}