1 /* $Id: feedback.c,v 1.20 2001/01/14 06:14:21 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" );
62 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
66 gl_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
67 ctx
->Feedback
.BufferSize
= 0;
73 ctx
->Feedback
._Mask
= 0;
76 ctx
->Feedback
._Mask
= FB_3D
;
79 ctx
->Feedback
._Mask
= (FB_3D
|
80 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
));
82 case GL_3D_COLOR_TEXTURE
:
83 ctx
->Feedback
._Mask
= (FB_3D
|
84 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
) |
87 case GL_4D_COLOR_TEXTURE
:
88 ctx
->Feedback
._Mask
= (FB_3D
| FB_4D
|
89 (ctx
->Visual
.RGBAflag
? FB_COLOR
: FB_INDEX
) |
93 gl_error( ctx
, GL_INVALID_ENUM
, "glFeedbackBuffer" );
97 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* Always flush */
98 ctx
->Feedback
.Type
= type
;
99 ctx
->Feedback
.BufferSize
= size
;
100 ctx
->Feedback
.Buffer
= buffer
;
101 ctx
->Feedback
.Count
= 0; /* Becaues of this. */
106 _mesa_PassThrough( GLfloat token
)
108 GET_CURRENT_CONTEXT(ctx
);
109 ASSERT_OUTSIDE_BEGIN_END(ctx
);
111 if (ctx
->RenderMode
==GL_FEEDBACK
) {
112 FLUSH_VERTICES(ctx
, 0);
113 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
114 FEEDBACK_TOKEN( ctx
, token
);
121 * Put a vertex into the feedback buffer.
123 void gl_feedback_vertex( GLcontext
*ctx
,
124 const GLfloat win
[4],
125 const GLfloat color
[4],
127 const GLfloat texcoord
[4] )
129 FEEDBACK_TOKEN( ctx
, win
[0] );
130 FEEDBACK_TOKEN( ctx
, win
[1] );
131 if (ctx
->Feedback
._Mask
& FB_3D
) {
132 FEEDBACK_TOKEN( ctx
, win
[2] );
134 if (ctx
->Feedback
._Mask
& FB_4D
) {
135 FEEDBACK_TOKEN( ctx
, win
[3] );
137 if (ctx
->Feedback
._Mask
& FB_INDEX
) {
138 FEEDBACK_TOKEN( ctx
, (GLfloat
) index
);
140 if (ctx
->Feedback
._Mask
& FB_COLOR
) {
141 FEEDBACK_TOKEN( ctx
, color
[0] );
142 FEEDBACK_TOKEN( ctx
, color
[1] );
143 FEEDBACK_TOKEN( ctx
, color
[2] );
144 FEEDBACK_TOKEN( ctx
, color
[3] );
146 if (ctx
->Feedback
._Mask
& FB_TEXTURE
) {
147 FEEDBACK_TOKEN( ctx
, texcoord
[0] );
148 FEEDBACK_TOKEN( ctx
, texcoord
[1] );
149 FEEDBACK_TOKEN( ctx
, texcoord
[2] );
150 FEEDBACK_TOKEN( ctx
, texcoord
[3] );
155 /**********************************************************************/
157 /**********************************************************************/
161 * NOTE: this function can't be put in a display list.
164 _mesa_SelectBuffer( GLsizei size
, GLuint
*buffer
)
166 GET_CURRENT_CONTEXT(ctx
);
167 ASSERT_OUTSIDE_BEGIN_END(ctx
);
169 if (ctx
->RenderMode
==GL_SELECT
) {
170 gl_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
171 return; /* KW: added return */
174 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
); /* why bother? */
175 ctx
->Select
.Buffer
= buffer
;
176 ctx
->Select
.BufferSize
= size
;
177 ctx
->Select
.BufferCount
= 0;
178 ctx
->Select
.HitFlag
= GL_FALSE
;
179 ctx
->Select
.HitMinZ
= 1.0;
180 ctx
->Select
.HitMaxZ
= 0.0;
184 #define WRITE_RECORD( CTX, V ) \
185 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
186 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
188 CTX->Select.BufferCount++;
192 void gl_update_hitflag( GLcontext
*ctx
, GLfloat z
)
194 ctx
->Select
.HitFlag
= GL_TRUE
;
195 if (z
< ctx
->Select
.HitMinZ
) {
196 ctx
->Select
.HitMinZ
= z
;
198 if (z
> ctx
->Select
.HitMaxZ
) {
199 ctx
->Select
.HitMaxZ
= z
;
204 static void write_hit_record( GLcontext
*ctx
)
207 GLuint zmin
, zmax
, zscale
= (~0u);
209 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
210 /* 2^32-1 and round to nearest unsigned integer. */
212 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
213 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
214 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
216 WRITE_RECORD( ctx
, ctx
->Select
.NameStackDepth
);
217 WRITE_RECORD( ctx
, zmin
);
218 WRITE_RECORD( ctx
, zmax
);
219 for (i
= 0; i
< ctx
->Select
.NameStackDepth
; i
++) {
220 WRITE_RECORD( ctx
, ctx
->Select
.NameStack
[i
] );
224 ctx
->Select
.HitFlag
= GL_FALSE
;
225 ctx
->Select
.HitMinZ
= 1.0;
226 ctx
->Select
.HitMaxZ
= -1.0;
232 _mesa_InitNames( void )
234 GET_CURRENT_CONTEXT(ctx
);
235 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
237 /* Record the hit before the HitFlag is wiped out again. */
238 if (ctx
->RenderMode
== GL_SELECT
) {
239 if (ctx
->Select
.HitFlag
) {
240 write_hit_record( ctx
);
243 ctx
->Select
.NameStackDepth
= 0;
244 ctx
->Select
.HitFlag
= GL_FALSE
;
245 ctx
->Select
.HitMinZ
= 1.0;
246 ctx
->Select
.HitMaxZ
= 0.0;
247 ctx
->NewState
|= _NEW_RENDERMODE
;
253 _mesa_LoadName( GLuint name
)
255 GET_CURRENT_CONTEXT(ctx
);
256 ASSERT_OUTSIDE_BEGIN_END(ctx
);
258 if (ctx
->RenderMode
!= GL_SELECT
) {
261 if (ctx
->Select
.NameStackDepth
== 0) {
262 gl_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
266 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
268 if (ctx
->Select
.HitFlag
) {
269 write_hit_record( ctx
);
271 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
272 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
275 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
281 _mesa_PushName( GLuint name
)
283 GET_CURRENT_CONTEXT(ctx
);
284 ASSERT_OUTSIDE_BEGIN_END(ctx
);
286 if (ctx
->RenderMode
!= GL_SELECT
) {
290 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
291 if (ctx
->Select
.HitFlag
) {
292 write_hit_record( ctx
);
294 if (ctx
->Select
.NameStackDepth
>= MAX_NAME_STACK_DEPTH
) {
295 gl_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
298 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
304 _mesa_PopName( void )
306 GET_CURRENT_CONTEXT(ctx
);
307 ASSERT_OUTSIDE_BEGIN_END(ctx
);
309 if (ctx
->RenderMode
!= GL_SELECT
) {
313 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
314 if (ctx
->Select
.HitFlag
) {
315 write_hit_record( ctx
);
317 if (ctx
->Select
.NameStackDepth
== 0) {
318 gl_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
321 ctx
->Select
.NameStackDepth
--;
326 /**********************************************************************/
328 /**********************************************************************/
333 * NOTE: this function can't be put in a display list.
336 _mesa_RenderMode( GLenum mode
)
338 GET_CURRENT_CONTEXT(ctx
);
340 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
342 if (MESA_VERBOSE
& VERBOSE_API
)
343 fprintf(stderr
, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode
));
345 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
346 ctx
->_TriangleCaps
&= ~(DD_FEEDBACK
|DD_SELECT
);
348 switch (ctx
->RenderMode
) {
353 if (ctx
->Select
.HitFlag
) {
354 write_hit_record( ctx
);
356 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
359 _mesa_warning(ctx
, "Feedback buffer overflow");
364 result
= ctx
->Select
.Hits
;
366 ctx
->Select
.BufferCount
= 0;
367 ctx
->Select
.Hits
= 0;
368 ctx
->Select
.NameStackDepth
= 0;
371 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
376 result
= ctx
->Feedback
.Count
;
378 ctx
->Feedback
.Count
= 0;
381 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
389 ctx
->_TriangleCaps
|= DD_SELECT
;
390 if (ctx
->Select
.BufferSize
==0) {
391 /* haven't called glSelectBuffer yet */
392 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
396 ctx
->_TriangleCaps
|= DD_FEEDBACK
;
397 if (ctx
->Feedback
.BufferSize
==0) {
398 /* haven't called glFeedbackBuffer yet */
399 gl_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
403 gl_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
407 ctx
->RenderMode
= mode
;
408 if (ctx
->Driver
.RenderMode
)
409 ctx
->Driver
.RenderMode( ctx
, mode
);