1 /* $Id: feedback.c,v 1.4 1999/10/08 09:27:10 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
38 #include "GL/xf86glx.h"
48 #include "GL/xf86glx.h"
58 #define FB_TEXTURE 0X10
63 gl_FeedbackBuffer( GLcontext
*ctx
, GLsizei size
, GLenum type
, GLfloat
*buffer
)
65 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
, "glFeedbackBuffer" );
67 if (ctx
->RenderMode
==GL_FEEDBACK
) {
68 gl_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
73 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
77 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
78 ctx
->Feedback
.BufferSize
= 0;
84 ctx
->Feedback
.Mask
= 0;
85 ctx
->Feedback
.Type
= type
;
88 ctx
->Feedback
.Mask
= FB_3D
;
89 ctx
->Feedback
.Type
= type
;
92 ctx
->Feedback
.Mask
= FB_3D
93 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
);
94 ctx
->Feedback
.Type
= type
;
96 case GL_3D_COLOR_TEXTURE
:
97 ctx
->Feedback
.Mask
= FB_3D
98 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
100 ctx
->Feedback
.Type
= type
;
102 case GL_4D_COLOR_TEXTURE
:
103 ctx
->Feedback
.Mask
= FB_3D
| FB_4D
104 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
106 ctx
->Feedback
.Type
= type
;
109 ctx
->Feedback
.Mask
= 0;
110 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
113 ctx
->Feedback
.BufferSize
= size
;
114 ctx
->Feedback
.Buffer
= buffer
;
115 ctx
->Feedback
.Count
= 0;
120 void gl_PassThrough( GLcontext
*ctx
, GLfloat token
)
122 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPassThrough");
124 if (ctx
->RenderMode
==GL_FEEDBACK
) {
125 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
126 FEEDBACK_TOKEN( ctx
, token
);
133 * Put a vertex into the feedback buffer.
135 void gl_feedback_vertex( GLcontext
*ctx
,
136 const GLfloat win
[4],
137 const GLfloat color
[4],
139 const GLfloat texcoord
[4] )
141 FEEDBACK_TOKEN( ctx
, win
[0] );
142 FEEDBACK_TOKEN( ctx
, win
[1] );
143 if (ctx
->Feedback
.Mask
& FB_3D
) {
144 FEEDBACK_TOKEN( ctx
, win
[2] );
146 if (ctx
->Feedback
.Mask
& FB_4D
) {
147 FEEDBACK_TOKEN( ctx
, win
[3] );
149 if (ctx
->Feedback
.Mask
& FB_INDEX
) {
150 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
152 if (ctx
->Feedback
.Mask
& FB_COLOR
) {
153 FEEDBACK_TOKEN( ctx
, color
[0] );
154 FEEDBACK_TOKEN( ctx
, color
[1] );
155 FEEDBACK_TOKEN( ctx
, color
[2] );
156 FEEDBACK_TOKEN( ctx
, color
[3] );
158 if (ctx
->Feedback
.Mask
& FB_TEXTURE
) {
159 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
160 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
161 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
162 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
168 static void gl_do_feedback_vertex( GLcontext
*ctx
, GLuint v
, GLuint pv
)
173 GLuint texUnit
= ctx
->Texture
.CurrentTransformUnit
;
174 struct vertex_buffer
*VB
= ctx
->VB
;
176 win
[0] = VB
->Win
.data
[v
][0];
177 win
[1] = VB
->Win
.data
[v
][1];
178 win
[2] = VB
->Win
.data
[v
][2] / DEPTH_SCALE
;
179 win
[3] = 1.0 / VB
->Win
.data
[v
][3];
181 if (ctx
->Light
.ShadeModel
==GL_SMOOTH
) pv
= v
;
183 UBYTE_RGBA_TO_FLOAT_RGBA( color
, VB
->ColorPtr
->data
[pv
] );
185 if (VB
->TexCoordPtr
[texUnit
]->size
== 4 &&
186 VB
->TexCoordPtr
[texUnit
]->data
[v
][3]!=0.0)
188 GLfloat invq
= 1.0F
/ VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
189 tc
[0] = VB
->TexCoordPtr
[texUnit
]->data
[v
][0] * invq
;
190 tc
[1] = VB
->TexCoordPtr
[texUnit
]->data
[v
][1] * invq
;
191 tc
[2] = VB
->TexCoordPtr
[texUnit
]->data
[v
][2] * invq
;
192 tc
[3] = VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
194 ASSIGN_4V(tc
, 0,0,0,1);
196 VB
->TexCoordPtr
[texUnit
]->size
,
197 VB
->TexCoordPtr
[texUnit
]->data
[v
]);
200 gl_feedback_vertex( ctx
, win
, color
, VB
->IndexPtr
->data
[v
], tc
);
206 * Put triangle in feedback buffer.
208 void gl_feedback_triangle( GLcontext
*ctx
,
209 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
211 if (gl_cull_triangle( ctx
, v0
, v1
, v2
, 0 )) {
212 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POLYGON_TOKEN
);
213 FEEDBACK_TOKEN( ctx
, (GLfloat
) 3 ); /* three vertices */
215 gl_do_feedback_vertex( ctx
, v0
, pv
);
216 gl_do_feedback_vertex( ctx
, v1
, pv
);
217 gl_do_feedback_vertex( ctx
, v2
, pv
);
222 void gl_feedback_line( GLcontext
*ctx
, GLuint v1
, GLuint v2
, GLuint pv
)
224 GLenum token
= GL_LINE_TOKEN
;
226 if (ctx
->StippleCounter
==0)
227 token
= GL_LINE_RESET_TOKEN
;
229 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) token
);
231 gl_do_feedback_vertex( ctx
, v1
, pv
);
232 gl_do_feedback_vertex( ctx
, v2
, pv
);
234 ctx
->StippleCounter
++;
238 void gl_feedback_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
240 struct vertex_buffer
*VB
= ctx
->VB
;
243 for (i
=first
;i
<=last
;i
++)
244 if (VB
->ClipMask
[i
]==0) {
245 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POINT_TOKEN
);
246 gl_do_feedback_vertex( ctx
, i
, i
);
254 /**********************************************************************/
256 /**********************************************************************/
260 * NOTE: this function can't be put in a display list.
262 void gl_SelectBuffer( GLcontext
*ctx
, GLsizei size
, GLuint
*buffer
)
264 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glSelectBuffer");
265 if (ctx
->RenderMode
==GL_SELECT
) {
266 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
268 ctx
->Select
.Buffer
= buffer
;
269 ctx
->Select
.BufferSize
= size
;
270 ctx
->Select
.BufferCount
= 0;
272 ctx
->Select
.HitFlag
= GL_FALSE
;
273 ctx
->Select
.HitMinZ
= 1.0;
274 ctx
->Select
.HitMaxZ
= 0.0;
278 #define WRITE_RECORD( CTX, V ) \
279 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
280 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
282 CTX->Select.BufferCount++;
286 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
288 ctx
->Select
.HitFlag
= GL_TRUE
;
289 if (z
< ctx
->Select
.HitMinZ
) {
290 ctx
->Select
.HitMinZ
= z
;
292 if (z
> ctx
->Select
.HitMaxZ
) {
293 ctx
->Select
.HitMaxZ
= z
;
297 void gl_select_triangle( GLcontext
*ctx
,
298 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
300 struct vertex_buffer
*VB
= ctx
->VB
;
302 if (gl_cull_triangle( ctx
, v0
, v1
, v2
, 0 )) {
303 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
304 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
305 gl_update_hitflag( ctx
, VB
->Win
.data
[v2
][3] / DEPTH_SCALE
);
310 void gl_select_line( GLcontext
*ctx
,
311 GLuint v0
, GLuint v1
, GLuint pv
)
313 struct vertex_buffer
*VB
= ctx
->VB
;
315 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
316 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
319 void gl_select_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
321 struct vertex_buffer
*VB
= ctx
->VB
;
324 for (i
=first
;i
<=last
;i
++)
325 if (VB
->ClipMask
[i
]==0)
326 gl_update_hitflag( ctx
, VB
->Win
.data
[i
][3] / DEPTH_SCALE
);
330 static void write_hit_record( GLcontext
*ctx
)
333 GLuint zmin
, zmax
, zscale
= (~0u);
335 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
336 /* 2^32-1 and round to nearest unsigned integer. */
338 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
339 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
340 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
342 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
343 WRITE_RECORD( ctx
, zmin
);
344 WRITE_RECORD( ctx
, zmax
);
345 for (i
=0;i
<ctx
->Select
.NameStackDepth
;i
++) {
346 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
350 ctx
->Select
.HitFlag
= GL_FALSE
;
351 ctx
->Select
.HitMinZ
= 1.0;
352 ctx
->Select
.HitMaxZ
= -1.0;
357 void gl_InitNames( GLcontext
*ctx
)
359 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glInitNames");
360 /* Record the hit before the HitFlag is wiped out again. */
361 if (ctx
->RenderMode
==GL_SELECT
) {
362 if (ctx
->Select
.HitFlag
) {
363 write_hit_record( ctx
);
366 ctx
->Select
.NameStackDepth
= 0;
367 ctx
->Select
.HitFlag
= GL_FALSE
;
368 ctx
->Select
.HitMinZ
= 1.0;
369 ctx
->Select
.HitMaxZ
= 0.0;
374 void gl_LoadName( GLcontext
*ctx
, GLuint name
)
376 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glLoadName");
377 if (ctx
->RenderMode
!=GL_SELECT
) {
380 if (ctx
->Select
.NameStackDepth
==0) {
381 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
384 if (ctx
->Select
.HitFlag
) {
385 write_hit_record( ctx
);
387 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
388 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
391 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
396 void gl_PushName( GLcontext
*ctx
, GLuint name
)
398 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPushName");
399 if (ctx
->RenderMode
!=GL_SELECT
) {
402 if (ctx
->Select
.HitFlag
) {
403 write_hit_record( ctx
);
405 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
406 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
409 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
415 void gl_PopName( GLcontext
*ctx
)
417 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPopName");
418 if (ctx
->RenderMode
!=GL_SELECT
) {
421 if (ctx
->Select
.HitFlag
) {
422 write_hit_record( ctx
);
424 if (ctx
->Select
.NameStackDepth
>0) {
425 ctx
->Select
.NameStackDepth
--;
428 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
434 /**********************************************************************/
436 /**********************************************************************/
441 * NOTE: this function can't be put in a display list.
443 GLint
gl_RenderMode( GLcontext
*ctx
, GLenum mode
)
447 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glRenderMode", 0);
449 if (MESA_VERBOSE
& VERBOSE_API
)
450 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
452 ctx
->TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
454 switch (ctx
->RenderMode
) {
459 if (ctx
->Select
.HitFlag
) {
460 write_hit_record( ctx
);
462 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
465 gl_warning(ctx
, "Feedback buffer overflow");
470 result
= ctx
->Select
.Hits
;
472 ctx
->Select
.BufferCount
= 0;
473 ctx
->Select
.Hits
= 0;
474 ctx
->Select
.NameStackDepth
= 0;
477 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
482 result
= ctx
->Feedback
.Count
;
484 ctx
->Feedback
.Count
= 0;
487 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
495 ctx
->TriangleCaps
|= DD_SELECT
;
496 if (ctx
->Select
.BufferSize
==0) {
497 /* haven't called glSelectBuffer yet */
498 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
502 ctx
->TriangleCaps
|= DD_FEEDBACK
;
503 if (ctx
->Feedback
.BufferSize
==0) {
504 /* haven't called glFeedbackBuffer yet */
505 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
509 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
514 ctx
->RenderMode
= mode
;
515 ctx
->NewState
|= NEW_ALL
;