Subversion Repositories gelsvn

Rev

Rev 630 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
594 jab 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
396 jab 7
#include "IDBufferWireFrameRenderer.h"
594 jab 8
 
601 jab 9
#include "../CGLA/Vec4f.h"
10
#include "../CGLA/Vec2f.h"
11
#include "../CGLA/Vec3f.h"
12
#include "../HMesh/Manifold.h"
13
#include "../HMesh/AttributeVector.h"
594 jab 14
 
601 jab 15
#include "../GLGraphics/draw.h"
396 jab 16
 
594 jab 17
#include "glsl_shader.h"
18
 
396 jab 19
using namespace std;
20
using namespace CGLA;
21
using namespace GLGraphics;
22
using namespace HMesh;
23
 
24
namespace
25
{
594 jab 26
    string line_atten_frag = 
27
        "uniform int ATTEN_MODE;\n"
28
        "uniform float THICKNESS;\n"
29
        "uniform sampler2DRect IDMAP;\n"
30
        "uniform float TRANSITION;\n"
31
        "\n"
32
        "varying vec3 _id;\n"
33
        "varying vec2 p_2d_0;\n"
34
        "varying vec2 p_2d_1;\n"
35
        "\n"
36
        "const int LINEAR_ATTENUATION = 1;\n"
37
        "const int HERMITE_ATTENUATION = 2;\n"
38
        "\n"
39
        "const float HERMITE_COL_ATTEN_BIAS = 0.25;\n"
40
        "const float LINEAR_COL_ATTEN_BIAS = 0.4;\n"
41
        "const float HERMITE_ATTEN_BEGIN = 0.75;\n"
42
        "const float HERMITE_ATTEN_END = 1.0;\n"
43
        "\n"
44
        "void main(void)\n"
45
        "{\n"
46
        "	vec2 dir = (p_2d_1-p_2d_0);\n"
47
        "	float sq_len01 = dot(dir,dir);\n"
48
        "	vec2 v0 = (gl_FragCoord.xy)-p_2d_0;\n"
49
        "	vec2 v1 = (gl_FragCoord.xy)-p_2d_1;\n"
50
        "	float t = dot(dir, v0);\n"
51
        "	float d;\n"
52
        "	\n"
53
        "	if(t<=0.0)\n"
54
        "			d = length(v0);\n"
55
        "	else if(t>= sq_len01)\n"
56
        "			d = length(v1);\n"
57
        "	else\n"
58
        "			d = length(dir * t / sq_len01 - v0);\n"
59
        "	\n"
60
        "	vec3 iddiff = texture2DRect(IDMAP,gl_FragCoord.xy).xyz - _id;\n"
61
        " 	if(dot(iddiff, iddiff)<1e-6)\n"
62
        "		gl_FragDepth = 0.0;\n"
63
        "	else	\n"
64
        "		gl_FragDepth = gl_FragCoord.z;\n"
65
        "	\n"
66
        "	\n"
67
        "	float t1 = THICKNESS;\n"
68
        "	if(ATTEN_MODE == HERMITE_ATTENUATION)\n"
69
        "		{\n"
70
        "			float width_atten = smoothstep(HERMITE_ATTEN_END,HERMITE_ATTEN_BEGIN,\n"
71
        "																		 gl_FragCoord.z);\n"
72
        "			t1 *= width_atten;\n"
73
        "		}\n"
74
        "	else if(ATTEN_MODE == LINEAR_ATTENUATION)\n"
75
        "		{\n"
76
        "			float width_atten = 1.0-gl_FragCoord.z;\n"
77
        "			t1 *= width_atten;\n"
78
        "		}			\n"
79
        "	float t2 = t1+TRANSITION;\n"
80
        "\n"
81
        "	float I;\n"
82
        "	if(d<t1) \n"
83
        "			I = 1.0;\n"
84
        "	else\n"
85
        "	{\n"
86
        "			float x = (d-t1);\n"
87
        "			I = exp2(-x*x*2);\n"
88
        "	}\n"
89
        " 	gl_FragColor.rgb = gl_Color.rgb;\n"
90
        "	gl_FragColor.a = I;\n"
91
        "}\n";
92
 
93
    string line_frag = 
94
        "uniform sampler2DRect IDMAP;\n"
95
        "uniform float TRANSITION;\n"
96
        "	\n"
97
        "varying vec3 _id;\n"
98
        "varying vec2 p_2d_0;\n"
99
        "varying vec2 p_2d_1;\n"
100
        "\n"
101
        "void main(void)\n"
102
        "{\n"
103
        "	vec2 dir = (p_2d_1-p_2d_0);\n"
104
        "	float sq_len01 = dot(dir,dir);\n"
105
        "	vec2 v0 = gl_FragCoord.xy-p_2d_0;\n"
106
        "	vec2 v1 = gl_FragCoord.xy-p_2d_1;\n"
107
        "	float t = dot(dir, v0);\n"
108
        "	float sq_d;\n"
109
        "	\n"
110
        "	if(t<=0.0)\n"
111
        "		sq_d = dot(v0,v0);\n"
112
        "	else if(t>= sq_len01)\n"
113
        "		sq_d = dot(v1,v1);\n"
114
        "	else\n"
115
        "		{\n"
116
        "			float area = (v0.x*v1.y - v0.y * v1.x);\n"
117
        "			sq_d = area*area/sq_len01;\n"
118
        "		}\n"
119
        "\n"
120
        "	vec3 iddiff = texture2DRect(IDMAP,gl_FragCoord.xy).xyz -_id;\n"
121
        "	if(dot(iddiff, iddiff)<1e-6)\n"
122
        "		gl_FragDepth = 0.0;\n"
123
        " 	else	\n"
124
        " 		gl_FragDepth = gl_FragCoord.z;\n"
125
        "	\n"
126
        "	gl_FragColor.a = exp2(-sq_d*2.0);\n"
657 janba 127
        "	gl_FragColor.rgb = vec3(1,0,0);\n"
594 jab 128
        "}\n";
129
 
130
    string line_vert = 
131
        "uniform float THICKNESS;\n"
132
        "uniform vec2 WIN_SCALE;\n"
133
        "uniform vec2 INV_WIN_SCALE;\n"
134
        "uniform float TRANSITION;\n"
135
        "\n"
136
        "attribute vec4 id;\n"
137
        "attribute vec4 opp_vertex;\n"
138
        "attribute vec2 displace;\n"
139
        "\n"
140
        "varying vec3 _id;\n"
141
        "varying vec2 p_2d_0;\n"
142
        "varying vec2 p_2d_1;\n"
143
        "\n"
144
        "\n"
145
        "void main(void)\n"
146
        "{\n"
147
        "	vec4 p0 = gl_ModelViewProjectionMatrix * opp_vertex;\n"
148
        "	float w0 = p0.w; \n"
149
        "\n"
150
        "	vec4 p1 = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
151
        "	float w1 = p1.w;\n"
152
        "		\n"
153
        "	p_2d_0 = (p0.xy/w0+vec2(1,1)) * WIN_SCALE;\n"
154
        "	p_2d_1 = (p1.xy/w1+vec2(1,1)) * WIN_SCALE;\n"
155
        "	\n"
156
        "	vec2 a = normalize(p_2d_1 - p_2d_0);\n"
157
        "	vec2 a_h = vec2(-a.y, a.x);\n"
158
        "	vec2 scale = (TRANSITION+THICKNESS)*INV_WIN_SCALE;\n"
159
        "\n"
160
        "	gl_Position = (displace.x>0.0) ? p1 : p0;\n"
161
        "	vec2 offset = a * displace.x + a_h * displace.y;\n"
162
        "	gl_Position.xy += scale * gl_Position.w * offset;\n"
163
        "\n"
164
        "	_id = id.rgb;\n"
165
        "}\n";
166
 
396 jab 167
}
168
 
169
namespace GLGraphics
170
{
594 jab 171
    IDBufferWireframeRenderer::~IDBufferWireframeRenderer()
172
    {
173
        glDeleteShader(vs);	
174
        glDeleteShader(fs);
175
        glDeleteProgram(line_prog);
176
        glDeleteTextures(1, &idmap);
177
        glDeleteBuffers(1, &vertex_buffername);
178
        glDeleteBuffers(1, &colors_buffername);
179
 
180
        glDeleteBuffers(1, &line_id_attrib);
181
        glDeleteBuffers(1, &line_vertex_pos);
182
        glDeleteBuffers(1, &line_disp_attrib);			
183
        glDeleteBuffers(1, &line_opp_attrib);
184
    }
185
 
186
    IDBufferWireframeRenderer::IDBufferWireframeRenderer(int _XSZ, int _YSZ,
187
        HMesh::Manifold& _mesh, 
188
        float _thickness, 
189
        float _transition, 
190
        int atten_mode): 
191
    mesh(&_mesh), XSZ(_XSZ), YSZ(_YSZ), thickness(_thickness), transition(_transition)
192
    {
193
 
194
        if(atten_mode == 0 && thickness == 0.0)
195
        {
196
            vs = create_glsl_shader(GL_VERTEX_SHADER, line_vert);
197
            fs = create_glsl_shader(GL_FRAGMENT_SHADER, line_frag);
396 jab 198
        }
594 jab 199
        else
200
        {
201
            vs = create_glsl_shader(GL_VERTEX_SHADER, line_vert);
202
            fs = create_glsl_shader(GL_FRAGMENT_SHADER, line_atten_frag);
203
        }
396 jab 204
 
594 jab 205
        line_prog = glCreateProgram();
206
        glAttachShader(line_prog, vs);
207
        glAttachShader(line_prog, fs);
208
        glLinkProgram(line_prog);
209
        glUseProgram(line_prog);
396 jab 210
 
594 jab 211
        glUniform1f(glGetUniformLocation(line_prog,"THICKNESS"), 
212
            thickness);
213
        glUniform1f(glGetUniformLocation(line_prog,"TRANSITION"), 
214
            transition);
215
        glUniform1i(glGetUniformLocation(line_prog,"ATTEN_MODE"),
216
            atten_mode);
217
        glUniform2f(glGetUniformLocation(line_prog,"WIN_SCALE"), 
218
            XSZ/2.0, YSZ/2.0);
219
        glUniform2f(glGetUniformLocation(line_prog,"INV_WIN_SCALE"), 
220
            2.0/XSZ, 2.0/YSZ);
221
        glUniform1i(glGetUniformLocation(line_prog,"IDMAP"), 0);
222
 
223
        id_attrib = glGetAttribLocation(line_prog, "id");
224
        popp_attrib = glGetAttribLocation(line_prog, "opp_vertex");
225
        disp_attrib = glGetAttribLocation(line_prog, "displace");
226
        glUseProgram(0);
227
 
228
        glGenTextures(1, &idmap);
229
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, idmap);
230
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
231
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
232
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_CLAMP);
233
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_CLAMP);
234
 
235
        //create the texture
236
        glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, XSZ, YSZ,
237
            0, GL_RGB, GL_FLOAT, 0);
238
 
239
 
240
        glGenBuffers(1, &vertex_buffername);
241
        glGenBuffers(1, &colors_buffername);
242
 
243
        glGenBuffers(1, &line_id_attrib);
244
        glGenBuffers(1, &line_vertex_pos);
245
        glGenBuffers(1, &line_disp_attrib);
246
        glGenBuffers(1, &line_opp_attrib);
247
 
248
        triangles = static_cast<int>(mesh->no_faces());
249
        vector<Vec3f> verts;
250
        vector<Vec3f> cols;
251
 
252
        unsigned int k = 0;
253
        for(FaceIDIterator f = mesh->faces_begin(); f != mesh->faces_end(); ++f, ++k){
254
            Vec3uc idv(id_get(k));
255
            Vec3f idvec(idv[0]/255.0, idv[1]/255.0, idv[2]/255.0);
256
            for(Walker w = mesh->walker(*f); !w.full_circle(); w = w.circulate_face_ccw()){
257
                cols.push_back(idvec);
258
                verts.push_back(Vec3f(mesh->pos(w.vertex())));
259
            }
260
        }
261
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffername);
262
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*verts.size(),
263
            (float*)&verts[0],GL_STATIC_DRAW);
264
 
265
 
266
 
267
        glBindBuffer(GL_ARRAY_BUFFER, colors_buffername);
268
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*cols.size(),
269
            (float*)&cols[0],GL_STATIC_DRAW);
270
 
271
 
272
        vector<Vec3f> line_ids;
273
        vector<Vec3f> vertex_positions;
274
        vector<Vec2f> displacements;
275
        vector<Vec3f> opposite_positions;
276
 
277
 
278
        quads = 0;
279
        unsigned int i = 0;
280
        for(FaceIDIterator f = mesh->faces_begin(); f != mesh->faces_end(); ++f,++i){
281
            for(Walker w = mesh->walker(*f); !w.full_circle(); w = w.circulate_face_ccw()){
282
                ++quads;
283
                Vec3uc idv(id_get(i));
284
                Vec3f v0(mesh->pos(w.next().vertex()));
285
                Vec3f v1(mesh->pos(w.next().opp().vertex()));
286
                Vec3f idvec(idv[0]/255.0, idv[1]/255.0, idv[2]/255.0);
287
 
288
                line_ids.push_back(idvec);
289
                opposite_positions.push_back(v0);
290
                displacements.push_back(Vec2f(1,-1));
291
                vertex_positions.push_back(v1);
292
 
293
 
294
                line_ids.push_back(idvec);
295
                opposite_positions.push_back(v0);
296
                displacements.push_back(Vec2f(1, 1));
297
                vertex_positions.push_back(v1);
298
 
299
 
300
                line_ids.push_back(idvec);
301
                opposite_positions.push_back(v0);
302
                displacements.push_back(Vec2f(-1,1));
303
                vertex_positions.push_back(v1);
304
 
305
 
306
                line_ids.push_back(idvec);
307
                opposite_positions.push_back(v0);
308
                displacements.push_back(Vec2f(-1,-1));
309
                vertex_positions.push_back(v1);
310
            }
311
        }
312
 
313
        glBindBuffer(GL_ARRAY_BUFFER, line_id_attrib);
314
 
315
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*line_ids.size(),
316
            (float*)&line_ids[0],GL_STATIC_DRAW);
317
 
318
        glBindBuffer(GL_ARRAY_BUFFER, line_opp_attrib);
319
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*opposite_positions.size(),
320
            (float*)&opposite_positions[0],GL_STATIC_DRAW);
321
 
322
        glBindBuffer(GL_ARRAY_BUFFER, line_disp_attrib);
323
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*displacements.size(),
324
            (float*)&displacements[0],GL_STATIC_DRAW);
325
 
326
        glBindBuffer(GL_ARRAY_BUFFER, line_vertex_pos);
327
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertex_positions.size(),
328
            (float*)&vertex_positions[0],GL_STATIC_DRAW);
329
 
330
 
331
 
332
    }
333
 
334
 
335
    void IDBufferWireframeRenderer::draw(const Vec3f& color, const Vec3f& clear_color)
336
    {
337
        // push those attributes we change.
338
        glPushAttrib(GL_COLOR_BUFFER_BIT|
339
            GL_CURRENT_BIT|
340
            GL_TRANSFORM_BIT|
341
            GL_DEPTH_BUFFER_BIT);
342
 
343
        // Store information about whether we use lighting
344
        GLboolean lights_on;
345
        glGetBooleanv(GL_LIGHTING, &lights_on);
346
 
347
        // Store color information
348
        Vec4f current_color;
349
        glGetFloatv(GL_CURRENT_COLOR, &current_color[0]);
350
 
351
        // Store the current draw buffer 
352
        GLint _currentDrawbuf;
353
        glGetIntegerv(GL_DRAW_BUFFER, &_currentDrawbuf); 
354
 
355
        // Enable depth testing
356
        glEnable(GL_DEPTH_TEST);
357
 
358
        // ------------------------------
359
        // Pass 1: Draw the ID map
360
        // Each polygon has a unique ID which is coded as a colour and drawn
361
        // into the ID buffer
362
        glDisable(GL_LIGHTING);
363
        glClearColor(0,0,0,0);
364
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
365
 
366
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffername);
367
        glVertexPointer(3,GL_FLOAT,0,static_cast<char*>(0));
368
        glEnableClientState(GL_VERTEX_ARRAY);
369
 
370
        glBindBuffer(GL_ARRAY_BUFFER, colors_buffername);
371
        glColorPointer(3,GL_FLOAT,0,static_cast<char*>(0));
372
        glEnableClientState(GL_COLOR_ARRAY);
373
 
374
        int vertex_idx = 0;
375
        for(FaceIDIterator f = mesh->faces_begin(); f != mesh->faces_end(); ++f){
376
            glBegin(GL_POLYGON);
377
            for(Walker w = mesh->walker(*f); !w.full_circle(); w = w.circulate_face_ccw())
378
                 glArrayElement(vertex_idx++);
379
            glEnd();
380
        }
381
        glFinish();
382
        glDisableClientState(GL_COLOR_ARRAY);
383
        glDisableClientState(GL_VERTEX_ARRAY);
384
 
385
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, idmap);
386
        glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0,0,0,0,XSZ, YSZ);
387
 
388
        // Clear color buffer but retain depth buffer.
389
        glClear(GL_COLOR_BUFFER_BIT);
390
 
391
        // Enable blending for all subsequent passes
392
        glEnable(GL_BLEND);
393
 
394
        // ------------------------------
395
        // PASS 3: Draw lines using ID map texture.
396
        // For each polygon, all edges are drawn as prefiltered
397
        // lines. A given fragment belonging to a line will be written
398
        // to the framebuffer if either of the following three conditions are met
399
        // - its ID matches the contents of the ID  buffer for the corresponding 
400
        // pixel (in the ID buffer)
401
        // - The ID of the corresponding pixel is 0 - meaning we are outside.
402
        // - The depth test is passed.
403
        // The final condition ensures that line pixels which are on an interior
404
        // contour will be drawn.
405
        //
406
        // If the line fragment is written into the framebuffer - two values are
407
        // actually written: The colour of the line and an alpha value which
408
        // corresponds to the value of the filter function.
409
        //
410
        // During this pass, blending is enabled and the blending equation is set
411
        // to max. Since the alpha values are the values of the filter (large if 
412
        // close to line) this means that we replace a pixel value with an 
413
        // incoming fragment if the incoming fragment is closer to a line
414
        // than the pixel value.
415
        //
416
        // The depth values are not changed during this pass.
417
        glEnable(GL_TEXTURE_RECTANGLE_ARB);
418
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, idmap);
419
        glDepthMask(GL_FALSE);
420
        glBlendEquation(GL_MAX);
421
        glUseProgram(line_prog);
422
 
423
        float lw;
424
        glGetFloatv(GL_LINE_WIDTH, &lw);
425
        glLineWidth(ceil(2.0*(thickness+transition)));
426
 
427
 
428
        glBindBuffer(GL_ARRAY_BUFFER, line_id_attrib);
429
        glVertexAttribPointer(id_attrib, 3,GL_FLOAT,GL_FALSE,0,static_cast<char*>(0));
430
        glEnableVertexAttribArray(id_attrib);
431
 
432
 
433
        glBindBuffer(GL_ARRAY_BUFFER, line_disp_attrib);
434
        glVertexAttribPointer(disp_attrib, 2,GL_FLOAT,GL_FALSE,0,static_cast<char*>(0));
435
        glEnableVertexAttribArray(disp_attrib);
436
 
437
 
438
        glBindBuffer(GL_ARRAY_BUFFER, line_opp_attrib);
439
        glVertexAttribPointer(popp_attrib, 3,GL_FLOAT,GL_FALSE,0,static_cast<char*>(0));
440
        glEnableVertexAttribArray(popp_attrib);
441
 
442
 
443
        glBindBuffer(GL_ARRAY_BUFFER, line_vertex_pos);
444
        glVertexPointer(3,GL_FLOAT,0,static_cast<char*>(0));
445
        glEnableClientState(GL_VERTEX_ARRAY);
446
 
447
        glDrawArrays(GL_QUADS, 0, quads*4);
448
 
449
        glDisableVertexAttribArray(id_attrib);
450
        glDisableVertexAttribArray(disp_attrib);
451
        glDisableVertexAttribArray(popp_attrib);
452
        glDisableClientState(GL_VERTEX_ARRAY);
453
 
454
 
455
        glLineWidth(lw);
456
 
457
        glUseProgram(0);
458
        glDisable(GL_TEXTURE_RECTANGLE_ARB);
459
        glDepthMask(GL_TRUE);
460
 
461
        // ------------------------------
462
        // Pass 4: Draw with shading
463
        // In this pass we draw the shaded model. At this point, the framebuffer
464
        // contains alpha values and line colours and also depth values.
465
        //
466
        // The depth test is set to `equal' and the shaded fragments from the 
467
        // filled polygons are combined with the line colours using the alpha 
468
        // values already stored in the frame buffer.
469
        //
470
        // The framebuffer lines along the contour also need to be blended. 
471
        // Hence, a screen filling quad is drawn. 
472
        glDepthFunc(GL_LEQUAL);
473
        glBlendEquation(GL_FUNC_ADD);
474
        glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, 
475
            GL_ZERO, GL_ONE);
476
        if(lights_on)
477
        {
478
            glEnable(GL_LIGHTING);
479
            glEnable(GL_LIGHT0);
480
        }else
481
            glColor4fv(current_color.get());
482
 
483
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffername);
484
        glVertexPointer(3,GL_FLOAT,0,static_cast<char*>(0));
485
        glEnableClientState(GL_VERTEX_ARRAY);
486
 
487
        vertex_idx = 0;
488
        for(FaceIDIterator f = mesh->faces_begin(); f != mesh->faces_end(); ++f){
489
			Vec3f n(normal(*mesh, *f));
490
            glNormal3fv(n.get());
491
            glBegin(GL_POLYGON);
492
            for(Walker w = mesh->walker(*f); !w.full_circle(); w = w.circulate_face_ccw())
493
                 glArrayElement(vertex_idx++);
494
            glEnd();
495
        }
496
        glDisableClientState(GL_VERTEX_ARRAY);
497
 
498
 
499
        glDisable(GL_LIGHTING);
500
 
501
 
502
        double mvmat[16];
503
        glGetDoublev(GL_MODELVIEW_MATRIX, mvmat);
504
        double prjmat[16];
505
        glGetDoublev(GL_PROJECTION_MATRIX, prjmat);
506
        glMatrixMode(GL_PROJECTION);
507
        glLoadIdentity();
508
        glMatrixMode(GL_MODELVIEW);
509
        glLoadIdentity();
510
        glColor3fv(clear_color.get());
511
        glBegin(GL_QUADS);
512
        glVertex3f(-1,-1,1);
513
        glVertex3f( 1,-1,1);
514
        glVertex3f( 1, 1,1);
515
        glVertex3f(-1, 1,1);
516
        glEnd();
517
 
518
 
519
 
520
        glMatrixMode(GL_PROJECTION);
521
        glLoadMatrixd(prjmat);
522
        glMatrixMode(GL_MODELVIEW);
523
        glLoadMatrixd(mvmat);
524
 
525
        glPopAttrib();
526
        if(lights_on)
527
            glEnable(GL_LIGHTING);
528
 
529
        //			cout << gluErrorString(glGetError()) << endl;
530
    }
396 jab 531
}