1 /* $Id: feedback.c,v 1.18 2000/12/26 05:09:28 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(ctx
);
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; /* XXX -- Sould this be here??? */
74 ctx
->Feedback
._Mask
= 0;
77 ctx
->Feedback
._Mask
= FB_3D
;
80 ctx
->Feedback
._Mask
= (FB_3D
|
81 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
));
83 case GL_3D_COLOR_TEXTURE
:
84 ctx
->Feedback
._Mask
= (FB_3D
|
85 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
) |
88 case GL_4D_COLOR_TEXTURE
:
89 ctx
->Feedback
._Mask
= (FB_3D
| FB_4D
|
90 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
) |
94 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
98 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* Always flush */
99 ctx
->Feedback
.Type
= type
;
100 ctx
->Feedback
.BufferSize
= size
;
101 ctx
->Feedback
.Buffer
= buffer
;
102 ctx
->Feedback
.Count
= 0; /* Becaues of this. */
108 _mesa_PassThrough( GLfloat token
)
110 GET_CURRENT_CONTEXT(ctx
);
111 ASSERT_OUTSIDE_BEGIN_END(ctx
);
113 if (ctx
->RenderMode
==GL_FEEDBACK
) {
114 FLUSH_VERTICES(ctx
, 0);
115 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
116 FEEDBACK_TOKEN( ctx
, token
);
123 * Put a vertex into the feedback buffer.
125 void gl_feedback_vertex( GLcontext
*ctx
,
126 const GLfloat win
[4],
127 const GLfloat color
[4],
129 const GLfloat texcoord
[4] )
131 FEEDBACK_TOKEN( ctx
, win
[0] );
132 FEEDBACK_TOKEN( ctx
, win
[1] );
133 if (ctx
->Feedback
._Mask
& FB_3D
) {
134 FEEDBACK_TOKEN( ctx
, win
[2] );
136 if (ctx
->Feedback
._Mask
& FB_4D
) {
137 FEEDBACK_TOKEN( ctx
, win
[3] );
139 if (ctx
->Feedback
._Mask
& FB_INDEX
) {
140 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
142 if (ctx
->Feedback
._Mask
& FB_COLOR
) {
143 FEEDBACK_TOKEN( ctx
, color
[0] );
144 FEEDBACK_TOKEN( ctx
, color
[1] );
145 FEEDBACK_TOKEN( ctx
, color
[2] );
146 FEEDBACK_TOKEN( ctx
, color
[3] );
148 if (ctx
->Feedback
._Mask
& FB_TEXTURE
) {
149 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
150 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
151 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
152 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
156 /**********************************************************************/
158 /**********************************************************************/
162 * NOTE: this function can't be put in a display list.
165 _mesa_SelectBuffer( GLsizei size
, GLuint
*buffer
)
167 GET_CURRENT_CONTEXT(ctx
);
168 ASSERT_OUTSIDE_BEGIN_END(ctx
);
170 if (ctx
->RenderMode
==GL_SELECT
) {
171 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
172 return; /* KW: added return */
175 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* why bother? */
176 ctx
->Select
.Buffer
= buffer
;
177 ctx
->Select
.BufferSize
= size
;
178 ctx
->Select
.BufferCount
= 0;
179 ctx
->Select
.HitFlag
= GL_FALSE
;
180 ctx
->Select
.HitMinZ
= 1.0;
181 ctx
->Select
.HitMaxZ
= 0.0;
185 #define WRITE_RECORD( CTX, V ) \
186 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
187 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
189 CTX->Select.BufferCount++;
193 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
195 ctx
->Select
.HitFlag
= GL_TRUE
;
196 if (z
< ctx
->Select
.HitMinZ
) {
197 ctx
->Select
.HitMinZ
= z
;
199 if (z
> ctx
->Select
.HitMaxZ
) {
200 ctx
->Select
.HitMaxZ
= z
;
205 static void write_hit_record( GLcontext
*ctx
)
208 GLuint zmin
, zmax
, zscale
= (~0u);
210 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
211 /* 2^32-1 and round to nearest unsigned integer. */
213 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
214 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
215 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
217 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
218 WRITE_RECORD( ctx
, zmin
);
219 WRITE_RECORD( ctx
, zmax
);
220 for (i
= 0; i
< ctx
->Select
.NameStackDepth
; i
++) {
221 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
225 ctx
->Select
.HitFlag
= GL_FALSE
;
226 ctx
->Select
.HitMinZ
= 1.0;
227 ctx
->Select
.HitMaxZ
= -1.0;
233 _mesa_InitNames( void )
235 GET_CURRENT_CONTEXT(ctx
);
236 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
238 /* Record the hit before the HitFlag is wiped out again. */
239 if (ctx
->RenderMode
== GL_SELECT
) {
240 if (ctx
->Select
.HitFlag
) {
241 write_hit_record( ctx
);
244 ctx
->Select
.NameStackDepth
= 0;
245 ctx
->Select
.HitFlag
= GL_FALSE
;
246 ctx
->Select
.HitMinZ
= 1.0;
247 ctx
->Select
.HitMaxZ
= 0.0;
248 ctx
->NewState
|= _NEW_RENDERMODE
;
254 _mesa_LoadName( GLuint name
)
256 GET_CURRENT_CONTEXT(ctx
);
257 ASSERT_OUTSIDE_BEGIN_END(ctx
);
259 if (ctx
->RenderMode
!= GL_SELECT
) {
262 if (ctx
->Select
.NameStackDepth
== 0) {
263 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
267 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
269 if (ctx
->Select
.HitFlag
) {
270 write_hit_record( ctx
);
272 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
273 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
276 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
282 _mesa_PushName( GLuint name
)
284 GET_CURRENT_CONTEXT(ctx
);
285 ASSERT_OUTSIDE_BEGIN_END(ctx
);
287 if (ctx
->RenderMode
!= GL_SELECT
) {
291 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
292 if (ctx
->Select
.HitFlag
) {
293 write_hit_record( ctx
);
295 if (ctx
->Select
.NameStackDepth
>= MAX_NAME_STACK_DEPTH
) {
296 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
299 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
305 _mesa_PopName( void )
307 GET_CURRENT_CONTEXT(ctx
);
308 ASSERT_OUTSIDE_BEGIN_END(ctx
);
310 if (ctx
->RenderMode
!= GL_SELECT
) {
314 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
315 if (ctx
->Select
.HitFlag
) {
316 write_hit_record( ctx
);
318 if (ctx
->Select
.NameStackDepth
== 0) {
319 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
322 ctx
->Select
.NameStackDepth
--;
327 /**********************************************************************/
329 /**********************************************************************/
334 * NOTE: this function can't be put in a display list.
337 _mesa_RenderMode( GLenum mode
)
339 GET_CURRENT_CONTEXT(ctx
);
341 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
343 if (MESA_VERBOSE
& VERBOSE_API
)
344 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
346 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
347 ctx
->_TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
349 switch (ctx
->RenderMode
) {
354 if (ctx
->Select
.HitFlag
) {
355 write_hit_record( ctx
);
357 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
360 _mesa_warning(ctx
, "Feedback buffer overflow");
365 result
= ctx
->Select
.Hits
;
367 ctx
->Select
.BufferCount
= 0;
368 ctx
->Select
.Hits
= 0;
369 ctx
->Select
.NameStackDepth
= 0;
372 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
377 result
= ctx
->Feedback
.Count
;
379 ctx
->Feedback
.Count
= 0;
382 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
390 ctx
->_TriangleCaps
|= DD_SELECT
;
391 if (ctx
->Select
.BufferSize
==0) {
392 /* haven't called glSelectBuffer yet */
393 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
397 ctx
->_TriangleCaps
|= DD_FEEDBACK
;
398 if (ctx
->Feedback
.BufferSize
==0) {
399 /* haven't called glFeedbackBuffer yet */
400 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
404 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
408 ctx
->RenderMode
= mode
;