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