← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2630: - Fix stripes display

 

------------------------------------------------------------
revno: 2630
committer: Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>
branch nick: yade
timestamp: Tue 2010-12-28 17:01:44 +0100
message:
  - Fix stripes display
  - Add secondary light and register light parameters
  - define specular exponent for smoother display
  - define and use GL display lists
modified:
  pkg/common/Gl1_Sphere.cpp
  pkg/common/Gl1_Sphere.hpp
  pkg/common/OpenGLRenderer.cpp
  pkg/common/OpenGLRenderer.hpp


--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription
=== modified file 'pkg/common/Gl1_Sphere.cpp'
--- pkg/common/Gl1_Sphere.cpp	2010-11-19 12:30:08 +0000
+++ pkg/common/Gl1_Sphere.cpp	2010-12-28 16:01:44 +0000
@@ -1,6 +1,7 @@
 /*************************************************************************
-*  Copyright (C) 2004 by Olivier Galizzi                                 *
-*  olivier.galizzi@xxxxxxx                                               *
+*  © 2004 Olivier Galizzi  <olivier.galizzi@xxxxxxx>                     *
+*  © 2008 Václav Šmilauer <eudoxos@xxxxxxxx>                             *
+*  © 2008 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>                    *
 *                                                                        *
 *  This program is free software; it is licensed under the terms of the  *
 *  GNU General Public License v2 or later. See file LICENSE for details. *
@@ -14,61 +15,55 @@
 
 bool Gl1_Sphere::wire;
 bool Gl1_Sphere::stripes;
-bool Gl1_Sphere::glutNormalize;
 int  Gl1_Sphere::glutSlices;
 int  Gl1_Sphere::glutStacks;
-
+Real  Gl1_Sphere::quality;
+bool  Gl1_Sphere::localSpecView;
 vector<Vector3r> Gl1_Sphere::vertices, Gl1_Sphere::faces;
 int Gl1_Sphere::glSphereList=-1;
+int Gl1_Sphere::glGlutSphereList=-1;
+Real  Gl1_Sphere::prevQuality=0;
 
 void Gl1_Sphere::go(const shared_ptr<Shape>& cm, const shared_ptr<State>& ,bool wire2, const GLViewInfo&)
 {
+	glClearDepth(1.0f);
+	glEnable(GL_NORMALIZE);
+	GLfloat glutMatSpecular[4]={0.5,0.5,0.5,1.0};
+	GLfloat glutMatEmit[4]={0.2,0.2,0.2,1.0};
+	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,glutMatSpecular);
+	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,glutMatEmit);
+	glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 80);
 	Real r=(static_cast<Sphere*>(cm.get()))->radius;
-	//glMaterialv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Vector3f(cm->color[0],cm->color[1],cm->color[2]));
+
 	glColor3v(cm->color);
-	if(glutNormalize)	glPushAttrib(GL_NORMALIZE); // as per http://lists.apple.com/archives/Mac-opengl/2002/Jul/msg00085.html
-		if (wire || wire2) glutWireSphere(r,glutSlices,glutStacks);
-		else {
- 			if(stripes) { glScalef(r,r,r); drawSphere();}
-			else { glutSolidSphere(r,glutSlices,glutStacks);}
-		}
-	if(glutNormalize) glPopAttrib();
+	if (wire || wire2) glutWireSphere(r,glutSlices,glutStacks);
+	else {
+		initGlLists();
+		glScalef(r,r,r);
+		if(stripes) glCallList(glSphereList);
+		else glCallList(glGlutSphereList);
+	}
 	return;
 }
 YADE_PLUGIN((Gl1_Sphere));
 
-
-/***************************** WARNING *********************
-***** The following code was written by Olivier Galizzi ****
-************ and hasn't been properly reviewed *************/
-
-// https://blueprints.launchpad.net/yade/+spec/sphere-gl-stripes
-
-void Gl1_Sphere::drawSphere(){
-	if(glSphereList<0) initGlLists();
-	glShadeModel(GL_SMOOTH);
-	//glScalef(radius,radius,radius);
-	glCallList(glSphereList);
-}
-
 void Gl1_Sphere::subdivideTriangle(Vector3r& v1,Vector3r& v2,Vector3r& v3, int depth){
-	Vector3r v12,v23,v31;
 	if (depth==0){
 		Vector3r v = (v1+v2+v3)/3.0;
 		Real angle = atan(v[2]/v[0])/v.norm();
-		GLfloat matAmbient[4];
+		GLfloat matEmit[4];
 		if (angle>-Mathr::PI/6.0 && angle<=Mathr::PI/6.0){
-			matAmbient[0] = .3;
-			matAmbient[1] = .3;
-			matAmbient[2] = .3;
-			matAmbient[3] = 1;
+			matEmit[0] = 0.4;
+			matEmit[1] = 0.4;
+			matEmit[2] = 0.4;
+			matEmit[3] = 1.f;
 		}else{
-			matAmbient[0] = 0.0;
-			matAmbient[1] = 0.0;
-			matAmbient[2] = 0.0;
-			matAmbient[3] = 0;
+			matEmit[0] = 0.2;
+			matEmit[1] = 0.2;
+			matEmit[2] = 0.2;
+			matEmit[3] = 1.f;
 		}
-		glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,matAmbient);
+ 		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matEmit);
 		glBegin(GL_TRIANGLES);
 			glNormal3v(v3); glVertex3v(v3);
 			glNormal3v(v2); glVertex3v(v2);
@@ -76,9 +71,9 @@
 		glEnd();
 		return;
 	}
-	v12 = v1+v2;
-	v23 = v2+v3;
-	v31 = v3+v1;
+	Vector3r v12 = v1+v2;
+	Vector3r v23 = v2+v3;
+	Vector3r v31 = v3+v1;
 	v12.normalize();
 	v23.normalize();
 	v31.normalize();
@@ -88,52 +83,64 @@
 	subdivideTriangle(v12,v23,v31,depth-1);
 }
 
-void Gl1_Sphere::initGlLists(void){
-	Real X = 0.525731112119133606;
-	Real Z = 0.850650808352039932;
-	vertices.push_back(Vector3r(-X,0,Z));
-	vertices.push_back(Vector3r(X,0,Z));
-	vertices.push_back(Vector3r(-X,0,-Z));
-	vertices.push_back(Vector3r(X,0,-Z));
-	vertices.push_back(Vector3r(0,Z,X));
-	vertices.push_back(Vector3r(0,Z,-X));
-	vertices.push_back(Vector3r(0,-Z,X));
-	vertices.push_back(Vector3r(0,-Z,-X));
-	vertices.push_back(Vector3r(Z,X,0));
-	vertices.push_back(Vector3r(-Z,X,0));
-	vertices.push_back(Vector3r(Z,-X,0));
-	vertices.push_back(Vector3r(-Z,-X,0));
-
-	faces.push_back(Vector3r(0,4,1));
-	faces.push_back(Vector3r(0,9,4));
-	faces.push_back(Vector3r(9,5,4));
-	faces.push_back(Vector3r(4,5,8));
-	faces.push_back(Vector3r(4,8,1));
-	faces.push_back(Vector3r(8,10,1));
-	faces.push_back(Vector3r(8,3,10));
-	faces.push_back(Vector3r(5,3,8));
-	faces.push_back(Vector3r(5,2,3));
-	faces.push_back(Vector3r(2,7,3));
-	faces.push_back(Vector3r(7,10,3));
-	faces.push_back(Vector3r(7,6,10));
-	faces.push_back(Vector3r(7,11,6));
-	faces.push_back(Vector3r(11,0,6));
-	faces.push_back(Vector3r(0,1,6));
-	faces.push_back(Vector3r(6,1,10));
-	faces.push_back(Vector3r(9,0,11));
-	faces.push_back(Vector3r(9,11,2));
-	faces.push_back(Vector3r(9,2,5));
-	faces.push_back(Vector3r(7,2,11));
-	
-	glSphereList = glGenLists(1);
-	glNewList(glSphereList,GL_COMPILE);
-		glEnable(GL_LIGHTING);
-		glShadeModel(GL_SMOOTH);	
-		// render the sphere now
-		for(int i=0;i<20;i++)
-			subdivideTriangle(vertices[(unsigned int)faces[i][0]],vertices[(unsigned int)faces[i][1]],vertices[(unsigned int)faces[i][2]],1);
-		//drawSphere();
-	glEndList();
+void Gl1_Sphere::initGlLists(){
+	//Generate the "stripes" dislpay list, only once
+	if (glSphereList<0) {
+		Real X = 0.525731112119133606;
+		Real Z = 0.850650808352039932;
+		vertices.push_back(Vector3r(-X,0,Z));
+		vertices.push_back(Vector3r(X,0,Z));
+		vertices.push_back(Vector3r(-X,0,-Z));
+		vertices.push_back(Vector3r(X,0,-Z));
+		vertices.push_back(Vector3r(0,Z,X));
+		vertices.push_back(Vector3r(0,Z,-X));
+		vertices.push_back(Vector3r(0,-Z,X));
+		vertices.push_back(Vector3r(0,-Z,-X));
+		vertices.push_back(Vector3r(Z,X,0));
+		vertices.push_back(Vector3r(-Z,X,0));
+		vertices.push_back(Vector3r(Z,-X,0));
+		vertices.push_back(Vector3r(-Z,-X,0));
+
+		faces.push_back(Vector3r(0,4,1));
+		faces.push_back(Vector3r(0,9,4));
+		faces.push_back(Vector3r(9,5,4));
+		faces.push_back(Vector3r(4,5,8));
+		faces.push_back(Vector3r(4,8,1));
+		faces.push_back(Vector3r(8,10,1));
+		faces.push_back(Vector3r(8,3,10));
+		faces.push_back(Vector3r(5,3,8));
+		faces.push_back(Vector3r(5,2,3));
+		faces.push_back(Vector3r(2,7,3));
+		faces.push_back(Vector3r(7,10,3));
+		faces.push_back(Vector3r(7,6,10));
+		faces.push_back(Vector3r(7,11,6));
+		faces.push_back(Vector3r(11,0,6));
+		faces.push_back(Vector3r(0,1,6));
+		faces.push_back(Vector3r(6,1,10));
+		faces.push_back(Vector3r(9,0,11));
+		faces.push_back(Vector3r(9,11,2));
+		faces.push_back(Vector3r(9,2,5));
+		faces.push_back(Vector3r(7,2,11));
+
+		glSphereList = glGenLists(1);
+		glNewList(glSphereList,GL_COMPILE);
+			glEnable(GL_LIGHTING);
+			glShadeModel(GL_SMOOTH);
+			// render the sphere now
+			for(int i=0;i<20;i++)
+				subdivideTriangle(vertices[(unsigned int)faces[i][0]],vertices[(unsigned int)faces[i][1]],vertices[(unsigned int)faces[i][2]],1);
+		glEndList();
+	}
+	//Generate the "no-stripes" display list, each time quality is modified
+	if (glGlutSphereList<0 || abs(quality-prevQuality)>0.001 /*detect any meaningfull change in quality to regenerate GL primitives*/) {
+		glGlutSphereList = glGenLists(1);
+		glNewList(glGlutSphereList,GL_COMPILE);
+			glEnable(GL_LIGHTING);
+			glShadeModel(GL_SMOOTH);
+			glutSolidSphere(1.0,quality*glutSlices,quality*glutStacks);
+		glEndList();
+		prevQuality=quality;
+	}
 }
 
 #endif /* YADE_OPENGL */

=== modified file 'pkg/common/Gl1_Sphere.hpp'
--- pkg/common/Gl1_Sphere.hpp	2010-11-07 11:46:20 +0000
+++ pkg/common/Gl1_Sphere.hpp	2010-12-28 16:01:44 +0000
@@ -1,6 +1,7 @@
 /*************************************************************************
-*  Copyright (C) 2004 by Olivier Galizzi                                 *
-*  olivier.galizzi@xxxxxxx                                               *
+*  © 2004 Olivier Galizzi  <olivier.galizzi@xxxxxxx>                     *
+*  © 2008 Václav Šmilauer <eudoxos@xxxxxxxx>                             *
+*  © 2008 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx>                    *
 *                                                                        *
 *  This program is free software; it is licensed under the terms of the  *
 *  GNU General Public License v2 or later. See file LICENSE for details. *
@@ -10,22 +11,26 @@
 
 #include<yade/pkg/common/GLDrawFunctors.hpp>
 
-class Gl1_Sphere : public GlShapeFunctor{	
+class Gl1_Sphere : public GlShapeFunctor{
 	private:
 		// for stripes
 		static vector<Vector3r> vertices, faces;
 		static int glSphereList;
+		static int glGlutSphereList;
 		void subdivideTriangle(Vector3r& v1,Vector3r& v2,Vector3r& v3, int depth);
-		void drawSphere(void);
-		void initGlLists(void);
+// 		void drawSphere(const Vector3r& color);
+		void initGlLists();
+		//for regenerating glutSphere list if needed
+		static Real prevQuality;
 	public:
 		virtual void go(const shared_ptr<Shape>&, const shared_ptr<State>&,bool,const GLViewInfo&);
 	YADE_CLASS_BASE_DOC_STATICATTRS(Gl1_Sphere,GlShapeFunctor,"Renders :yref:`Sphere` object",
+		((Real,quality,1.0,,"Change discretization level of spheres. quality>1  for better image quality, at the price of more cpu/gpu usage, 0<quality<1 for faster rendering. This unique factor mutiplies :yref:`Gl1_Sphere::glutSlices` and :yref:`Gl1_Sphere::glutStacks`"))
 		((bool,wire,false,,"Only show wireframe (controlled by ``glutSlices`` and ``glutStacks``."))
 		((bool,stripes,false,,"In non-wire rendering, show stripes clearly showing particle rotation."))
-		((bool,glutNormalize,true,,"Fix normals for non-wire rendering; see http://lists.apple.com/archives/Mac-opengl/2002/Jul/msg00085.html";))
-		((int,glutSlices,12,,"Number of sphere slices; not used with ``stripes`` (see `glut{Solid,Wire}Sphere reference <http://www.opengl.org/documentation/specs/glut/spec3/node81.html>`_)"))
-		((int,glutStacks,6,,"Number of sphere stacks; not used with ``stripes`` (see `glut{Solid,Wire}Sphere reference <http://www.opengl.org/documentation/specs/glut/spec3/node81.html>`_)"))
+		((bool,localSpecView,true,,"Compute specular light in local eye coordinate system."))
+		((int,glutSlices,12,(Attr::noSave | Attr::readonly),"Base number of sphere slices, multiplied by :yref:`Gl1_Sphere::quality` before use); not used with ``stripes`` (see `glut{Solid,Wire}Sphere reference <http://www.opengl.org/documentation/specs/glut/spec3/node81.html>`_)"))
+		((int,glutStacks,6,(Attr::noSave | Attr::readonly),"Base number of sphere stacks, multiplied by :yref:`Gl1_Sphere::quality` before use; not used with ``stripes`` (see `glut{Solid,Wire}Sphere reference <http://www.opengl.org/documentation/specs/glut/spec3/node81.html>`_)"))
 	);
 	RENDERS(Sphere);
 };

=== modified file 'pkg/common/OpenGLRenderer.cpp'
--- pkg/common/OpenGLRenderer.cpp	2010-11-30 13:51:41 +0000
+++ pkg/common/OpenGLRenderer.cpp	2010-12-28 16:01:44 +0000
@@ -98,7 +98,7 @@
 		#ifdef YADE_SUBDOMAINS
 			int subDom; Body::id_t localId;
 			boost::tie(subDom,localId)=scene->bodies->subDomId2domNumLocalId(b->subDomId);
-			if(subDomMask!=0 && (((1<<subDom) & subDomMask)==0)) bodyDisp[id].isDisplayed=false; 
+			if(subDomMask!=0 && (((1<<subDom) & subDomMask)==0)) bodyDisp[id].isDisplayed=false;
 		#endif
 		// if no scaling and no periodic, return quickly
 		if(!(scaleDisplacements||scaleRotations||scene->isPeriodic)){ bodyDisp[id].pos=pos; bodyDisp[id].ori=ori; continue; }
@@ -130,10 +130,11 @@
 }
 
 void OpenGLRenderer::resetSpecularEmission(){
-	const GLfloat specular[4]={.3,.3,.3,1};
+	const GLfloat specular[4]={.3,.03,.03,0.1};
 	const GLfloat emission[4]={0,0,0,0};
 	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular);
 	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,emission);
+	glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
 }
 
 void OpenGLRenderer::render(const shared_ptr<Scene>& _scene,Body::id_t selection){
@@ -158,7 +159,7 @@
 	Real now=TimingInfo::getNow(/*even if timing is disabled*/true)*1e-9;
 	highlightEmission0[0]=highlightEmission0[1]=highlightEmission0[2]=.8*normSquare(now,1);
 	highlightEmission1[0]=highlightEmission1[1]=highlightEmission0[2]=.5*normSaw(now,2);
-		
+
 	// clipping
 	assert(clipPlaneNormals.size()==(size_t)numClipPlanes);
 	for(size_t i=0;i<(size_t)numClipPlanes; i++){
@@ -170,26 +171,42 @@
 		if(clipPlaneActive[i]) clipPlaneNormals[i]=clipPlaneSe3[i].orientation*Vector3r(0,0,1);
 		/* glBegin(GL_LINES);glVertex3v(clipPlaneSe3[i].position);glVertex3v(clipPlaneSe3[i].position+clipPlaneNormals[i]);glEnd(); */
 	}
-
 	// set displayed Se3 of body (scaling) and isDisplayed (clipping)
 	setBodiesDispInfo();
 
-	// set light source
+	glClearColor(bgColor[0],bgColor[1],bgColor[2],1.0);
+
+	// set light sources
+	glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1); // important: do lighting calculations on both sides of polygons
+
 	const GLfloat pos[4]	= {lightPos[0],lightPos[1],lightPos[2],1.0};
-	const GLfloat ambientColor[4]={0.5,0.5,0.5,1.0};	
-	//const GLfloat specularColor[4]={0.5,0.5,0.5,1.0};	
-	glClearColor(bgColor[0],bgColor[1],bgColor[2],1.0);
+	const GLfloat ambientColor[4]={0.2,0.2,0.2,1.0};
+	const GLfloat specularColor[4]={1,1,1,1.f};
+	const GLfloat diffuseLight[4] = { lightColor[0], lightColor[1], lightColor[2], 1.0f };
 	glLightfv(GL_LIGHT0, GL_POSITION,pos);
-	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColor);
-	glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1); // important: do lighting calculations on both sides of polygons
-	//glLightfv(GL_LIGHT0, GL_SPECULAR, specularColor);
-	glEnable(GL_LIGHT0);
+	glLightfv(GL_LIGHT0, GL_SPECULAR, specularColor);
+	glLightfv(GL_LIGHT0, GL_AMBIENT, ambientColor);
+	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
+	if (light1) glEnable(GL_LIGHT0); else glDisable(GL_LIGHT0);
+
+	const GLfloat pos2[4]	= {light2Pos[0],light2Pos[1],light2Pos[2],1.0};
+	const GLfloat ambientColor2[4]={0.0,0.0,0.0,1.0};
+	const GLfloat specularColor2[4]={1,1,0.6,1.f};
+	const GLfloat diffuseLight2[4] = { light2Color[0], light2Color[1], light2Color[2], 1.0f };
+	glLightfv(GL_LIGHT1, GL_POSITION,pos2);
+	glLightfv(GL_LIGHT1, GL_SPECULAR, specularColor2);
+	glLightfv(GL_LIGHT1, GL_AMBIENT, ambientColor2);
+	glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseLight2);
+	if (light2) glEnable(GL_LIGHT1); else glDisable(GL_LIGHT1);
+
 	glEnable(GL_LIGHTING);
 
 	glEnable(GL_CULL_FACE);
 	// http://www.sjbaker.org/steve/omniv/opengl_lighting.html
+	glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
 	glEnable(GL_COLOR_MATERIAL);
-	glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
+	//Shared material settings
+	glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
 
 	resetSpecularEmission();
 
@@ -203,7 +220,7 @@
 	if (intrPhys) renderIPhys();
 
 	FOREACH(const shared_ptr<GlExtraDrawer> d, extraDrawers){
-		if(d->dead) continue; 
+		if(d->dead) continue;
 		glPushMatrix();
 			d->scene=scene.get();
 			d->render();
@@ -228,9 +245,9 @@
 	}
 }
 
-void OpenGLRenderer::renderDOF_ID(){	
-	const GLfloat ambientColorSelected[4]={10.0,0.0,0.0,1.0};	
-	const GLfloat ambientColorUnselected[4]={0.5,0.5,0.5,1.0};	
+void OpenGLRenderer::renderDOF_ID(){
+	const GLfloat ambientColorSelected[4]={10.0,0.0,0.0,1.0};
+	const GLfloat ambientColorUnselected[4]={0.5,0.5,0.5,1.0};
 	FOREACH(const shared_ptr<Body> b, *scene->bodies){
 		if(!b) continue;
 		if(b->shape && ((b->getGroupMask() & mask) || b->getGroupMask()==0)){
@@ -254,7 +271,7 @@
 	}
 }
 
-void OpenGLRenderer::renderIGeom(){	
+void OpenGLRenderer::renderIGeom(){
 	geomDispatcher.scene=scene.get(); geomDispatcher.updateScenePtr();
 	{
 		boost::mutex::scoped_lock lock(scene->interactions->drawloopmutex);
@@ -268,7 +285,7 @@
 }
 
 
-void OpenGLRenderer::renderIPhys(){	
+void OpenGLRenderer::renderIPhys(){
 	physDispatcher.scene=scene.get(); physDispatcher.updateScenePtr();
 	{
 		boost::mutex::scoped_lock lock(scene->interactions->drawloopmutex);
@@ -283,7 +300,7 @@
 	}
 }
 
-void OpenGLRenderer::renderBound(){	
+void OpenGLRenderer::renderBound(){
 	boundDispatcher.scene=scene.get(); boundDispatcher.updateScenePtr();
 
 	FOREACH(const shared_ptr<Body>& b, *scene->bodies){
@@ -332,7 +349,7 @@
 		bool highlight=(b->id==selId || (b->clumpId>=0 && b->clumpId==selId) || b->shape->highlight);
 
 		glPushMatrix();
-			AngleAxisr aa(ori);	
+			AngleAxisr aa(ori);
 			glTranslatef(pos[0],pos[1],pos[2]);
 			glRotatef(aa.angle()*Mathr::RAD_TO_DEG,aa.axis()[0],aa.axis()[1],aa.axis()[2]);
 			if(highlight){

=== modified file 'pkg/common/OpenGLRenderer.hpp'
--- pkg/common/OpenGLRenderer.hpp	2010-12-10 15:07:56 +0000
+++ pkg/common/OpenGLRenderer.hpp	2010-12-28 16:01:44 +0000
@@ -63,7 +63,7 @@
 		vector<string>
 			// stateFunctorNames,
 			boundFunctorNames,
-			shapeFunctorNames, 
+			shapeFunctorNames,
 			geomFunctorNames,
 			physFunctorNames;
 
@@ -71,13 +71,13 @@
 
 	public :
 		// updated after every call to render
-		shared_ptr<Scene> scene; 
+		shared_ptr<Scene> scene;
 
 		void init();
 		void initgl();
 		void render(const shared_ptr<Scene>& scene, Body::id_t selection=Body::id_t(-1));
 		void pyRender(){render(Omega::instance().getScene());}
-	
+
 		void renderDOF_ID();
 		void renderIPhys();
 		void renderIGeom();
@@ -90,8 +90,13 @@
 		((Vector3r,dispScale,((void)"disable scaling",Vector3r::Ones()),,"Artificially enlarge (scale) dispalcements from bodies' :yref:`reference positions<State.refPos>` by this relative amount, so that they become better visible (independently in 3 dimensions). Disbled if (1,1,1)."))
 		((Real,rotScale,((void)"disable scaling",1.),,"Artificially enlarge (scale) rotations of bodies relative to their :yref:`reference orientation<State.refOri>`, so the they are better visible."))
 		((Vector3r,lightPos,Vector3r(75,130,0),,"Position of OpenGL light source in the scene."))
+		((Vector3r,light2Pos,Vector3r(-130,75,30),,"Position of secondary OpenGL light source in the scene."))
+		((Vector3r,lightColor,Vector3r(0.8,0.8,0.8),,"Per-color intensity of primary light (RGB)."))
+		((Vector3r,light2Color,Vector3r(0.5,0.5,0.1),,"Per-color intensity of secondary light (RGB)."))
 		((Vector3r,bgColor,Vector3r(.2,.2,.2),,"Color of the backgroud canvas (RGB)"))
 		((bool,wire,false,,"Render all bodies with wire only (faster)"))
+		((bool,light1,true,,"Turn light 1 on."))
+		((bool,light2,true,,"Turn light 2 on."))
 		((bool,dof,false,,"Show which degrees of freedom are blocked for each body"))
 		((bool,id,false,,"Show body id's"))
 		((bool,bound,false,,"Render body :yref:`Bound`"))