2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12 package org.scilab.forge.scirenderer.implementation.jogl.drawer;
14 import org.scilab.forge.scirenderer.SciRendererException;
15 import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
16 import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
17 import org.scilab.forge.scirenderer.implementation.jogl.buffers.JoGLBuffersManager;
18 import org.scilab.forge.scirenderer.implementation.jogl.buffers.JoGLElementsBuffer;
19 import org.scilab.forge.scirenderer.implementation.jogl.utils.GLShortCuts;
20 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
21 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
22 import org.scilab.forge.scirenderer.texture.Texture;
23 import org.scilab.forge.scirenderer.lightning.LightManager;
24 import org.scilab.forge.scirenderer.shapes.appearance.Material;
26 import javax.media.opengl.GL2;
27 import java.nio.FloatBuffer;
28 import java.nio.IntBuffer;
31 * Utility class for drawing shapes.
32 * @author Pierre Lando
34 public final class JoGLShapeDrawer {
36 private static JoGLShapeDrawer drawer;
39 * Private constructor : this is an utility class.
41 private JoGLShapeDrawer() {
46 * @return the unique {@link JoGLShapeDrawer}.
48 public static JoGLShapeDrawer getDrawer() {
50 drawer = new JoGLShapeDrawer();
56 * Draw a given geometry with given appearance.
57 * @param drawingTools the drawing tools.
58 * @param geometry the geometry.
59 * @param appearance the appearance.
60 * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
62 public void draw(JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance) throws SciRendererException {
63 GL2 gl = drawingTools.getGl().getGL2();
64 gl.glFrontFace(GL2.GL_CCW);
65 switch (geometry.getFaceCullingMode()) {
67 gl.glEnable(GL2.GL_CULL_FACE);
68 gl.glCullFace(GL2.GL_FRONT);
71 gl.glEnable(GL2.GL_CULL_FACE);
72 gl.glCullFace(GL2.GL_BACK);
75 gl.glDisable(GL2.GL_CULL_FACE);
78 gl.glDisable(GL2.GL_CULL_FACE);
82 if (drawingTools.getCanvas().getJoGLParameters().useVBO()) {
83 vboDrawing(drawingTools, geometry, appearance);
85 directDrawing(drawingTools, geometry, appearance);
88 GLShortCuts.useLineAppearance(gl, null);
89 gl.glDisable(GL2.GL_CULL_FACE);
93 * Perform geometry drawing using VBO.
94 * @param drawingTools the drawing tools.
95 * @param geometry the geometry to draw.
96 * @param appearance the current appearance.
97 * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
99 private void vboDrawing(JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance) throws SciRendererException {
100 final GL2 gl = drawingTools.getGl().getGL2();
101 final JoGLBuffersManager buffersManager = drawingTools.getCanvas().getBuffersManager();
102 final Texture texture = appearance.getTexture();
104 int verticesNumber = buffersManager.bindVertexBuffer(gl, geometry.getVertices());
105 if (verticesNumber == 0) {
106 gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
110 buffersManager.bindNormalsBuffer(gl, geometry.getNormals());
112 if (texture != null && geometry.getTextureCoordinates() != null) {
113 synchronized (texture) {
114 if (texture.isValid()) {
115 drawingTools.bind(texture);
116 buffersManager.bindTextureCoordinatesBuffer(gl, geometry.getTextureCoordinates());
120 buffersManager.bindColorsBuffer(gl, geometry.getColors());
123 // We use polygon offset for filled geometry if required.
124 if (geometry.getPolygonOffsetMode()) {
125 gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
126 gl.glPolygonOffset(1, 1);
129 GLShortCuts.useColor(gl, appearance.getFillColor());
131 LightManager lm = drawingTools.getLightManager();
132 boolean lighting = lm.isLightningEnable();
134 lm.setMaterial(appearance.getMaterial());
135 gl.glEnable(GL2.GL_NORMALIZE);
138 IndicesBuffer indices = geometry.getIndices();
139 if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
140 if (indices != null) {
141 int indicesSize = buffersManager.bindIndicesBuffer(gl, indices);
142 if (indicesSize > 0) {
143 gl.glDrawElements(getGlMode(geometry.getFillDrawingMode()), indicesSize, GL2.GL_UNSIGNED_INT, 0);
144 gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0);
147 int count = geometry.getVertices().getSize();
149 gl.glDrawArrays(getGlMode(geometry.getFillDrawingMode()), 0, count);
154 if (geometry.getPolygonOffsetMode()) {
155 gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL);
158 gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
159 gl.glDisableClientState(GL2.GL_NORMAL_ARRAY);
160 gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
161 gl.glDisable(GL2.GL_TEXTURE_2D);
162 //disable lighting to draw lines
163 lm.setLightningEnable(false);
164 gl.glDisable(GL2.GL_NORMALIZE);
166 if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
167 // to avoid color smoothing between edge
168 // TODO: add an option in Appearance
169 gl.glShadeModel(GL2.GL_FLAT);
170 if (appearance.getLineColor() != null || geometry.getColors() != null) {
171 GLShortCuts.useLineAppearance(gl, appearance);
172 if (appearance.getLineColor() == null) {
173 buffersManager.bindColorsBuffer(gl, geometry.getColors());
176 if (geometry.getWireIndices() != null) {
177 int edgesIndicesSize = buffersManager.bindIndicesBuffer(gl, geometry.getWireIndices());
178 if (edgesIndicesSize > 0) {
179 gl.glDrawElements(getGlMode(geometry.getLineDrawingMode()), edgesIndicesSize, GL2.GL_UNSIGNED_INT, 0);
180 gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0);
183 int count = geometry.getVertices().getSize();
185 gl.glDrawArrays(getGlMode(geometry.getLineDrawingMode()), 0, count);
189 gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
193 gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
194 lm.setLightningEnable(lighting);
198 * Perform geometry drawing by direct OpenGl call.
199 * @param drawingTools the drawing tools.
200 * @param geometry the geometry to draw.
201 * @param appearance the used appearance.
202 * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
204 private void directDrawing(
205 JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance
206 ) throws SciRendererException {
207 final double sfactor;
208 final double tfactor;
209 final float[] fbuffer = new float[4];
211 GL2 gl = drawingTools.getGl().getGL2();
212 if (geometry.getVertices() == null) {
216 FloatBuffer vertexBuffer = geometry.getVertices().getData();
217 IndicesBuffer indices = geometry.getIndices();
219 FloatBuffer colorBuffer;
220 if (geometry.getColors() != null) {
221 colorBuffer = geometry.getColors().getData();
226 FloatBuffer normalBuffer;
227 if (geometry.getNormals() != null) {
228 normalBuffer = geometry.getNormals().getData();
233 Texture texture = appearance.getTexture();
234 FloatBuffer textureCoordinatesBuffer;
235 if (texture != null && geometry.getTextureCoordinates() != null) {
236 synchronized (texture) {
237 drawingTools.bind(texture);
238 textureCoordinatesBuffer = geometry.getTextureCoordinates().getData();
239 sfactor = texture.getSScaleFactor();
240 tfactor = texture.getTScaleFactor();
243 textureCoordinatesBuffer = null;
248 final int elementsSize = JoGLElementsBuffer.ELEMENT_SIZE;
250 if (geometry.getPolygonOffsetMode()) {
251 gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
252 gl.glPolygonOffset(1, 1);
255 LightManager lm = drawingTools.getLightManager();
256 boolean lighting = lm.isLightningEnable();
258 lm.setMaterial(appearance.getMaterial());
261 if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
262 GLShortCuts.useColor(gl, appearance.getFillColor());
263 gl.glShadeModel(GL2.GL_FLAT);
264 gl.glBegin(getGlMode(geometry.getFillDrawingMode()));
265 if (indices != null) {
266 IntBuffer indicesBuffer = indices.getData();
267 indicesBuffer.rewind();
268 for (int i = 0; i < indicesBuffer.limit(); i++) {
269 int index = indicesBuffer.get(i);
270 if ((index * elementsSize) < vertexBuffer.limit()) {
272 if (colorBuffer != null) {
273 colorBuffer.position(index * elementsSize);
274 gl.glColor4fv(colorBuffer);
277 if (normalBuffer != null) {
278 normalBuffer.position(index * elementsSize);
279 gl.glNormal3fv(normalBuffer);
282 if (textureCoordinatesBuffer != null) {
283 textureCoordinatesBuffer.position(index * elementsSize);
284 textureCoordinatesBuffer.get(fbuffer);
286 gl.glTexCoord4f((float) (sfactor * fbuffer[0]), (float) (tfactor * fbuffer[1]), fbuffer[2], fbuffer[3]);
289 vertexBuffer.position(index * elementsSize);
290 gl.glVertex4fv(vertexBuffer);
295 vertexBuffer.rewind();
297 if (colorBuffer != null) {
298 colorBuffer.rewind();
301 if (normalBuffer != null) {
302 normalBuffer.rewind();
305 for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
306 if (colorBuffer != null) {
307 colorBuffer.position(i);
308 gl.glColor4fv(colorBuffer);
311 if (normalBuffer != null) {
312 normalBuffer.position(i);
313 gl.glNormal3fv(normalBuffer);
316 if (textureCoordinatesBuffer != null) {
317 textureCoordinatesBuffer.position(i);
318 gl.glTexCoord4fv(textureCoordinatesBuffer);
321 vertexBuffer.position(i);
322 gl.glVertex4fv(vertexBuffer);
328 if (geometry.getPolygonOffsetMode()) {
329 gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL);
332 gl.glDisable(GL2.GL_TEXTURE_2D);
333 //disable lighting to draw lines
334 lm.setLightningEnable(false);
336 // Draw edges if any.
337 if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
338 GLShortCuts.useLineAppearance(gl, appearance);
339 if (appearance.getLineColor() != null) {
340 gl.glBegin(getGlMode(geometry.getLineDrawingMode()));
341 if (geometry.getWireIndices() != null) {
342 IntBuffer edgesIndicesBuffer = geometry.getWireIndices().getData();
343 edgesIndicesBuffer.rewind();
344 while (edgesIndicesBuffer.remaining() != 0) {
345 int index = edgesIndicesBuffer.get();
346 if ((index * elementsSize) < vertexBuffer.limit()) {
347 vertexBuffer.position(index * elementsSize);
348 gl.glVertex4fv(vertexBuffer);
352 for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
353 vertexBuffer.position(i);
354 gl.glVertex4fv(vertexBuffer);
358 } else if (colorBuffer != null) {
359 gl.glBegin(getGlMode(geometry.getLineDrawingMode()));
360 if (geometry.getWireIndices() != null) {
361 IntBuffer edgesIndicesBuffer = geometry.getWireIndices().getData();
362 edgesIndicesBuffer.rewind();
363 while (edgesIndicesBuffer.remaining() != 0) {
364 int index = edgesIndicesBuffer.get();
365 if ((index * elementsSize) < vertexBuffer.limit()) {
366 colorBuffer.position(index * elementsSize);
367 gl.glColor4fv(colorBuffer);
369 vertexBuffer.position(index * elementsSize);
370 gl.glVertex4fv(vertexBuffer);
375 for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
376 colorBuffer.position(i);
377 vertexBuffer.position(i);
378 gl.glColor4fv(colorBuffer);
379 gl.glVertex4fv(vertexBuffer);
385 lm.setLightningEnable(lighting);
390 * Return the gl drawing mode corresponding to the given {@link Geometry.FillDrawingMode}.
391 * @param drawingMode the given drawing mode..
392 * @return the gl drawing mode corresponding to the given {@link Geometry.FillDrawingMode}.
394 private int getGlMode(Geometry.FillDrawingMode drawingMode) {
395 switch (drawingMode) {
397 return GL2.GL_TRIANGLE_FAN;
399 return GL2.GL_TRIANGLE_STRIP;
401 return GL2.GL_TRIANGLES;
403 return GL2.GL_TRIANGLES;
408 * Return the gl drawing mode corresponding to the given {@link org.scilab.forge.scirenderer.shapes.geometry.Geometry.LineDrawingMode}
409 * @param drawingMode the given drawing mode.
410 * @return the gl drawing mode corresponding to the given {@link org.scilab.forge.scirenderer.shapes.geometry.Geometry.LineDrawingMode}
412 private int getGlMode(Geometry.LineDrawingMode drawingMode) {
413 switch (drawingMode) {
417 return GL2.GL_LINE_LOOP;
419 return GL2.GL_LINE_STRIP;