java left logo
java middle logo
java right logo
 

Home arrow Other API Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 4100
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Cel shading - NeHe Tutorial JOGL Port E-mail
User Rating: / 3
PoorBest 

This tutorial will teach you Cel-Shading. A very cool effect that makes images look like cartoons!

This is the Java port of the one of the NeHe OpenGL tutorials.

You can get complete IntelliJ IDEA project structure (all source, resources, build script, …) by downloading the source distribution from here.

The original post of the programmer who ported the examples can be found here.


Image

package demos.nehe.lesson37;

/*--.          .-"-.
/   o_O        / O o \
\_  (__\       \_ v _/
//   \\        //   \\
((     ))      ((     ))
¤¤¤¤¤¤¤¤¤¤¤¤¤¤--""---""--¤¤¤¤--""---""--¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
¤                 |||            |||                             ¤
¤                  |              |                              ¤
¤                                                                ¤
¤ Programmer:Abdul Bezrati                                       ¤
¤ Program   :Nehe's 37th lesson port to JOGL                     ¤
¤ Comments  :None                                                ¤
¤    _______                                                     ¤
¤  /` _____ `\;,     This e-mail address is being protected from spam bots, you need JavaScript enabled to view it                          ¤
¤ (__(^===^)__)';,                                 ___           ¤
¤   /  :::  \   ,;                               /^   ^\         ¤
¤  |   :::   | ,;'                              ( Ö   Ö )        ¤
¤¤¤'._______.'`¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ --°oOo--(_)--oOo°--¤¤*/

import demos.common.GLDisplay;

/**
 @author Abdul Bezrati
 */
public class Lesson37 {
    public static void main(String[] args) {
        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay("Lesson 37: Cell shading");
        Renderer renderer = new Renderer();
        InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.addKeyListener(inputHandler);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson37;

import demos.common.GLDisplay;

import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

class InputHandler extends KeyAdapter {
    private Renderer renderer;

    public InputHandler(Renderer renderer, GLDisplay glDisplay) {
        this.renderer = renderer;
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)"Toggle rotation");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_1, 0)"Toggle outline drawing");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_2, 0)"Toggle outline smoothing");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)"Increase outline width");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)"Decrease outline width");
    }

    public void keyPressed(KeyEvent e) {
        processKeyEvent(e, true);
    }

    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_SPACE:                         
                // Is the Space Bar Being Pressed? ( NEW )
                // Toggle Model Rotation On/Off ( NEW )
                renderer.toggleModelRotation();             
                break;

            case KeyEvent.VK_1:                             
                // Is The Number 1 Being Pressed? ( NEW )
                // Toggle Outline Drawing On/Off ( NEW )
                renderer.toggelOutlineDraw();               
                break;

            case KeyEvent.VK_2:                             
                // Is The Number 2 Being Pressed? ( NEW )
                // Toggle Anti-Aliasing On/Off ( NEW )
                renderer.toggleOutlineSmooth();             
                break;
            default:
                processKeyEvent(e, false);
        }
    }

    private void processKeyEvent(KeyEvent e, boolean pressed) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP:                            
                // Is The Up Arrow Being Pressed? ( NEW )
                // Increase Line Width ( NEW )
                renderer.increaseOutlineWidth(pressed);       
                break;

            case KeyEvent.VK_DOWN:                          
                // Is The Down Arrow Being Pressed? ( NEW )
                // Decrease Line Width ( NEW )
                renderer.decreaseOutlineWidth(pressed);       
                break;
        }
    }
}


package demos.nehe.lesson37;

import demos.common.ResourceRetriever;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
import java.nio.FloatBuffer;

import com.sun.opengl.util.BufferUtil;

class Renderer implements GLEventListener {
    private boolean outlineSmooth;        // Flag To Anti-Alias The Lines ( NEW )
    private boolean outlineDraw = true;   // Flag To Draw The Outline ( NEW )
    private boolean modelRotate = false;  // Flag To Rotate The Model ( NEW )

    // User Defined Variables
    private float[] outlineColor = {0.0f0.0f0.0f}// Color Of The Lines ( NEW )
    private float outlineWidth = 3f;              // Width Of The Lines ( NEW )
    private float modelAngle = 0f;                // Y-Axis Angle Of The Model ( NEW )

    private Polygon[] polyData;                   // Polygon Data ( NEW )
    private Vector lightAngle = new Vector();     // The Direction Of The Light ( NEW )

    private int polyNum = 0;                      // Number Of Polygons ( NEW )
    private int[] shaderTexture = new int[1];     // Storage For One Texture ( NEW )
    private boolean increaseWidth;
    private boolean decreaseWidth;

    private GLU glu = new GLU();

    public void toggleOutlineSmooth() {
        this.outlineSmooth = !outlineSmooth;
    }

    public void toggelOutlineDraw() {
        this.outlineDraw = !outlineDraw;
    }

    public void increaseOutlineWidth(boolean increase) {
        increaseWidth = increase;
    }

    public void decreaseOutlineWidth(boolean decrease) {
        decreaseWidth = decrease;
    }

    public void toggleModelRotation() {
        this.modelRotate = !modelRotate;
    }

    private void readMesh() throws IOException {
        InputStream in = ResourceRetriever.getResourceAsStream(
                "demos/data/models/Model.txt");

        polyNum = byteToInt(readNextFourBytes(in));
        polyData = new Polygon[polyNum];

        for (int i = 0; i < polyData.length; i++) {
            polyData[inew Polygon();
            for (int j = 0; j < 3; j++) {
                polyData[i].Verts[j].Nor.X = byteToFloat(readNextFourBytes(in));
                polyData[i].Verts[j].Nor.Y = byteToFloat(readNextFourBytes(in));
                polyData[i].Verts[j].Nor.Z = byteToFloat(readNextFourBytes(in));

                polyData[i].Verts[j].Pos.X = byteToFloat(readNextFourBytes(in));
                polyData[i].Verts[j].Pos.Y = byteToFloat(readNextFourBytes(in));
                polyData[i].Verts[j].Pos.Z = byteToFloat(readNextFourBytes(in));
            }
        }
    }

    private static byte[] readNextFourBytes(InputStream inthrows IOException {
        byte[] bytes = new byte[4];

        for (int i = 0; i < 4; i++)
            bytes[i(bytein.read();
        return bytes;
    }

    private static int byteToInt(byte[] array) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int b = array[i];
            b &= 0xff;
            value |= (b << (i * 8));
        }
        return value;
    }

    private static float byteToFloat(byte[] array) {
        int value = 0;
        for (int i = 3; i >= 0; i--) {
            int b = array[i];
            b &= 0xff;
            value |= (b << (i * 8));
        }
        return Float.intBitsToFloat(value);
    }

    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        // Storate For The 96 Shader Values ( NEW )
        FloatBuffer shaderData = BufferUtil.newFloatBuffer(96);                        

        // Start Of User Initialization
        // Realy Nice perspective calculations
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST)
        gl.glClearColor(0.7f0.7f0.7f0.0f);  // Light Grey Background
        gl.glClearDepth(1.0f);             // Depth Buffer Setup

        gl.glEnable(GL.GL_DEPTH_TEST);     // Enable Depth Testing
        gl.glDepthFunc(GL.GL_LESS);        // The Type Of Depth Test To Do

        gl.glShadeModel(GL.GL_SMOOTH);     // Enables Smooth Color Shading ( NEW )
        gl.glDisable(GL.GL_LINE_SMOOTH);   // Initially Disable Line Smoothing ( NEW )

        gl.glEnable(GL.GL_CULL_FACE);      // Enable OpenGL Face Culling ( NEW )

        gl.glDisable(GL.GL_LIGHTING);      // Disable OpenGL Lighting ( NEW )

        StringBuffer readShaderData = new StringBuffer();

        try {
            InputStream inputStream = ResourceRetriever.getResourceAsStream(
                    "demos/data/models/Shader.txt");
            int info;
            while ((info = inputStream.read()) != -1)
                readShaderData.append((charinfo);
            inputStream.close();
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        StringTokenizer tokenizer = new StringTokenizer(readShaderData.toString());

        // Loop Though The 32 Greyscale Values ( NEW )
        while (tokenizer.hasMoreTokens()) {                                      
            float value = Float.parseFloat(tokenizer.nextToken());
            shaderData.put(value);
            shaderData.put(value);
            shaderData.put(value);
        }
        shaderData.flip();

        // Get A Free Texture ID ( NEW )
        gl.glGenTextures(1, shaderTexture, 0);                           
        // Bind This Texture. From Now On It Will Be 1D ( NEW )
        gl.glBindTexture(GL.GL_TEXTURE_1D, shaderTexture[0]);         

        // For Crying Out Loud Don't Let OpenGL Use Bi/Trilinear Filtering! ( NEW )
        gl.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
        gl.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);

        gl.glTexImage1D(GL.GL_TEXTURE_1D, 0, GL.GL_RGB, 320, GL.GL_RGB, 
                GL.GL_FLOAT, shaderData)// Upload ( NEW )

        lightAngle.X = 0.0f;            // Set The X Direction ( NEW )
        lightAngle.Y = 0.0f;            // Set The Y Direction ( NEW )
        lightAngle.Z = 1.0f;            // Set The Z Direction ( NEW )
        lightAngle.normalize();

        try {
            readMesh();                 // Return The Value Of ReadMesh ( NEW )
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void update() {
        if (increaseWidth)
            outlineWidth += 1;         // Increase Line Width ( NEW )
        if (decreaseWidth)
            outlineWidth -= 1;         // Decrease Line Width ( NEW )
    }

    public void display(GLAutoDrawable drawable) {
        update();

        GL gl = drawable.getGL();
        // Clear Color Buffer, Depth Buffer
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        Matrix TmpMatrix = new Matrix();   // Temporary MATRIX Structure ( NEW )
        Vector TmpVector = new Vector(),
                TmpNormal = new Vector();  // Temporary VECTOR Structures ( NEW )

        gl.glLoadIdentity();               // Reset The Matrix

        if (outlineSmooth) {  // Check To See If We Want Anti-Aliased Lines ( NEW )
            // Use The Good Calculations ( NEW )
            gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST)
            gl.glEnable(GL.GL_LINE_SMOOTH);     // Enable Anti-Aliasing ( NEW )
        else                                  // We Don't Want Smooth Lines ( NEW )
            gl.glDisable(GL.GL_LINE_SMOOTH);    // Disable Anti-Aliasing ( NEW )

        gl.glTranslatef(0.0f0.0f, -2.0f)// Move 2 Units Away From The Screen ( NEW )
        // Rotate The Model On It's Y-Axis ( NEW )
        gl.glRotatef(modelAngle, 0.0f1.0f0.0f)

        // Get The Generated Matrix ( NEW )
        gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, TmpMatrix.Data, 0);     

        // Cel-Shading Code //
        gl.glEnable(GL.GL_TEXTURE_1D);          // Enable 1D Texturing ( NEW )
        // Bind Our Texture ( NEW )
        gl.glBindTexture(GL.GL_TEXTURE_1D, shaderTexture[0]);       
        gl.glColor3f(1.0f1.0f1.0f);         // Set The Color Of The Model ( NEW )

        gl.glBegin(GL.GL_TRIANGLES);            // Tell OpenGL That We're Drawing Triangles

        for (int i = 0; i < polyNum; i++)       // Loop Through Each Polygon ( NEW )
            for (int j = 0; j < 3; j++) {       // Loop Through Each Vertex ( NEW )

                // Fill Up The TmpNormal Structure With
                TmpNormal.X = polyData[i].Verts[j].Nor.X; 
                // The Current Vertices' Normal Values ( NEW )
                TmpNormal.Y = polyData[i].Verts[j].Nor.Y;               
                TmpNormal.Z = polyData[i].Verts[j].Nor.Z;
                // Rotate This By The Matrix ( NEW )
                TmpMatrix.rotateVector(TmpNormal, TmpVector);         
                TmpVector.normalize();  // Normalize The New Normal ( NEW )

                // Calculate The Shade Value ( NEW )
                float TmpShade = Vector.dotProduct(TmpVector, lightAngle);           
                if (TmpShade < 0.0f)
                    TmpShade = 0.0f;  // Clamp The Value to 0 If Negative ( NEW )

                // Set The Texture Co-ordinate As The Shade Value ( NEW )
                gl.glTexCoord1f(TmpShade);  
                gl.glVertex3f(polyData[i].Verts[j].Pos.X,
                        polyData[i].Verts[j].Pos.Y,
                        polyData[i].Verts[j].Pos.Z)// Send The Vertex Position ( NEW )
            }

        gl.glEnd();                      // Tell OpenGL To Finish Drawing
        gl.glDisable(GL.GL_TEXTURE_1D);  // Disable 1D Textures ( NEW )

        // Outline Code //
        if (outlineDraw) { // Check To See If We Want To Draw The Outline ( NEW )
            gl.glEnable(GL.GL_BLEND);   // Enable Blending ( NEW )
            // Set The Blend Mode ( NEW )
            gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

            // Draw Backfacing Polygons As Wireframes ( NEW )
            gl.glPolygonMode(GL.GL_BACK, GL.GL_LINE);  
            gl.glLineWidth(outlineWidth);  // Set The Line Width ( NEW )
            gl.glCullFace(GL.GL_FRONT);    // Don't Draw Any Front-Facing Polygons ( NEW )

            gl.glDepthFunc(GL.GL_LEQUAL);  // Change The Depth Mode ( NEW )
            gl.glColor3fv(outlineColor, 0)// Set The Outline Color ( NEW )

            gl.glBegin(GL.GL_TRIANGLES);    // Tell OpenGL What We Want To Draw

            for (int i = 0; i < polyNum; i++// Loop Through Each Polygon ( NEW )
                for (int j = 0; j < 3; j++)   // Loop Through Each Vertex ( NEW )
                    gl.glVertex3f(polyData[i].Verts[j].Pos.X,
                            polyData[i].Verts[j].Pos.Y,
                            // Send The Vertex Position ( NEW )
                            polyData[i].Verts[j].Pos.Z)

            gl.glEnd();                  // Tell OpenGL We've Finished
            gl.glDepthFunc(GL.GL_LESS);  // Reset The Depth-Testing Mode ( NEW )
            gl.glCullFace(GL.GL_BACK);   // Reset The Face To Be Culled ( NEW )
            // Reset Back-Facing Polygon Drawing Mode ( NEW )
            gl.glPolygonMode(GL.GL_BACK, GL.GL_FILL);  
            gl.glDisable(GL.GL_BLEND);   // Disable Blending ( NEW )
        }

        if (modelRotate)         // Check To See If Rotation Is Enabled ( NEW )
            modelAngle += .2f;   // Update Angle Based On The Clock
    }

    public void reshape(GLAutoDrawable drawable,
                        int xstart,
                        int ystart,
                        int width,
                        int height) {
        GL gl = drawable.getGL();

        height = (height == 0: height;

        gl.glViewport(00, width, height);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();

        glu.gluPerspective(45(floatwidth / height, 11000);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void displayChanged(GLAutoDrawable drawable,
                               boolean modeChanged,
                               boolean deviceChanged) {
    }

    private static class Matrix {
        float Data[] new float[16];

        // Rotate A Vector Using The Supplied Matrix ( NEW )
        public void rotateVector(Vector V, Vector D) {              
            // Rotate Around The X Axis ( NEW )
            D.X = (Data[0* V.X(Data[4* V.Y(Data[8* V.Z);  
            // Rotate Around The Y Axis ( NEW )
            D.Y = (Data[1* V.X(Data[5* V.Y(Data[9* V.Z);  
            // Rotate Around The Z Axis ( NEW )
            D.Z = (Data[2* V.X(Data[6* V.Y(Data[10* V.Z);  
        }
    }               // A Structure To Hold An OpenGL Matrix ( NEW )

    // We Use [16] Due To OpenGL's Matrix Format ( NEW )
    private static class Vector {
        float X, Y, Z;

        // Math Functions
        // Calculate The Angle Between The 2 Vectors ( NEW )
        public static float dotProduct(Vector V1, Vector V2) {                       
            return V1.X * V2.X + V1.Y * V2.Y + V1.Z * V2.Z; // Return The Angle ( NEW )
        }

        public float magnitude() {  // Calculate The Length Of The Vector ( NEW )
            // Return The Length Of The Vector ( NEW )
            return (floatMath.sqrt(X * X + Y * Y + Z * Z)
        }

        public void normalize() {   // Creates A Vector With A Unit Length Of 1 ( NEW )
            float M = magnitude();  // Calculate The Length Of The Vector  ( NEW )

            if (M != 0.0f) {        // Make Sure We Don't Divide By 0  ( NEW )
                X /= M;             // Normalize The 3 Components  ( NEW )
                Y /= M;
                Z /= M;
            }
        }
    }   // A Structure To Hold A Single Vector ( NEW )

    private static class Vertex {     // A Structure To Hold A Single Vertex ( NEW )
        Vector Nor = new Vector(),    // Vertex Normal ( NEW )
        Pos = new Vector();           // Vertex Position ( NEW )
    }

    private static class Polygon {     // A Structure To Hold A Single Polygon ( NEW )
        Vertex Verts[] new Vertex[3]// Array Of 3 VERTEX Structures ( NEW )

        public Polygon() {
            for (int i = 0; i < 3; i++)
                Verts[inew Vertex();
        }
    }
}

 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.