# Stencil Shadows



## Elvenone (7. Nov 2007)

hello

iam trying to recode the "Stencil Shadow Volume" from C to java, but i dont know why, i cant get it to work, althrough its the same

netbeans project : www.politea.sk/tmp/Shadows.zip


```
package org.yourorghere;

import com.sun.opengl.impl.windows.PIXELFORMATDESCRIPTOR;
import java.awt.*;
import java.awt.event.*;

import javax.media.opengl.*;
import com.sun.opengl.util.*;
import javax.media.opengl.glu.GLU;

public class Shadows implements GLEventListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener {

        boolean g_bRenderShadowVolume = true;
        float g_fAmountOfExtrusion  = 5.0f;
        float g_lightPosition[]     = { 2.0f, 6.0f, 0.0f, 1.0f }; // World position of light source

        static float view_scale = 1.0f;
        
        // GL_C3F_V3F
        public class Vertex {
            public float r, g, b;
            public float x, y, z;
            
            private Vertex(float ir, float ig, float ib, float ix,float iy, float iz) {
                r = ir; g = ig; b = ib; x = ix; y = iy; z = iz;
            }
            
            public  float getX() {return x;}
        };
        
        public Vertex[] g_shadowCasterVerts = 
        {
            new Vertex(1.0f, 1.0f, 1.0f, -1.0f, 2.5f, -1.0f),
            new Vertex(1.0f, 1.0f, 1.0f, -1.0f, 2.5f,  1.0f ),
            new Vertex(1.0f, 1.0f, 1.0f,  1.0f, 2.5f,  1.0f ),
            new Vertex(1.0f, 1.0f, 1.0f,  1.0f, 2.5f, -1.0f ),
        };     
        
        public float[] g_shadowCasterNormal = { 0.0f, 1.0f, 0.0f };
        
        class ShadowCaster {
            Vertex[] verts;// = new Vertex(0f,0f,0f,0f,0f,0f);        // Vertices of the actual shadow casting object
            float[]  normal;       // A surface normal for lighting
            int    numVerts;     // Total number of vertices
            int    shadowVolume; // Display list for holding the shadow volume
        };

        ShadowCaster g_shadowCaster = new ShadowCaster();
    
        public static void main(String[] args)
	{
                
		Frame frame = new Frame("Simple JOGL Application");
		GLCanvas canvas = new GLCanvas();
		
		canvas.addGLEventListener(new Shadows());
		frame.add(canvas);
		frame.setSize(640, 480);
		final Animator animator = new Animator(canvas);
		frame.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				// Run this on another thread than the AWT event queue to
				// make sure the call to Animator.stop() completes before
				// exiting
				new Thread(new Runnable()
				{
					public void run()
					{
						animator.stop();
						System.exit(0);
					}
				}).start();
			}
		});
		// Center frame
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		animator.start();
	}
        
        void extendVertex(float[] newVert, float[] lightPosit, Vertex vert, float ext) {
            float[] lightDir = new float[3];

            // Create a vector that points from the light's position to the original vertex.
            lightDir[0] = vert.x - lightPosit[0];
            lightDir[1] = vert.y - lightPosit[1];
            lightDir[2] = vert.z - lightPosit[2];

            // Then use that vector to extend the original vertex out to a new position.
            // The distance to extend or extrude the new vector is specified by t.
            newVert[0] = lightPosit[0] + lightDir[0] * ext;
            newVert[1] = lightPosit[1] + lightDir[1] * ext;
            newVert[2] = lightPosit[2] + lightDir[2] * ext;
        }        
	
        void buildShadowVolume(GLAutoDrawable drawable, ShadowCaster caster, float[] lightPosit, float ext ) {
            GL gl = drawable.getGL();
            
            if ( caster.shadowVolume != -1 )
                gl.glDeleteLists( caster.shadowVolume, 0 );

            caster.shadowVolume = gl.glGenLists(1);

            gl.glNewList( caster.shadowVolume, gl.GL_COMPILE );
            {
                gl.glDisable( gl.GL_LIGHTING );

                gl.glBegin( gl.GL_QUADS );
                {
                    gl.glColor3f( 0.2f, 0.8f, 0.4f );

                    float[] vExtended = new float[3];

                    //
                    // For each vertex of the shadow casting object, find the edge 
                    // that it helps define and extrude a quad out from that edge.
                    //

                    for( int i = 0; i < caster.numVerts; ++i )
                    {
                        // Define the edge we're currently working on extruding...
                        int e0 = i;
                        int e1 = i+1;

                        // If the edge's second vertex is out of array range, 
                        // place it back at 0
                        if( e1 >= caster.numVerts )
                            e1 = 0;

                        // v0 of our extruded quad will simply use the edge's first 
                        // vertex or e0.
                        gl.glVertex3f(caster.verts[e0].x, caster.verts[e0].y, caster.verts[e0].z);

                        // v1 of our quad is created by taking the edge's first 
                        // vertex and extending it out by some amount.
                        extendVertex(vExtended, lightPosit, caster.verts[e0], ext);
                        gl.glVertex3f(vExtended[0], vExtended[1], vExtended[2]);

                        // v2 of our quad is created by taking the edge's second 
                        // vertex and extending it out by some amount.
                        extendVertex( vExtended, lightPosit, caster.verts[e1], ext );
                        gl.glVertex3f( vExtended[0], vExtended[1], vExtended[2] );

                        // v3 of our extruded quad will simply use the edge's second 
                        // vertex or e1.
                        gl.glVertex3f( caster.verts[e1].x, caster.verts[e1].y, caster.verts[e1].z );
                    }
                }
                gl.glEnd();

                gl.glEnable( gl.GL_LIGHTING );
            }
            gl.glEndList();
        }    
        
        void renderScene(GLAutoDrawable drawable) {
            //
            // Place the view
            //
            GL gl = drawable.getGL();
            GLUT glut = new GLUT();
            
            gl.glMatrixMode( gl.GL_MODELVIEW );
            gl.glLoadIdentity();
            gl.glTranslatef( 0.0f, -2.0f, -15.0f );
            //gl.glRotatef( 0, 1.0f, 0.0f, 0.0f );
            //gl.glRotatef( 0, 0.0f, 1.0f, 0.0f );
            //gl.glRotatef(90, 1, 0, 0);    
            
            if (mouseRButtonDown) {
                view_scale += (prevMouseY - nowMouseY) / 10000f;                 
            }
                
            //gl.glScalef(view_scale, view_scale, view_scale);
            
            gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
            gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
            gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);

            //
            // Render the floor...
            //

            gl.glPushMatrix();
            {
                gl.glBegin( gl.GL_QUADS );
                {
                    gl.glNormal3f( 0.0f, 1.0f,  0.0f );
                    gl.glVertex3f(-5.0f, 0.0f, -5.0f );
                    gl.glVertex3f(-5.0f, 0.0f,  5.0f );
                    gl.glVertex3f( 5.0f, 0.0f,  5.0f );
                    gl.glVertex3f( 5.0f, 0.0f, -5.0f );
                }
                gl.glEnd();
            }
            gl.glPopMatrix();

            //
            // Render a teapot so we'll have something else to cast a shadow on  
            // besides the floor.
            //

            gl.glPushMatrix();
            {
                gl.glTranslatef( -2.0f, 0.8f, 0.0f );
                gl.glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
                gl.glColor3f( 1.0f, 1.0f ,1.0f );
                glut.glutSolidTeapot(1.0);
            }
            gl.glPopMatrix();

            //
            // Render the light's position as a sphere...
            //

            gl.glDisable( gl.GL_LIGHTING );

            gl.glPushMatrix();
            {
                // Place the light...
                gl.glLightfv( gl.GL_LIGHT0, gl.GL_POSITION, g_lightPosition, 0);

                // Place a sphere to represent the light
                gl.glTranslatef( g_lightPosition[0], g_lightPosition[1], g_lightPosition[2] );

                gl.glColor3f(1.0f, 1.0f, 0.5f);
                glut.glutSolidSphere( 0.1, 8, 8 );
            }
            gl.glPopMatrix();

            gl.glEnable( gl.GL_LIGHTING );

            //
            // Render the shadow caster (i.e. the quad)
            //

            gl.glPushMatrix();
            {
                // Hmmm... I can't transform the shadow caster unless the 
                // buildShadowVolume function is able to take this into account. 
                // This is because the shadow volume is built in world space.

                //glTranslatef( 0.0f, 2.5f, 0.0f );
                //glRotatef( -g_fSpinY_R, 1.0f, 0.0f, 0.0f );
                //glRotatef( -g_fSpinX_R, 0.0f, 1.0f, 0.0f );

                gl.glBegin( gl.GL_POLYGON );
                {
                    gl.glNormal3f(g_shadowCaster.normal[0],g_shadowCaster.normal[1], g_shadowCaster.normal[2]);

                    for( int i = 0; i < g_shadowCaster.numVerts; ++i )
                    {
                        gl.glVertex3f( g_shadowCaster.verts[i].x, g_shadowCaster.verts[i].y, g_shadowCaster.verts[i].z );
                    }
                }
                gl.glEnd();
            }
            gl.glPopMatrix();
        }                
        
	public void init(GLAutoDrawable drawable)
	{
		// Use debug pipeline
		// drawable.setGL(new DebugGL(drawable.getGL()));
		
                //PIXELFORMATDESCRIPTOR pfd = null;
            
                //pfd.nVersion((short)1);
                //pfd.dwFlags( PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER);
                //pfd.iPixelType(PFD_TYPE_RGBA);
                //pfd.cColorBits((byte)16);
                //pfd.cDepthBits((byte)16);
                //pfd.cStencilBits((byte)8);

                //int PixelFormat;
                //g_hDC = GetDC( g_hWnd );
                //PixelFormat = ChoosePixelFormat( g_hDC, &pfd );
                //SetPixelFormat( g_hDC, PixelFormat, &pfd);
                //g_hRC = wglCreateContext( g_hDC );
                //wglMakeCurrent( g_hDC, g_hRC );                
                
		GL gl = drawable.getGL();                
		GLU glu = new GLU();
                //System.err.println("INIT GL IS: " + gl.getClass().getName());
		gl.glClearStencil(128);
		// Enable VSync
		gl.setSwapInterval(1);
		
		// Setup the drawing area and shading mode
		//gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		//gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see what happens.
                
                
                gl.glClearColor( 0.35f, 0.53f, 0.7f, 1.0f );
                gl.glEnable(gl.GL_LIGHTING);
                gl.glEnable(gl.GL_LIGHT0);
                gl.glEnable(gl.GL_DEPTH_TEST);

                gl.glMatrixMode( gl.GL_PROJECTION );
                gl.glLoadIdentity();
                glu.gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);

                // Enable a single OpenGL light.
                float[] lightAmbient  = {0.2f, 0.2f, 0.2f, 1.0f};
                float[] lightDiffuse  = {1.0f, 1.0f, 1.0f, 1.0f}; 
                float[] lightSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
                gl.glLightfv(gl.GL_LIGHT0, gl.GL_DIFFUSE,  lightDiffuse, 0);
                gl.glLightfv(gl.GL_LIGHT0, gl.GL_SPECULAR, lightSpecular, 0);
                gl.glLightfv(gl.GL_LIGHT0, gl.GL_AMBIENT,  lightAmbient, 0);

                //
                // Set up the shadow caster...
                //

                g_shadowCaster.verts        = g_shadowCasterVerts;
                g_shadowCaster.normal       = g_shadowCasterNormal;
                g_shadowCaster.numVerts     = (4);
                g_shadowCaster.shadowVolume = -1;
                
                drawable.addMouseListener(this);
                drawable.addMouseMotionListener(this);
                drawable.addMouseWheelListener(this); 
                drawable.addKeyListener(this);
	}
        

	
	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
	{
		GL gl = drawable.getGL();
		GLU glu = new GLU();

		if (height <= 0) // avoid a divide by zero error!
				height = 1;
		final float h = (float) width / (float) height;
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(45.0f, h, 1.0, 20.0);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
	}
	
	public void display(GLAutoDrawable drawable)
	{
		GL gl = drawable.getGL();
		
                //
                // Using the light's position, extend or extrude each vertex of the shadow
                // caster out by an amount specified by g_fAmountOfExtrusion.
                //

                buildShadowVolume(drawable, g_shadowCaster, g_lightPosition, g_fAmountOfExtrusion );

                //
                // Prepare to render a new scene by clearing out all of the buffers.
                //

                gl.glClear( gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT );
               
                // Initialize the depth buffer by rendering the scene into it.
                gl.glColorMask( false, false, false, false );
                renderScene(drawable);

                //
                // Create the special shadow stencil...
                //

                // Set the appropriate states for creating a stencil for shadowing.
                gl.glEnable( gl.GL_CULL_FACE );
                gl.glEnable( gl.GL_STENCIL_TEST );
                gl.glDepthMask(false);
                //gl.glDisable(GL.GL_DEPTH_TEST);  
                gl.glStencilFunc( gl.GL_ALWAYS, 0, 0 );

                // Render the shadow volume and increment the stencil every where a front
                // facing polygon is rendered.
                gl.glStencilOp( gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR );
                gl.glCullFace( gl.GL_BACK );
                gl.glCallList( g_shadowCaster.shadowVolume );

                // Render the shadow volume and decrement the stencil every where a back
                // facing polygon is rendered.
                gl.glStencilOp( gl.GL_KEEP, gl.GL_KEEP, gl.GL_DECR );
                gl.glCullFace( gl.GL_FRONT );
                gl.glCallList( g_shadowCaster.shadowVolume );

                // When done, set the states back to something more typical.
                gl.glDepthMask( true );                
                gl.glDepthFunc( gl.GL_LEQUAL );                
                gl.glColorMask( true, true, true, true );
                gl.glStencilOp( gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP );              
                gl.glCullFace( gl.GL_BACK );
                gl.glDisable( gl.GL_CULL_FACE );

                //
                // Render the shadowed part...
                //

                gl.glStencilFunc( gl.GL_EQUAL, 1, 1 );
                                
                gl.glDisable( gl.GL_LIGHT0 );
                renderScene(drawable);

                //
                // Render the lit part...
                //
                
                gl.glStencilFunc( gl.GL_EQUAL, 0, 1 );
                gl.glEnable( gl.GL_LIGHT0 );
                renderScene(drawable);

                // When done, set the states back to something more typical.
                gl.glDepthFunc( gl.GL_LESS );
                gl.glDisable( gl.GL_STENCIL_TEST );

                if( g_bRenderShadowVolume )
                {
                    gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE );
                    gl.glCallList( g_shadowCaster.shadowVolume );
                    gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
                }

                //gl.SwapBuffers(1);
	}
	
	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged)
	{}
        
        static int prevMouseX = 0, prevMouseY = 0, nowMouseX, nowMouseY;    
        static boolean mouseRButtonDown = false;
        private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;

        public void mouseClicked(MouseEvent e) {
            //prevMouseX = e.getX();
            //prevMouseY = e.getY();    
             //System.out.println("Pressed");
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mousePressed(MouseEvent e) {           
            if ((e.getModifiers() & e.BUTTON1_MASK) != 0) {
                //view_scale += 0.5;    
            }
            if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
                //view_scale -= 0.5;    
            }

            prevMouseX = e.getX();
            prevMouseY = e.getY(); 
            //System.out.println("Pressed");     

            //throw new UnsupportedOperationException("Not supported yet.");
            if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
                mouseRButtonDown = true;
            }
        }

        public void mouseReleased(MouseEvent e) {   
            if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
                mouseRButtonDown = false;
            }
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mouseEntered(MouseEvent e) {
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mouseExited(MouseEvent e) {
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mouseDragged(MouseEvent e) {           
            //System.out.println("> " + e.getY() + " #" + prevMouseY);

            if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
                nowMouseX = e.getX();
                nowMouseY = e.getY();

                //if (e.getY() > prevMouseY) {
                //    view_scale += (e.getY() - prevMouseY) / 10000f;    
                //} else {

                //}

                //System.out.println(Float.toString((e.getY() - prevMouseY) / 1000f));
                //view_scale += 0.01;
                //System.out.println(Float.toString(view_scale));
            }
            if ((e.getModifiers() & e.BUTTON1_MASK) != 0) {
                int x = e.getX();
                int y = e.getY();
                Dimension size = e.getComponent().getSize();

                float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)size.width);
                float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)size.height);

                prevMouseX = x;
                prevMouseY = y;

                view_rotx += thetaX;
                view_roty += thetaY;     
            }    
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mouseMoved(MouseEvent e) {            

            //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void mouseWheelMoved(MouseWheelEvent e) {
            //System.out.println("");    
            if (e.getWheelRotation() < 0) {
                view_scale += 0.1;            
            } else {
                view_scale -= 0.1;                   
            }

            //throw new UnsupportedOperationException("Not supported yet.");
        }

    public void keyTyped(KeyEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void keyPressed(KeyEvent e) {
        //System.out.print("dfsdf");
        if (e.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
            int key = e.getKeyCode();
         
            if (key == KeyEvent.VK_F5) {
                g_lightPosition[0] += 0.1f;          
            }
            if (key == KeyEvent.VK_F6) {
                g_lightPosition[0] -= 0.1f;              
            }
            if (key == KeyEvent.VK_F7) {
                g_lightPosition[1] += 0.1f;       
            }
            if (key == KeyEvent.VK_F8) {
                g_lightPosition[1] -= 0.1f;           
            }         
        }   
    }

    public void keyReleased(KeyEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }
}
```


----------



## Gast (8. Nov 2007)

the C++ code from which iam trying to get into java si on http://www.codesampler.com/source/ogl_shadow_volume.zip (http://www.codesampler.com/oglsrc/oglsrc_8.htm)


----------



## Guest (8. Nov 2007)

(on the left, the same code in C++)
(on the right rewritten code to java)

i cant figure out why it isnt working

thank you


----------

