1 #include "renderer.h"
2 #include "rendersettings.h"
3 #include "Geometry.h"
4 #include "polyset.h"
5 #include "Polygon2d.h"
6 #include "colormap.h"
7 #include "printutils.h"
8 #include "feature.h"
9 
10 #include "polyset-utils.h"
11 #include "grid.h"
12 #include <Eigen/LU>
13 
Renderer()14 Renderer::Renderer() : colorscheme(nullptr)
15 {
16 	PRINTD("Renderer() start");
17 
18 	renderer_shader.progid = 0;
19 
20 	// Setup default colors
21 	// The main colors, MATERIAL and CUTOUT, come from this object's
22 	// colorscheme. Colorschemes don't currently hold information
23 	// for Highlight/Background colors
24 	// but it wouldn't be too hard to make them do so.
25 
26 	// MATERIAL is set by this object's colorscheme
27 	// CUTOUT is set by this object's colorscheme
28 	colormap[ColorMode::HIGHLIGHT] = {255, 81, 81, 128};
29 	colormap[ColorMode::BACKGROUND] = {180, 180, 180, 128};
30 	// MATERIAL_EDGES is set by this object's colorscheme
31 	// CUTOUT_EDGES is set by this object's colorscheme
32 	colormap[ColorMode::HIGHLIGHT_EDGES] = {255, 171, 86, 128};
33 	colormap[ColorMode::BACKGROUND_EDGES] = {150, 150, 150, 128};
34 
35 	setColorScheme(ColorMap::inst()->defaultColorScheme());
36 
37 	const char *vs_source = R"VS_PROG(
38           #version 110
39 
40           uniform vec4 color1;        // face color
41           uniform vec4 color2;        // edge color
42           attribute vec3 barycentric; // barycentric form of vertex coord
43                                       // either [1,0,0], [0,1,0] or [0,0,1] under normal circumstances (no edges disabled)
44           varying vec3 vBC;           // varying barycentric coords
45           varying float shading;      // multiplied by color1. color2 is without lighting
46 
47           void main(void) {
48             gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
49             vBC = barycentric;
50             vec3 normal, lightDir;
51             normal = normalize(gl_NormalMatrix * gl_Normal);
52             lightDir = normalize(vec3(gl_LightSource[0].position));
53             shading = 0.2 + abs(dot(normal, lightDir));
54           }
55         )VS_PROG";
56 
57         const char *fs_source = R"FS_PROG(
58           #version 110
59 
60           uniform vec4 color1, color2;
61           varying vec3 vBC;
62           varying float shading;
63 
64           vec3 smoothstep3f(vec3 edge0, vec3 edge1, vec3 x) {
65             vec3 t;
66             t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
67             return t * t * (3.0 - 2.0 * t);
68           }
69 
70           float edgeFactor() {
71             const float th = 1.414; // total thickness of half-edge (per triangle) including fade, (must be >= fade)
72             const float fade = 1.414; // thickness of fade (antialiasing) in screen pixels
73             vec3 d = fwidth(vBC);
74             vec3 a3 = smoothstep((th-fade)*d, th*d, vBC);
75             return min(min(a3.x, a3.y), a3.z);
76           }
77 
78           void main(void) {
79             gl_FragColor = mix(color2, vec4(color1.rgb * shading, color1.a), edgeFactor());
80           }
81         )FS_PROG";
82 
83 	GLint status;
84 	GLenum err;
85 	auto vs = glCreateShader(GL_VERTEX_SHADER);
86 	glShaderSource(vs, 1, (const GLchar**)&vs_source, nullptr);
87 	glCompileShader(vs);
88 	err = glGetError();
89 	if (err != GL_NO_ERROR) {
90 		PRINTDB("OpenGL Error: %s\n", gluErrorString(err));
91 		return;
92 	}
93 	glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
94 	if (status == GL_FALSE) {
95 		int loglen;
96 		char logbuffer[1000];
97 		glGetShaderInfoLog(vs, sizeof(logbuffer), &loglen, logbuffer);
98 		PRINTDB("OpenGL Program Compile Vertex Shader Error:\n%s", logbuffer);
99 		return;
100 	}
101 
102 	auto fs = glCreateShader(GL_FRAGMENT_SHADER);
103 	glShaderSource(fs, 1, (const GLchar**)&fs_source, nullptr);
104 	glCompileShader(fs);
105 	err = glGetError();
106 	if (err != GL_NO_ERROR) {
107 		PRINTDB("OpenGL Error: %s\n", gluErrorString(err));
108 		return;
109 	}
110 	glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
111 	if (status == GL_FALSE) {
112 		int loglen;
113 		char logbuffer[1000];
114 		glGetShaderInfoLog(fs, sizeof(logbuffer), &loglen, logbuffer);
115 		PRINTDB("OpenGL Program Compile Fragement Shader Error:\n%s", logbuffer);
116 		return;
117 	}
118 
119 	auto edgeshader_prog = glCreateProgram();
120 	glAttachShader(edgeshader_prog, vs);
121 	glAttachShader(edgeshader_prog, fs);
122 	glLinkProgram(edgeshader_prog);
123 
124 	err = glGetError();
125 	if (err != GL_NO_ERROR) {
126 		PRINTDB("OpenGL Error: %s\n", gluErrorString(err));
127 		return;
128 	}
129 
130 	glGetProgramiv(edgeshader_prog, GL_LINK_STATUS, &status);
131 	if (status == GL_FALSE) {
132 		int loglen;
133 		char logbuffer[1000];
134 		glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
135 		PRINTDB("OpenGL Program Linker Error:\n%s", logbuffer);
136 		return;
137 	}
138 
139 	int loglen;
140 	char logbuffer[1000];
141 	glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
142 	if (loglen > 0) {
143 		PRINTDB("OpenGL Program Link OK:\n%s", logbuffer);
144 	}
145 	glValidateProgram(edgeshader_prog);
146 	glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
147 	if (loglen > 0) {
148 		PRINTDB("OpenGL Program Validation results:\n%s", logbuffer);
149 	}
150 
151 	renderer_shader.progid = edgeshader_prog; // 0
152 	renderer_shader.type = EDGE_RENDERING;
153 	renderer_shader.data.csg_rendering.color_area = glGetUniformLocation(edgeshader_prog, "color1"); // 1
154         renderer_shader.data.csg_rendering.color_edge = glGetUniformLocation(edgeshader_prog, "color2"); // 2
155         renderer_shader.data.csg_rendering.barycentric = glGetAttribLocation(edgeshader_prog, "barycentric"); // 3
156 
157 	PRINTD("Renderer() end");
158 }
159 
resize(int,int)160 void Renderer::resize(int /*w*/, int /*h*/)
161 {
162 }
163 
getColor(Renderer::ColorMode colormode,Color4f & col) const164 bool Renderer::getColor(Renderer::ColorMode colormode, Color4f &col) const
165 {
166 	if (colormode==ColorMode::NONE) return false;
167 	if (colormap.count(colormode) > 0) {
168 		col = colormap.at(colormode);
169 		return true;
170 	}
171 	return false;
172 }
173 
get_csgmode(const bool highlight_mode,const bool background_mode,const OpenSCADOperator type) const174 Renderer::csgmode_e Renderer::get_csgmode(const bool highlight_mode, const bool background_mode, const OpenSCADOperator type) const {
175     int csgmode = highlight_mode ? CSGMODE_HIGHLIGHT : (background_mode ? CSGMODE_BACKGROUND : CSGMODE_NORMAL);
176     if (type == OpenSCADOperator::DIFFERENCE) csgmode |= CSGMODE_DIFFERENCE_FLAG;
177     return csgmode_e(csgmode);
178 }
179 
setColor(const float color[4],const shaderinfo_t * shaderinfo) const180 void Renderer::setColor(const float color[4], const shaderinfo_t *shaderinfo) const
181 {
182 	if (shaderinfo && shaderinfo->type != EDGE_RENDERING) {
183 		return;
184 	}
185 
186 	PRINTD("setColor a");
187 	Color4f col;
188 	getColor(ColorMode::MATERIAL,col);
189 	float c[4] = {color[0], color[1], color[2], color[3]};
190 	if (c[0] < 0) c[0] = col[0];
191 	if (c[1] < 0) c[1] = col[1];
192 	if (c[2] < 0) c[2] = col[2];
193 	if (c[3] < 0) c[3] = col[3];
194 	glColor4fv(c);
195 #ifdef ENABLE_OPENCSG
196 	if (shaderinfo) {
197 		glUniform4f(shaderinfo->data.csg_rendering.color_area, c[0], c[1], c[2], c[3]);
198 		glUniform4f(shaderinfo->data.csg_rendering.color_edge, (c[0]+1)/2, (c[1]+1)/2, (c[2]+1)/2, 1.0);
199 	}
200 #endif
201 }
202 
203 // returns the color which has been set, which may differ from the color input parameter
setColor(ColorMode colormode,const float color[4],const shaderinfo_t * shaderinfo) const204 Color4f Renderer::setColor(ColorMode colormode, const float color[4], const shaderinfo_t *shaderinfo) const
205 {
206 	PRINTD("setColor b");
207 	Color4f basecol;
208 	if (getColor(colormode, basecol)) {
209 		if (colormode == ColorMode::BACKGROUND) {
210 			basecol = {color[0] >= 0 ? color[0] : basecol[0],
211 								 color[1] >= 0 ? color[1] : basecol[1],
212 								 color[2] >= 0 ? color[2] : basecol[2],
213 								 color[3] >= 0 ? color[3] : basecol[3]};
214 		}
215 		else if (colormode != ColorMode::HIGHLIGHT) {
216 			basecol = {color[0] >= 0 ? color[0] : basecol[0],
217 								 color[1] >= 0 ? color[1] : basecol[1],
218 								 color[2] >= 0 ? color[2] : basecol[2],
219 								 color[3] >= 0 ? color[3] : basecol[3]};
220 		}
221 		setColor(basecol.data(), shaderinfo);
222 	}
223 	return basecol;
224 }
225 
setColor(ColorMode colormode,const shaderinfo_t * shaderinfo) const226 void Renderer::setColor(ColorMode colormode, const shaderinfo_t *shaderinfo) const
227 {
228 	PRINTD("setColor c");
229 	float c[4] = {-1,-1,-1,-1};
230 	setColor(colormode, c, shaderinfo);
231 }
232 
233 /* fill this->colormap with matching entries from the colorscheme. note
234 this does not change Highlight or Background colors as they are not
235 represented in the colorscheme (yet). Also edgecolors are currently the
236 same for CGAL & OpenCSG */
setColorScheme(const ColorScheme & cs)237 void Renderer::setColorScheme(const ColorScheme &cs) {
238 	PRINTD("setColorScheme");
239 	colormap[ColorMode::MATERIAL] = ColorMap::getColor(cs, RenderColor::OPENCSG_FACE_FRONT_COLOR);
240 	colormap[ColorMode::CUTOUT] = ColorMap::getColor(cs, RenderColor::OPENCSG_FACE_BACK_COLOR);
241 	colormap[ColorMode::MATERIAL_EDGES] = ColorMap::getColor(cs, RenderColor::CGAL_EDGE_FRONT_COLOR);
242 	colormap[ColorMode::CUTOUT_EDGES] = ColorMap::getColor(cs, RenderColor::CGAL_EDGE_BACK_COLOR);
243 	colormap[ColorMode::EMPTY_SPACE] = ColorMap::getColor(cs, RenderColor::BACKGROUND_COLOR);
244 	this->colorscheme = &cs;
245 }
246 
247 #ifdef ENABLE_OPENCSG
draw_triangle(const Renderer::shaderinfo_t * shaderinfo,const Vector3d & p0,const Vector3d & p1,const Vector3d & p2,bool e0,bool e1,bool e2,double z,bool mirror)248 static void draw_triangle(const Renderer::shaderinfo_t *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2,
249                           bool e0, bool e1, bool e2, double z, bool mirror)
250 {
251 	Renderer::shader_type_t type =
252 			(shaderinfo) ? shaderinfo->type : Renderer::NONE;
253 
254 	// e0,e1,e2 are used to disable some edges from display.
255 	// Edges are numbered to correspond with the vertex opposite of them.
256 	// The edge shader draws edges when the minimum component of barycentric coords is near 0
257 	// Disabled edges have their corresponding components set to 1.0 when they would otherwise be 0.0.
258 	double d0 = e0 ? 0.0 : 1.0;
259 	double d1 = e1 ? 0.0 : 1.0;
260 	double d2 = e2 ? 0.0 : 1.0;
261 
262 	switch (type) {
263 	case Renderer::EDGE_RENDERING:
264 		if (mirror) {
265 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, 1.0, d1, d2);
266 			glVertex3f(p0[0], p0[1], p0[2] + z);
267 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, d0, d1, 1.0);
268 			glVertex3f(p2[0], p2[1], p2[2] + z);
269 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, d0, 1.0, d2);
270 			glVertex3f(p1[0], p1[1], p1[2] + z);
271 		} else {
272 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, 1.0, d1, d2);
273 			glVertex3f(p0[0], p0[1], p0[2] + z);
274 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, d0, 1.0, d2);
275 			glVertex3f(p1[0], p1[1], p1[2] + z);
276 			glVertexAttrib3f(shaderinfo->data.csg_rendering.barycentric, d0, d1, 1.0);
277 			glVertex3f(p2[0], p2[1], p2[2] + z);
278 		}
279 		break;
280 	default:
281 	case Renderer::SELECT_RENDERING:
282 		glVertex3d(p0[0], p0[1], p0[2] + z);
283 		if (!mirror) {
284 			glVertex3d(p1[0], p1[1], p1[2] + z);
285 		}
286 		glVertex3d(p2[0], p2[1], p2[2] + z);
287 		if (mirror) {
288 			glVertex3d(p1[0], p1[1], p1[2] + z);
289 		}
290 	}
291 }
292 #endif
293 
294 #ifndef NULLGL
draw_tri(const Vector3d & p0,const Vector3d & p1,const Vector3d & p2,double z,bool mirror)295 static void draw_tri(const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, double z, bool mirror)
296 {
297 	glVertex3d(p0[0], p0[1], p0[2] + z);
298 	if (!mirror) glVertex3d(p1[0], p1[1], p1[2] + z);
299 	glVertex3d(p2[0], p2[1], p2[2] + z);
300 	if (mirror) glVertex3d(p1[0], p1[1], p1[2] + z);
301 }
302 
gl_draw_triangle(const Renderer::shaderinfo_t * shaderinfo,const Vector3d & p0,const Vector3d & p1,const Vector3d & p2,bool e0,bool e1,bool e2,double z,bool mirrored)303 static void gl_draw_triangle(const Renderer::shaderinfo_t *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored)
304 {
305 	double ax = p1[0] - p0[0], bx = p1[0] - p2[0];
306 	double ay = p1[1] - p0[1], by = p1[1] - p2[1];
307 	double az = p1[2] - p0[2], bz = p1[2] - p2[2];
308 	double nx = ay*bz - az*by;
309 	double ny = az*bx - ax*bz;
310 	double nz = ax*by - ay*bx;
311 	double nl = sqrt(nx*nx + ny*ny + nz*nz);
312 	glNormal3d(nx / nl, ny / nl, nz / nl);
313 #ifdef ENABLE_OPENCSG
314 	if (shaderinfo) {
315 		draw_triangle(shaderinfo, p0, p1, p2, e0, e1, e2, z, mirrored);
316 	}
317 	else
318 #endif
319 	{
320 		draw_tri(p0, p1, p2, z, mirrored);
321 	}
322 }
323 
render_surface(const PolySet & ps,csgmode_e csgmode,const Transform3d & m,const shaderinfo_t * shaderinfo) const324 void Renderer::render_surface(const PolySet &ps, csgmode_e csgmode, const Transform3d &m, const shaderinfo_t *shaderinfo) const
325 {
326 	PRINTD("Renderer render");
327 	bool mirrored = m.matrix().determinant() < 0;
328 
329 	if (ps.getDimension() == 2) {
330 		// Render 2D objects 1mm thick, but differences slightly larger
331 		double zbase = 1 + ((csgmode & CSGMODE_DIFFERENCE_FLAG) ? 0.1 : 0);
332 		glBegin(GL_TRIANGLES);
333 
334 		// Render top+bottom
335 		for (double z = -zbase/2; z < zbase; z += zbase) {
336 			for (size_t i = 0; i < ps.polygons.size(); ++i) {
337 				const Polygon *poly = &ps.polygons[i];
338 				if (poly->size() == 3) {
339 					if (z < 0) {
340 						gl_draw_triangle(shaderinfo, poly->at(0), poly->at(2), poly->at(1), true, true, true, z, mirrored);
341 					} else {
342 						gl_draw_triangle(shaderinfo, poly->at(0), poly->at(1), poly->at(2), true, true, true, z, mirrored);
343 					}
344 				}
345 				else if (poly->size() == 4) {
346 					if (z < 0) {
347 						gl_draw_triangle(shaderinfo, poly->at(0), poly->at(3), poly->at(1), false, true, true, z, mirrored);
348 						gl_draw_triangle(shaderinfo, poly->at(2), poly->at(1), poly->at(3), false, true, true, z, mirrored);
349 					} else {
350 						gl_draw_triangle(shaderinfo, poly->at(0), poly->at(1), poly->at(3), false, true, true, z, mirrored);
351 						gl_draw_triangle(shaderinfo, poly->at(2), poly->at(3), poly->at(1), false, true, true, z, mirrored);
352 					}
353 				}
354 				else {
355 					Vector3d center = Vector3d::Zero();
356 					for (size_t j = 0; j < poly->size(); ++j) {
357 						center[0] += poly->at(j)[0];
358 						center[1] += poly->at(j)[1];
359 					}
360 					center[0] /= poly->size();
361 					center[1] /= poly->size();
362 					for (size_t j = 1; j <= poly->size(); ++j) {
363 						if (z < 0) {
364 							gl_draw_triangle(shaderinfo, center, poly->at(j % poly->size()), poly->at(j - 1),
365 									true, false, false, z, mirrored);
366 						} else {
367 							gl_draw_triangle(shaderinfo, center, poly->at(j - 1), poly->at(j % poly->size()),
368 									true, false, false, z, mirrored);
369 						}
370 					}
371 				}
372 			}
373 		}
374 
375 		// Render sides
376 		if (ps.getPolygon().outlines().size() > 0) {
377 			for (const Outline2d &o : ps.getPolygon().outlines()) {
378 				for (size_t j = 1; j <= o.vertices.size(); ++j) {
379 					Vector3d p1(o.vertices[j-1][0], o.vertices[j-1][1], -zbase/2);
380 					Vector3d p2(o.vertices[j-1][0], o.vertices[j-1][1], zbase/2);
381 					Vector3d p3(o.vertices[j % o.vertices.size()][0], o.vertices[j % o.vertices.size()][1], -zbase/2);
382 					Vector3d p4(o.vertices[j % o.vertices.size()][0], o.vertices[j % o.vertices.size()][1], zbase/2);
383 					gl_draw_triangle(shaderinfo, p2, p1, p3, true, false, true, 0, mirrored);
384 					gl_draw_triangle(shaderinfo, p2, p3, p4, true, true, false, 0, mirrored);
385 				}
386 }
387 		}
388 		else {
389 			// If we don't have borders, use the polygons as borders.
390 			// FIXME: When is this used?
391 			const Polygons *borders_p = &ps.polygons;
392 			for (size_t i = 0; i < borders_p->size(); ++i) {
393 				const Polygon *poly = &borders_p->at(i);
394 				for (size_t j = 1; j <= poly->size(); ++j) {
395 					Vector3d p1 = poly->at(j - 1), p2 = poly->at(j - 1);
396 					Vector3d p3 = poly->at(j % poly->size()), p4 = poly->at(j % poly->size());
397 					p1[2] -= zbase/2, p2[2] += zbase/2;
398 					p3[2] -= zbase/2, p4[2] += zbase/2;
399 					gl_draw_triangle(shaderinfo, p2, p1, p3, true, false, true, 0, mirrored);
400 					gl_draw_triangle(shaderinfo, p2, p3, p4, true, true, false, 0, mirrored);
401 				}
402 			}
403 		}
404 		glEnd();
405 	} else if (ps.getDimension() == 3) {
406 		for (size_t i = 0; i < ps.polygons.size(); ++i) {
407 			const Polygon *poly = &ps.polygons[i];
408 			glBegin(GL_TRIANGLES);
409 			if (poly->size() == 3) {
410 				gl_draw_triangle(shaderinfo, poly->at(0), poly->at(1), poly->at(2), true, true, true, 0, mirrored);
411 			}
412 			else if (poly->size() == 4) {
413 				gl_draw_triangle(shaderinfo, poly->at(0), poly->at(1), poly->at(3), false, true, true, 0, mirrored);
414 				gl_draw_triangle(shaderinfo, poly->at(2), poly->at(3), poly->at(1), false, true, true, 0, mirrored);
415 			}
416 			else {
417 				Vector3d center = Vector3d::Zero();
418 				for (size_t j = 0; j < poly->size(); ++j) {
419 					center[0] += poly->at(j)[0];
420 					center[1] += poly->at(j)[1];
421 					center[2] += poly->at(j)[2];
422 				}
423 				center[0] /= poly->size();
424 				center[1] /= poly->size();
425 				center[2] /= poly->size();
426 				for (size_t j = 1; j <= poly->size(); ++j) {
427 					gl_draw_triangle(shaderinfo, center, poly->at(j - 1), poly->at(j % poly->size()), true, false, false, 0, mirrored);
428 				}
429 			}
430 			glEnd();
431 		}
432 	}
433 	else {
434 		assert(false && "Cannot render object with no dimension");
435 	}
436 }
437 
438 /*! This is used in throwntogether and CGAL mode
439 
440 	csgmode is set to CSGMODE_NONE in CGAL mode. In this mode a pure 2D rendering is performed.
441 
442 	For some reason, this is not used to render edges in Preview mode
443 */
render_edges(const PolySet & ps,csgmode_e csgmode) const444 void Renderer::render_edges(const PolySet &ps, csgmode_e csgmode) const
445 {
446 	glDisable(GL_LIGHTING);
447 	if (ps.getDimension() == 2) {
448 		if (csgmode == Renderer::CSGMODE_NONE) {
449 			// Render only outlines
450 			for (const Outline2d &o : ps.getPolygon().outlines()) {
451 				glBegin(GL_LINE_LOOP);
452 				for (const Vector2d &v : o.vertices) {
453 					glVertex3d(v[0], v[1], 0);
454 				}
455 				glEnd();
456 			}
457 		}
458 		else {
459 			// Render 2D objects 1mm thick, but differences slightly larger
460 			double zbase = 1 + ((csgmode & CSGMODE_DIFFERENCE_FLAG) ? 0.1 : 0);
461 
462 			for (const Outline2d &o : ps.getPolygon().outlines()) {
463 				// Render top+bottom outlines
464 				for (double z = -zbase/2; z < zbase; z += zbase) {
465 					glBegin(GL_LINE_LOOP);
466 					for (const Vector2d &v : o.vertices) {
467 						glVertex3d(v[0], v[1], z);
468 					}
469 					glEnd();
470 				}
471 				// Render sides
472 				glBegin(GL_LINES);
473 				for (const Vector2d &v : o.vertices) {
474 					glVertex3d(v[0], v[1], -zbase/2);
475 					glVertex3d(v[0], v[1], +zbase/2);
476 				}
477 				glEnd();
478 			}
479 		}
480 	} else if (ps.getDimension() == 3) {
481 		for (size_t i = 0; i < ps.polygons.size(); ++i) {
482 			const Polygon *poly = &ps.polygons[i];
483 			glBegin(GL_LINE_LOOP);
484 			for (size_t j = 0; j < poly->size(); ++j) {
485 				const Vector3d &p = poly->at(j);
486 				glVertex3d(p[0], p[1], p[2]);
487 			}
488 			glEnd();
489 		}
490 	}
491 	else {
492 		assert(false && "Cannot render object with no dimension");
493 	}
494 	glEnable(GL_LIGHTING);
495 }
496 
497 
498 #else //NULLGL
gl_draw_triangle(const Renderer::shaderinfo_t * shaderinfo,const Vector3d & p0,const Vector3d & p1,const Vector3d & p2,bool e0,bool e1,bool e2,double z,bool mirrored)499 static void gl_draw_triangle(const Renderer::shaderinfo_t *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored) {}
render_surface(const PolySet & ps,csgmode_e csgmode,const Transform3d & m,const shaderinfo_t * shaderinfo) const500 void Renderer::render_surface(const PolySet &ps, csgmode_e csgmode, const Transform3d &m, const shaderinfo_t *shaderinfo) const {}
render_edges(const PolySet & ps,csgmode_e csgmode) const501 void Renderer::render_edges(const PolySet &ps, csgmode_e csgmode) const {}
502 #endif //NULLGL
503