| /******************************************************************************* |
| * 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 Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.opengl.examples; |
| |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.layout.*; |
| import org.eclipse.swt.opengl.*; |
| 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(); |
| } |
| } |