Removed all RCS / CVS tags (Id, Header, Date, etc.) from everything.
[mesa.git] / src / mesa / main / feedback.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 5.1
5 *
6 * Copyright (C) 1999-2003 Brian Paul 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 #include "glheader.h"
28 #include "colormac.h"
29 #include "context.h"
30 #include "enums.h"
31 #include "feedback.h"
32 #include "macros.h"
33 #include "mtypes.h"
34
35
36
37 #define FB_3D 0x01
38 #define FB_4D 0x02
39 #define FB_INDEX 0x04
40 #define FB_COLOR 0x08
41 #define FB_TEXTURE 0X10
42
43
44
45 void
46 _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
47 {
48 GET_CURRENT_CONTEXT(ctx);
49 ASSERT_OUTSIDE_BEGIN_END(ctx);
50
51 if (ctx->RenderMode==GL_FEEDBACK) {
52 _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
53 return;
54 }
55 if (size<0) {
56 _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
57 return;
58 }
59 if (!buffer) {
60 _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
61 ctx->Feedback.BufferSize = 0;
62 return;
63 }
64
65 switch (type) {
66 case GL_2D:
67 ctx->Feedback._Mask = 0;
68 break;
69 case GL_3D:
70 ctx->Feedback._Mask = FB_3D;
71 break;
72 case GL_3D_COLOR:
73 ctx->Feedback._Mask = (FB_3D |
74 (ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX));
75 break;
76 case GL_3D_COLOR_TEXTURE:
77 ctx->Feedback._Mask = (FB_3D |
78 (ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX) |
79 FB_TEXTURE);
80 break;
81 case GL_4D_COLOR_TEXTURE:
82 ctx->Feedback._Mask = (FB_3D | FB_4D |
83 (ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX) |
84 FB_TEXTURE);
85 break;
86 default:
87 _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
88 return;
89 }
90
91 FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */
92 ctx->Feedback.Type = type;
93 ctx->Feedback.BufferSize = size;
94 ctx->Feedback.Buffer = buffer;
95 ctx->Feedback.Count = 0; /* Becaues of this. */
96 }
97
98
99 void
100 _mesa_PassThrough( GLfloat token )
101 {
102 GET_CURRENT_CONTEXT(ctx);
103 ASSERT_OUTSIDE_BEGIN_END(ctx);
104
105 if (ctx->RenderMode==GL_FEEDBACK) {
106 FLUSH_VERTICES(ctx, 0);
107 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
108 FEEDBACK_TOKEN( ctx, token );
109 }
110 }
111
112
113
114 /*
115 * Put a vertex into the feedback buffer.
116 */
117 void _mesa_feedback_vertex( GLcontext *ctx,
118 const GLfloat win[4],
119 const GLfloat color[4],
120 GLuint index,
121 const GLfloat texcoord[4] )
122 {
123 FEEDBACK_TOKEN( ctx, win[0] );
124 FEEDBACK_TOKEN( ctx, win[1] );
125 if (ctx->Feedback._Mask & FB_3D) {
126 FEEDBACK_TOKEN( ctx, win[2] );
127 }
128 if (ctx->Feedback._Mask & FB_4D) {
129 FEEDBACK_TOKEN( ctx, win[3] );
130 }
131 if (ctx->Feedback._Mask & FB_INDEX) {
132 FEEDBACK_TOKEN( ctx, (GLfloat) index );
133 }
134 if (ctx->Feedback._Mask & FB_COLOR) {
135 FEEDBACK_TOKEN( ctx, color[0] );
136 FEEDBACK_TOKEN( ctx, color[1] );
137 FEEDBACK_TOKEN( ctx, color[2] );
138 FEEDBACK_TOKEN( ctx, color[3] );
139 }
140 if (ctx->Feedback._Mask & FB_TEXTURE) {
141 FEEDBACK_TOKEN( ctx, texcoord[0] );
142 FEEDBACK_TOKEN( ctx, texcoord[1] );
143 FEEDBACK_TOKEN( ctx, texcoord[2] );
144 FEEDBACK_TOKEN( ctx, texcoord[3] );
145 }
146 }
147
148
149 /**********************************************************************/
150 /* Selection */
151 /**********************************************************************/
152
153
154 /*
155 * NOTE: this function can't be put in a display list.
156 */
157 void
158 _mesa_SelectBuffer( GLsizei size, GLuint *buffer )
159 {
160 GET_CURRENT_CONTEXT(ctx);
161 ASSERT_OUTSIDE_BEGIN_END(ctx);
162
163 if (ctx->RenderMode==GL_SELECT) {
164 _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
165 return; /* KW: added return */
166 }
167
168 FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* why bother? */
169 ctx->Select.Buffer = buffer;
170 ctx->Select.BufferSize = size;
171 ctx->Select.BufferCount = 0;
172 ctx->Select.HitFlag = GL_FALSE;
173 ctx->Select.HitMinZ = 1.0;
174 ctx->Select.HitMaxZ = 0.0;
175 }
176
177
178 #define WRITE_RECORD( CTX, V ) \
179 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
180 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
181 } \
182 CTX->Select.BufferCount++;
183
184
185
186 void _mesa_update_hitflag( GLcontext *ctx, GLfloat z )
187 {
188 ctx->Select.HitFlag = GL_TRUE;
189 if (z < ctx->Select.HitMinZ) {
190 ctx->Select.HitMinZ = z;
191 }
192 if (z > ctx->Select.HitMaxZ) {
193 ctx->Select.HitMaxZ = z;
194 }
195 }
196
197
198 static void write_hit_record( GLcontext *ctx )
199 {
200 GLuint i;
201 GLuint zmin, zmax, zscale = (~0u);
202
203 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
204 /* 2^32-1 and round to nearest unsigned integer. */
205
206 assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
207 zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
208 zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
209
210 WRITE_RECORD( ctx, ctx->Select.NameStackDepth );
211 WRITE_RECORD( ctx, zmin );
212 WRITE_RECORD( ctx, zmax );
213 for (i = 0; i < ctx->Select.NameStackDepth; i++) {
214 WRITE_RECORD( ctx, ctx->Select.NameStack[i] );
215 }
216
217 ctx->Select.Hits++;
218 ctx->Select.HitFlag = GL_FALSE;
219 ctx->Select.HitMinZ = 1.0;
220 ctx->Select.HitMaxZ = -1.0;
221 }
222
223
224
225 void
226 _mesa_InitNames( void )
227 {
228 GET_CURRENT_CONTEXT(ctx);
229 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
230
231 /* Record the hit before the HitFlag is wiped out again. */
232 if (ctx->RenderMode == GL_SELECT) {
233 if (ctx->Select.HitFlag) {
234 write_hit_record( ctx );
235 }
236 }
237 ctx->Select.NameStackDepth = 0;
238 ctx->Select.HitFlag = GL_FALSE;
239 ctx->Select.HitMinZ = 1.0;
240 ctx->Select.HitMaxZ = 0.0;
241 ctx->NewState |= _NEW_RENDERMODE;
242 }
243
244
245
246 void
247 _mesa_LoadName( GLuint name )
248 {
249 GET_CURRENT_CONTEXT(ctx);
250 ASSERT_OUTSIDE_BEGIN_END(ctx);
251
252 if (ctx->RenderMode != GL_SELECT) {
253 return;
254 }
255 if (ctx->Select.NameStackDepth == 0) {
256 _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
257 return;
258 }
259
260 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
261
262 if (ctx->Select.HitFlag) {
263 write_hit_record( ctx );
264 }
265 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
266 ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
267 }
268 else {
269 ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
270 }
271 }
272
273
274 void
275 _mesa_PushName( GLuint name )
276 {
277 GET_CURRENT_CONTEXT(ctx);
278 ASSERT_OUTSIDE_BEGIN_END(ctx);
279
280 if (ctx->RenderMode != GL_SELECT) {
281 return;
282 }
283
284 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
285 if (ctx->Select.HitFlag) {
286 write_hit_record( ctx );
287 }
288 if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) {
289 _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
290 }
291 else
292 ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
293 }
294
295
296
297 void
298 _mesa_PopName( void )
299 {
300 GET_CURRENT_CONTEXT(ctx);
301 ASSERT_OUTSIDE_BEGIN_END(ctx);
302
303 if (ctx->RenderMode != GL_SELECT) {
304 return;
305 }
306
307 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
308 if (ctx->Select.HitFlag) {
309 write_hit_record( ctx );
310 }
311 if (ctx->Select.NameStackDepth == 0) {
312 _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
313 }
314 else
315 ctx->Select.NameStackDepth--;
316 }
317
318
319
320 /**********************************************************************/
321 /* Render Mode */
322 /**********************************************************************/
323
324
325
326 /*
327 * NOTE: this function can't be put in a display list.
328 */
329 GLint
330 _mesa_RenderMode( GLenum mode )
331 {
332 GET_CURRENT_CONTEXT(ctx);
333 GLint result;
334 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
335
336 if (MESA_VERBOSE & VERBOSE_API)
337 _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode));
338
339 FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
340
341 switch (ctx->RenderMode) {
342 case GL_RENDER:
343 result = 0;
344 break;
345 case GL_SELECT:
346 if (ctx->Select.HitFlag) {
347 write_hit_record( ctx );
348 }
349 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
350 /* overflow */
351 #ifdef DEBUG
352 _mesa_warning(ctx, "Feedback buffer overflow");
353 #endif
354 result = -1;
355 }
356 else {
357 result = ctx->Select.Hits;
358 }
359 ctx->Select.BufferCount = 0;
360 ctx->Select.Hits = 0;
361 ctx->Select.NameStackDepth = 0;
362 break;
363 case GL_FEEDBACK:
364 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
365 /* overflow */
366 result = -1;
367 }
368 else {
369 result = ctx->Feedback.Count;
370 }
371 ctx->Feedback.Count = 0;
372 break;
373 default:
374 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
375 return 0;
376 }
377
378 switch (mode) {
379 case GL_RENDER:
380 break;
381 case GL_SELECT:
382 if (ctx->Select.BufferSize==0) {
383 /* haven't called glSelectBuffer yet */
384 _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
385 }
386 break;
387 case GL_FEEDBACK:
388 if (ctx->Feedback.BufferSize==0) {
389 /* haven't called glFeedbackBuffer yet */
390 _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
391 }
392 break;
393 default:
394 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
395 return 0;
396 }
397
398 ctx->RenderMode = mode;
399 if (ctx->Driver.RenderMode)
400 ctx->Driver.RenderMode( ctx, mode );
401
402 return result;
403 }