1 /* $Id: feedback.c,v 1.28 2003/03/01 01:50:20 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2003 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.
42 #define FB_TEXTURE 0X10
47 _mesa_FeedbackBuffer( GLsizei size
, GLenum type
, GLfloat
*buffer
)
49 GET_CURRENT_CONTEXT(ctx
);
50 ASSERT_OUTSIDE_BEGIN_END(ctx
);
52 if (ctx
->RenderMode
==GL_FEEDBACK
) {
53 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
57 _mesa_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
61 _mesa_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
62 ctx
->Feedback
.BufferSize
= 0;
68 ctx
->Feedback
._Mask
= 0;
71 ctx
->Feedback
._Mask
= FB_3D
;
74 ctx
->Feedback
._Mask
= (FB_3D
|
75 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
));
77 case GL_3D_COLOR_TEXTURE
:
78 ctx
->Feedback
._Mask
= (FB_3D
|
79 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
) |
82 case GL_4D_COLOR_TEXTURE
:
83 ctx
->Feedback
._Mask
= (FB_3D
| FB_4D
|
84 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
) |
88 _mesa_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
92 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* Always flush */
93 ctx
->Feedback
.Type
= type
;
94 ctx
->Feedback
.BufferSize
= size
;
95 ctx
->Feedback
.Buffer
= buffer
;
96 ctx
->Feedback
.Count
= 0; /* Becaues of this. */
101 _mesa_PassThrough( GLfloat token
)
103 GET_CURRENT_CONTEXT(ctx
);
104 ASSERT_OUTSIDE_BEGIN_END(ctx
);
106 if (ctx
->RenderMode
==GL_FEEDBACK
) {
107 FLUSH_VERTICES(ctx
, 0);
108 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
109 FEEDBACK_TOKEN( ctx
, token
);
116 * Put a vertex into the feedback buffer.
118 void _mesa_feedback_vertex( GLcontext
*ctx
,
119 const GLfloat win
[4],
120 const GLfloat color
[4],
122 const GLfloat texcoord
[4] )
124 FEEDBACK_TOKEN( ctx
, win
[0] );
125 FEEDBACK_TOKEN( ctx
, win
[1] );
126 if (ctx
->Feedback
._Mask
& FB_3D
) {
127 FEEDBACK_TOKEN( ctx
, win
[2] );
129 if (ctx
->Feedback
._Mask
& FB_4D
) {
130 FEEDBACK_TOKEN( ctx
, win
[3] );
132 if (ctx
->Feedback
._Mask
& FB_INDEX
) {
133 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
135 if (ctx
->Feedback
._Mask
& FB_COLOR
) {
136 FEEDBACK_TOKEN( ctx
, color
[0] );
137 FEEDBACK_TOKEN( ctx
, color
[1] );
138 FEEDBACK_TOKEN( ctx
, color
[2] );
139 FEEDBACK_TOKEN( ctx
, color
[3] );
141 if (ctx
->Feedback
._Mask
& FB_TEXTURE
) {
142 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
143 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
144 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
145 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
150 /**********************************************************************/
152 /**********************************************************************/
156 * NOTE: this function can't be put in a display list.
159 _mesa_SelectBuffer( GLsizei size
, GLuint
*buffer
)
161 GET_CURRENT_CONTEXT(ctx
);
162 ASSERT_OUTSIDE_BEGIN_END(ctx
);
164 if (ctx
->RenderMode
==GL_SELECT
) {
165 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
166 return; /* KW: added return */
169 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* why bother? */
170 ctx
->Select
.Buffer
= buffer
;
171 ctx
->Select
.BufferSize
= size
;
172 ctx
->Select
.BufferCount
= 0;
173 ctx
->Select
.HitFlag
= GL_FALSE
;
174 ctx
->Select
.HitMinZ
= 1.0;
175 ctx
->Select
.HitMaxZ
= 0.0;
179 #define WRITE_RECORD( CTX, V ) \
180 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
181 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
183 CTX->Select.BufferCount++;
187 void _mesa_update_hitflag( GLcontext
*ctx
, GLfloat z
)
189 ctx
->Select
.HitFlag
= GL_TRUE
;
190 if (z
< ctx
->Select
.HitMinZ
) {
191 ctx
->Select
.HitMinZ
= z
;
193 if (z
> ctx
->Select
.HitMaxZ
) {
194 ctx
->Select
.HitMaxZ
= z
;
199 static void write_hit_record( GLcontext
*ctx
)
202 GLuint zmin
, zmax
, zscale
= (~0u);
204 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
205 /* 2^32-1 and round to nearest unsigned integer. */
207 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
208 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
209 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
211 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
212 WRITE_RECORD( ctx
, zmin
);
213 WRITE_RECORD( ctx
, zmax
);
214 for (i
= 0; i
< ctx
->Select
.NameStackDepth
; i
++) {
215 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
219 ctx
->Select
.HitFlag
= GL_FALSE
;
220 ctx
->Select
.HitMinZ
= 1.0;
221 ctx
->Select
.HitMaxZ
= -1.0;
227 _mesa_InitNames( void )
229 GET_CURRENT_CONTEXT(ctx
);
230 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
232 /* Record the hit before the HitFlag is wiped out again. */
233 if (ctx
->RenderMode
== GL_SELECT
) {
234 if (ctx
->Select
.HitFlag
) {
235 write_hit_record( ctx
);
238 ctx
->Select
.NameStackDepth
= 0;
239 ctx
->Select
.HitFlag
= GL_FALSE
;
240 ctx
->Select
.HitMinZ
= 1.0;
241 ctx
->Select
.HitMaxZ
= 0.0;
242 ctx
->NewState
|= _NEW_RENDERMODE
;
248 _mesa_LoadName( GLuint name
)
250 GET_CURRENT_CONTEXT(ctx
);
251 ASSERT_OUTSIDE_BEGIN_END(ctx
);
253 if (ctx
->RenderMode
!= GL_SELECT
) {
256 if (ctx
->Select
.NameStackDepth
== 0) {
257 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
261 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
263 if (ctx
->Select
.HitFlag
) {
264 write_hit_record( ctx
);
266 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
267 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
270 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
276 _mesa_PushName( GLuint name
)
278 GET_CURRENT_CONTEXT(ctx
);
279 ASSERT_OUTSIDE_BEGIN_END(ctx
);
281 if (ctx
->RenderMode
!= GL_SELECT
) {
285 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
286 if (ctx
->Select
.HitFlag
) {
287 write_hit_record( ctx
);
289 if (ctx
->Select
.NameStackDepth
>= MAX_NAME_STACK_DEPTH
) {
290 _mesa_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
293 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
299 _mesa_PopName( void )
301 GET_CURRENT_CONTEXT(ctx
);
302 ASSERT_OUTSIDE_BEGIN_END(ctx
);
304 if (ctx
->RenderMode
!= GL_SELECT
) {
308 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
309 if (ctx
->Select
.HitFlag
) {
310 write_hit_record( ctx
);
312 if (ctx
->Select
.NameStackDepth
== 0) {
313 _mesa_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
316 ctx
->Select
.NameStackDepth
--;
321 /**********************************************************************/
323 /**********************************************************************/
328 * NOTE: this function can't be put in a display list.
331 _mesa_RenderMode( GLenum mode
)
333 GET_CURRENT_CONTEXT(ctx
);
335 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
337 if (MESA_VERBOSE
& VERBOSE_API
)
338 _mesa_debug(ctx
, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode
));
340 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
342 switch (ctx
->RenderMode
) {
347 if (ctx
->Select
.HitFlag
) {
348 write_hit_record( ctx
);
350 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
353 _mesa_warning(ctx
, "Feedback buffer overflow");
358 result
= ctx
->Select
.Hits
;
360 ctx
->Select
.BufferCount
= 0;
361 ctx
->Select
.Hits
= 0;
362 ctx
->Select
.NameStackDepth
= 0;
365 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
370 result
= ctx
->Feedback
.Count
;
372 ctx
->Feedback
.Count
= 0;
375 _mesa_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
383 if (ctx
->Select
.BufferSize
==0) {
384 /* haven't called glSelectBuffer yet */
385 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
389 if (ctx
->Feedback
.BufferSize
==0) {
390 /* haven't called glFeedbackBuffer yet */
391 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
395 _mesa_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
399 ctx
->RenderMode
= mode
;
400 if (ctx
->Driver
.RenderMode
)
401 ctx
->Driver
.RenderMode( ctx
, mode
);