com.ardor3d.scene.state.lwjgl.LwjglLightStateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.ardor3d.scene.state.lwjgl.LwjglLightStateUtil.java

Source

/**
 * Copyright (c) 2008-2012 Ardor Labs, Inc.
 *
 * This file is part of Ardor3D.
 *
 * Ardor3D is free software: you can redistribute it and/or modify it 
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
 */

package com.ardor3d.scene.state.lwjgl;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

import com.ardor3d.light.DirectionalLight;
import com.ardor3d.light.Light;
import com.ardor3d.light.PointLight;
import com.ardor3d.light.SpotLight;
import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.ardor3d.math.type.ReadOnlyMatrix4;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.RenderContext;
import com.ardor3d.renderer.state.LightState;
import com.ardor3d.renderer.state.RenderState.StateType;
import com.ardor3d.renderer.state.record.LightRecord;
import com.ardor3d.renderer.state.record.LightStateRecord;

public abstract class LwjglLightStateUtil {

    public static void apply(final LightState state) {
        final RenderContext context = ContextManager.getCurrentContext();
        final LightStateRecord record = (LightStateRecord) context.getStateRecord(StateType.Light);
        context.setCurrentState(StateType.Light, state);

        if (state.isEnabled() && LightState.LIGHTS_ENABLED) {
            setLightEnabled(true, record);
            setTwoSided(state.getTwoSidedLighting(), record);
            setLocalViewer(state.getLocalViewer(), record);
            if (context.getCapabilities().isOpenGL1_2Supported()) {
                setSpecularControl(state.getSeparateSpecular(), record);
            }

            for (int i = 0, max = state.getNumberOfChildren(); i < max; i++) {
                final Light light = state.get(i);
                LightRecord lr = record.getLightRecord(i);
                // TODO: use the reference to get the lightrecord - rherlitz

                if (lr == null) {
                    lr = new LightRecord();
                    record.setLightRecord(lr, i);
                }

                if (light == null) {
                    setSingleLightEnabled(false, i, record, lr);
                } else {
                    if (light.isEnabled()) {
                        setLight(i, light, state, record, lr);
                    } else {
                        setSingleLightEnabled(false, i, record, lr);
                    }
                }
            }

            // disable lights at and above the max count in this state
            for (int i = state.getNumberOfChildren(); i < LightState.MAX_LIGHTS_ALLOWED; i++) {
                LightRecord lr = record.getLightRecord(i);

                if (lr == null) {
                    lr = new LightRecord();
                    record.setLightRecord(lr, i);
                }
                setSingleLightEnabled(false, i, record, lr);
            }

            if ((state.getLightMask() & LightState.MASK_GLOBALAMBIENT) == 0) {
                setModelAmbient(record, state.getGlobalAmbient());
            } else {
                setModelAmbient(record, ColorRGBA.BLACK_NO_ALPHA);
            }
        } else {
            setLightEnabled(false, record);
        }

        if (!record.isValid()) {
            record.validate();
        }
    }

    private static void setLight(final int index, final Light light, final LightState state,
            final LightStateRecord record, final LightRecord lr) {
        setSingleLightEnabled(true, index, record, lr);

        if ((state.getLightMask() & LightState.MASK_AMBIENT) == 0
                && (light.getLightMask() & LightState.MASK_AMBIENT) == 0) {
            setAmbient(index, record, light.getAmbient(), lr);
        } else {
            setAmbient(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
        }

        if ((state.getLightMask() & LightState.MASK_DIFFUSE) == 0
                && (light.getLightMask() & LightState.MASK_DIFFUSE) == 0) {
            setDiffuse(index, record, light.getDiffuse(), lr);
        } else {
            setDiffuse(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
        }

        if ((state.getLightMask() & LightState.MASK_SPECULAR) == 0
                && (light.getLightMask() & LightState.MASK_SPECULAR) == 0) {
            setSpecular(index, record, light.getSpecular(), lr);
        } else {
            setSpecular(index, record, ColorRGBA.BLACK_NO_ALPHA, lr);
        }

        if (light.isAttenuate()) {
            setAttenuate(true, index, light, record, lr);

        } else {
            setAttenuate(false, index, light, record, lr);

        }

        switch (light.getType()) {
        case Directional: {
            final DirectionalLight dirLight = (DirectionalLight) light;

            final ReadOnlyVector3 direction = dirLight.getDirection();
            setPosition(index, record, -direction.getXf(), -direction.getYf(), -direction.getZf(), 0, lr);
            break;
        }
        case Point:
        case Spot: {
            final PointLight pointLight = (PointLight) light;
            final ReadOnlyVector3 location = pointLight.getLocation();
            setPosition(index, record, location.getXf(), location.getYf(), location.getZf(), 1, lr);
            break;
        }
        }

        if (light.getType() == Light.Type.Spot) {
            final SpotLight spot = (SpotLight) light;
            setSpotCutoff(index, record, spot.getAngle(), lr);
            final ReadOnlyVector3 direction = spot.getDirection();
            setSpotDirection(index, record, direction.getXf(), direction.getYf(), direction.getZf(), 0);
            setSpotExponent(index, record, spot.getExponent(), lr);
        } else {
            // set the cutoff to 180, which causes the other spot params to be
            // ignored.
            setSpotCutoff(index, record, 180, lr);
        }
    }

    private static void setSingleLightEnabled(final boolean enable, final int index, final LightStateRecord record,
            final LightRecord lr) {
        if (!record.isValid() || lr.isEnabled() != enable) {
            if (enable) {
                GL11.glEnable(GL11.GL_LIGHT0 + index);
            } else {
                GL11.glDisable(GL11.GL_LIGHT0 + index);
            }

            lr.setEnabled(enable);
        }
    }

    private static void setLightEnabled(final boolean enable, final LightStateRecord record) {
        if (!record.isValid() || record.isEnabled() != enable) {
            if (enable) {
                GL11.glEnable(GL11.GL_LIGHTING);
            } else {
                GL11.glDisable(GL11.GL_LIGHTING);
            }
            record.setEnabled(enable);
        }
    }

    private static void setTwoSided(final boolean twoSided, final LightStateRecord record) {
        if (!record.isValid() || record.isTwoSidedOn() != twoSided) {
            if (twoSided) {
                GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_TRUE);
            } else {
                GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_FALSE);
            }
            record.setTwoSidedOn(twoSided);
        }
    }

    private static void setLocalViewer(final boolean localViewer, final LightStateRecord record) {
        if (!record.isValid() || record.isLocalViewer() != localViewer) {
            if (localViewer) {
                GL11.glLightModeli(GL11.GL_LIGHT_MODEL_LOCAL_VIEWER, GL11.GL_TRUE);
            } else {
                GL11.glLightModeli(GL11.GL_LIGHT_MODEL_LOCAL_VIEWER, GL11.GL_FALSE);
            }
            record.setLocalViewer(localViewer);
        }
    }

    private static void setSpecularControl(final boolean separateSpecularOn, final LightStateRecord record) {
        if (!record.isValid() || record.isSeparateSpecular() != separateSpecularOn) {
            if (separateSpecularOn) {
                GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SEPARATE_SPECULAR_COLOR);
            } else {
                GL11.glLightModeli(GL12.GL_LIGHT_MODEL_COLOR_CONTROL, GL12.GL_SINGLE_COLOR);
            }
            record.setSeparateSpecular(separateSpecularOn);
        }
    }

    private static void setModelAmbient(final LightStateRecord record, final ReadOnlyColorRGBA color) {
        if (!record.isValid() || !record.globalAmbient.equals(color)) {
            record.lightBuffer.clear();
            record.lightBuffer.put(color.getRed());
            record.lightBuffer.put(color.getGreen());
            record.lightBuffer.put(color.getBlue());
            record.lightBuffer.put(color.getAlpha());
            record.lightBuffer.flip();
            GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, record.lightBuffer);
            record.globalAmbient.set(color);
        }
    }

    private static void setAmbient(final int index, final LightStateRecord record, final ReadOnlyColorRGBA ambient,
            final LightRecord lr) {
        if (!record.isValid() || !lr.ambient.equals(ambient)) {
            record.lightBuffer.clear();
            record.lightBuffer.put(ambient.getRed());
            record.lightBuffer.put(ambient.getGreen());
            record.lightBuffer.put(ambient.getBlue());
            record.lightBuffer.put(ambient.getAlpha());
            record.lightBuffer.flip();
            GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_AMBIENT, record.lightBuffer);
            lr.ambient.set(ambient);
        }
    }

    private static void setDiffuse(final int index, final LightStateRecord record, final ReadOnlyColorRGBA diffuse,
            final LightRecord lr) {
        if (!record.isValid() || !lr.diffuse.equals(diffuse)) {
            record.lightBuffer.clear();
            record.lightBuffer.put(diffuse.getRed());
            record.lightBuffer.put(diffuse.getGreen());
            record.lightBuffer.put(diffuse.getBlue());
            record.lightBuffer.put(diffuse.getAlpha());
            record.lightBuffer.flip();
            GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_DIFFUSE, record.lightBuffer);
            lr.diffuse.set(diffuse);
        }
    }

    private static void setSpecular(final int index, final LightStateRecord record,
            final ReadOnlyColorRGBA specular, final LightRecord lr) {
        if (!record.isValid() || !lr.specular.equals(specular)) {
            record.lightBuffer.clear();
            record.lightBuffer.put(specular.getRed());
            record.lightBuffer.put(specular.getGreen());
            record.lightBuffer.put(specular.getBlue());
            record.lightBuffer.put(specular.getAlpha());
            record.lightBuffer.flip();
            GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_SPECULAR, record.lightBuffer);
            lr.specular.set(specular);
        }
    }

    private static void setPosition(final int index, final LightStateRecord record, final float positionX,
            final float positionY, final float positionZ, final float positionW, final LightRecord lr) {
        // From OpenGL Docs:
        // The light position is transformed by the contents of the current top
        // of the ModelView matrix stack when you specify the light position
        // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change
        // the ModelView matrix, such as when the view changes for the next
        // frame, the light position isn't automatically retransformed by the
        // new contents of the ModelView matrix. If you want to update the
        // light's position, you must again specify the light position with a
        // call to glLightfv(GL_LIGHT_POSITION,...).

        // XXX: This is a hack until we get a better lighting model up
        final ReadOnlyMatrix4 modelViewMatrix = Camera.getCurrentCamera().getModelViewMatrix();

        if (!record.isValid() || lr.position.getXf() != positionX || lr.position.getYf() != positionY
                || lr.position.getZf() != positionZ || lr.position.getWf() != positionW
                || !lr.modelViewMatrix.equals(modelViewMatrix)) {

            record.lightBuffer.clear();
            record.lightBuffer.put(positionX);
            record.lightBuffer.put(positionY);
            record.lightBuffer.put(positionZ);
            record.lightBuffer.put(positionW);
            record.lightBuffer.flip();
            GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_POSITION, record.lightBuffer);

            lr.position.set(positionX, positionY, positionZ, positionW);
            if (!Camera.getCurrentCamera().isFrameDirty()) {
                lr.modelViewMatrix.set(modelViewMatrix);
            }
        }
    }

    private static void setSpotDirection(final int index, final LightStateRecord record, final float directionX,
            final float directionY, final float directionZ, final float value) {
        // From OpenGL Docs:
        // The light position is transformed by the contents of the current top
        // of the ModelView matrix stack when you specify the light position
        // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change
        // the ModelView matrix, such as when the view changes for the next
        // frame, the light position isn't automatically retransformed by the
        // new contents of the ModelView matrix. If you want to update the
        // light's position, you must again specify the light position with a
        // call to glLightfv(GL_LIGHT_POSITION,...).
        record.lightBuffer.clear();
        record.lightBuffer.put(directionX);
        record.lightBuffer.put(directionY);
        record.lightBuffer.put(directionZ);
        record.lightBuffer.put(value);
        record.lightBuffer.flip();
        GL11.glLight(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_DIRECTION, record.lightBuffer);
    }

    private static void setConstant(final int index, final float constant, final LightRecord lr,
            final boolean force) {
        if (force || constant != lr.getConstant()) {
            GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_CONSTANT_ATTENUATION, constant);
            lr.setConstant(constant);
        }
    }

    private static void setLinear(final int index, final float linear, final LightRecord lr, final boolean force) {
        if (force || linear != lr.getLinear()) {
            GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_LINEAR_ATTENUATION, linear);
            lr.setLinear(linear);
        }
    }

    private static void setQuadratic(final int index, final float quad, final LightRecord lr, final boolean force) {
        if (force || quad != lr.getQuadratic()) {
            GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_QUADRATIC_ATTENUATION, quad);
            lr.setQuadratic(quad);
        }
    }

    private static void setAttenuate(final boolean attenuate, final int index, final Light light,
            final LightStateRecord record, final LightRecord lr) {
        if (attenuate) {
            setConstant(index, light.getConstant(), lr, !record.isValid());
            setLinear(index, light.getLinear(), lr, !record.isValid());
            setQuadratic(index, light.getQuadratic(), lr, !record.isValid());
        } else {
            setConstant(index, 1, lr, !record.isValid());
            setLinear(index, 0, lr, !record.isValid());
            setQuadratic(index, 0, lr, !record.isValid());
        }
        lr.setAttenuate(attenuate);
    }

    private static void setSpotExponent(final int index, final LightStateRecord record, final float exponent,
            final LightRecord lr) {
        if (!record.isValid() || lr.getSpotExponent() != exponent) {
            GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_EXPONENT, exponent);
            lr.setSpotExponent(exponent);
        }
    }

    private static void setSpotCutoff(final int index, final LightStateRecord record, final float cutoff,
            final LightRecord lr) {
        if (!record.isValid() || lr.getSpotCutoff() != cutoff) {
            GL11.glLightf(GL11.GL_LIGHT0 + index, GL11.GL_SPOT_CUTOFF, cutoff);
            lr.setSpotCutoff(cutoff);
        }
    }
}