Børre Stenseth
JOGL>Bezier surface

Bezier

What
screen
Drawing a Bezier surface, with and without texture

We will render e Bezier surface with and without texture. Bezier surfaces are explained in Bezier and texturing is explained in module: Textures.

The code for loading and preparing textures is implemented in class TextureReader below. This class is a modified version of the class used by NeHe's [1] texture examples.

The Bezier surface is implemented in class oneBezier below and we use the stdMaterial class from Some Materials

The application has mouse action and a zoom controller, all implemented in the main class Tex2.java.

TextureReader

This is a simplified version. The complete class as used by NeHe [1] may be found at koders [2] , search with TextureReader

_TextureReader.java
package tex2;
/**
 *
 * @author bs
 */
import com.sun.opengl.util.BufferUtil;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
 * Image loading class that converts BufferedImages into a data
 * structure that can be easily passed to OpenGL.
 * @author Pepijn Van Eeckhoudt
 *
 * Modified by bs: simplified: no .bmp load, no resource access
 * Search in: www.koders.com/? for original
 */
public class TextureReader {
    public static Texture readTexture(String filename)
            throws IOException {
        return readTexture(filename, false);
    }
    public static Texture readTexture(String filename, 
                                      boolean storeAlphaChannel)
            throws IOException {
        BufferedImage bufferedImage;
        bufferedImage=ImageIO.read(new FileInputStream(filename));
        return readPixels(bufferedImage, storeAlphaChannel);
    }

    private static Texture readPixels(BufferedImage img,
                                      boolean storeAlphaChannel) {
        int[] packedPixels = new int[img.getWidth() * img.getHeight()];
        PixelGrabber pixelgrabber =
                new PixelGrabber(img, 0, 0,
                                 img.getWidth(), img.getHeight(),
                                 packedPixels, 0, img.getWidth());
        try {
            pixelgrabber.grabPixels();
        } catch (InterruptedException e) {
            throw new RuntimeException();
        }
        int bytesPerPixel = storeAlphaChannel ? 4 : 3;
        ByteBuffer unpackedPixels =
                BufferUtil.newByteBuffer(packedPixels.length * bytesPerPixel);
        for (int row = img.getHeight() - 1; row >= 0; row--) {
            for (int col = 0; col < img.getWidth(); col++) {
                int packedPixel = packedPixels[row * img.getWidth() + col];
                unpackedPixels.put((byte) ((packedPixel >> 16) & 0xFF));
                unpackedPixels.put((byte) ((packedPixel >> 8) & 0xFF));
                unpackedPixels.put((byte) ((packedPixel >> 0) & 0xFF));
                if (storeAlphaChannel) {
                    unpackedPixels.put((byte) ((packedPixel >> 24) & 0xFF));
                }
            }
        }
        unpackedPixels.flip();
        return new Texture(unpackedPixels, img.getWidth(), img.getHeight());
    }
    public static class Texture {
        private ByteBuffer pixels;
        private int width;
        private int height;
        public Texture(ByteBuffer pixels, int width, int height) {
            this.height = height;
            this.pixels = pixels;
            this.width = width;
        }
        public int getHeight() {return height;}
        public ByteBuffer getPixels() {return pixels;}
        public int getWidth() {return width;}
    }
}

oneBezier

We load two textures, only the last is used ( you may modify the code to use the other)

    TextureReader.Texture bs_texture=null;
    TextureReader.Texture spider_texture=null;
	
	...
	
	try {
			bs_texture = TextureReader.readTexture("images/bs-1.png");
			spider_texture = TextureReader.readTexture("images/spiderman.jpg");
		} 
	catch (IOException ex) {
			System.out.println(ex.getMessage());
		}	

The controlpoints for the Bezier is described like this:

    float ctrlpoints[];
	
	...
	
	ctrlpoints= new float[]// [v][u][xyz] [4][4][3]
	{

		-1.5f,-1.5f,0.0f, -0.5f,-1.5f,0.0f,
		0.5f,-1.5f,0.0f,  1.5f,-1.5f,0.0f
	  ,
		-1.5f,-0.5f,0.0f, -0.5f,-0.5f,0.0f,
		0.5f,-0.5f,0.0f,  1.5f,-0.5f,0.0f
	  ,
		-1.5f,0.5f,0.0f,  -0.5f,0.5f,0.0f,
		0.5f,0.5f, 0.0f,  1.5f,0.5f,0.0f
	  ,
		-1.5f,1.5f,0.0f,  -0.5f,1.5f,0.0f,
	   0.5f,1.5f,0.0f,   1.5f,1.5f,0.0f
	};	

and the 4 center controlpoints may be offset to "stretch" the surface

    private void offsetControls(float offset)
    {
      // adjust z-values of the 4 "center" points
      ctrlpoints[18-1]= ctrlpoints[21-1]=
      ctrlpoints[30-1]= ctrlpoints[33-1]=offset;
    }

We render the Bezier surface like this (without texture):

public void drawMe(GL gl,float offset,
                    boolean showGrid,boolean showCtrls,boolean showTexture)
{
    offsetControls(offset);
    if(showCtrls)
        drawControls(gl);        
    if(showTexture && bs_texture!=null)
    {
        textureMe(gl,spider_texture);
        //textureMe(gl,bs_texture);
    }
    else
    {
        stdMaterials.setMaterial(gl, stdMaterials.MAT_RED_PLASTIC, GL.GL_FRONT);
        stdMaterials.setMaterial(gl, stdMaterials.MAT_GREEN_PLASTIC, GL.GL_BACK);
        gl.glMap2f(GL.GL_MAP2_VERTEX_3,0.0f,1.0f,3,4,0.0f,1.0f,12,4,ctrlpoints,0);
        gl.glEnable(GL.GL_MAP2_VERTEX_3);
        gl.glEnable(GL.GL_AUTO_NORMAL);
        gl.glEnable(GL.GL_NORMALIZE);
        gl.glMapGrid2f(20,0.0f,1.0f,20,0.0f, 1.0f);
        gl.glFrontFace(GL.GL_CW);
        if(showGrid)
            gl.glEvalMesh2(GL.GL_LINE, 0, 20, 0, 20);
        else
            gl.glEvalMesh2(GL.GL_FILL, 0, 20, 0, 20);
         gl.glFrontFace(GL.GL_CCW);
    }
 }

Render with texture:

private void textureMe(GL gl,TextureReader.Texture tex)
 {
    gl.glTexEnvi(GL.GL_TEXTURE_ENV,GL.GL_TEXTURE_ENV_MODE,GL.GL_DECAL);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_NEAREST);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_NEAREST);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_S,GL.GL_REPEAT);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_T,GL.GL_REPEAT);
    gl.glEnable(GL.GL_TEXTURE_2D);
    gl.glEnable(GL.GL_MAP2_VERTEX_3);
    gl.glEnable(GL.GL_MAP2_TEXTURE_COORD_1);
    gl.glEnable(GL.GL_MAP2_TEXTURE_COORD_2);
    gl.glTexImage2D(GL.GL_TEXTURE_2D,0,3,
                tex.getWidth(),
                tex.getHeight(),
                0,GL.GL_RGB,GL.GL_UNSIGNED_BYTE,
                tex.getPixels());
    // map geometri
    gl.glMap2f(GL.GL_MAP2_VERTEX_3,
            0.0f,1.0f,3,4,0.0f,1.0f,12,4,
            ctrlpoints,0);
    // map bs_texture
    float txpts[]=new float[]{0.0f, 0.0f, 1.0f, 0.0f,
                   0.0f, 1.0f, 1.0f, 1.0f};        
    gl.glMap2f(GL.GL_MAP2_TEXTURE_COORD_2,0,1,2,2,0,1,4,2,
            txpts,0);
    gl.glMapGrid2f(20,0.0f,1.0f,20,0.0f, 1.0f);
    gl.glEvalMesh2(GL.GL_FILL, 0, 20, 0, 20);
 }

The controlpoints are rendered like this:

private void drawControls(GL gl)
 {
    // assuming they are offset correctly
     stdMaterials.setMaterial(gl, 
                              stdMaterials.MAT_BLACK_PLASTIC,
                              GL.GL_FRONT_AND_BACK);
    // ctrlpoints[4][4][3]
    int u,v;
    for(u=0;u<4;u++)
    {
        gl.glBegin(GL.GL_LINE_STRIP);
        for(v=0;v<4;v++)
        {
            gl.glVertex3f(  ctrlpoints[v*12+u*3+0],
                            ctrlpoints[v*12+u*3+1],
                            ctrlpoints[v*12+u*3+2]);
        }
        gl.glEnd();
    }
    for(v=0;v<4;v++)
    {
        gl.glBegin(GL.GL_LINE_STRIP);
        for(u=0;u<4;u++)
        {
            gl.glVertex3f(  ctrlpoints[v*12+u*3+0],
                            ctrlpoints[v*12+u*3+1],
                            ctrlpoints[v*12+u*3+2]);
        }
        gl.glEnd();
    }       
}
References
  1. Latest 'NEHE' NewsNEHE, NeonHelium ProductionsOpenGL-tutorials.nehe.gamedev.net/14-03-2009
  1. KodersA site with a lot of searchable code exampleswww.koders.com/?14-05-2009
  • Program project: https://svn.hiof.no/svn/psource/JOGL/tex2
Maintainance
May 2009, Børre Stenseth
(Welcome) JOGL>Bezier surface (Ball)