blob: be5ee724e29ba093d7d4dff2c5da580968b8741d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.opengl.examples;
import org.eclipse.opengl.*;
import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
class AreaTab extends OpenGLTab {
abstract class Shape {
abstract void draw();
}
class State {
private String name;
private int index;
/**
* Constructor.
*
* @param name the display name of this state
* @param index the display list index corresponding to this state
*/
State (String name, int index) {
super();
this.index = index;
this.name = name;
}
void display() {
GL.glCallList(index);
}
void dispose() {
GL.glDeleteLists(index, 1);
}
String getName() {
return name;
}
}
private State[] states;
private State currentState;
private float xPos = 0.0f, yPos = 0.0f, zPos = -30.0f;
private float xRot = 90.0f, yRot = 0.0f, zRot = 0.0f;
private int quadratic, disk;
/**
* @see OpenGLTab#createControls(Composite)
*/
void createControls(Composite composite) {
Group movementGroup = new Group(composite, SWT.NONE);
movementGroup.setText("Translation");
movementGroup.setLayout(new GridLayout(2, false));
new Label(movementGroup, SWT.NONE).setText("X:");
final Slider xMove = new Slider(movementGroup, SWT.NONE);
xMove.setIncrement(1);
xMove.setMaximum(22);
xMove.setMinimum(0);
xMove.setThumb(2);
xMove.setPageIncrement(2);
xMove.setSelection(10);
xMove.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
xPos = xMove.getSelection() - 10;
}
});
new Label(movementGroup, SWT.NONE).setText("Y:");
final Slider yMove = new Slider(movementGroup, SWT.NONE);
yMove.setIncrement(1);
yMove.setMaximum(22);
yMove.setMinimum(0);
yMove.setThumb(2);
yMove.setPageIncrement(2);
yMove.setSelection(10);
yMove.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
yPos = yMove.getSelection() - 10;
}
});
new Label(movementGroup, SWT.NONE).setText("Z:");
final Slider zMove = new Slider(movementGroup, SWT.NONE);
zMove.setIncrement(1);
zMove.setMaximum(22);
zMove.setMinimum(0);
zMove.setThumb(2);
zMove.setPageIncrement(2);
zMove.setSelection(10);
zMove.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
zPos = zMove.getSelection() - 40;
}
});
Group rotationGroup = new Group(composite, SWT.NONE);
rotationGroup.setText("Rotation");
rotationGroup.setLayout(new GridLayout(2, false));
new Label(rotationGroup, SWT.NONE).setText("X:");
final Slider xRotation = new Slider(rotationGroup, SWT.NONE);
xRotation.setIncrement(10);
xRotation.setMaximum(362);
xRotation.setMinimum(0);
xRotation.setThumb(2);
xRotation.setPageIncrement(20);
xRotation.setSelection(90);
xRotation.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
xRot = xRotation.getSelection();
}
});
new Label(rotationGroup, SWT.NONE).setText("Y:");
final Slider yRotation = new Slider(rotationGroup, SWT.NONE);
yRotation.setIncrement(10);
yRotation.setMaximum(362);
yRotation.setMinimum(0);
yRotation.setThumb(2);
yRotation.setPageIncrement(20);
yRotation.setSelection(0);
yRotation.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
yRot = yRotation.getSelection();
}
});
new Label(rotationGroup, SWT.NONE).setText("Z:");
final Slider zRotation = new Slider(rotationGroup, SWT.NONE);
zRotation.setIncrement(10);
zRotation.setMaximum(362);
zRotation.setMinimum(0);
zRotation.setThumb(2);
zRotation.setPageIncrement(20);
zRotation.setSelection(0);
zRotation.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
zRot = zRotation.getSelection();
}
});
Composite optionsGroup = new Composite(composite, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
layout.marginWidth = 0;
optionsGroup.setLayout(layout);
new Label(optionsGroup, SWT.NONE).setText("Shape:");
final Combo statesCombo = new Combo(optionsGroup, SWT.READ_ONLY);
for (int i = 0; i < states.length; i++) {
statesCombo.add(states[i].getName());
}
statesCombo.select(0);
statesCombo.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
currentState = states[statesCombo.getSelectionIndex()];
}
});
final Button lightsButton = new Button(composite, SWT.CHECK);
lightsButton.setText("Lights");
lightsButton.setSelection(true);
lightsButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
if (lightsButton.getSelection()) {
GL.glEnable(GL.GL_LIGHTING);
} else {
GL.glDisable(GL.GL_LIGHTING);
}
}
});
}
/**
* @see OpenGLTab#dispose()
*/
void dispose() {
super.dispose();
GLU.gluDeleteQuadric(quadratic);
GLU.gluDeleteQuadric(disk);
if (states != null) {
for (int i = 0; i < states.length; i++) {
states [i].dispose();
}
}
}
/**
* Draws the logical AND of two shapes.
*
* @param a shape A
* @param b shape B
*/
void drawAandB(Shape a, Shape b) {
// draw parts of B that are inside A
drawAinsideB(a, b, GL.GL_BACK, GL.GL_NOTEQUAL);
// we do not want the following to show up
GL.glColorMask(false, false, false, false);
// turn on depth testing
GL.glEnable(GL.GL_DEPTH_TEST);
GL.glDepthFunc(GL.GL_ALWAYS);
// render the front face of B
b.draw();
// reset the depth function
GL.glDepthFunc(GL.GL_LESS);
// draw parts of A that are inside B
drawAinsideB(b, a, GL.GL_BACK, GL.GL_NOTEQUAL);
}
/**
* Draws the contents of one shape that appear within another.
*
* @param a the shape to draw
* @param b the constraining shape
* @param face
* @param test
*/
void drawAinsideB(Shape a, Shape b, int face, int test) {
// turn off the color buffer
GL.glColorMask(false, false, false, false);
// clear the stencil buffer
GL.glClearStencil(0);
GL.glEnable(GL.GL_DEPTH_TEST);
// set to proper Culling
GL.glCullFace(face);
// render shape A
a.draw();
// set depth mask
GL.glDepthMask(false);
// enable stencil test
GL.glEnable(GL.GL_STENCIL_TEST);
GL.glStencilFunc(GL.GL_ALWAYS, 0, 0);
// set the stencil buffer to increment if the depth test passes
GL.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR);
// turn on back face culling
GL.glCullFace(GL.GL_BACK);
// render B
b.draw();
// set the stencil buffer to decrement if the depth test passes
GL.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_DECR);
// cull the front face
GL.glCullFace(GL.GL_FRONT);
// render B again
b.draw();
// set depth mask
GL.glDepthMask(true);
GL.glColorMask(true, true, true, true);
// set the stencil buffer
GL.glStencilFunc(test, 0, 1);
// turn off depth testing
GL.glDisable(GL.GL_DEPTH_TEST);
// set to proper culling
GL.glCullFace(face);
// render A
a.draw();
// disable stencil test
GL.glDisable(GL.GL_STENCIL_TEST);
}
/**
* Draws the logical OR of two shapes.
*
* @param a shape A
* @param b shape B
*/
void drawAorB(Shape a, Shape b) {
GL.glEnable(GL.GL_DEPTH_TEST);
a.draw();
b.draw();
GL.glDisable(GL.GL_DEPTH_TEST);
}
/**
* Draws one shape subtracted from another.
*
* @param a the base shape
* @param b the shape to subtract
*/
void drawAsubB(Shape a, Shape b) {
// draw back parts of B inside A
drawAinsideB(b, a, GL.GL_FRONT, GL.GL_NOTEQUAL);
// we do not want the following to show up
GL.glColorMask(false, false, false, false);
GL.glEnable(GL.GL_DEPTH_TEST);
// change the depth test to GL_ALWAYS
GL.glDepthFunc(GL.GL_ALWAYS);
// render the front face of B
a.draw();
// reset the depth function
GL.glDepthFunc(GL.GL_LESS);
// draw front parts of A outside B
drawAinsideB(a, b, GL.GL_BACK, GL.GL_EQUAL);
}
/**
* Draws the specifed shape.
*
* @param shape the shape to draw
*/
void drawShape(Shape shape) {
GL.glEnable(GL.GL_DEPTH_TEST);
shape.draw();
GL.glDisable(GL.GL_DEPTH_TEST);
}
/**
* @see OpenGLTab#getTabText()
*/
String getTabText() {
return "Area";
}
/**
* @see OpenGLTab#init()
*/
void init() {
if (!hasStencilSupport()) return;
GL.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
float[] lightPos = { 0.0f, 5.0f, -10.0f, 1.0f };
GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPos);
quadratic = GLU.gluNewQuadric();
disk = GLU.gluNewQuadric();
GL.glEnable(GL.GL_CULL_FACE);
GL.glEnable(GL.GL_LIST_MODE);
GL.glEnable(GL.GL_LIGHT0);
GL.glEnable(GL.GL_LIGHTING);
GL.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE);
final float[] sphereMaterial = { 0.0f, 1.0f, 0.0f, 1.0f };
final float[] cylinderMaterial = { 1.0f, 0.0f, 0.0f, 1.0f };
Shape sphere = new Shape() {
public void draw() {
GL.glMaterialfv(
GL.GL_FRONT_AND_BACK,
GL.GL_AMBIENT_AND_DIFFUSE,
sphereMaterial);
GL.glColor3f(0.0f, 1.0f, 0.0f);
GLU.gluSphere(quadratic, 3, 32, 32);
}
};
Shape cylinder = new Shape() {
public void draw() {
GL.glMaterialfv(
GL.GL_FRONT_AND_BACK,
GL.GL_AMBIENT_AND_DIFFUSE,
cylinderMaterial);
GL.glColor3f(1.0f, 0.0f, 0.0f);
GLU.gluQuadricOrientation(disk, GLU.GLU_INSIDE);
GL.glPushMatrix();
GL.glTranslatef(1.0f, 1.0f, 0.0f);
GLU.gluDisk(disk, 0, 3, 32, 32);
GLU.gluCylinder(quadratic, 3, 3, 6, 32, 32);
GL.glPushMatrix();
GL.glTranslatef(0.0f, 0.0f, 6.0f);
GLU.gluQuadricOrientation(disk, GLU.GLU_OUTSIDE);
GLU.gluDisk(disk, 0, 3, 32, 32);
GL.glPopMatrix();
GL.glPopMatrix();
}
};
// create the display lists and states
states = new State[6];
int index = 1;
GL.glNewList(index, GL.GL_COMPILE);
drawShape(cylinder);
GL.glEndList();
states[0] = new State("Cylinder",index++);
GL.glNewList(index, GL.GL_COMPILE);
drawShape(sphere);
GL.glEndList();
states[1] = new State("Sphere",index++);
GL.glNewList(index, GL.GL_COMPILE);
drawAorB(cylinder, sphere);
GL.glEndList();
states[2] = new State("Cylinder OR Sphere",index++);
GL.glNewList(index, GL.GL_COMPILE);
drawAandB(cylinder, sphere);
GL.glEndList();
states[3] = new State("Cylinder AND Sphere",index++);
GL.glNewList(index, GL.GL_COMPILE);
drawAsubB(cylinder, sphere);
GL.glEndList();
states[4] = new State("Cylinder SUB Sphere",index++);
GL.glNewList(index, GL.GL_COMPILE);
drawAsubB(sphere, cylinder);
GL.glEndList();
states[5] = new State("Sphere SUB Cylinder",index++);
currentState = states[0];
}
/**
* @see OpenGLTab#isStencilSupportNeeded
*/
boolean isStencilSupportNeeded() {
return true;
}
/**
* @see OpenGLTab#renderScene()
*/
void renderScene() {
GL.glClear(
GL.GL_COLOR_BUFFER_BIT
| GL.GL_DEPTH_BUFFER_BIT
| GL.GL_STENCIL_BUFFER_BIT);
GL.glLoadIdentity();
GL.glTranslatef(xPos, yPos, zPos);
GL.glRotatef(xRot, 1.0f, 0.0f, 0.0f);
GL.glRotatef(yRot, 0.0f, 1.0f, 0.0f);
GL.glRotatef(zRot, 0.0f, 0.0f, 1.0f);
currentState.display();
}
}