OpenGL 1.1 renderer (LwjglGL1Renderer)

I tried to make LwjglGL1Renderer work. A first smoke test looks like this (test scene below):



GL2:





GL1:





The red and blue boxes use per pixel lighting (GL2 only), so the spot light looks good. The white disc has lots of vertices, so the spot light is recognizable even with vertex lighting in GL1. The cyan box uses vertex colors whereas all other geometry uses material colors.



I’m no expert and assume there’s lots of bugs and optimization potential in the code, but here it is:



[patch]

This patch file was generated by NetBeans IDE

Following Index: paths are relative to: C:UserssurvivorDocumentsjMonkeyProjectsjmonkeyengineenginesrclwjgl-oglcomjme3rendererlwjgl

This patch can be applied using context Tools: Patch action on respective folder.

It uses platform neutral UTF-8 encoding and n newlines.

Above lines and this line are ignored by the patching process.

Index: LwjglGL1Renderer.java

— LwjglGL1Renderer.java Base (BASE)

+++ LwjglGL1Renderer.java Locally Modified (Based On LOCAL)

@@ -1,5 +1,11 @@

package com.jme3.renderer.lwjgl;



+import com.jme3.light.SpotLight;

+import com.jme3.light.PointLight;

+import com.jme3.light.AmbientLight;

+import com.jme3.math.Vector3f;

+import com.jme3.light.DirectionalLight;

+import com.jme3.light.Light;

import org.lwjgl.opengl.GL14;

import com.jme3.math.FastMath;

import com.jme3.renderer.GL1Renderer;

@@ -48,6 +54,7 @@

private final IntBuffer ib1 = BufferUtils.createIntBuffer(1);

private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16);

private final FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);

  • private final FloatBuffer fb4Null = BufferUtils.createFloatBuffer(4);

    private final RenderContext context = new RenderContext();

    private final GLObjectManager objManager = new GLObjectManager();

    private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);

    @@ -63,7 +70,8 @@

    private Matrix4f viewMatrix = new Matrix4f();

    // private Matrix4f projMatrix = new Matrix4f();

    private boolean colorSet = false;
  • private boolean materialSet = false;
  • private boolean colorMaterialSet = false;
  • private int usedLightsCount = 0;



    protected void updateNameBuffer() {

    int len = stringBuf.length();

    @@ -86,6 +94,7 @@

    }



    public void initialize() {
  •    fb4Null.put(0.0f).put(0.0f).put(0.0f).put(0.0f).flip();<br />
    

//glDisable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

@@ -145,26 +154,11 @@

}



private void setMaterialColor(int type, ColorRGBA color) {

  •    if (!materialSet) {<br />
    
  •        materialSet = true;<br />
    
  •        glEnable(GL_COLOR_MATERIAL);<br />
    
  •    }<br />
    

-

fb16.clear();

  •    fb16.put(color.r).put(color.g).put(color.b).put(color.a);<br />
    
  •    fb16.clear();<br />
    
  •    fb16.put(color.r).put(color.g).put(color.b).put(color.a).flip();<br />
    

glMaterial(GL_FRONT_AND_BACK, type, fb16);

}


  • private void setMaterialFloat(int type, float value){
  •    if (!materialSet) {<br />
    
  •        materialSet = true;<br />
    
  •        glEnable(GL_COLOR_MATERIAL);<br />
    
  •    }<br />
    

-

  •    glMaterialf(GL_FRONT_AND_BACK, type, value);<br />
    
  • }

    -

    public void setFixedFuncBinding(FixedFuncBinding ffBinding, Object val) {

    switch (ffBinding) {

    case Color:

    @@ -186,9 +180,17 @@

    break;

    case MaterialShininess:

    float shiny = (Float) val;
  •            setMaterialFloat(GL_SPECULAR, shiny);<br />
    
  •            glMaterialf(GL_FRONT_AND_BACK, GL_SPECULAR, shiny);<br />
    

break;

  •        case UseVertexColor:<br />
    
  •            if (((Boolean) val) &amp;&amp; !colorMaterialSet)<br />
    
  •            {<br />
    
  •                glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE | GL_SPECULAR);<br />
    
  •                glEnable(GL_COLOR_MATERIAL);<br />
    
  •                colorMaterialSet = true;<br />
    
  •            }<br />
    

+ break;
}
}

@@ -197,9 +199,9 @@
glColor4f(1, 1, 1, 1);
colorSet = false;
}
- if (materialSet) {
+ if (colorMaterialSet) {
glDisable(GL_COLOR_MATERIAL);
- materialSet = false; // TODO: not efficient
+ colorMaterialSet = false; // TODO: not efficient
}
}

@@ -417,15 +419,144 @@
}

public void setLighting(LightList list) {
- if (list == null || list.size() == 0) {
- // turn off lighting
- //glDisable(GL_LIGHTING);
- return;
+ if ((list != null) && (list.size() > 0))
+ {
+ int nLights = list.size();
+ int glMaxLights = glGetInteger(GL_MAX_LIGHTS);
+ if (nLights <= glMaxLights)
+ {
+ for (int i = 0; i < glMaxLights; i++)
+ {
+ int glLightIndex = GL_LIGHT0 + i;
+ if (i < nLights)
+ {
+ Light light = list.get(i);
+ Light.Type lightType = light.getType();
+ ColorRGBA col = light.getColor();
+
+ 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);
+ glLight(glLightIndex, GL_AMBIENT, fb4Null);
+
+ Vector3f pos = dLight.getDirection().negate().normalize();
+ fb16.clear();
+ fb16.put(pos.x).put(pos.y).put(pos.z).put(0.0f).flip();
+ glLight(glLightIndex, GL_POSITION, fb16);
+ break;
}

- //glEnable(GL_LIGHTING);
+ 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);
+ glLight(glLightIndex, GL_AMBIENT, fb4Null);
+
+ Vector3f pos = pLight.getPosition();
+ fb16.clear();
+ fb16.put(pos.x).put(pos.y).put(pos.z).put(1.0f).flip();
+ glLight(glLightIndex, GL_POSITION, fb16);
+
+ if (pLight.getRadius() > 0)
+ {
+ glLightf(glLightIndex, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf(glLightIndex, GL_LINEAR_ATTENUATION, pLight.getInvRadius());
}

+ 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);
+ glLight(glLightIndex, GL_AMBIENT, fb4Null);
+
+ Vector3f 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().normalize();
+ 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());
+ }
+
+ break;
+ }
+
+ case Ambient:
+ {
+ fb16.clear();
+ fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
+ glLight(glLightIndex, GL_AMBIENT, fb16);
+ glLight(glLightIndex, GL_DIFFUSE, fb4Null);
+ glLight(glLightIndex, GL_SPECULAR, fb4Null);
+ break;
+ }
+
+ default:
+ throw new UnsupportedOperationException(
+ "Unrecognized light type: " + lightType);
+ }
+
+ glEnable(glLightIndex);
+ }
+ else
+ {
+ glDisable(glLightIndex);
+ }
+ }
+
+ fb16.clear();
+ fb16.put(0.0f).put(0.0f).put(0.0f).put(0.0f).flip();
+ glLightModel(GL_LIGHT_MODEL_AMBIENT, fb16);
+ glEnable(GL_LIGHTING);
+ }
+ else
+ {
+ throw new UnsupportedOperationException(
+ "Too many lights defined!");
+ }
+ }
+ else
+ {
+ glDisable(GL_LIGHTING);
+ }
+ }
+
private int convertTextureType(Texture.Type type) {
switch (type) {
case TwoDimensional:
[/patch]

[patch]
# This patch file was generated by NetBeans IDE
# Following Index: paths are relative to: C:UserssurvivorDocumentsjMonkeyProjectsjmonkeyengineenginesrccorecomjme3material
# This patch can be applied using context Tools: Patch action on respective folder.
# It uses platform neutral UTF-8 encoding and n newlines.
# Above lines and this line are ignored by the patching process.
Index: FixedFuncBinding.java
--- FixedFuncBinding.java Base (BASE)
+++ FixedFuncBinding.java Locally Modified (Based On LOCAL)
@@ -69,5 +69,10 @@
*
* Same as GL_SHININESS for OpenGL.
*/
- MaterialShininess
+ MaterialShininess,
+
+ /**
+ * Use vertex color as an additional diffuse color.
+ */
+ UseVertexColor
}
[/patch]

[patch]
# This patch file was generated by NetBeans IDE
# Following Index: paths are relative to: C:UserssurvivorDocumentsjMonkeyProjectsjmonkeyengineenginesrccore-dataCommonMatDefsLight
# This patch can be applied using context Tools: Patch action on respective folder.
# It uses platform neutral UTF-8 encoding and n newlines.
# Above lines and this line are ignored by the patching process.
Index: Lighting.j3md
--- Lighting.j3md Base (BASE)
+++ Lighting.j3md Locally Modified (Based On LOCAL)
@@ -35,7 +35,7 @@
Boolean WardIso

// Use vertex color as an additional diffuse color.
- Boolean UseVertexColor
No newline at end of file
+ Boolean UseVertexColor (UseVertexColor)
No newline at end of file

// Ambient color
Color Ambient (MaterialAmbient)
[/patch]

And finally, the test scene:

[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.light.SpotLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import com.jme3.system.AppSettings;
import java.util.logging.Level;
import java.util.logging.Logger;

public class HelloOpenGL1 extends SimpleApplication {

public static void main(String[] args) {
AppSettings apps = new AppSettings(true);
apps.setRenderer(AppSettings.LWJGL_OPENGL1);
apps.setAudioRenderer(null);

Logger.getLogger("").setLevel(Level.SEVERE);
HelloOpenGL1 app = new HelloOpenGL1();
app.setSettings(apps);
app.start();
}

@Override
public void simpleInitApp() {
setDisplayStatView(false);
flyCam.setMoveSpeed(5.0f);

Cylinder disc = new Cylinder(128, 128, 10.0f, 1.0f, 1.0f, false, true);
//disc.setMode(Mesh.Mode.LineLoop);
this.setVertexColors(disc, ColorRGBA.White);

Spatial disc1 = new Geometry("Disc1", disc);
Material disc1mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
disc1mat.setColor("Diffuse", ColorRGBA.White);
//disc1mat.setBoolean("UseMaterialColors", true);
disc1mat.setBoolean("VertexLighting", false);
disc1mat.setBoolean("UseVertexColor", true);
disc1.setMaterial(disc1mat);
rootNode.attachChild(disc1);

Box box = new Box(Vector3f.ZERO, 2.5f, 2.5f, 1.0f);
this.setVertexColors(box, ColorRGBA.Cyan);

Geometry box1 = new Geometry("Box1", box);
//Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
//mat1.setColor("Color", new ColorRGBA(0.8f, 0.0f, 0.0f, 1.0f));
//mat1.setBoolean("VertexColor", true);
Material mat1 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mat1.setColor("Diffuse", new ColorRGBA(0.8f, 0.0f, 0.0f, 1.0f));
mat1.setBoolean("UseMaterialColors", true);
mat1.setBoolean("UseVertexColor", false);
//mat1.setBoolean("VertexLighting", true);
box1.setMaterial(mat1);
//box1.setMaterial(boxMat);
box1.setLocalTranslation(5.0f, 0.0f, 0.0f);
//box1.rotate(0, FastMath.PI / 4, 0);
rootNode.attachChild(box1);

Geometry box2 = new Geometry("Box2", box);
Material mat2 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
//mat2.setColor("Color", ColorRGBA.Green);
mat2.setColor("Diffuse", new ColorRGBA(0.0f, 0.8f, 0.0f, 1.0f));
mat2.setBoolean("UseMaterialColors", true);
//mat2.setBoolean("UseVertexColor", true);
mat2.setBoolean("VertexLighting", true);
box2.setMaterial(mat2);
box2.setLocalTranslation(0.0f, 5.0f, 0.0f);
//box2.rotate(0, FastMath.PI * 0.25f, 0);
rootNode.attachChild(box2);

Geometry box3 = new Geometry("Box3", box);
Material mat3 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
//mat3.setColor("Color", ColorRGBA.Green);
mat3.setColor("Diffuse", new ColorRGBA(0.0f, 0.0f, 0.8f, 1.0f));
mat3.setBoolean("UseMaterialColors", true);
//mat3.setBoolean("UseVertexColor", true);
//mat3.setBoolean("VertexLighting", true);
box3.setMaterial(mat3);
box3.setLocalTranslation(-5.0f, 0.0f, 0.0f);
//box3.rotate(0, FastMath.PI * 0.5f, 0);
rootNode.attachChild(box3);

Geometry box4 = new Geometry("Box4", box);
Material mat4 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
//mat4.setColor("Color", ColorRGBA.Green);
mat4.setColor("Diffuse", new ColorRGBA(0.2f, 0.4f, 0.2f, 1.0f));
mat4.setBoolean("UseMaterialColors", false);
mat4.setBoolean("UseVertexColor", true);
mat4.setBoolean("VertexLighting", true);
box4.setMaterial(mat4);
box4.setLocalTranslation(0.0f, -5.0f, 0.0f);
//box4.rotate(0, FastMath.PI * 0.75f, 0);
rootNode.attachChild(box4);

DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(1.5f, 0.5f, -1.0f));
sun.setColor(ColorRGBA.DarkGray);
rootNode.addLight(sun);

// PointLight bulb = new PointLight();
// bulb.setPosition(new Vector3f(-15.0f, -5.0f, 10.0f));
// bulb.setColor(ColorRGBA.White);
// bulb.setRadius(15.0f);
// rootNode.addLight(bulb);

SpotLight torch = new SpotLight();
torch.setPosition(new Vector3f(-15.0f, -5.0f, 10.0f));
torch.setDirection(new Vector3f(15.0f, 5.0f, -10.0f));
torch.setColor(ColorRGBA.White);
torch.setSpotRange(1500.0f);
torch.setSpotOuterAngle(9.5f * FastMath.DEG_TO_RAD);
torch.setSpotInnerAngle(9.1f * FastMath.DEG_TO_RAD);
rootNode.addLight(torch);

AmbientLight cloud = new AmbientLight();
cloud.setColor(new ColorRGBA(0.05f, 0.05f, 0.05f, 1.0f));
rootNode.addLight(cloud);
}

@Override
public void simpleUpdate(float tpf) {
}

@Override
public void simpleRender(RenderManager rm) {
}

private void setVertexColors(Mesh mesh, ColorRGBA color)
{
float[] colors = new float[mesh.getVertexCount() * 4];
for (int i = 0; i < colors.length; i += 4)
{
colors[0 + i] = color.r;
colors[1 + i] = color.g;
colors[2 + i] = color.b;
colors[3 + i] = color.a;
}

mesh.setBuffer(Type.Color, 4, colors);
}
}
[/java]
3 Likes

Thanks for fixing them. It also helps me to shorten the gaps in my knowledge.



Edit: Awesome! The corners of the boxes are correctly lit by the spot light now. Thanks a lot!



That’s great news!



What kind of lights we can use with OpenGL1? Ambient, Spot, Point?



Will OpenGL1 be support different texture coordinates (for lightmaps)?

Is it possible to use lightmaps with OpenGL1?



What about specular lighting in Opengl1?

All jME3 light types seem to work (at least similarly). Simple texturing also works:







I have no idea if light maps work. Just test it.

Hey, awesome work man! I’m sure you’ll make some NetBook users very happy with this :slight_smile: Thanks very much for contributing!

Sweet! I mean really awesome!

You can edit the topic (top right, above the “normal” edit links), just join the group (Contribution Depot jME3).

1 Like

I have commited a heavily modified version of this patch to SVN (the original had quite a few bugs)

Thanks

2 Likes

Probably light maps won’t work. There some fixes still that can be made.