1 /* $Id: feedback.c,v 1.16 2000/11/05 18:40:57 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 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.
47 #define FB_TEXTURE 0X10
52 _mesa_FeedbackBuffer( GLsizei size
, GLenum type
, GLfloat
*buffer
)
54 GET_CURRENT_CONTEXT(ctx
);
55 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
, "glFeedbackBuffer" );
57 if (ctx
->RenderMode
==GL_FEEDBACK
) {
58 gl_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
63 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
67 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
68 ctx
->Feedback
.BufferSize
= 0;
74 ctx
->Feedback
.Mask
= 0;
75 ctx
->Feedback
.Type
= type
;
78 ctx
->Feedback
.Mask
= FB_3D
;
79 ctx
->Feedback
.Type
= type
;
82 ctx
->Feedback
.Mask
= FB_3D
83 | (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
);
84 ctx
->Feedback
.Type
= type
;
86 case GL_3D_COLOR_TEXTURE
:
87 ctx
->Feedback
.Mask
= FB_3D
88 | (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
)
90 ctx
->Feedback
.Type
= type
;
92 case GL_4D_COLOR_TEXTURE
:
93 ctx
->Feedback
.Mask
= FB_3D
| FB_4D
94 | (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
)
96 ctx
->Feedback
.Type
= type
;
99 ctx
->Feedback
.Mask
= 0;
100 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
103 ctx
->Feedback
.BufferSize
= size
;
104 ctx
->Feedback
.Buffer
= buffer
;
105 ctx
->Feedback
.Count
= 0;
106 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
112 _mesa_PassThrough( GLfloat token
)
114 GET_CURRENT_CONTEXT(ctx
);
115 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPassThrough");
117 if (ctx
->RenderMode
==GL_FEEDBACK
) {
118 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
119 FEEDBACK_TOKEN( ctx
, token
);
126 * Put a vertex into the feedback buffer.
128 void gl_feedback_vertex( GLcontext
*ctx
,
129 const GLfloat win
[4],
130 const GLfloat color
[4],
132 const GLfloat texcoord
[4] )
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] );
139 if (ctx
->Feedback
.Mask
& FB_4D
) {
140 FEEDBACK_TOKEN( ctx
, win
[3] );
142 if (ctx
->Feedback
.Mask
& FB_INDEX
) {
143 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
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] );
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] );
159 /**********************************************************************/
161 /**********************************************************************/
165 * NOTE: this function can't be put in a display list.
168 _mesa_SelectBuffer( GLsizei size
, GLuint
*buffer
)
170 GET_CURRENT_CONTEXT(ctx
);
171 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glSelectBuffer");
172 if (ctx
->RenderMode
==GL_SELECT
) {
173 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
175 ctx
->Select
.Buffer
= buffer
;
176 ctx
->Select
.BufferSize
= size
;
177 ctx
->Select
.BufferCount
= 0;
179 ctx
->Select
.HitFlag
= GL_FALSE
;
180 ctx
->Select
.HitMinZ
= 1.0;
181 ctx
->Select
.HitMaxZ
= 0.0;
183 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
187 #define WRITE_RECORD( CTX, V ) \
188 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
189 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
191 CTX->Select.BufferCount++;
195 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
197 ctx
->Select
.HitFlag
= GL_TRUE
;
198 if (z
< ctx
->Select
.HitMinZ
) {
199 ctx
->Select
.HitMinZ
= z
;
201 if (z
> ctx
->Select
.HitMaxZ
) {
202 ctx
->Select
.HitMaxZ
= z
;
207 static void write_hit_record( GLcontext
*ctx
)
210 GLuint zmin
, zmax
, zscale
= (~0u);
212 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
213 /* 2^32-1 and round to nearest unsigned integer. */
215 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
216 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
217 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
219 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
220 WRITE_RECORD( ctx
, zmin
);
221 WRITE_RECORD( ctx
, zmax
);
222 for (i
= 0; i
< ctx
->Select
.NameStackDepth
; i
++) {
223 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
227 ctx
->Select
.HitFlag
= GL_FALSE
;
228 ctx
->Select
.HitMinZ
= 1.0;
229 ctx
->Select
.HitMaxZ
= -1.0;
235 _mesa_InitNames( void )
237 GET_CURRENT_CONTEXT(ctx
);
238 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glInitNames");
239 /* Record the hit before the HitFlag is wiped out again. */
240 if (ctx
->RenderMode
== GL_SELECT
) {
241 if (ctx
->Select
.HitFlag
) {
242 write_hit_record( ctx
);
245 ctx
->Select
.NameStackDepth
= 0;
246 ctx
->Select
.HitFlag
= GL_FALSE
;
247 ctx
->Select
.HitMinZ
= 1.0;
248 ctx
->Select
.HitMaxZ
= 0.0;
249 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
255 _mesa_LoadName( GLuint name
)
257 GET_CURRENT_CONTEXT(ctx
);
258 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glLoadName");
259 if (ctx
->RenderMode
!= GL_SELECT
) {
262 if (ctx
->Select
.NameStackDepth
== 0) {
263 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
266 if (ctx
->Select
.HitFlag
) {
267 write_hit_record( ctx
);
269 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
270 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
273 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
275 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
280 _mesa_PushName( GLuint name
)
282 GET_CURRENT_CONTEXT(ctx
);
283 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPushName");
284 if (ctx
->RenderMode
!= GL_SELECT
) {
287 if (ctx
->Select
.HitFlag
) {
288 write_hit_record( ctx
);
290 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
291 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
294 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
296 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
302 _mesa_PopName( void )
304 GET_CURRENT_CONTEXT(ctx
);
305 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPopName");
306 if (ctx
->RenderMode
!= GL_SELECT
) {
309 if (ctx
->Select
.HitFlag
) {
310 write_hit_record( ctx
);
312 if (ctx
->Select
.NameStackDepth
> 0) {
313 ctx
->Select
.NameStackDepth
--;
316 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
318 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
323 /**********************************************************************/
325 /**********************************************************************/
330 * NOTE: this function can't be put in a display list.
333 _mesa_RenderMode( GLenum mode
)
335 GET_CURRENT_CONTEXT(ctx
);
338 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glRenderMode", 0);
340 if (MESA_VERBOSE
& VERBOSE_API
)
341 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
343 ctx
->_TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
345 switch (ctx
->RenderMode
) {
350 if (ctx
->Select
.HitFlag
) {
351 write_hit_record( ctx
);
353 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
356 _mesa_warning(ctx
, "Feedback buffer overflow");
361 result
= ctx
->Select
.Hits
;
363 ctx
->Select
.BufferCount
= 0;
364 ctx
->Select
.Hits
= 0;
365 ctx
->Select
.NameStackDepth
= 0;
366 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
369 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
374 result
= ctx
->Feedback
.Count
;
376 ctx
->Feedback
.Count
= 0;
377 ctx
->NewState
|= _NEW_FEEDBACK_SELECT
;
380 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
388 ctx
->_TriangleCaps
|= DD_SELECT
;
389 if (ctx
->Select
.BufferSize
==0) {
390 /* haven't called glSelectBuffer yet */
391 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
395 ctx
->_TriangleCaps
|= DD_FEEDBACK
;
396 if (ctx
->Feedback
.BufferSize
==0) {
397 /* haven't called glFeedbackBuffer yet */
398 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
402 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
406 ctx
->RenderMode
= mode
;
407 ctx
->NewState
|= _NEW_RENDERMODE
;