fix GL_BACK color material bug
[mesa.git] / src / mesa / main / feedback.c
1 /* $Id: feedback.c,v 1.10 2000/05/09 23:54:09 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "context.h"
33 #include "enums.h"
34 #include "feedback.h"
35 #include "macros.h"
36 #include "mmath.h"
37 #include "types.h"
38 #include "triangle.h"
39 #endif
40
41
42
43 #define FB_3D 0x01
44 #define FB_4D 0x02
45 #define FB_INDEX 0x04
46 #define FB_COLOR 0x08
47 #define FB_TEXTURE 0X10
48
49
50
51 void
52 _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
53 {
54 GET_CURRENT_CONTEXT(ctx);
55 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx, "glFeedbackBuffer" );
56
57 if (ctx->RenderMode==GL_FEEDBACK) {
58 gl_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
59 return;
60 }
61
62 if (size<0) {
63 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
64 return;
65 }
66 if (!buffer) {
67 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
68 ctx->Feedback.BufferSize = 0;
69 return;
70 }
71
72 switch (type) {
73 case GL_2D:
74 ctx->Feedback.Mask = 0;
75 ctx->Feedback.Type = type;
76 break;
77 case GL_3D:
78 ctx->Feedback.Mask = FB_3D;
79 ctx->Feedback.Type = type;
80 break;
81 case GL_3D_COLOR:
82 ctx->Feedback.Mask = FB_3D
83 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX);
84 ctx->Feedback.Type = type;
85 break;
86 case GL_3D_COLOR_TEXTURE:
87 ctx->Feedback.Mask = FB_3D
88 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX)
89 | FB_TEXTURE;
90 ctx->Feedback.Type = type;
91 break;
92 case GL_4D_COLOR_TEXTURE:
93 ctx->Feedback.Mask = FB_3D | FB_4D
94 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX)
95 | FB_TEXTURE;
96 ctx->Feedback.Type = type;
97 break;
98 default:
99 ctx->Feedback.Mask = 0;
100 gl_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
101 }
102
103 ctx->Feedback.BufferSize = size;
104 ctx->Feedback.Buffer = buffer;
105 ctx->Feedback.Count = 0;
106 }
107
108
109
110 void
111 _mesa_PassThrough( GLfloat token )
112 {
113 GET_CURRENT_CONTEXT(ctx);
114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPassThrough");
115
116 if (ctx->RenderMode==GL_FEEDBACK) {
117 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
118 FEEDBACK_TOKEN( ctx, token );
119 }
120 }
121
122
123
124 /*
125 * Put a vertex into the feedback buffer.
126 */
127 void gl_feedback_vertex( GLcontext *ctx,
128 const GLfloat win[4],
129 const GLfloat color[4],
130 GLuint index,
131 const GLfloat texcoord[4] )
132 {
133 FEEDBACK_TOKEN( ctx, win[0] );
134 FEEDBACK_TOKEN( ctx, win[1] );
135 if (ctx->Feedback.Mask & FB_3D) {
136 FEEDBACK_TOKEN( ctx, win[2] );
137 }
138 if (ctx->Feedback.Mask & FB_4D) {
139 FEEDBACK_TOKEN( ctx, win[3] );
140 }
141 if (ctx->Feedback.Mask & FB_INDEX) {
142 FEEDBACK_TOKEN( ctx, (GLfloat) index );
143 }
144 if (ctx->Feedback.Mask & FB_COLOR) {
145 FEEDBACK_TOKEN( ctx, color[0] );
146 FEEDBACK_TOKEN( ctx, color[1] );
147 FEEDBACK_TOKEN( ctx, color[2] );
148 FEEDBACK_TOKEN( ctx, color[3] );
149 }
150 if (ctx->Feedback.Mask & FB_TEXTURE) {
151 FEEDBACK_TOKEN( ctx, texcoord[0] );
152 FEEDBACK_TOKEN( ctx, texcoord[1] );
153 FEEDBACK_TOKEN( ctx, texcoord[2] );
154 FEEDBACK_TOKEN( ctx, texcoord[3] );
155 }
156 }
157
158
159
160 static void feedback_vertex( GLcontext *ctx, GLuint v, GLuint pv )
161 {
162 GLfloat win[4];
163 GLfloat color[4];
164 GLfloat tc[4];
165 GLuint texUnit = ctx->Texture.CurrentTransformUnit;
166 const struct vertex_buffer *VB = ctx->VB;
167 GLuint index;
168
169 win[0] = VB->Win.data[v][0];
170 win[1] = VB->Win.data[v][1];
171 win[2] = VB->Win.data[v][2] / ctx->Visual->DepthMaxF;
172 win[3] = 1.0 / VB->Win.data[v][3];
173
174 if (ctx->Light.ShadeModel == GL_SMOOTH)
175 pv = v;
176
177 UBYTE_RGBA_TO_FLOAT_RGBA( color, VB->ColorPtr->data[pv] );
178
179 if (VB->TexCoordPtr[texUnit]->size == 4 &&
180 VB->TexCoordPtr[texUnit]->data[v][3] != 0.0) {
181 GLfloat invq = 1.0F / VB->TexCoordPtr[texUnit]->data[v][3];
182 tc[0] = VB->TexCoordPtr[texUnit]->data[v][0] * invq;
183 tc[1] = VB->TexCoordPtr[texUnit]->data[v][1] * invq;
184 tc[2] = VB->TexCoordPtr[texUnit]->data[v][2] * invq;
185 tc[3] = VB->TexCoordPtr[texUnit]->data[v][3];
186 }
187 else {
188 ASSIGN_4V(tc, 0,0,0,1);
189 COPY_SZ_4V(tc,
190 VB->TexCoordPtr[texUnit]->size,
191 VB->TexCoordPtr[texUnit]->data[v]);
192 }
193
194 if (VB->IndexPtr)
195 index = VB->IndexPtr->data[v];
196 else
197 index = 0;
198
199 gl_feedback_vertex( ctx, win, color, index, tc );
200 }
201
202
203
204 /*
205 * Put triangle in feedback buffer.
206 */
207 void gl_feedback_triangle( GLcontext *ctx,
208 GLuint v0, GLuint v1, GLuint v2, GLuint pv )
209 {
210 if (gl_cull_triangle( ctx, v0, v1, v2, 0 )) {
211 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_POLYGON_TOKEN );
212 FEEDBACK_TOKEN( ctx, (GLfloat) 3 ); /* three vertices */
213
214 feedback_vertex( ctx, v0, pv );
215 feedback_vertex( ctx, v1, pv );
216 feedback_vertex( ctx, v2, pv );
217 }
218 }
219
220
221 void gl_feedback_line( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv )
222 {
223 GLenum token = GL_LINE_TOKEN;
224
225 if (ctx->StippleCounter==0)
226 token = GL_LINE_RESET_TOKEN;
227
228 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) token );
229
230 feedback_vertex( ctx, v1, pv );
231 feedback_vertex( ctx, v2, pv );
232
233 ctx->StippleCounter++;
234 }
235
236
237 void gl_feedback_points( GLcontext *ctx, GLuint first, GLuint last )
238 {
239 const struct vertex_buffer *VB = ctx->VB;
240 GLuint i;
241
242 for (i=first;i<=last;i++) {
243 if (VB->ClipMask[i]==0) {
244 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_POINT_TOKEN );
245 feedback_vertex( ctx, i, i );
246 }
247 }
248 }
249
250
251
252
253
254 /**********************************************************************/
255 /* Selection */
256 /**********************************************************************/
257
258
259 /*
260 * NOTE: this function can't be put in a display list.
261 */
262 void
263 _mesa_SelectBuffer( GLsizei size, GLuint *buffer )
264 {
265 GET_CURRENT_CONTEXT(ctx);
266 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSelectBuffer");
267 if (ctx->RenderMode==GL_SELECT) {
268 gl_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
269 }
270 ctx->Select.Buffer = buffer;
271 ctx->Select.BufferSize = size;
272 ctx->Select.BufferCount = 0;
273
274 ctx->Select.HitFlag = GL_FALSE;
275 ctx->Select.HitMinZ = 1.0;
276 ctx->Select.HitMaxZ = 0.0;
277 }
278
279
280 #define WRITE_RECORD( CTX, V ) \
281 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
282 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
283 } \
284 CTX->Select.BufferCount++;
285
286
287
288 void gl_update_hitflag( GLcontext *ctx, GLfloat z )
289 {
290 ctx->Select.HitFlag = GL_TRUE;
291 if (z < ctx->Select.HitMinZ) {
292 ctx->Select.HitMinZ = z;
293 }
294 if (z > ctx->Select.HitMaxZ) {
295 ctx->Select.HitMaxZ = z;
296 }
297 }
298
299 void gl_select_triangle( GLcontext *ctx,
300 GLuint v0, GLuint v1, GLuint v2, GLuint pv )
301 {
302 const struct vertex_buffer *VB = ctx->VB;
303
304 if (gl_cull_triangle( ctx, v0, v1, v2, 0 )) {
305 const GLfloat zs = 1.0F / ctx->Visual->DepthMaxF;
306 gl_update_hitflag( ctx, VB->Win.data[v0][2] * zs );
307 gl_update_hitflag( ctx, VB->Win.data[v1][2] * zs );
308 gl_update_hitflag( ctx, VB->Win.data[v2][2] * zs );
309 }
310 }
311
312
313 void gl_select_line( GLcontext *ctx,
314 GLuint v0, GLuint v1, GLuint pv )
315 {
316 const struct vertex_buffer *VB = ctx->VB;
317 const GLfloat zs = 1.0F / ctx->Visual->DepthMaxF;
318 gl_update_hitflag( ctx, VB->Win.data[v0][2] * zs );
319 gl_update_hitflag( ctx, VB->Win.data[v1][2] * zs );
320 }
321
322
323 void gl_select_points( GLcontext *ctx, GLuint first, GLuint last )
324 {
325 struct vertex_buffer *VB = ctx->VB;
326 const GLfloat zs = 1.0F / ctx->Visual->DepthMaxF;
327 GLuint i;
328
329 for (i=first;i<=last;i++) {
330 if (VB->ClipMask[i]==0) {
331 gl_update_hitflag( ctx, VB->Win.data[i][2] * zs );
332 }
333 }
334 }
335
336
337 static void write_hit_record( GLcontext *ctx )
338 {
339 GLuint i;
340 GLuint zmin, zmax, zscale = (~0u);
341
342 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
343 /* 2^32-1 and round to nearest unsigned integer. */
344
345 assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
346 zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
347 zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
348
349 WRITE_RECORD( ctx, ctx->Select.NameStackDepth );
350 WRITE_RECORD( ctx, zmin );
351 WRITE_RECORD( ctx, zmax );
352 for (i = 0; i < ctx->Select.NameStackDepth; i++) {
353 WRITE_RECORD( ctx, ctx->Select.NameStack[i] );
354 }
355
356 ctx->Select.Hits++;
357 ctx->Select.HitFlag = GL_FALSE;
358 ctx->Select.HitMinZ = 1.0;
359 ctx->Select.HitMaxZ = -1.0;
360 }
361
362
363
364 void
365 _mesa_InitNames( void )
366 {
367 GET_CURRENT_CONTEXT(ctx);
368 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glInitNames");
369 /* Record the hit before the HitFlag is wiped out again. */
370 if (ctx->RenderMode == GL_SELECT) {
371 if (ctx->Select.HitFlag) {
372 write_hit_record( ctx );
373 }
374 }
375 ctx->Select.NameStackDepth = 0;
376 ctx->Select.HitFlag = GL_FALSE;
377 ctx->Select.HitMinZ = 1.0;
378 ctx->Select.HitMaxZ = 0.0;
379 }
380
381
382
383 void
384 _mesa_LoadName( GLuint name )
385 {
386 GET_CURRENT_CONTEXT(ctx);
387 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glLoadName");
388 if (ctx->RenderMode != GL_SELECT) {
389 return;
390 }
391 if (ctx->Select.NameStackDepth == 0) {
392 gl_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
393 return;
394 }
395 if (ctx->Select.HitFlag) {
396 write_hit_record( ctx );
397 }
398 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
399 ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
400 }
401 else {
402 ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
403 }
404 }
405
406
407 void
408 _mesa_PushName( GLuint name )
409 {
410 GET_CURRENT_CONTEXT(ctx);
411 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPushName");
412 if (ctx->RenderMode != GL_SELECT) {
413 return;
414 }
415 if (ctx->Select.HitFlag) {
416 write_hit_record( ctx );
417 }
418 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
419 ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
420 }
421 else {
422 gl_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
423 }
424 }
425
426
427
428 void
429 _mesa_PopName( void )
430 {
431 GET_CURRENT_CONTEXT(ctx);
432 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPopName");
433 if (ctx->RenderMode != GL_SELECT) {
434 return;
435 }
436 if (ctx->Select.HitFlag) {
437 write_hit_record( ctx );
438 }
439 if (ctx->Select.NameStackDepth > 0) {
440 ctx->Select.NameStackDepth--;
441 }
442 else {
443 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
444 }
445 }
446
447
448
449 /**********************************************************************/
450 /* Render Mode */
451 /**********************************************************************/
452
453
454
455 /*
456 * NOTE: this function can't be put in a display list.
457 */
458 GLint
459 _mesa_RenderMode( GLenum mode )
460 {
461 GET_CURRENT_CONTEXT(ctx);
462 GLint result;
463
464 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glRenderMode", 0);
465
466 if (MESA_VERBOSE & VERBOSE_API)
467 fprintf(stderr, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode));
468
469 ctx->TriangleCaps &= ~(DD_FEEDBACK|DD_SELECT);
470
471 switch (ctx->RenderMode) {
472 case GL_RENDER:
473 result = 0;
474 break;
475 case GL_SELECT:
476 if (ctx->Select.HitFlag) {
477 write_hit_record( ctx );
478 }
479 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
480 /* overflow */
481 #ifdef DEBUG
482 gl_warning(ctx, "Feedback buffer overflow");
483 #endif
484 result = -1;
485 }
486 else {
487 result = ctx->Select.Hits;
488 }
489 ctx->Select.BufferCount = 0;
490 ctx->Select.Hits = 0;
491 ctx->Select.NameStackDepth = 0;
492 break;
493 case GL_FEEDBACK:
494 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
495 /* overflow */
496 result = -1;
497 }
498 else {
499 result = ctx->Feedback.Count;
500 }
501 ctx->Feedback.Count = 0;
502 break;
503 default:
504 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
505 return 0;
506 }
507
508 switch (mode) {
509 case GL_RENDER:
510 break;
511 case GL_SELECT:
512 ctx->TriangleCaps |= DD_SELECT;
513 if (ctx->Select.BufferSize==0) {
514 /* haven't called glSelectBuffer yet */
515 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
516 }
517 break;
518 case GL_FEEDBACK:
519 ctx->TriangleCaps |= DD_FEEDBACK;
520 if (ctx->Feedback.BufferSize==0) {
521 /* haven't called glFeedbackBuffer yet */
522 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
523 }
524 break;
525 default:
526 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
527 return 0;
528 }
529
530 ctx->RenderMode = mode;
531 ctx->NewState |= NEW_ALL;
532
533 return result;
534 }
535