xref: /reactos/dll/opengl/mesa/feedback.c (revision 5f2bebf7)
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