0fb09d07563c451147517772ab43478be1cc15a4
1 /* $Id: feedback.c,v 1.3 1999/09/19 02:03:19 tjump 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.
44 #include "GL/xf86glx.h"
54 #define FB_TEXTURE 0X10
59 gl_FeedbackBuffer( GLcontext
*ctx
, GLsizei size
, GLenum type
, GLfloat
*buffer
)
61 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
, "glFeedbackBuffer" );
63 if (ctx
->RenderMode
==GL_FEEDBACK
) {
64 gl_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
69 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
73 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
74 ctx
->Feedback
.BufferSize
= 0;
80 ctx
->Feedback
.Mask
= 0;
81 ctx
->Feedback
.Type
= type
;
84 ctx
->Feedback
.Mask
= FB_3D
;
85 ctx
->Feedback
.Type
= type
;
88 ctx
->Feedback
.Mask
= FB_3D
89 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
);
90 ctx
->Feedback
.Type
= type
;
92 case GL_3D_COLOR_TEXTURE
:
93 ctx
->Feedback
.Mask
= FB_3D
94 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
96 ctx
->Feedback
.Type
= type
;
98 case GL_4D_COLOR_TEXTURE
:
99 ctx
->Feedback
.Mask
= FB_3D
| FB_4D
100 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
102 ctx
->Feedback
.Type
= type
;
105 ctx
->Feedback
.Mask
= 0;
106 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
109 ctx
->Feedback
.BufferSize
= size
;
110 ctx
->Feedback
.Buffer
= buffer
;
111 ctx
->Feedback
.Count
= 0;
116 void gl_PassThrough( GLcontext
*ctx
, GLfloat token
)
118 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPassThrough");
120 if (ctx
->RenderMode
==GL_FEEDBACK
) {
121 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
122 FEEDBACK_TOKEN( ctx
, token
);
129 * Put a vertex into the feedback buffer.
131 void gl_feedback_vertex( GLcontext
*ctx
,
132 const GLfloat win
[4],
133 const GLfloat color
[4],
135 const GLfloat texcoord
[4] )
137 FEEDBACK_TOKEN( ctx
, win
[0] );
138 FEEDBACK_TOKEN( ctx
, win
[1] );
139 if (ctx
->Feedback
.Mask
& FB_3D
) {
140 FEEDBACK_TOKEN( ctx
, win
[2] );
142 if (ctx
->Feedback
.Mask
& FB_4D
) {
143 FEEDBACK_TOKEN( ctx
, win
[3] );
145 if (ctx
->Feedback
.Mask
& FB_INDEX
) {
146 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
148 if (ctx
->Feedback
.Mask
& FB_COLOR
) {
149 FEEDBACK_TOKEN( ctx
, color
[0] );
150 FEEDBACK_TOKEN( ctx
, color
[1] );
151 FEEDBACK_TOKEN( ctx
, color
[2] );
152 FEEDBACK_TOKEN( ctx
, color
[3] );
154 if (ctx
->Feedback
.Mask
& FB_TEXTURE
) {
155 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
156 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
157 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
158 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
164 static void gl_do_feedback_vertex( GLcontext
*ctx
, GLuint v
, GLuint pv
)
169 GLuint texUnit
= ctx
->Texture
.CurrentTransformUnit
;
170 struct vertex_buffer
*VB
= ctx
->VB
;
172 win
[0] = VB
->Win
.data
[v
][0];
173 win
[1] = VB
->Win
.data
[v
][1];
174 win
[2] = VB
->Win
.data
[v
][2] / DEPTH_SCALE
;
175 win
[3] = 1.0 / VB
->Win
.data
[v
][3];
177 if (ctx
->Light
.ShadeModel
==GL_SMOOTH
) pv
= v
;
179 UBYTE_RGBA_TO_FLOAT_RGBA( color
, VB
->ColorPtr
->data
[pv
] );
181 if (VB
->TexCoordPtr
[texUnit
]->size
== 4 &&
182 VB
->TexCoordPtr
[texUnit
]->data
[v
][3]!=0.0)
184 GLfloat invq
= 1.0F
/ VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
185 tc
[0] = VB
->TexCoordPtr
[texUnit
]->data
[v
][0] * invq
;
186 tc
[1] = VB
->TexCoordPtr
[texUnit
]->data
[v
][1] * invq
;
187 tc
[2] = VB
->TexCoordPtr
[texUnit
]->data
[v
][2] * invq
;
188 tc
[3] = VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
190 ASSIGN_4V(tc
, 0,0,0,1);
192 VB
->TexCoordPtr
[texUnit
]->size
,
193 VB
->TexCoordPtr
[texUnit
]->data
[v
]);
196 gl_feedback_vertex( ctx
, win
, color
, VB
->IndexPtr
->data
[v
], tc
);
202 * Put triangle in feedback buffer.
204 void gl_feedback_triangle( GLcontext
*ctx
,
205 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
207 if (gl_cull_triangle( ctx
, v0
, v1
, v2
, 0 )) {
208 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POLYGON_TOKEN
);
209 FEEDBACK_TOKEN( ctx
, (GLfloat
) 3 ); /* three vertices */
211 gl_do_feedback_vertex( ctx
, v0
, pv
);
212 gl_do_feedback_vertex( ctx
, v1
, pv
);
213 gl_do_feedback_vertex( ctx
, v2
, pv
);
218 void gl_feedback_line( GLcontext
*ctx
, GLuint v1
, GLuint v2
, GLuint pv
)
220 GLenum token
= GL_LINE_TOKEN
;
222 if (ctx
->StippleCounter
==0)
223 token
= GL_LINE_RESET_TOKEN
;
225 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) token
);
227 gl_do_feedback_vertex( ctx
, v1
, pv
);
228 gl_do_feedback_vertex( ctx
, v2
, pv
);
230 ctx
->StippleCounter
++;
234 void gl_feedback_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
236 struct vertex_buffer
*VB
= ctx
->VB
;
239 for (i
=first
;i
<=last
;i
++)
240 if (VB
->ClipMask
[i
]==0) {
241 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POINT_TOKEN
);
242 gl_do_feedback_vertex( ctx
, i
, i
);
250 /**********************************************************************/
252 /**********************************************************************/
256 * NOTE: this function can't be put in a display list.
258 void gl_SelectBuffer( GLcontext
*ctx
, GLsizei size
, GLuint
*buffer
)
260 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glSelectBuffer");
261 if (ctx
->RenderMode
==GL_SELECT
) {
262 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
264 ctx
->Select
.Buffer
= buffer
;
265 ctx
->Select
.BufferSize
= size
;
266 ctx
->Select
.BufferCount
= 0;
268 ctx
->Select
.HitFlag
= GL_FALSE
;
269 ctx
->Select
.HitMinZ
= 1.0;
270 ctx
->Select
.HitMaxZ
= 0.0;
274 #define WRITE_RECORD( CTX, V ) \
275 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
276 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
278 CTX->Select.BufferCount++;
282 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
284 ctx
->Select
.HitFlag
= GL_TRUE
;
285 if (z
< ctx
->Select
.HitMinZ
) {
286 ctx
->Select
.HitMinZ
= z
;
288 if (z
> ctx
->Select
.HitMaxZ
) {
289 ctx
->Select
.HitMaxZ
= z
;
293 void gl_select_triangle( GLcontext
*ctx
,
294 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
296 struct vertex_buffer
*VB
= ctx
->VB
;
298 if (gl_cull_triangle( ctx
, v0
, v1
, v2
, 0 )) {
299 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
300 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
301 gl_update_hitflag( ctx
, VB
->Win
.data
[v2
][3] / DEPTH_SCALE
);
306 void gl_select_line( GLcontext
*ctx
,
307 GLuint v0
, GLuint v1
, GLuint pv
)
309 struct vertex_buffer
*VB
= ctx
->VB
;
311 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
312 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
315 void gl_select_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
317 struct vertex_buffer
*VB
= ctx
->VB
;
320 for (i
=first
;i
<=last
;i
++)
321 if (VB
->ClipMask
[i
]==0)
322 gl_update_hitflag( ctx
, VB
->Win
.data
[i
][3] / DEPTH_SCALE
);
326 static void write_hit_record( GLcontext
*ctx
)
329 GLuint zmin
, zmax
, zscale
= (~0u);
331 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
332 /* 2^32-1 and round to nearest unsigned integer. */
334 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
335 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
336 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
338 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
339 WRITE_RECORD( ctx
, zmin
);
340 WRITE_RECORD( ctx
, zmax
);
341 for (i
=0;i
<ctx
->Select
.NameStackDepth
;i
++) {
342 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
346 ctx
->Select
.HitFlag
= GL_FALSE
;
347 ctx
->Select
.HitMinZ
= 1.0;
348 ctx
->Select
.HitMaxZ
= -1.0;
353 void gl_InitNames( GLcontext
*ctx
)
355 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glInitNames");
356 /* Record the hit before the HitFlag is wiped out again. */
357 if (ctx
->RenderMode
==GL_SELECT
) {
358 if (ctx
->Select
.HitFlag
) {
359 write_hit_record( ctx
);
362 ctx
->Select
.NameStackDepth
= 0;
363 ctx
->Select
.HitFlag
= GL_FALSE
;
364 ctx
->Select
.HitMinZ
= 1.0;
365 ctx
->Select
.HitMaxZ
= 0.0;
370 void gl_LoadName( GLcontext
*ctx
, GLuint name
)
372 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glLoadName");
373 if (ctx
->RenderMode
!=GL_SELECT
) {
376 if (ctx
->Select
.NameStackDepth
==0) {
377 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
380 if (ctx
->Select
.HitFlag
) {
381 write_hit_record( ctx
);
383 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
384 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
387 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
392 void gl_PushName( GLcontext
*ctx
, GLuint name
)
394 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPushName");
395 if (ctx
->RenderMode
!=GL_SELECT
) {
398 if (ctx
->Select
.HitFlag
) {
399 write_hit_record( ctx
);
401 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
402 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
405 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
411 void gl_PopName( GLcontext
*ctx
)
413 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPopName");
414 if (ctx
->RenderMode
!=GL_SELECT
) {
417 if (ctx
->Select
.HitFlag
) {
418 write_hit_record( ctx
);
420 if (ctx
->Select
.NameStackDepth
>0) {
421 ctx
->Select
.NameStackDepth
--;
424 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
430 /**********************************************************************/
432 /**********************************************************************/
437 * NOTE: this function can't be put in a display list.
439 GLint
gl_RenderMode( GLcontext
*ctx
, GLenum mode
)
443 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glRenderMode", 0);
445 if (MESA_VERBOSE
& VERBOSE_API
)
446 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
448 ctx
->TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
450 switch (ctx
->RenderMode
) {
455 if (ctx
->Select
.HitFlag
) {
456 write_hit_record( ctx
);
458 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
461 gl_warning(ctx
, "Feedback buffer overflow");
466 result
= ctx
->Select
.Hits
;
468 ctx
->Select
.BufferCount
= 0;
469 ctx
->Select
.Hits
= 0;
470 ctx
->Select
.NameStackDepth
= 0;
473 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
478 result
= ctx
->Feedback
.Count
;
480 ctx
->Feedback
.Count
= 0;
483 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
491 ctx
->TriangleCaps
|= DD_SELECT
;
492 if (ctx
->Select
.BufferSize
==0) {
493 /* haven't called glSelectBuffer yet */
494 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
498 ctx
->TriangleCaps
|= DD_FEEDBACK
;
499 if (ctx
->Feedback
.BufferSize
==0) {
500 /* haven't called glFeedbackBuffer yet */
501 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
505 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
510 ctx
->RenderMode
= mode
;
511 ctx
->NewState
|= NEW_ALL
;