Mondschein Engine  0.3.0
renderer.cpp
1 /* Mondschein Engine is a fast, powerful, and easy-to-use 3D realtime rendering engine.
2  *
3  * Copyright (C) 2009-2013 by Andreas Amereller
4  * E-Mail: andreas.amereller.dev@googlemail.com
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "gl13/renderer.h"
22 #include "gl13/display_list.h"
23 #include "gl13/pose.h"
24 #include "gl13/texture.h"
25 #include "core/context.h"
26 #include "core/scenegraph.h"
27 #include "core/camera.h"
28 #include "core/light.h"
29 #include "core/material.h"
30 #include "core/mesh.h"
31 #include "core/pose.h"
32 #include "core/texture.h"
33 #include <GL/glu.h>
34 #include <GL/glext.h>
35 
36 using namespace mondschein;
37 using namespace renderer;
38 
39 GL13::GL13() : Renderer(), renderstack()
40 {
41  return;
42 }
43 
44 GL13::~GL13()
45 {
46  return;
47 }
48 
49 void GL13::set_renderstack(const std::list<Renderable_c> &_rs)
50 {
51  renderstack=_rs;
52  return;
53 }
54 
55 std::list<Renderable_c> GL13::get_renderstack() const
56 {
57  return renderstack;
58 }
59 
60 void GL13::toggle_feature(const std::string &_feature,bool _state)
61 {
62  Renderer::toggle_feature("",false);
63  if (_state)
64  {
65  if (_feature == "2D Texturing") glEnable(GL_TEXTURE_2D);
66  else if (_feature == "Depth Test") glEnable(GL_DEPTH);
67  else if (_feature == "Colour Material") glEnable(GL_COLOR_MATERIAL);
68  else if (_feature == "Vertex Lighting") glEnable(GL_LIGHTING);
69  }
70  else
71  {
72  if (_feature == "2D_Texturing") glDisable(GL_TEXTURE_2D);
73  else if (_feature == "Depth_Test") glDisable(GL_DEPTH);
74  else if (_feature == "Colour Material") glDisable(GL_COLOR_MATERIAL);
75  else if (_feature == "Vertex Lighting") glDisable(GL_LIGHTING);
76  }
77  return;
78 }
79 
80 void GL13::set_clear_color(const Eigen::Vector4d &_color)
81 {
83  glClearColor(_color(0),_color(1),_color(2),_color(3));
84  return;
85 }
86 
88 {
90  glClear(GL_COLOR_BUFFER_BIT);
91  return;
92 }
93 
95 {
97  glClear(GL_DEPTH_BUFFER_BIT);
98  return;
99 }
100 
101 std::string GL13::id() const
102 {
103  return std::string("GL13");
104 }
105 
106 void GL13::create_camera(const std::string& _id,const scene::camera_attribs_t& _c)
107 {
108  uint32 dsp=glGenLists(1);
109  float64 f=_c.near*std::tan(_c.fovy/2.0*TO_RAD);
110  glNewList(dsp,GL_COMPILE);
111  glViewport(_c.x,_c.y,_c.w,_c.h);
112  glMatrixMode(GL_PROJECTION);
113  glLoadIdentity();
114  glFrustum(-f*_c.aspect,f*_c.aspect,-f,f,_c.near,_c.far);
115  glEndList();
116  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
117  r.erase(_id);
118  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Display_List_c(new GL13_Display_List(dsp))));
119  get_context()->set_renderables(r);
120  return;
121 }
122 
123 void GL13::create_light(const std::string& _id,const scene::light_attribs_t& _l)
124 {
125  uint32 dsp=glGenLists(1);
126  float32 v[4];
127  glNewList(dsp,GL_COMPILE);
128  v[0]=_l.ambient(0); v[1]=_l.ambient(1); v[2]=_l.ambient(2); v[3]=_l.ambient(3);
129  glLightfv(GL_LIGHT0+_l.unit,GL_AMBIENT,v);
130  v[0]=_l.diffuse(0); v[1]=_l.diffuse(1); v[2]=_l.diffuse(2); v[3]=_l.diffuse(3);
131  glLightfv(GL_LIGHT0+_l.unit,GL_DIFFUSE,v);
132  v[0]=_l.specular(0); v[1]=_l.specular(1); v[2]=_l.specular(2); v[3]=_l.specular(3);
133  glLightfv(GL_LIGHT0+_l.unit,GL_SPECULAR,v);
134  v[0]=_l.position(0); v[1]=_l.position(1); v[2]=_l.position(2); v[3]=_l.position(3);
135  glLightfv(GL_LIGHT0+_l.unit,GL_POSITION,v);
136  v[0]=_l.direction(0); v[1]=_l.direction(1); v[2]=_l.direction(2); v[3]=_l.direction(3);
137  glLightfv(GL_LIGHT0+_l.unit,GL_SPOT_DIRECTION,v);
138  glLightf(GL_LIGHT0+_l.unit,GL_SPOT_CUTOFF,_l.cutoff);
139  glLightf(GL_LIGHT0+_l.unit,GL_SPOT_EXPONENT,_l.exponent);
140  glLightf(GL_LIGHT0+_l.unit,GL_CONSTANT_ATTENUATION,_l.constant_attenuation);
141  glLightf(GL_LIGHT0+_l.unit,GL_LINEAR_ATTENUATION,_l.linear_attenuation);
142  glLightf(GL_LIGHT0+_l.unit,GL_QUADRATIC_ATTENUATION,_l.quadratic_attenuation);
143  glEndList();
144  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
145  r.erase(_id);
146  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Display_List_c(new GL13_Display_List(dsp))));
147  get_context()->set_renderables(r);
148  return;
149 }
150 
151 void GL13::create_material(const std::string& _id,const scene::material_attribs_t& _m)
152 {
153  uint32 dsp=glGenLists(1);
154  float32 amb_array[]= {_m.ambient(0), _m.ambient(1), _m.ambient(2), _m.ambient(3)};
155  float32 dif_array[]= {_m.diffuse(0), _m.diffuse(1), _m.diffuse(2), _m.diffuse(3)};
156  float32 spc_array[]= {_m.specular(0), _m.specular(1), _m.specular(2), _m.specular(3)};
157  float32 emi_array[]= {_m.emission(0), _m.emission(1), _m.emission(2), _m.emission(3)};
158  glNewList(dsp,GL_COMPILE);
159  //glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
160  glMaterialfv(GL_FRONT,GL_AMBIENT,amb_array);
161  glMaterialfv(GL_FRONT,GL_DIFFUSE,dif_array);
162  glMaterialfv(GL_FRONT,GL_SPECULAR,spc_array);
163  glMaterialfv(GL_FRONT,GL_EMISSION,emi_array);
164  glMaterialf(GL_FRONT,GL_SHININESS,_m.shininess);
165  glEndList();
166  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
167  r.erase(_id);
168  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Display_List_c(new GL13_Display_List(dsp))));
169  get_context()->set_renderables(r);
170  return;
171 }
172 
173 void GL13::create_mesh(const std::string& _id,const scene::mesh_attribs_t& _m)
174 {
175  uint32 dsp=glGenLists(1);
176  uint32 vs=_m.v.size()*4;
177  uint32 vns=_m.vn.size()*3;
178  uint32 vts=_m.vt.size()*4;
179  uint32 vcs=_m.vc.size()*4;
180  float64 v[vs];
181  float64 vn[vns];
182  float64 vt[vts];
183  float64 vc[vcs];
184  for (uint32 i=0; i<vs; ++i) v[i]=_m.v.at(i/4)(i%4);
185  for (uint32 j=0; j<vns; ++j) vn[j]=_m.vn.at(j/3)(j%3);
186  for (uint32 k=0; k<vts; ++k) vt[k]=_m.vt.at(k/4)(k%4);
187  for (uint32 l=0; l<vcs; ++l) vc[l]=_m.vc.at(l/4)(l%4);
188  glNewList(dsp,GL_COMPILE);
189  glClientActiveTexture(GL_TEXTURE0);
190  glVertexPointer(4,GL_DOUBLE,0,v);
191  glNormalPointer(GL_DOUBLE,0,vn);
192  glTexCoordPointer(4,GL_DOUBLE,0,vt);
193  glColorPointer(4,GL_DOUBLE,0,vc);
194  glEnableClientState(GL_VERTEX_ARRAY);
195  glEnableClientState(GL_NORMAL_ARRAY);
196  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
197  glEnableClientState(GL_COLOR_ARRAY);
198  glDrawArrays(GL_TRIANGLES,0,_m.v.size());
199  glEndList();
200  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
201  r.erase(_id);
202  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Display_List_c(new GL13_Display_List(dsp))));
203  get_context()->set_renderables(r);
204  return;
205 }
206 
207 void GL13::create_pose(const std::string& _id,const Eigen::Matrix4d& _m)
208 {
209  std::array<float64,16> pose;
210  for (uint32 i=0; i<16; ++i) pose.at(i)=_m(i%4,i/4);
211  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
212  r.erase(_id);
213  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Pose_c(new GL13_Pose(pose))));
214  get_context()->set_renderables(r);
215  return;
216 }
217 
218 void GL13::create_texture(const std::string& _id,const scene::texture_attribs_t& _t)
219 {
220  uint32 tex=0;
221  uint32 unit=0;
222  glGenTextures(1,&tex);
223  int32 max_tex_units=0;
224  glGetIntegerv(GL_MAX_TEXTURE_UNITS,&max_tex_units);
225  if ( _t.unit >= max_tex_units)
226  {
227  std::string err("Mondschein Engine ERROR: ");
228  err+="This OpenGL implementation only supports ";
229  err+=max_tex_units;
230  err+=" texture units. Exception raised in function\n\t";
231  err+="void mondschein::renderer::GL13::create_texture(const std::string& _id,const texture_attribs_t& _t)";
232  throw boost::enable_current_exception(exception()) << exception_error(err);
233  }
234  unit=_t.unit;
235  uint32 mipmaps=std::log2(std::max(_t.width,_t.height));
236  glActiveTexture(GL_TEXTURE0);
237  glBindTexture(GL_TEXTURE_2D,tex);
238  GLenum format;
239  switch (_t.bpp)
240  {
241  case 32:
242  if (_t.rgb) format=GL_RGBA;
243  else format=GL_BGRA;
244  break;
245 
246  case 24:
247  if (_t.rgb) format=GL_RGB;
248  else format=GL_BGR;
249  break;
250 
251  default:
252  std::string err("Mondschein Engine ERROR: Texture format not supported. ");
253  err+="Exception raised in function\n\t";
254  err+="void mondschein::renderer::GL13::create_texture(const std::string& _id,const texture_attribs_t& _t)";
255  throw boost::enable_current_exception(exception()) << exception_error(err);
256  break;
257  }
258  switch (_t.texture_filter)
259  {
260  case ONN:
261  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
262  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
263  mipmaps=1;
264  break;
265 
266  case ONL:
267  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
268  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
269  mipmaps=1;
270  break;
271 
272  case OLN:
273  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
274  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
275  mipmaps=1;
276  break;
277  case OLL:
278  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
279  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
280  mipmaps=1;
281  break;
282 
283  case NNN:
284  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
285  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
286  break;
287 
288  case NNL:
289  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
290  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
291  break;
292 
293  case NLN:
294  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
295  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
296  break;
297  case NLL:
298  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
299  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
300  break;
301 
302  case LNN:
303  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
304  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
305  break;
306 
307  case LNL:
308  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
309  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
310  break;
311 
312  case LLN:
313  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
314  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
315  break;
316 
317  case LLL:
318  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
319  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
320  break;
321 
322  default:
323  std::string err("Mondschein Engine ERROR: Texture filtering mode not supported. Exception raised in function\n\t");
324  err+="void mondschein::renderer::GL13::create_texture(const std::string& _id,const texture_attribs_t& _t)";
325  throw boost::enable_current_exception(exception()) << exception_error(err);
326  break;
327  }
328  if (query_extension("GL_EXT_texture_filter_anisotropic"))
329  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,_t.anisotropic_filter);
330  gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,_t.width,_t.height,format,GL_UNSIGNED_BYTE,_t.data.data());
331  std::map<std::string,Renderable_c> r=get_context()->get_renderables();
332  r.erase(_id);
333  r.insert(std::make_pair<const std::string&,Renderable_c>(_id,GL13_Texture_c(new GL13_Texture(tex,unit))));
334  get_context()->set_renderables(r);
335  return;
336 }
337 
338 void GL13::make_renderable(scene::Scenenode_c _sn)
339 {
341  scene::Camera_c cam;
342  scene::Light_c light;
343  scene::Material_c mat;
344  scene::Mesh_c mesh;
345  scene::Pose_c pose;
346  scene::Texture_c tex;
347  if ((cam=boost::dynamic_pointer_cast<const scene::Camera>(_sn)).get()!=nullptr)
348  create_camera(cam->get_id(),cam->get_camera_attribs());
349  else if ((light=boost::dynamic_pointer_cast<const scene::Light>(_sn)).get()!=nullptr)
350  create_light(light->get_id(),light->get_light_attribs());
351  else if ((mat=boost::dynamic_pointer_cast<const scene::Material>(_sn)).get()!=nullptr)
352  create_material(mat->get_id(),mat->get_material_attribs());
353  else if ((mesh=boost::dynamic_pointer_cast<const scene::Mesh>(_sn)).get()!=nullptr)
354  create_mesh(mesh->get_id(),mesh->get_mesh_attribs());
355  else if ((pose=boost::dynamic_pointer_cast<const scene::Pose>(_sn)).get()!=nullptr)
356  create_pose(pose->get_id(),pose->get_matrix());
357  else if ((tex=boost::dynamic_pointer_cast<const scene::Texture>(_sn)).get()!=nullptr)
358  create_texture(tex->get_id(),tex->get_texture_attribs());
359  else
360  {
361  std::string err("Mondschein Engine ERROR: Scenenode type is not supported by this renderer. ");
362  err+="Exception raised in function\n\t";
363  err+="std::pair<std::string,mondschein::renderer::Renderable_c> mondschein::renderer:GL13::make_renderable(";
364  err+="mondschein::scene::Scenenode_c _sn)";
365  throw boost::enable_current_exception(exception()) << exception_error(err);
366  }
367  return;
368 }
369 
370 void GL13::render(scene::Scenegraph_c _sg,const uint32 _start)
371 {
372  Renderer::render(0,0);
373  boost::adjacency_list<> g=_sg->get_scenegraph_attribs().edges;
374  std::pair<adj_it,adj_it> range=boost::adjacent_vertices(_start,g);
375  std::map<std::string,Renderable_c> objects=get_context()->get_renderables();
376  scene::Scenenode_c sn=_sg->get_scenegraph_attribs().nodes.at(_start);
377  if (boost::dynamic_pointer_cast<const scene::Camera>(sn).get()!=nullptr)
378  {
379  Renderable_c obj=objects.at(sn->get_id());
380  obj->render();
381  renderstack.push_back(obj);
382  render_children(_sg,range);
383  renderstack.pop_back();
384  if (!renderstack.empty()) renderstack.back()->render();
385  }
386  else if (boost::dynamic_pointer_cast<const scene::Light>(sn).get()!=nullptr)
387  {
388  Renderable_c obj=objects.at(sn->get_id());
389  obj->render();
390  renderstack.push_back(obj);
391  render_children(_sg,range);
392  renderstack.pop_back();
393  if (!renderstack.empty()) renderstack.back()->render();
394  }
395  else if (boost::dynamic_pointer_cast<const scene::Material>(sn).get()!=nullptr)
396  {
397  Renderable_c obj=objects.at(sn->get_id());
398  obj->render();
399  renderstack.push_back(obj);
400  render_children(_sg,range);
401  renderstack.pop_back();
402  if (!renderstack.empty()) renderstack.back()->render();
403  }
404  else if (boost::dynamic_pointer_cast<const scene::Mesh>(sn).get()!=nullptr)
405  {
406  Renderable_c obj=objects.at(sn->get_id());
407  obj->render();
408  render_children(_sg,range);
409  }
410  else if (boost::dynamic_pointer_cast<const scene::Pose>(sn).get()!=nullptr)
411  {
412  Renderable_c obj=objects.at(sn->get_id());
413  glMatrixMode(GL_MODELVIEW);
414  glPushMatrix();
415  obj->render();
416  render_children(_sg,range);
417  glMatrixMode(GL_MODELVIEW);
418  glPopMatrix();
419  }
420  else if (boost::dynamic_pointer_cast<const scene::Texture>(sn).get()!=nullptr)
421  {
422  Renderable_c obj=objects.at(sn->get_id());
423  obj->render();
424  renderstack.push_back(obj);
425  render_children(_sg,range);
426  renderstack.pop_back();
427  if (!renderstack.empty()) renderstack.back()->render();
428  }
429  else
430  {
431  std::string err("Mondschein Engine ERROR: This scene node cannot be rendered by this renderer.");
432  err+=" Exception raised in function\n\t";
433  err+="void mondschein::renderer::GL13::render(mondschein::scene::Scenegraph_c _sg,const uint32 _start)";
434  throw boost::enable_current_exception(exception()) << exception_error(err);
435  }
436  return;
437 }
438 
439 void GL13::render_children(scene::Scenegraph_c _sg,std::pair<adj_it,adj_it> _c)
440 {
441  for (; _c.first!=_c.second; ++_c.first) GL13::render(_sg,*_c.first);
442  return;
443 }