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