* Add lighting support to OpenGL1 renderer

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8387 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
sha..rd 13 years ago
parent 52d1aaaaf2
commit 0372a5ed6d
  1. 9
      engine/src/core/com/jme3/material/FixedFuncBinding.java
  2. 35
      engine/src/core/com/jme3/renderer/RenderContext.java
  3. 334
      engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java

@ -69,5 +69,12 @@ public enum FixedFuncBinding {
* *
* Same as GL_SHININESS for OpenGL. * Same as GL_SHININESS for OpenGL.
*/ */
MaterialShininess MaterialShininess,
/**
* Use vertex color as an additional diffuse color, if lighting is enabled.
* If lighting is disabled, vertex color is modulated with
* {@link #Color material color}.
*/
UseVertexColor
} }

@ -33,6 +33,7 @@
package com.jme3.renderer; package com.jme3.renderer;
import com.jme3.material.RenderState; import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer;
import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer;
@ -233,6 +234,36 @@ public class RenderContext {
* IDList for vertex attributes * IDList for vertex attributes
*/ */
public IDList attribIndexList = new IDList(); public IDList attribIndexList = new IDList();
/**
* Ambient color (GL1 only)
*/
public ColorRGBA ambient;
/**
* Diffuse color (GL1 only)
*/
public ColorRGBA diffuse;
/**
* Specular color (GL1 only)
*/
public ColorRGBA specular;
/**
* Material color (GL1 only)
*/
public ColorRGBA color;
/**
* Shininess (GL1 only)
*/
public float shininess;
/**
* Use vertex color (GL1 only)
*/
public boolean useVertexColor;
/** /**
* Reset the RenderContext to default GL state * Reset the RenderContext to default GL state
@ -280,5 +311,9 @@ public class RenderContext {
backStencilDepthPassOperation = RenderState.StencilOperation.Keep; backStencilDepthPassOperation = RenderState.StencilOperation.Keep;
frontStencilFunction = RenderState.TestFunction.Always; frontStencilFunction = RenderState.TestFunction.Always;
backStencilFunction = RenderState.TestFunction.Always; backStencilFunction = RenderState.TestFunction.Always;
ambient = diffuse = specular = color = null;
shininess = 0;
useVertexColor = false;
} }
} }

@ -1,5 +1,11 @@
package com.jme3.renderer.lwjgl; package com.jme3.renderer.lwjgl;
import com.jme3.light.SpotLight;
import java.util.ArrayList;
import com.jme3.light.PointLight;
import com.jme3.math.Vector3f;
import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL14;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.renderer.GL1Renderer; import com.jme3.renderer.GL1Renderer;
@ -48,6 +54,7 @@ public class LwjglGL1Renderer implements GL1Renderer {
private final IntBuffer ib1 = BufferUtils.createIntBuffer(1); private final IntBuffer ib1 = BufferUtils.createIntBuffer(1);
private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16);
private final FloatBuffer fb16 = BufferUtils.createFloatBuffer(16); private final FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
private final FloatBuffer fb4Null = BufferUtils.createFloatBuffer(4);
private final RenderContext context = new RenderContext(); private final RenderContext context = new RenderContext();
private final GLObjectManager objManager = new GLObjectManager(); private final GLObjectManager objManager = new GLObjectManager();
private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class); private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);
@ -55,15 +62,18 @@ public class LwjglGL1Renderer implements GL1Renderer {
private int maxCubeTexSize; private int maxCubeTexSize;
private int maxVertCount; private int maxVertCount;
private int maxTriCount; private int maxTriCount;
private int maxLights;
private boolean gl12 = false; private boolean gl12 = false;
private final Statistics statistics = new Statistics(); private final Statistics statistics = new Statistics();
private int vpX, vpY, vpW, vpH; private int vpX, vpY, vpW, vpH;
private int clipX, clipY, clipW, clipH; private int clipX, clipY, clipW, clipH;
// private Matrix4f worldMatrix = new Matrix4f();
private Matrix4f worldMatrix = new Matrix4f();
private Matrix4f viewMatrix = new Matrix4f(); private Matrix4f viewMatrix = new Matrix4f();
// private Matrix4f projMatrix = new Matrix4f();
private boolean colorSet = false; private ArrayList<Light> lightList = new ArrayList<Light>(8);
private boolean materialSet = false; private ColorRGBA materialAmbientColor = new ColorRGBA();
private Vector3f tempVec = new Vector3f();
protected void updateNameBuffer() { protected void updateNameBuffer() {
int len = stringBuf.length(); int len = stringBuf.length();
@ -86,9 +96,22 @@ public class LwjglGL1Renderer implements GL1Renderer {
} }
public void initialize() { public void initialize() {
//glDisable(GL_DEPTH_TEST); if (GLContext.getCapabilities().OpenGL12){
gl12 = true;
}
// Default values for certain GL state.
glShadeModel(GL_SMOOTH); glShadeModel(GL_SMOOTH);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// Enable rescaling/normaling of normal vectors.
// Fixes lighting issues with scaled models.
if (gl12){
glEnable(GL12.GL_RESCALE_NORMAL);
}else{
glEnable(GL_NORMALIZE);
}
if (GLContext.getCapabilities().GL_ARB_texture_non_power_of_two) { if (GLContext.getCapabilities().GL_ARB_texture_non_power_of_two) {
caps.add(Caps.NonPowerOfTwoTextures); caps.add(Caps.NonPowerOfTwoTextures);
@ -98,26 +121,26 @@ public class LwjglGL1Renderer implements GL1Renderer {
+ "Some features might not work."); + "Some features might not work.");
} }
if (GLContext.getCapabilities().OpenGL12){ maxLights = glGetInteger(GL_MAX_LIGHTS);
gl12 = true;
}
} }
public void invalidateState() { public void invalidateState() {
context.reset(); context.reset();
} }
public void resetGLObjects() { public void resetGLObjects() {
colorSet = false; logger.log(Level.INFO, "Reseting objects and invalidating state");
objManager.resetObjects(); objManager.resetObjects();
statistics.clearMemory(); statistics.clearMemory();
context.reset(); invalidateState();
} }
public void cleanup() { public void cleanup() {
logger.log(Level.INFO, "Deleting objects and invalidating state");
objManager.deleteAllObjects(this); objManager.deleteAllObjects(this);
statistics.clearMemory(); statistics.clearMemory();
invalidateState();
} }
public void setDepthRange(float start, float end) { public void setDepthRange(float start, float end) {
@ -127,9 +150,23 @@ public class LwjglGL1Renderer implements GL1Renderer {
public void clearBuffers(boolean color, boolean depth, boolean stencil) { public void clearBuffers(boolean color, boolean depth, boolean stencil) {
int bits = 0; int bits = 0;
if (color) { if (color) {
//See explanations of the depth below, we must enable color write to be able to clear the color buffer
if (context.colorWriteEnabled == false) {
glColorMask(true, true, true, true);
context.colorWriteEnabled = true;
}
bits = GL_COLOR_BUFFER_BIT; bits = GL_COLOR_BUFFER_BIT;
} }
if (depth) { if (depth) {
//glClear(GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false
//here s some link on openl board
//http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223
//if depth clear is requested, we enable the depthMask
if (context.depthWriteEnabled == false) {
glDepthMask(true);
context.depthWriteEnabled = true;
}
bits |= GL_DEPTH_BUFFER_BIT; bits |= GL_DEPTH_BUFFER_BIT;
} }
if (stencil) { if (stencil) {
@ -144,65 +181,77 @@ public class LwjglGL1Renderer implements GL1Renderer {
glClearColor(color.r, color.g, color.b, color.a); glClearColor(color.r, color.g, color.b, color.a);
} }
private void setMaterialColor(int type, ColorRGBA color) { private void setMaterialColor(int type, ColorRGBA color, ColorRGBA defaultColor) {
if (!materialSet) { if (color != null){
materialSet = true; fb16.put(color.r).put(color.g).put(color.b).put(color.a).flip();
glEnable(GL_COLOR_MATERIAL); }else{
fb16.put(defaultColor.r).put(defaultColor.g).put(defaultColor.b).put(defaultColor.a).flip();
} }
fb16.clear();
fb16.put(color.r).put(color.g).put(color.b).put(color.a);
fb16.clear();
glMaterial(GL_FRONT_AND_BACK, type, fb16); glMaterial(GL_FRONT_AND_BACK, type, fb16);
} }
private void setMaterialFloat(int type, float value){ /**
if (!materialSet) { * Applies fixed function bindings from the context to OpenGL
materialSet = true; */
glEnable(GL_COLOR_MATERIAL); private void applyFixedFuncBindings(boolean forLighting){
if (forLighting){
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, context.shininess);
setMaterialColor(GL_AMBIENT, context.ambient, ColorRGBA.DarkGray);
setMaterialColor(GL_DIFFUSE, context.diffuse, ColorRGBA.White);
setMaterialColor(GL_SPECULAR, context.specular, ColorRGBA.Black);
if (context.useVertexColor){
glEnable(GL_COLOR_MATERIAL);
}else{
glDisable(GL_COLOR_MATERIAL);
}
}else{
// Ignore other values as they have no effect when
// GL_LIGHTING is disabled.
ColorRGBA color = context.color;
if (color != null){
glColor4f(color.r, color.g, color.b, color.a);
}else{
glColor4f(1,1,1,1);
}
} }
}
glMaterialf(GL_FRONT_AND_BACK, type, value);
/**
* Reset fixed function bindings to default values.
*/
private void resetFixedFuncBindings(){
context.color = null;
context.ambient = null;
context.diffuse = null;
context.specular = null;
context.shininess = 0;
context.useVertexColor = false;
} }
public void setFixedFuncBinding(FixedFuncBinding ffBinding, Object val) { public void setFixedFuncBinding(FixedFuncBinding ffBinding, Object val) {
switch (ffBinding) { switch (ffBinding) {
case Color: case Color:
ColorRGBA color = (ColorRGBA) val; context.color = (ColorRGBA) val;
glColor4f(color.r, color.g, color.b, color.a);
colorSet = true;
break; break;
case MaterialAmbient: case MaterialAmbient:
ColorRGBA ambient = (ColorRGBA) val; context.ambient = (ColorRGBA) val;
setMaterialColor(GL_AMBIENT, ambient);
break; break;
case MaterialDiffuse: case MaterialDiffuse:
ColorRGBA diffuse = (ColorRGBA) val; context.diffuse = (ColorRGBA) val;
setMaterialColor(GL_DIFFUSE, diffuse);
break; break;
case MaterialSpecular: case MaterialSpecular:
ColorRGBA specular = (ColorRGBA) val; context.specular = (ColorRGBA) val;
setMaterialColor(GL_SPECULAR, specular);
break; break;
case MaterialShininess: case MaterialShininess:
float shiny = (Float) val; context.shininess = (Float) val;
setMaterialFloat(GL_SPECULAR, shiny); break;
case UseVertexColor:
context.useVertexColor = (Boolean) val;
break; break;
}
}
public void clearSetFixedFuncBindings() {
if (colorSet) {
glColor4f(1, 1, 1, 1);
colorSet = false;
}
if (materialSet) {
glDisable(GL_COLOR_MATERIAL);
materialSet = false; // TODO: not efficient
} }
} }
public void applyRenderState(RenderState state) { public void applyRenderState(RenderState state) {
if (state.isWireframe() && !context.wireframe) { if (state.isWireframe() && !context.wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@ -393,37 +442,194 @@ public class LwjglGL1Renderer implements GL1Renderer {
store.clear(); store.clear();
return store; return store;
} }
public void setWorldMatrix(Matrix4f worldMatrix) { private void setModelView(Matrix4f modelMatrix, Matrix4f viewMatrix){
if (context.matrixMode != GL_MODELVIEW) { if (context.matrixMode != GL_MODELVIEW) {
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
context.matrixMode = GL_MODELVIEW; context.matrixMode = GL_MODELVIEW;
} }
glLoadMatrix(storeMatrix(viewMatrix, fb16)); glLoadMatrix(storeMatrix(viewMatrix, fb16));
glMultMatrix(storeMatrix(worldMatrix, fb16)); glMultMatrix(storeMatrix(modelMatrix, fb16));
} }
public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { private void setProjection(Matrix4f projMatrix){
if (context.matrixMode != GL_PROJECTION) { if (context.matrixMode != GL_PROJECTION) {
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
context.matrixMode = GL_PROJECTION; context.matrixMode = GL_PROJECTION;
} }
storeMatrix(projMatrix, fb16); glLoadMatrix(storeMatrix(projMatrix, fb16));
glLoadMatrix(fb16); }
public void setWorldMatrix(Matrix4f worldMatrix) {
this.worldMatrix.set(worldMatrix);
}
public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
this.viewMatrix.set(viewMatrix); this.viewMatrix.set(viewMatrix);
setProjection(projMatrix);
} }
public void setLighting(LightList list) { public void setLighting(LightList list) {
if (list == null || list.size() == 0) { // XXX: This is abuse of setLighting() to
// turn off lighting // apply fixed function bindings
//glDisable(GL_LIGHTING); // and do other book keeping.
if (list == null || list.size() == 0){
glDisable(GL_LIGHTING);
applyFixedFuncBindings(false);
setModelView(worldMatrix, viewMatrix);
return; return;
} }
// Number of lights set previously
int numLightsSetPrev = lightList.size();
// If more than maxLights are defined, they will be ignored.
// The GL1 renderer is not permitted to crash due to a
// GL1 limitation. It must render anything that the GL2 renderer
// can render (even incorrectly).
lightList.clear();
materialAmbientColor.set(0, 0, 0, 0);
for (int i = 0; i < list.size(); i++){
Light l = list.get(i);
if (l.getType() == Light.Type.Ambient){
// Gather
materialAmbientColor.addLocal(l.getColor());
}else{
// Add to list
lightList.add(l);
// Once maximum lights reached, exit loop.
if (lightList.size() >= maxLights){
break;
}
}
}
applyFixedFuncBindings(true);
glEnable(GL_LIGHTING);
fb16.clear();
fb16.put(materialAmbientColor.r)
.put(materialAmbientColor.g)
.put(materialAmbientColor.b)
.put(1).flip();
glLightModel(GL_LIGHT_MODEL_AMBIENT, fb16);
if (context.matrixMode != GL_MODELVIEW) {
glMatrixMode(GL_MODELVIEW);
context.matrixMode = GL_MODELVIEW;
}
// Lights are already in world space, so just convert
// them to view space.
glLoadMatrix(storeMatrix(viewMatrix, fb16));
for (int i = 0; i < lightList.size(); i++){
int glLightIndex = GL_LIGHT0 + i;
Light light = lightList.get(i);
Light.Type lightType = light.getType();
ColorRGBA col = light.getColor();
Vector3f pos;
// Enable the light
glEnable(glLightIndex);
// OGL spec states default value for light ambient is black
switch (lightType){
case Directional:
DirectionalLight dLight = (DirectionalLight) light;
fb16.clear();
fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
glLight(glLightIndex, GL_DIFFUSE, fb16);
glLight(glLightIndex, GL_SPECULAR, fb16);
pos = tempVec.set(dLight.getDirection()).negateLocal().normalizeLocal();
fb16.clear();
fb16.put(pos.x).put(pos.y).put(pos.z).put(0.0f).flip();
glLight(glLightIndex, GL_POSITION, fb16);
glLightf(glLightIndex, GL_SPOT_CUTOFF, 180);
break;
case Point:
PointLight pLight = (PointLight) light;
fb16.clear();
fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
glLight(glLightIndex, GL_DIFFUSE, fb16);
glLight(glLightIndex, GL_SPECULAR, fb16);
pos = pLight.getPosition();
fb16.clear();
fb16.put(pos.x).put(pos.y).put(pos.z).put(1.0f).flip();
glLight(glLightIndex, GL_POSITION, fb16);
glLightf(glLightIndex, GL_SPOT_CUTOFF, 180);
if (pLight.getRadius() > 0) {
// Note: this doesn't follow the same attenuation model
// as the one used in the lighting shader.
glLightf(glLightIndex, GL_CONSTANT_ATTENUATION, 1);
glLightf(glLightIndex, GL_LINEAR_ATTENUATION, pLight.getInvRadius() * 2);
glLightf(glLightIndex, GL_QUADRATIC_ATTENUATION, pLight.getInvRadius() * pLight.getInvRadius());
}else{
glLightf(glLightIndex, GL_CONSTANT_ATTENUATION, 1);
glLightf(glLightIndex, GL_LINEAR_ATTENUATION, 0);
glLightf(glLightIndex, GL_QUADRATIC_ATTENUATION, 0);
}
//glEnable(GL_LIGHTING); break;
case Spot:
SpotLight sLight = (SpotLight) light;
fb16.clear();
fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
glLight(glLightIndex, GL_DIFFUSE, fb16);
glLight(glLightIndex, GL_SPECULAR, fb16);
pos = sLight.getPosition();
fb16.clear();
fb16.put(pos.x).put(pos.y).put(pos.z).put(1.0f).flip();
glLight(glLightIndex, GL_POSITION, fb16);
Vector3f dir = sLight.getDirection();
fb16.clear();
fb16.put(dir.x).put(dir.y).put(dir.z).put(1.0f).flip();
glLight(glLightIndex, GL_SPOT_DIRECTION, fb16);
float outerAngleRad = sLight.getSpotOuterAngle();
float innerAngleRad = sLight.getSpotInnerAngle();
float spotCut = outerAngleRad * FastMath.RAD_TO_DEG;
float spotExpo = 0.0f;
if (outerAngleRad > 0) {
spotExpo = (1.0f - (innerAngleRad / outerAngleRad)) * 128.0f;
}
glLightf(glLightIndex, GL_SPOT_CUTOFF, spotCut);
glLightf(glLightIndex, GL_SPOT_EXPONENT, spotExpo);
if (sLight.getSpotRange() > 0) {
glLightf(glLightIndex, GL_LINEAR_ATTENUATION, sLight.getInvSpotRange());
}else{
glLightf(glLightIndex, GL_LINEAR_ATTENUATION, 0);
}
break;
default:
throw new UnsupportedOperationException(
"Unrecognized light type: " + lightType);
}
}
// Disable lights after the index
for (int i = lightList.size(); i < numLightsSetPrev; i++){
glDisable(GL_LIGHT0 + i);
}
// This will set view matrix as well.
setModelView(worldMatrix, viewMatrix);
} }
private int convertTextureType(Texture.Type type) { private int convertTextureType(Texture.Type type) {
@ -889,7 +1095,7 @@ public class LwjglGL1Renderer implements GL1Renderer {
// TODO: Fix these to use IDList?? // TODO: Fix these to use IDList??
clearVertexAttribs(); clearVertexAttribs();
clearTextureUnits(); clearTextureUnits();
clearSetFixedFuncBindings(); resetFixedFuncBindings();
} }
public void renderMesh(Mesh mesh, int lod, int count) { public void renderMesh(Mesh mesh, int lod, int count) {
@ -905,7 +1111,7 @@ public class LwjglGL1Renderer implements GL1Renderer {
glLineWidth(mesh.getLineWidth()); glLineWidth(mesh.getLineWidth());
context.lineWidth = mesh.getLineWidth(); context.lineWidth = mesh.getLineWidth();
} }
boolean dynamic = false; boolean dynamic = false;
if (mesh.getBuffer(Type.InterleavedData) != null) { if (mesh.getBuffer(Type.InterleavedData) != null) {
throw new UnsupportedOperationException("Interleaved meshes are not supported"); throw new UnsupportedOperationException("Interleaved meshes are not supported");

Loading…
Cancel
Save