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