beab535b15fd24d010b40c87ee8097b997d91de1
2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Selection and feedback modes functions.
48 #define FB_TEXTURE 0X10
53 _mesa_FeedbackBuffer( GLsizei size
, GLenum type
, GLfloat
*buffer
)
55 GET_CURRENT_CONTEXT(ctx
);
56 ASSERT_OUTSIDE_BEGIN_END(ctx
);
58 if (ctx
->RenderMode
==GL_FEEDBACK
) {
59 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glFeedbackBuffer" );
63 _mesa_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(size<0)" );
67 _mesa_error( ctx
, GL_INVALID_VALUE
, "glFeedbackBuffer(buffer==NULL)" );
68 ctx
->Feedback
.BufferSize
= 0;
74 ctx
->Feedback
._Mask
= 0;
77 ctx
->Feedback
._Mask
= FB_3D
;
80 ctx
->Feedback
._Mask
= (FB_3D
|
81 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
));
83 case GL_3D_COLOR_TEXTURE
:
84 ctx
->Feedback
._Mask
= (FB_3D
|
85 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
) |
88 case GL_4D_COLOR_TEXTURE
:
89 ctx
->Feedback
._Mask
= (FB_3D
| FB_4D
|
90 (ctx
->Visual
.rgbMode
? FB_COLOR
: FB_INDEX
) |
94 _mesa_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. */
107 _mesa_PassThrough( GLfloat token
)
109 GET_CURRENT_CONTEXT(ctx
);
110 ASSERT_OUTSIDE_BEGIN_END(ctx
);
112 if (ctx
->RenderMode
==GL_FEEDBACK
) {
113 FLUSH_VERTICES(ctx
, 0);
114 _mesa_feedback_token( ctx
, (GLfloat
) (GLint
) GL_PASS_THROUGH_TOKEN
);
115 _mesa_feedback_token( ctx
, token
);
121 * Put a vertex into the feedback buffer.
124 _mesa_feedback_vertex(GLcontext
*ctx
,
125 const GLfloat win
[4],
126 const GLfloat color
[4],
128 const GLfloat texcoord
[4])
130 _mesa_feedback_token( ctx
, win
[0] );
131 _mesa_feedback_token( ctx
, win
[1] );
132 if (ctx
->Feedback
._Mask
& FB_3D
) {
133 _mesa_feedback_token( ctx
, win
[2] );
135 if (ctx
->Feedback
._Mask
& FB_4D
) {
136 _mesa_feedback_token( ctx
, win
[3] );
138 if (ctx
->Feedback
._Mask
& FB_INDEX
) {
139 _mesa_feedback_token( ctx
, (GLfloat
) index
);
141 if (ctx
->Feedback
._Mask
& FB_COLOR
) {
142 _mesa_feedback_token( ctx
, color
[0] );
143 _mesa_feedback_token( ctx
, color
[1] );
144 _mesa_feedback_token( ctx
, color
[2] );
145 _mesa_feedback_token( ctx
, color
[3] );
147 if (ctx
->Feedback
._Mask
& FB_TEXTURE
) {
148 _mesa_feedback_token( ctx
, texcoord
[0] );
149 _mesa_feedback_token( ctx
, texcoord
[1] );
150 _mesa_feedback_token( ctx
, texcoord
[2] );
151 _mesa_feedback_token( ctx
, texcoord
[3] );
156 #endif /* _HAVE_FULL_GL */
159 /**********************************************************************/
160 /** \name Selection */
164 * Establish a buffer for selection mode values.
166 * \param size buffer size.
167 * \param buffer buffer.
169 * \sa glSelectBuffer().
171 * \note this function can't be put in a display list.
173 * Verifies we're not in selection mode, flushes the vertices and initialize
174 * the fields in __GLcontextRec::Select with the given buffer.
177 _mesa_SelectBuffer( GLsizei size
, GLuint
*buffer
)
179 GET_CURRENT_CONTEXT(ctx
);
180 ASSERT_OUTSIDE_BEGIN_END(ctx
);
182 if (ctx
->RenderMode
==GL_SELECT
) {
183 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glSelectBuffer" );
184 return; /* KW: added return */
187 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
188 ctx
->Select
.Buffer
= buffer
;
189 ctx
->Select
.BufferSize
= size
;
190 ctx
->Select
.BufferCount
= 0;
191 ctx
->Select
.HitFlag
= GL_FALSE
;
192 ctx
->Select
.HitMinZ
= 1.0;
193 ctx
->Select
.HitMaxZ
= 0.0;
198 * Write a value of a record into the selection buffer.
200 * \param CTX GL context.
203 * Verifies there is free space in the buffer to write the value and
204 * increments the pointer.
207 write_record(GLcontext
*ctx
, GLuint value
)
209 if (ctx
->Select
.BufferCount
< ctx
->Select
.BufferSize
) {
210 ctx
->Select
.Buffer
[ctx
->Select
.BufferCount
] = value
;
212 ctx
->Select
.BufferCount
++;
217 * Update the hit flag and the maximum and minimum depth values.
219 * \param ctx GL context.
222 * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and
223 * gl_selection::HitMaxZ.
226 _mesa_update_hitflag(GLcontext
*ctx
, GLfloat z
)
228 ctx
->Select
.HitFlag
= GL_TRUE
;
229 if (z
< ctx
->Select
.HitMinZ
) {
230 ctx
->Select
.HitMinZ
= z
;
232 if (z
> ctx
->Select
.HitMaxZ
) {
233 ctx
->Select
.HitMaxZ
= z
;
239 * Write the hit record.
241 * \param ctx GL context.
243 * Write the hit record, i.e., the number of names in the stack, the minimum and
244 * maximum depth values and the number of names in the name stack at the time
245 * of the event. Resets the hit flag.
250 write_hit_record(GLcontext
*ctx
)
253 GLuint zmin
, zmax
, zscale
= (~0u);
255 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
256 /* 2^32-1 and round to nearest unsigned integer. */
258 assert( ctx
!= NULL
); /* this line magically fixes a SunOS 5.x/gcc bug */
259 zmin
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMinZ
);
260 zmax
= (GLuint
) ((GLfloat
) zscale
* ctx
->Select
.HitMaxZ
);
262 write_record( ctx
, ctx
->Select
.NameStackDepth
);
263 write_record( ctx
, zmin
);
264 write_record( ctx
, zmax
);
265 for (i
= 0; i
< ctx
->Select
.NameStackDepth
; i
++) {
266 write_record( ctx
, ctx
->Select
.NameStack
[i
] );
270 ctx
->Select
.HitFlag
= GL_FALSE
;
271 ctx
->Select
.HitMinZ
= 1.0;
272 ctx
->Select
.HitMaxZ
= -1.0;
277 * Initialize the name stack.
279 * Verifies we are in select mode and resets the name stack depth and resets
280 * the hit record data in gl_selection. Marks new render mode in
281 * __GLcontextRec::NewState.
284 _mesa_InitNames( void )
286 GET_CURRENT_CONTEXT(ctx
);
287 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
289 /* Record the hit before the HitFlag is wiped out again. */
290 if (ctx
->RenderMode
== GL_SELECT
) {
291 if (ctx
->Select
.HitFlag
) {
292 write_hit_record( ctx
);
295 ctx
->Select
.NameStackDepth
= 0;
296 ctx
->Select
.HitFlag
= GL_FALSE
;
297 ctx
->Select
.HitMinZ
= 1.0;
298 ctx
->Select
.HitMaxZ
= 0.0;
299 ctx
->NewState
|= _NEW_RENDERMODE
;
304 * Load the top-most name of the name stack.
308 * Verifies we are in selection mode and that the name stack is not empty.
309 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
310 * and replace the top-most name in the stack.
312 * sa __GLcontextRec::Select.
315 _mesa_LoadName( GLuint name
)
317 GET_CURRENT_CONTEXT(ctx
);
318 ASSERT_OUTSIDE_BEGIN_END(ctx
);
320 if (ctx
->RenderMode
!= GL_SELECT
) {
323 if (ctx
->Select
.NameStackDepth
== 0) {
324 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glLoadName" );
328 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
330 if (ctx
->Select
.HitFlag
) {
331 write_hit_record( ctx
);
333 if (ctx
->Select
.NameStackDepth
< MAX_NAME_STACK_DEPTH
) {
334 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
-1] = name
;
337 ctx
->Select
.NameStack
[MAX_NAME_STACK_DEPTH
-1] = name
;
343 * Push a name into the name stack.
347 * Verifies we are in selection mode and that the name stack is not full.
348 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
349 * and adds the name to the top of the name stack.
351 * sa __GLcontextRec::Select.
354 _mesa_PushName( GLuint name
)
356 GET_CURRENT_CONTEXT(ctx
);
357 ASSERT_OUTSIDE_BEGIN_END(ctx
);
359 if (ctx
->RenderMode
!= GL_SELECT
) {
363 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
364 if (ctx
->Select
.HitFlag
) {
365 write_hit_record( ctx
);
367 if (ctx
->Select
.NameStackDepth
>= MAX_NAME_STACK_DEPTH
) {
368 _mesa_error( ctx
, GL_STACK_OVERFLOW
, "glPushName" );
371 ctx
->Select
.NameStack
[ctx
->Select
.NameStackDepth
++] = name
;
376 * Pop a name into the name stack.
378 * Verifies we are in selection mode and that the name stack is not empty.
379 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
380 * and removes top-most name in the name stack.
382 * sa __GLcontextRec::Select.
385 _mesa_PopName( void )
387 GET_CURRENT_CONTEXT(ctx
);
388 ASSERT_OUTSIDE_BEGIN_END(ctx
);
390 if (ctx
->RenderMode
!= GL_SELECT
) {
394 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
395 if (ctx
->Select
.HitFlag
) {
396 write_hit_record( ctx
);
398 if (ctx
->Select
.NameStackDepth
== 0) {
399 _mesa_error( ctx
, GL_STACK_UNDERFLOW
, "glPopName" );
402 ctx
->Select
.NameStackDepth
--;
408 /**********************************************************************/
409 /** \name Render Mode */
413 * Set rasterization mode.
415 * \param mode rasterization mode.
417 * \note this function can't be put in a display list.
419 * \sa glRenderMode().
421 * Flushes the vertices and do the necessary cleanup according to the previous
422 * rasterization mode, such as writing the hit record or resent the select
423 * buffer index when exiting the select mode. Updates
424 * __GLcontextRec::RenderMode and notifies the driver via the
425 * dd_function_table::RenderMode callback.
428 _mesa_RenderMode( GLenum mode
)
430 GET_CURRENT_CONTEXT(ctx
);
432 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
434 if (MESA_VERBOSE
& VERBOSE_API
)
435 _mesa_debug(ctx
, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode
));
437 FLUSH_VERTICES(ctx
, _NEW_RENDERMODE
);
439 switch (ctx
->RenderMode
) {
444 if (ctx
->Select
.HitFlag
) {
445 write_hit_record( ctx
);
447 if (ctx
->Select
.BufferCount
> ctx
->Select
.BufferSize
) {
450 _mesa_warning(ctx
, "Feedback buffer overflow");
455 result
= ctx
->Select
.Hits
;
457 ctx
->Select
.BufferCount
= 0;
458 ctx
->Select
.Hits
= 0;
459 ctx
->Select
.NameStackDepth
= 0;
463 if (ctx
->Feedback
.Count
> ctx
->Feedback
.BufferSize
) {
468 result
= ctx
->Feedback
.Count
;
470 ctx
->Feedback
.Count
= 0;
474 _mesa_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
482 if (ctx
->Select
.BufferSize
==0) {
483 /* haven't called glSelectBuffer yet */
484 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
489 if (ctx
->Feedback
.BufferSize
==0) {
490 /* haven't called glFeedbackBuffer yet */
491 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glRenderMode" );
496 _mesa_error( ctx
, GL_INVALID_ENUM
, "glRenderMode" );
500 ctx
->RenderMode
= mode
;
501 if (ctx
->Driver
.RenderMode
)
502 ctx
->Driver
.RenderMode( ctx
, mode
);
510 /**********************************************************************/
511 /** \name Initialization */
515 * Initialize context feedback data.
517 void _mesa_init_feedback( GLcontext
* ctx
)
520 ctx
->Feedback
.Type
= GL_2D
; /* TODO: verify */
521 ctx
->Feedback
.Buffer
= NULL
;
522 ctx
->Feedback
.BufferSize
= 0;
523 ctx
->Feedback
.Count
= 0;
525 /* Selection/picking */
526 ctx
->Select
.Buffer
= NULL
;
527 ctx
->Select
.BufferSize
= 0;
528 ctx
->Select
.BufferCount
= 0;
529 ctx
->Select
.Hits
= 0;
530 ctx
->Select
.NameStackDepth
= 0;
533 ctx
->RenderMode
= GL_RENDER
;