433d0391e880b7bd58c507e98a9381abdc247ba2
1 /* $Id: feedback.c,v 1.2 1999/09/18 20:41:23 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.
43 #include "GL/xf86glx.h"
53 #define FB_TEXTURE 0X10
58 gl_FeedbackBuffer( GLcontext
*ctx
, GLsizei size
, GLenum type
, GLfloat
*buffer
)
60 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
, "glFeedbackBuffer" );
62 if (ctx
->RenderMode
==GL_FEEDBACK
) {
63 gl_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
68 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
72 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
73 ctx
->Feedback
.BufferSize
= 0;
79 ctx
->Feedback
.Mask
= 0;
80 ctx
->Feedback
.Type
= type
;
83 ctx
->Feedback
.Mask
= FB_3D
;
84 ctx
->Feedback
.Type
= type
;
87 ctx
->Feedback
.Mask
= FB_3D
88 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
);
89 ctx
->Feedback
.Type
= type
;
91 case GL_3D_COLOR_TEXTURE
:
92 ctx
->Feedback
.Mask
= FB_3D
93 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
95 ctx
->Feedback
.Type
= type
;
97 case GL_4D_COLOR_TEXTURE
:
98 ctx
->Feedback
.Mask
= FB_3D
| FB_4D
99 | (ctx
->Visual
->RGBAflag
? FB_COLOR
: FB_INDEX
)
101 ctx
->Feedback
.Type
= type
;
104 ctx
->Feedback
.Mask
= 0;
105 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
108 ctx
->Feedback
.BufferSize
= size
;
109 ctx
->Feedback
.Buffer
= buffer
;
110 ctx
->Feedback
.Count
= 0;
115 void gl_PassThrough( GLcontext
*ctx
, GLfloat token
)
117 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPassThrough");
119 if (ctx
->RenderMode
==GL_FEEDBACK
) {
120 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
121 FEEDBACK_TOKEN( ctx
, token
);
128 * Put a vertex into the feedback buffer.
130 void gl_feedback_vertex( GLcontext
*ctx
,
131 const GLfloat win
[4],
132 const GLfloat color
[4],
134 const GLfloat texcoord
[4] )
136 FEEDBACK_TOKEN( ctx
, win
[0] );
137 FEEDBACK_TOKEN( ctx
, win
[1] );
138 if (ctx
->Feedback
.Mask
& FB_3D
) {
139 FEEDBACK_TOKEN( ctx
, win
[2] );
141 if (ctx
->Feedback
.Mask
& FB_4D
) {
142 FEEDBACK_TOKEN( ctx
, win
[3] );
144 if (ctx
->Feedback
.Mask
& FB_INDEX
) {
145 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
147 if (ctx
->Feedback
.Mask
& FB_COLOR
) {
148 FEEDBACK_TOKEN( ctx
, color
[0] );
149 FEEDBACK_TOKEN( ctx
, color
[1] );
150 FEEDBACK_TOKEN( ctx
, color
[2] );
151 FEEDBACK_TOKEN( ctx
, color
[3] );
153 if (ctx
->Feedback
.Mask
& FB_TEXTURE
) {
154 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
155 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
156 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
157 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
163 static void gl_do_feedback_vertex( GLcontext
*ctx
, GLuint v
, GLuint pv
)
168 GLuint texUnit
= ctx
->Texture
.CurrentTransformUnit
;
169 struct vertex_buffer
*VB
= ctx
->VB
;
171 win
[0] = VB
->Win
.data
[v
][0];
172 win
[1] = VB
->Win
.data
[v
][1];
173 win
[2] = VB
->Win
.data
[v
][2] / DEPTH_SCALE
;
174 win
[3] = 1.0 / VB
->Win
.data
[v
][3];
176 if (ctx
->Light
.ShadeModel
==GL_SMOOTH
) pv
= v
;
178 UBYTE_RGBA_TO_FLOAT_RGBA( color
, VB
->ColorPtr
->data
[pv
] );
180 if (VB
->TexCoordPtr
[texUnit
]->size
== 4 &&
181 VB
->TexCoordPtr
[texUnit
]->data
[v
][3]!=0.0)
183 GLfloat invq
= 1.0F
/ VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
184 tc
[0] = VB
->TexCoordPtr
[texUnit
]->data
[v
][0] * invq
;
185 tc
[1] = VB
->TexCoordPtr
[texUnit
]->data
[v
][1] * invq
;
186 tc
[2] = VB
->TexCoordPtr
[texUnit
]->data
[v
][2] * invq
;
187 tc
[3] = VB
->TexCoordPtr
[texUnit
]->data
[v
][3];
189 ASSIGN_4V(tc
, 0,0,0,1);
191 VB
->TexCoordPtr
[texUnit
]->size
,
192 VB
->TexCoordPtr
[texUnit
]->data
[v
]);
195 gl_feedback_vertex( ctx
, win
, color
, VB
->IndexPtr
->data
[v
], tc
);
201 * Put triangle in feedback buffer.
203 void gl_feedback_triangle( GLcontext
*ctx
,
204 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
206 if (gl_cull_triangle( ctx
, v0
, v1
, v2
)) {
207 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POLYGON_TOKEN
);
208 FEEDBACK_TOKEN( ctx
, (GLfloat
) 3 ); /* three vertices */
210 gl_do_feedback_vertex( ctx
, v0
, pv
);
211 gl_do_feedback_vertex( ctx
, v1
, pv
);
212 gl_do_feedback_vertex( ctx
, v2
, pv
);
217 void gl_feedback_line( GLcontext
*ctx
, GLuint v1
, GLuint v2
, GLuint pv
)
219 GLenum token
= GL_LINE_TOKEN
;
221 if (ctx
->StippleCounter
==0)
222 token
= GL_LINE_RESET_TOKEN
;
224 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) token
);
226 gl_do_feedback_vertex( ctx
, v1
, pv
);
227 gl_do_feedback_vertex( ctx
, v2
, pv
);
229 ctx
->StippleCounter
++;
233 void gl_feedback_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
235 struct vertex_buffer
*VB
= ctx
->VB
;
238 for (i
=first
;i
<=last
;i
++)
239 if (VB
->ClipMask
[i
]==0) {
240 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POINT_TOKEN
);
241 gl_do_feedback_vertex( ctx
, i
, i
);
249 /**********************************************************************/
251 /**********************************************************************/
255 * NOTE: this function can't be put in a display list.
257 void gl_SelectBuffer( GLcontext
*ctx
, GLsizei size
, GLuint
*buffer
)
259 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glSelectBuffer");
260 if (ctx
->RenderMode
==GL_SELECT
) {
261 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
263 ctx
->Select
.Buffer
= buffer
;
264 ctx
->Select
.BufferSize
= size
;
265 ctx
->Select
.BufferCount
= 0;
267 ctx
->Select
.HitFlag
= GL_FALSE
;
268 ctx
->Select
.HitMinZ
= 1.0;
269 ctx
->Select
.HitMaxZ
= 0.0;
273 #define WRITE_RECORD( CTX, V ) \
274 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
275 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
277 CTX->Select.BufferCount++;
281 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
283 ctx
->Select
.HitFlag
= GL_TRUE
;
284 if (z
< ctx
->Select
.HitMinZ
) {
285 ctx
->Select
.HitMinZ
= z
;
287 if (z
> ctx
->Select
.HitMaxZ
) {
288 ctx
->Select
.HitMaxZ
= z
;
292 void gl_select_triangle( GLcontext
*ctx
,
293 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
295 struct vertex_buffer
*VB
= ctx
->VB
;
297 if (gl_cull_triangle( ctx
, v0
, v1
, v2
)) {
298 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
299 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
300 gl_update_hitflag( ctx
, VB
->Win
.data
[v2
][3] / DEPTH_SCALE
);
305 void gl_select_line( GLcontext
*ctx
,
306 GLuint v0
, GLuint v1
, GLuint pv
)
308 struct vertex_buffer
*VB
= ctx
->VB
;
310 gl_update_hitflag( ctx
, VB
->Win
.data
[v0
][3] / DEPTH_SCALE
);
311 gl_update_hitflag( ctx
, VB
->Win
.data
[v1
][3] / DEPTH_SCALE
);
314 void gl_select_points( GLcontext
*ctx
, GLuint first
, GLuint last
)
316 struct vertex_buffer
*VB
= ctx
->VB
;
319 for (i
=first
;i
<=last
;i
++)
320 if (VB
->ClipMask
[i
]==0)
321 gl_update_hitflag( ctx
, VB
->Win
.data
[i
][3] / DEPTH_SCALE
);
325 static void write_hit_record( GLcontext
*ctx
)
328 GLuint zmin
, zmax
, zscale
= (~0u);
330 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
331 /* 2^32-1 and round to nearest unsigned integer. */
333 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
334 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
335 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
337 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
338 WRITE_RECORD( ctx
, zmin
);
339 WRITE_RECORD( ctx
, zmax
);
340 for (i
=0;i
<ctx
->Select
.NameStackDepth
;i
++) {
341 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
345 ctx
->Select
.HitFlag
= GL_FALSE
;
346 ctx
->Select
.HitMinZ
= 1.0;
347 ctx
->Select
.HitMaxZ
= -1.0;
352 void gl_InitNames( GLcontext
*ctx
)
354 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glInitNames");
355 /* Record the hit before the HitFlag is wiped out again. */
356 if (ctx
->RenderMode
==GL_SELECT
) {
357 if (ctx
->Select
.HitFlag
) {
358 write_hit_record( ctx
);
361 ctx
->Select
.NameStackDepth
= 0;
362 ctx
->Select
.HitFlag
= GL_FALSE
;
363 ctx
->Select
.HitMinZ
= 1.0;
364 ctx
->Select
.HitMaxZ
= 0.0;
369 void gl_LoadName( GLcontext
*ctx
, GLuint name
)
371 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glLoadName");
372 if (ctx
->RenderMode
!=GL_SELECT
) {
375 if (ctx
->Select
.NameStackDepth
==0) {
376 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
379 if (ctx
->Select
.HitFlag
) {
380 write_hit_record( ctx
);
382 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
383 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
386 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
391 void gl_PushName( GLcontext
*ctx
, GLuint name
)
393 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPushName");
394 if (ctx
->RenderMode
!=GL_SELECT
) {
397 if (ctx
->Select
.HitFlag
) {
398 write_hit_record( ctx
);
400 if (ctx
->Select
.NameStackDepth
<MAX_NAME_STACK_DEPTH
) {
401 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
404 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
410 void gl_PopName( GLcontext
*ctx
)
412 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPopName");
413 if (ctx
->RenderMode
!=GL_SELECT
) {
416 if (ctx
->Select
.HitFlag
) {
417 write_hit_record( ctx
);
419 if (ctx
->Select
.NameStackDepth
>0) {
420 ctx
->Select
.NameStackDepth
--;
423 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
429 /**********************************************************************/
431 /**********************************************************************/
436 * NOTE: this function can't be put in a display list.
438 GLint
gl_RenderMode( GLcontext
*ctx
, GLenum mode
)
442 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glRenderMode", 0);
444 if (MESA_VERBOSE
& VERBOSE_API
)
445 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
447 ctx
->TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
449 switch (ctx
->RenderMode
) {
454 if (ctx
->Select
.HitFlag
) {
455 write_hit_record( ctx
);
457 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
460 gl_warning(ctx
, "Feedback buffer overflow");
465 result
= ctx
->Select
.Hits
;
467 ctx
->Select
.BufferCount
= 0;
468 ctx
->Select
.Hits
= 0;
469 ctx
->Select
.NameStackDepth
= 0;
472 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
477 result
= ctx
->Feedback
.Count
;
479 ctx
->Feedback
.Count
= 0;
482 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
490 ctx
->TriangleCaps
|= DD_SELECT
;
491 if (ctx
->Select
.BufferSize
==0) {
492 /* haven't called glSelectBuffer yet */
493 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
497 ctx
->TriangleCaps
|= DD_FEEDBACK
;
498 if (ctx
->Feedback
.BufferSize
==0) {
499 /* haven't called glFeedbackBuffer yet */
500 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
504 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
509 ctx
->RenderMode
= mode
;
510 ctx
->NewState
|= NEW_ALL
;