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 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 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 */ 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 */ 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 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 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 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 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 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 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 */ 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