Fixed typo
[reactos.git] / dll / opengl / mesa / main / feedback.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.5
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
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.
24 */
25
26 /**
27 * \file feedback.c
28 * Selection and feedback modes functions.
29 */
30
31 #include <precomp.h>
32
33 #if FEATURE_feedback
34
35
36 #define FB_3D 0x01
37 #define FB_4D 0x02
38 #define FB_COLOR 0x04
39 #define FB_TEXTURE 0X08
40
41
42
43 static void GLAPIENTRY
44 _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
45 {
46 GET_CURRENT_CONTEXT(ctx);
47 ASSERT_OUTSIDE_BEGIN_END(ctx);
48
49 if (ctx->RenderMode==GL_FEEDBACK) {
50 _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
51 return;
52 }
53 if (size<0) {
54 _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
55 return;
56 }
57 if (!buffer && size > 0) {
58 _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
59 ctx->Feedback.BufferSize = 0;
60 return;
61 }
62
63 switch (type) {
64 case GL_2D:
65 ctx->Feedback._Mask = 0;
66 break;
67 case GL_3D:
68 ctx->Feedback._Mask = FB_3D;
69 break;
70 case GL_3D_COLOR:
71 ctx->Feedback._Mask = (FB_3D | FB_COLOR);
72 break;
73 case GL_3D_COLOR_TEXTURE:
74 ctx->Feedback._Mask = (FB_3D | FB_COLOR | FB_TEXTURE);
75 break;
76 case GL_4D_COLOR_TEXTURE:
77 ctx->Feedback._Mask = (FB_3D | FB_4D | FB_COLOR | FB_TEXTURE);
78 break;
79 default:
80 _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
81 return;
82 }
83
84 FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */
85 ctx->Feedback.Type = type;
86 ctx->Feedback.BufferSize = size;
87 ctx->Feedback.Buffer = buffer;
88 ctx->Feedback.Count = 0; /* Becaues of this. */
89 }
90
91
92 static void GLAPIENTRY
93 _mesa_PassThrough( GLfloat token )
94 {
95 GET_CURRENT_CONTEXT(ctx);
96 ASSERT_OUTSIDE_BEGIN_END(ctx);
97
98 if (ctx->RenderMode==GL_FEEDBACK) {
99 FLUSH_VERTICES(ctx, 0);
100 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
101 _mesa_feedback_token( ctx, token );
102 }
103 }
104
105
106 /**
107 * Put a vertex into the feedback buffer.
108 */
109 void
110 _mesa_feedback_vertex(struct gl_context *ctx,
111 const GLfloat win[4],
112 const GLfloat color[4],
113 const GLfloat texcoord[4])
114 {
115 _mesa_feedback_token( ctx, win[0] );
116 _mesa_feedback_token( ctx, win[1] );
117 if (ctx->Feedback._Mask & FB_3D) {
118 _mesa_feedback_token( ctx, win[2] );
119 }
120 if (ctx->Feedback._Mask & FB_4D) {
121 _mesa_feedback_token( ctx, win[3] );
122 }
123 if (ctx->Feedback._Mask & FB_COLOR) {
124 _mesa_feedback_token( ctx, color[0] );
125 _mesa_feedback_token( ctx, color[1] );
126 _mesa_feedback_token( ctx, color[2] );
127 _mesa_feedback_token( ctx, color[3] );
128 }
129 if (ctx->Feedback._Mask & FB_TEXTURE) {
130 _mesa_feedback_token( ctx, texcoord[0] );
131 _mesa_feedback_token( ctx, texcoord[1] );
132 _mesa_feedback_token( ctx, texcoord[2] );
133 _mesa_feedback_token( ctx, texcoord[3] );
134 }
135 }
136
137
138 /**********************************************************************/
139 /** \name Selection */
140 /*@{*/
141
142 /**
143 * Establish a buffer for selection mode values.
144 *
145 * \param size buffer size.
146 * \param buffer buffer.
147 *
148 * \sa glSelectBuffer().
149 *
150 * \note this function can't be put in a display list.
151 *
152 * Verifies we're not in selection mode, flushes the vertices and initialize
153 * the fields in __struct gl_contextRec::Select with the given buffer.
154 */
155 static void GLAPIENTRY
156 _mesa_SelectBuffer( GLsizei size, GLuint *buffer )
157 {
158 GET_CURRENT_CONTEXT(ctx);
159 ASSERT_OUTSIDE_BEGIN_END(ctx);
160
161 if (size < 0) {
162 _mesa_error(ctx, GL_INVALID_VALUE, "glSelectBuffer(size)");
163 return;
164 }
165
166 if (ctx->RenderMode==GL_SELECT) {
167 _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
168 return; /* KW: added return */
169 }
170
171 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
172 ctx->Select.Buffer = buffer;
173 ctx->Select.BufferSize = size;
174 ctx->Select.BufferCount = 0;
175 ctx->Select.HitFlag = GL_FALSE;
176 ctx->Select.HitMinZ = 1.0;
177 ctx->Select.HitMaxZ = 0.0;
178 }
179
180
181 /**
182 * Write a value of a record into the selection buffer.
183 *
184 * \param ctx GL context.
185 * \param value value.
186 *
187 * Verifies there is free space in the buffer to write the value and
188 * increments the pointer.
189 */
190 static inline void
191 write_record(struct gl_context *ctx, GLuint value)
192 {
193 if (ctx->Select.BufferCount < ctx->Select.BufferSize) {
194 ctx->Select.Buffer[ctx->Select.BufferCount] = value;
195 }
196 ctx->Select.BufferCount++;
197 }
198
199
200 /**
201 * Update the hit flag and the maximum and minimum depth values.
202 *
203 * \param ctx GL context.
204 * \param z depth.
205 *
206 * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and
207 * gl_selection::HitMaxZ.
208 */
209 void
210 _mesa_update_hitflag(struct gl_context *ctx, GLfloat z)
211 {
212 ctx->Select.HitFlag = GL_TRUE;
213 if (z < ctx->Select.HitMinZ) {
214 ctx->Select.HitMinZ = z;
215 }
216 if (z > ctx->Select.HitMaxZ) {
217 ctx->Select.HitMaxZ = z;
218 }
219 }
220
221
222 /**
223 * Write the hit record.
224 *
225 * \param ctx GL context.
226 *
227 * Write the hit record, i.e., the number of names in the stack, the minimum and
228 * maximum depth values and the number of names in the name stack at the time
229 * of the event. Resets the hit flag.
230 *
231 * \sa gl_selection.
232 */
233 static void
234 write_hit_record(struct gl_context *ctx)
235 {
236 GLuint i;
237 GLuint zmin, zmax, zscale = (~0u);
238
239 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
240 /* 2^32-1 and round to nearest unsigned integer. */
241
242 assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
243 zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
244 zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
245
246 write_record( ctx, ctx->Select.NameStackDepth );
247 write_record( ctx, zmin );
248 write_record( ctx, zmax );
249 for (i = 0; i < ctx->Select.NameStackDepth; i++) {
250 write_record( ctx, ctx->Select.NameStack[i] );
251 }
252
253 ctx->Select.Hits++;
254 ctx->Select.HitFlag = GL_FALSE;
255 ctx->Select.HitMinZ = 1.0;
256 ctx->Select.HitMaxZ = -1.0;
257 }
258
259
260 /**
261 * Initialize the name stack.
262 *
263 * Verifies we are in select mode and resets the name stack depth and resets
264 * the hit record data in gl_selection. Marks new render mode in
265 * __struct gl_contextRec::NewState.
266 */
267 static void GLAPIENTRY
268 _mesa_InitNames( void )
269 {
270 GET_CURRENT_CONTEXT(ctx);
271 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
272
273 /* Record the hit before the HitFlag is wiped out again. */
274 if (ctx->RenderMode == GL_SELECT) {
275 if (ctx->Select.HitFlag) {
276 write_hit_record( ctx );
277 }
278 }
279 ctx->Select.NameStackDepth = 0;
280 ctx->Select.HitFlag = GL_FALSE;
281 ctx->Select.HitMinZ = 1.0;
282 ctx->Select.HitMaxZ = 0.0;
283 ctx->NewState |= _NEW_RENDERMODE;
284 }
285
286
287 /**
288 * Load the top-most name of the name stack.
289 *
290 * \param name name.
291 *
292 * Verifies we are in selection mode and that the name stack is not empty.
293 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
294 * and replace the top-most name in the stack.
295 *
296 * sa __struct gl_contextRec::Select.
297 */
298 static void GLAPIENTRY
299 _mesa_LoadName( GLuint name )
300 {
301 GET_CURRENT_CONTEXT(ctx);
302 ASSERT_OUTSIDE_BEGIN_END(ctx);
303
304 if (ctx->RenderMode != GL_SELECT) {
305 return;
306 }
307 if (ctx->Select.NameStackDepth == 0) {
308 _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
309 return;
310 }
311
312 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
313
314 if (ctx->Select.HitFlag) {
315 write_hit_record( ctx );
316 }
317 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
318 ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
319 }
320 else {
321 ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
322 }
323 }
324
325
326 /**
327 * Push a name into the name stack.
328 *
329 * \param name name.
330 *
331 * Verifies we are in selection mode and that the name stack is not full.
332 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
333 * and adds the name to the top of the name stack.
334 *
335 * sa __struct gl_contextRec::Select.
336 */
337 static void GLAPIENTRY
338 _mesa_PushName( GLuint name )
339 {
340 GET_CURRENT_CONTEXT(ctx);
341 ASSERT_OUTSIDE_BEGIN_END(ctx);
342
343 if (ctx->RenderMode != GL_SELECT) {
344 return;
345 }
346
347 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
348 if (ctx->Select.HitFlag) {
349 write_hit_record( ctx );
350 }
351 if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) {
352 _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
353 }
354 else
355 ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
356 }
357
358
359 /**
360 * Pop a name into the name stack.
361 *
362 * Verifies we are in selection mode and that the name stack is not empty.
363 * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
364 * and removes top-most name in the name stack.
365 *
366 * sa __struct gl_contextRec::Select.
367 */
368 static void GLAPIENTRY
369 _mesa_PopName( void )
370 {
371 GET_CURRENT_CONTEXT(ctx);
372 ASSERT_OUTSIDE_BEGIN_END(ctx);
373
374 if (ctx->RenderMode != GL_SELECT) {
375 return;
376 }
377
378 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
379 if (ctx->Select.HitFlag) {
380 write_hit_record( ctx );
381 }
382 if (ctx->Select.NameStackDepth == 0) {
383 _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
384 }
385 else
386 ctx->Select.NameStackDepth--;
387 }
388
389 /*@}*/
390
391
392 /**********************************************************************/
393 /** \name Render Mode */
394 /*@{*/
395
396 /**
397 * Set rasterization mode.
398 *
399 * \param mode rasterization mode.
400 *
401 * \note this function can't be put in a display list.
402 *
403 * \sa glRenderMode().
404 *
405 * Flushes the vertices and do the necessary cleanup according to the previous
406 * rasterization mode, such as writing the hit record or resent the select
407 * buffer index when exiting the select mode. Updates
408 * __struct gl_contextRec::RenderMode and notifies the driver via the
409 * dd_function_table::RenderMode callback.
410 */
411 GLint GLAPIENTRY
412 _mesa_RenderMode( GLenum mode )
413 {
414 GET_CURRENT_CONTEXT(ctx);
415 GLint result;
416 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
417
418 if (MESA_VERBOSE & VERBOSE_API)
419 _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode));
420
421 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
422
423 switch (ctx->RenderMode) {
424 case GL_RENDER:
425 result = 0;
426 break;
427 case GL_SELECT:
428 if (ctx->Select.HitFlag) {
429 write_hit_record( ctx );
430 }
431 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
432 /* overflow */
433 #ifdef DEBUG
434 _mesa_warning(ctx, "Feedback buffer overflow");
435 #endif
436 result = -1;
437 }
438 else {
439 result = ctx->Select.Hits;
440 }
441 ctx->Select.BufferCount = 0;
442 ctx->Select.Hits = 0;
443 ctx->Select.NameStackDepth = 0;
444 break;
445 #if _HAVE_FULL_GL
446 case GL_FEEDBACK:
447 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
448 /* overflow */
449 result = -1;
450 }
451 else {
452 result = ctx->Feedback.Count;
453 }
454 ctx->Feedback.Count = 0;
455 break;
456 #endif
457 default:
458 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
459 return 0;
460 }
461
462 switch (mode) {
463 case GL_RENDER:
464 break;
465 case GL_SELECT:
466 if (ctx->Select.BufferSize==0) {
467 /* haven't called glSelectBuffer yet */
468 _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
469 }
470 break;
471 #if _HAVE_FULL_GL
472 case GL_FEEDBACK:
473 if (ctx->Feedback.BufferSize==0) {
474 /* haven't called glFeedbackBuffer yet */
475 _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
476 }
477 break;
478 #endif
479 default:
480 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
481 return 0;
482 }
483
484 ctx->RenderMode = mode;
485 if (ctx->Driver.RenderMode)
486 ctx->Driver.RenderMode( ctx, mode );
487
488 return result;
489 }
490
491 /*@}*/
492
493
494 void
495 _mesa_init_feedback_dispatch(struct _glapi_table *disp)
496 {
497 SET_InitNames(disp, _mesa_InitNames);
498 SET_FeedbackBuffer(disp, _mesa_FeedbackBuffer);
499 SET_LoadName(disp, _mesa_LoadName);
500 SET_PassThrough(disp, _mesa_PassThrough);
501 SET_PopName(disp, _mesa_PopName);
502 SET_PushName(disp, _mesa_PushName);
503 SET_SelectBuffer(disp, _mesa_SelectBuffer);
504 SET_RenderMode(disp, _mesa_RenderMode);
505 }
506
507
508 #endif /* FEATURE_feedback */
509
510
511 /**********************************************************************/
512 /** \name Initialization */
513 /*@{*/
514
515 /**
516 * Initialize context feedback data.
517 */
518 void _mesa_init_feedback( struct gl_context * ctx )
519 {
520 /* Feedback */
521 ctx->Feedback.Type = GL_2D; /* TODO: verify */
522 ctx->Feedback.Buffer = NULL;
523 ctx->Feedback.BufferSize = 0;
524 ctx->Feedback.Count = 0;
525
526 /* Selection/picking */
527 ctx->Select.Buffer = NULL;
528 ctx->Select.BufferSize = 0;
529 ctx->Select.BufferCount = 0;
530 ctx->Select.Hits = 0;
531 ctx->Select.NameStackDepth = 0;
532
533 /* Miscellaneous */
534 ctx->RenderMode = GL_RENDER;
535 }
536
537 /*@}*/