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