1 /* $Id: feedback.c,v 1.12 1998/02/03 23:45:02 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.4
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: feedback.c,v $
26 * Revision 1.12 1998/02/03 23:45:02 brianp
27 * added casts to prevent warnings with Amiga StormC compiler
28 *
29 * Revision 1.11 1997/11/07 03:38:07 brianp
30 * added stdio.h include for SunOS 4.x
31 *
32 * Revision 1.10 1997/07/24 01:25:01 brianp
33 * changed precompiled header symbol from PCH to PC_HEADER
34 *
35 * Revision 1.9 1997/05/28 03:24:54 brianp
36 * added precompiled header (PCH) support
37 *
38 * Revision 1.8 1997/03/08 02:03:46 brianp
39 * better error checking
40 *
41 * Revision 1.7 1997/01/21 03:09:15 brianp
42 * fixed an error message in gl_RenderMode()
43 *
44 * Revision 1.6 1997/01/16 19:10:24 brianp
45 * kludged around a SunOS 5.x/GCC bug in write_hit_record()
46 *
47 * Revision 1.5 1996/12/13 21:03:19 brianp
48 * fixed feedback buffer overflow bug in write_hit_record()
49 *
50 * Revision 1.4 1996/10/22 22:58:25 brianp
51 * fixed bug in gl_update_hitflag() reported by Erich Eder
52 *
53 * Revision 1.3 1996/09/27 01:28:13 brianp
54 * added missing error check to gl_RenderMode()
55 *
56 * Revision 1.2 1996/09/15 14:17:30 brianp
57 * now use GLframebuffer and GLvisual
58 *
59 * Revision 1.1 1996/09/13 01:38:16 brianp
60 * Initial revision
61 *
62 */
63
64
65 #ifdef PC_HEADER
66 #include "all.h"
67 #else
68 #include <assert.h>
69 #include <stdio.h>
70 #include "context.h"
71 #include "feedback.h"
72 #include "dlist.h"
73 #include "macros.h"
74 #include "types.h"
75 #endif
76
77
78
79 #define FB_3D 0x01
80 #define FB_4D 0x02
81 #define FB_INDEX 0x04
82 #define FB_COLOR 0x08
83 #define FB_TEXTURE 0X10
84
85
86
87 void
gl_FeedbackBuffer(GLcontext * ctx,GLsizei size,GLenum type,GLfloat * buffer)88 gl_FeedbackBuffer( GLcontext *ctx, GLsizei size, GLenum type, GLfloat *buffer )
89 {
90 if (ctx->RenderMode==GL_FEEDBACK || INSIDE_BEGIN_END(ctx)) {
91 gl_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
92 return;
93 }
94
95 if (size<0) {
96 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
97 return;
98 }
99 if (!buffer) {
100 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
101 ctx->Feedback.BufferSize = 0;
102 return;
103 }
104
105 switch (type) {
106 case GL_2D:
107 ctx->Feedback.Mask = 0;
108 ctx->Feedback.Type = type;
109 break;
110 case GL_3D:
111 ctx->Feedback.Mask = FB_3D;
112 ctx->Feedback.Type = type;
113 break;
114 case GL_3D_COLOR:
115 ctx->Feedback.Mask = FB_3D
116 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX);
117 ctx->Feedback.Type = type;
118 break;
119 case GL_3D_COLOR_TEXTURE:
120 ctx->Feedback.Mask = FB_3D
121 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX)
122 | FB_TEXTURE;
123 ctx->Feedback.Type = type;
124 break;
125 case GL_4D_COLOR_TEXTURE:
126 ctx->Feedback.Mask = FB_3D | FB_4D
127 | (ctx->Visual->RGBAflag ? FB_COLOR : FB_INDEX)
128 | FB_TEXTURE;
129 ctx->Feedback.Type = type;
130 break;
131 default:
132 ctx->Feedback.Mask = 0;
133 gl_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
134 }
135
136 ctx->Feedback.BufferSize = size;
137 ctx->Feedback.Buffer = buffer;
138 ctx->Feedback.Count = 0;
139 }
140
141
142
gl_PassThrough(GLcontext * ctx,GLfloat token)143 void gl_PassThrough( GLcontext *ctx, GLfloat token )
144 {
145 if (INSIDE_BEGIN_END(ctx)) {
146 gl_error( ctx, GL_INVALID_OPERATION, "glPassThrough" );
147 return;
148 }
149
150 if (ctx->RenderMode==GL_FEEDBACK) {
151 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
152 FEEDBACK_TOKEN( ctx, token );
153 }
154 }
155
156
157
158 /*
159 * Put a vertex into the feedback buffer.
160 */
gl_feedback_vertex(GLcontext * ctx,GLfloat x,GLfloat y,GLfloat z,GLfloat w,const GLfloat color[4],GLfloat index,const GLfloat texcoord[4])161 void gl_feedback_vertex( GLcontext *ctx,
162 GLfloat x, GLfloat y, GLfloat z, GLfloat w,
163 const GLfloat color[4], GLfloat index,
164 const GLfloat texcoord[4] )
165 {
166 FEEDBACK_TOKEN( ctx, x );
167 FEEDBACK_TOKEN( ctx, y );
168 if (ctx->Feedback.Mask & FB_3D) {
169 FEEDBACK_TOKEN( ctx, z );
170 }
171 if (ctx->Feedback.Mask & FB_4D) {
172 FEEDBACK_TOKEN( ctx, w );
173 }
174 if (ctx->Feedback.Mask & FB_INDEX) {
175 FEEDBACK_TOKEN( ctx, index );
176 }
177 if (ctx->Feedback.Mask & FB_COLOR) {
178 FEEDBACK_TOKEN( ctx, color[0] );
179 FEEDBACK_TOKEN( ctx, color[1] );
180 FEEDBACK_TOKEN( ctx, color[2] );
181 FEEDBACK_TOKEN( ctx, color[3] );
182 }
183 if (ctx->Feedback.Mask & FB_TEXTURE) {
184 FEEDBACK_TOKEN( ctx, texcoord[0] );
185 FEEDBACK_TOKEN( ctx, texcoord[1] );
186 FEEDBACK_TOKEN( ctx, texcoord[2] );
187 FEEDBACK_TOKEN( ctx, texcoord[3] );
188 }
189 }
190
191
192
193 /**********************************************************************/
194 /* Selection */
195 /**********************************************************************/
196
197
198 /*
199 * NOTE: this function can't be put in a display list.
200 */
gl_SelectBuffer(GLcontext * ctx,GLsizei size,GLuint * buffer)201 void gl_SelectBuffer( GLcontext *ctx, GLsizei size, GLuint *buffer )
202 {
203 if (INSIDE_BEGIN_END(ctx)) {
204 gl_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
205 }
206 if (ctx->RenderMode==GL_SELECT) {
207 gl_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
208 }
209 ctx->Select.Buffer = buffer;
210 ctx->Select.BufferSize = size;
211 ctx->Select.BufferCount = 0;
212
213 ctx->Select.HitFlag = GL_FALSE;
214 ctx->Select.HitMinZ = 1.0;
215 ctx->Select.HitMaxZ = 0.0;
216 }
217
218
gl_InitNames(GLcontext * ctx)219 void gl_InitNames( GLcontext *ctx )
220 {
221 if (INSIDE_BEGIN_END(ctx)) {
222 gl_error( ctx, GL_INVALID_OPERATION, "glInitNames" );
223 }
224 ctx->Select.NameStackDepth = 0;
225 ctx->Select.HitFlag = GL_FALSE;
226 ctx->Select.HitMinZ = 1.0;
227 ctx->Select.HitMaxZ = 0.0;
228 }
229
230
231
232 #define WRITE_RECORD( CTX, V ) \
233 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \
234 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \
235 } \
236 CTX->Select.BufferCount++;
237
238
239
gl_update_hitflag(GLcontext * ctx,GLfloat z)240 void gl_update_hitflag( GLcontext *ctx, GLfloat z )
241 {
242 ctx->Select.HitFlag = GL_TRUE;
243 if (z < ctx->Select.HitMinZ) {
244 ctx->Select.HitMinZ = z;
245 }
246 if (z > ctx->Select.HitMaxZ) {
247 ctx->Select.HitMaxZ = z;
248 }
249 }
250
251
252
write_hit_record(GLcontext * ctx)253 static void write_hit_record( GLcontext *ctx )
254 {
255 GLuint i;
256 GLuint zmin, zmax, zscale = (~0u);
257
258 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */
259 /* 2^32-1 and round to nearest unsigned integer. */
260
261 assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
262 zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
263 zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
264
265 WRITE_RECORD( ctx, ctx->Select.NameStackDepth );
266 WRITE_RECORD( ctx, zmin );
267 WRITE_RECORD( ctx, zmax );
268 for (i=0;i<ctx->Select.NameStackDepth;i++) {
269 WRITE_RECORD( ctx, ctx->Select.NameStack[i] );
270 }
271
272 ctx->Select.Hits++;
273 ctx->Select.HitFlag = GL_FALSE;
274 ctx->Select.HitMinZ = 1.0;
275 ctx->Select.HitMaxZ = -1.0;
276 }
277
278
279
gl_LoadName(GLcontext * ctx,GLuint name)280 void gl_LoadName( GLcontext *ctx, GLuint name )
281 {
282 if (INSIDE_BEGIN_END(ctx)) {
283 gl_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
284 return;
285 }
286 if (ctx->RenderMode!=GL_SELECT) {
287 return;
288 }
289 if (ctx->Select.NameStackDepth==0) {
290 gl_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
291 return;
292 }
293 if (ctx->Select.HitFlag) {
294 write_hit_record( ctx );
295 }
296 if (ctx->Select.NameStackDepth<MAX_NAME_STACK_DEPTH) {
297 ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
298 }
299 else {
300 ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
301 }
302 }
303
304
gl_PushName(GLcontext * ctx,GLuint name)305 void gl_PushName( GLcontext *ctx, GLuint name )
306 {
307 if (INSIDE_BEGIN_END(ctx)) {
308 gl_error( ctx, GL_INVALID_OPERATION, "glPushName" );
309 return;
310 }
311 if (ctx->RenderMode!=GL_SELECT) {
312 return;
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++] = name;
319 }
320 else {
321 gl_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
322 }
323 }
324
325
326
gl_PopName(GLcontext * ctx)327 void gl_PopName( GLcontext *ctx )
328 {
329 if (INSIDE_BEGIN_END(ctx)) {
330 gl_error( ctx, GL_INVALID_OPERATION, "glPopName" );
331 return;
332 }
333 if (ctx->RenderMode!=GL_SELECT) {
334 return;
335 }
336 if (ctx->Select.HitFlag) {
337 write_hit_record( ctx );
338 }
339 if (ctx->Select.NameStackDepth>0) {
340 ctx->Select.NameStackDepth--;
341 }
342 else {
343 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
344 }
345 }
346
347
348
349 /**********************************************************************/
350 /* Render Mode */
351 /**********************************************************************/
352
353
354
355 /*
356 * NOTE: this function can't be put in a display list.
357 */
gl_RenderMode(GLcontext * ctx,GLenum mode)358 GLint gl_RenderMode( GLcontext *ctx, GLenum mode )
359 {
360 GLint result;
361
362 if (INSIDE_BEGIN_END(ctx)) {
363 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
364 }
365
366 switch (ctx->RenderMode) {
367 case GL_RENDER:
368 result = 0;
369 break;
370 case GL_SELECT:
371 if (ctx->Select.HitFlag) {
372 write_hit_record( ctx );
373 }
374 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
375 /* overflow */
376 #ifdef DEBUG
377 gl_warning(ctx, "Feedback buffer overflow");
378 #endif
379 result = -1;
380 }
381 else {
382 result = ctx->Select.Hits;
383 }
384 ctx->Select.BufferCount = 0;
385 ctx->Select.Hits = 0;
386 ctx->Select.NameStackDepth = 0;
387 break;
388 case GL_FEEDBACK:
389 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
390 /* overflow */
391 result = -1;
392 }
393 else {
394 result = ctx->Feedback.Count;
395 }
396 ctx->Feedback.Count = 0;
397 break;
398 default:
399 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
400 return 0;
401 }
402
403 switch (mode) {
404 case GL_RENDER:
405 break;
406 case GL_SELECT:
407 if (ctx->Select.BufferSize==0) {
408 /* haven't called glSelectBuffer yet */
409 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
410 }
411 break;
412 case GL_FEEDBACK:
413 if (ctx->Feedback.BufferSize==0) {
414 /* haven't called glFeedbackBuffer yet */
415 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
416 }
417 break;
418 default:
419 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
420 return 0;
421 }
422
423 ctx->RenderMode = mode;
424 ctx->NewState |= NEW_ALL;
425
426 return result;
427 }
428
429