feedback.c revision a96308c37db0bc0086a017d318bc3504aa5f0b1a
1/* $Id: feedback.c,v 1.14 2000/10/30 13:32:00 keithw Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.3 6 * 7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#ifdef PC_HEADER 29#include "all.h" 30#else 31#include "glheader.h" 32#include "colormac.h" 33#include "context.h" 34#include "enums.h" 35#include "feedback.h" 36#include "macros.h" 37#include "mmath.h" 38#include "types.h" 39#include "triangle.h" 40#endif 41 42 43 44#define FB_3D 0x01 45#define FB_4D 0x02 46#define FB_INDEX 0x04 47#define FB_COLOR 0x08 48#define FB_TEXTURE 0X10 49 50 51 52void 53_mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer ) 54{ 55 GET_CURRENT_CONTEXT(ctx); 56 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx, "glFeedbackBuffer" ); 57 58 if (ctx->RenderMode==GL_FEEDBACK) { 59 gl_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" ); 60 return; 61 } 62 63 if (size<0) { 64 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" ); 65 return; 66 } 67 if (!buffer) { 68 gl_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" ); 69 ctx->Feedback.BufferSize = 0; 70 return; 71 } 72 73 switch (type) { 74 case GL_2D: 75 ctx->Feedback.Mask = 0; 76 ctx->Feedback.Type = type; 77 break; 78 case GL_3D: 79 ctx->Feedback.Mask = FB_3D; 80 ctx->Feedback.Type = type; 81 break; 82 case GL_3D_COLOR: 83 ctx->Feedback.Mask = FB_3D 84 | (ctx->Visual.RGBAflag ? FB_COLOR : FB_INDEX); 85 ctx->Feedback.Type = type; 86 break; 87 case GL_3D_COLOR_TEXTURE: 88 ctx->Feedback.Mask = FB_3D 89 | (ctx->Visual.RGBAflag ? FB_COLOR : FB_INDEX) 90 | FB_TEXTURE; 91 ctx->Feedback.Type = type; 92 break; 93 case GL_4D_COLOR_TEXTURE: 94 ctx->Feedback.Mask = FB_3D | FB_4D 95 | (ctx->Visual.RGBAflag ? FB_COLOR : FB_INDEX) 96 | FB_TEXTURE; 97 ctx->Feedback.Type = type; 98 break; 99 default: 100 ctx->Feedback.Mask = 0; 101 gl_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" ); 102 } 103 104 ctx->Feedback.BufferSize = size; 105 ctx->Feedback.Buffer = buffer; 106 ctx->Feedback.Count = 0; 107 ctx->NewState |= _NEW_FEEDBACK_SELECT; 108} 109 110 111 112void 113_mesa_PassThrough( GLfloat token ) 114{ 115 GET_CURRENT_CONTEXT(ctx); 116 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPassThrough"); 117 118 if (ctx->RenderMode==GL_FEEDBACK) { 119 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN ); 120 FEEDBACK_TOKEN( ctx, token ); 121 } 122} 123 124 125 126/* 127 * Put a vertex into the feedback buffer. 128 */ 129void gl_feedback_vertex( GLcontext *ctx, 130 const GLfloat win[4], 131 const GLfloat color[4], 132 GLuint index, 133 const GLfloat texcoord[4] ) 134{ 135 FEEDBACK_TOKEN( ctx, win[0] ); 136 FEEDBACK_TOKEN( ctx, win[1] ); 137 if (ctx->Feedback.Mask & FB_3D) { 138 FEEDBACK_TOKEN( ctx, win[2] ); 139 } 140 if (ctx->Feedback.Mask & FB_4D) { 141 FEEDBACK_TOKEN( ctx, win[3] ); 142 } 143 if (ctx->Feedback.Mask & FB_INDEX) { 144 FEEDBACK_TOKEN( ctx, (GLfloat) index ); 145 } 146 if (ctx->Feedback.Mask & FB_COLOR) { 147 FEEDBACK_TOKEN( ctx, color[0] ); 148 FEEDBACK_TOKEN( ctx, color[1] ); 149 FEEDBACK_TOKEN( ctx, color[2] ); 150 FEEDBACK_TOKEN( ctx, color[3] ); 151 } 152 if (ctx->Feedback.Mask & FB_TEXTURE) { 153 FEEDBACK_TOKEN( ctx, texcoord[0] ); 154 FEEDBACK_TOKEN( ctx, texcoord[1] ); 155 FEEDBACK_TOKEN( ctx, texcoord[2] ); 156 FEEDBACK_TOKEN( ctx, texcoord[3] ); 157 } 158} 159 160 161 162static void feedback_vertex( GLcontext *ctx, GLuint v, GLuint pv ) 163{ 164 GLfloat win[4]; 165 GLfloat color[4]; 166 GLfloat tc[4]; 167 GLuint texUnit = ctx->Texture.CurrentTransformUnit; 168 const struct vertex_buffer *VB = ctx->VB; 169 GLuint index; 170 171 win[0] = VB->Win.data[v][0]; 172 win[1] = VB->Win.data[v][1]; 173 win[2] = VB->Win.data[v][2] / ctx->Visual.DepthMaxF; 174 win[3] = 1.0 / VB->Win.data[v][3]; 175 176 if (ctx->Light.ShadeModel == GL_SMOOTH) 177 pv = v; 178 179 color[0] = CHAN_TO_FLOAT(VB->ColorPtr->data[pv][0]); 180 color[1] = CHAN_TO_FLOAT(VB->ColorPtr->data[pv][1]); 181 color[2] = CHAN_TO_FLOAT(VB->ColorPtr->data[pv][2]); 182 color[3] = CHAN_TO_FLOAT(VB->ColorPtr->data[pv][3]); 183 184 if (VB->TexCoordPtr[texUnit]->size == 4 && 185 VB->TexCoordPtr[texUnit]->data[v][3] != 0.0) { 186 GLfloat invq = 1.0F / VB->TexCoordPtr[texUnit]->data[v][3]; 187 tc[0] = VB->TexCoordPtr[texUnit]->data[v][0] * invq; 188 tc[1] = VB->TexCoordPtr[texUnit]->data[v][1] * invq; 189 tc[2] = VB->TexCoordPtr[texUnit]->data[v][2] * invq; 190 tc[3] = VB->TexCoordPtr[texUnit]->data[v][3]; 191 } 192 else { 193 ASSIGN_4V(tc, 0,0,0,1); 194 COPY_SZ_4V(tc, 195 VB->TexCoordPtr[texUnit]->size, 196 VB->TexCoordPtr[texUnit]->data[v]); 197 } 198 199 if (VB->IndexPtr) 200 index = VB->IndexPtr->data[v]; 201 else 202 index = 0; 203 204 gl_feedback_vertex( ctx, win, color, index, tc ); 205} 206 207 208 209/* 210 * Put triangle in feedback buffer. 211 */ 212void gl_feedback_triangle( GLcontext *ctx, 213 GLuint v0, GLuint v1, GLuint v2, GLuint pv ) 214{ 215 if (gl_cull_triangle( ctx, v0, v1, v2, 0 )) { 216 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_POLYGON_TOKEN ); 217 FEEDBACK_TOKEN( ctx, (GLfloat) 3 ); /* three vertices */ 218 219 feedback_vertex( ctx, v0, pv ); 220 feedback_vertex( ctx, v1, pv ); 221 feedback_vertex( ctx, v2, pv ); 222 } 223} 224 225 226void gl_feedback_line( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv ) 227{ 228 GLenum token = GL_LINE_TOKEN; 229 230 if (ctx->StippleCounter==0) 231 token = GL_LINE_RESET_TOKEN; 232 233 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) token ); 234 235 feedback_vertex( ctx, v1, pv ); 236 feedback_vertex( ctx, v2, pv ); 237 238 ctx->StippleCounter++; 239} 240 241 242void gl_feedback_points( GLcontext *ctx, GLuint first, GLuint last ) 243{ 244 const struct vertex_buffer *VB = ctx->VB; 245 GLuint i; 246 247 for (i=first;i<=last;i++) { 248 if (VB->ClipMask[i]==0) { 249 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_POINT_TOKEN ); 250 feedback_vertex( ctx, i, i ); 251 } 252 } 253} 254 255 256 257 258 259/**********************************************************************/ 260/* Selection */ 261/**********************************************************************/ 262 263 264/* 265 * NOTE: this function can't be put in a display list. 266 */ 267void 268_mesa_SelectBuffer( GLsizei size, GLuint *buffer ) 269{ 270 GET_CURRENT_CONTEXT(ctx); 271 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSelectBuffer"); 272 if (ctx->RenderMode==GL_SELECT) { 273 gl_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" ); 274 } 275 ctx->Select.Buffer = buffer; 276 ctx->Select.BufferSize = size; 277 ctx->Select.BufferCount = 0; 278 279 ctx->Select.HitFlag = GL_FALSE; 280 ctx->Select.HitMinZ = 1.0; 281 ctx->Select.HitMaxZ = 0.0; 282 283 ctx->NewState |= _NEW_FEEDBACK_SELECT; 284} 285 286 287#define WRITE_RECORD( CTX, V ) \ 288 if (CTX->Select.BufferCount < CTX->Select.BufferSize) { \ 289 CTX->Select.Buffer[CTX->Select.BufferCount] = (V); \ 290 } \ 291 CTX->Select.BufferCount++; 292 293 294 295void gl_update_hitflag( GLcontext *ctx, GLfloat z ) 296{ 297 ctx->Select.HitFlag = GL_TRUE; 298 if (z < ctx->Select.HitMinZ) { 299 ctx->Select.HitMinZ = z; 300 } 301 if (z > ctx->Select.HitMaxZ) { 302 ctx->Select.HitMaxZ = z; 303 } 304} 305 306void gl_select_triangle( GLcontext *ctx, 307 GLuint v0, GLuint v1, GLuint v2, GLuint pv ) 308{ 309 const struct vertex_buffer *VB = ctx->VB; 310 311 if (gl_cull_triangle( ctx, v0, v1, v2, 0 )) { 312 const GLfloat zs = 1.0F / ctx->Visual.DepthMaxF; 313 gl_update_hitflag( ctx, VB->Win.data[v0][2] * zs ); 314 gl_update_hitflag( ctx, VB->Win.data[v1][2] * zs ); 315 gl_update_hitflag( ctx, VB->Win.data[v2][2] * zs ); 316 } 317} 318 319 320void gl_select_line( GLcontext *ctx, 321 GLuint v0, GLuint v1, GLuint pv ) 322{ 323 const struct vertex_buffer *VB = ctx->VB; 324 const GLfloat zs = 1.0F / ctx->Visual.DepthMaxF; 325 gl_update_hitflag( ctx, VB->Win.data[v0][2] * zs ); 326 gl_update_hitflag( ctx, VB->Win.data[v1][2] * zs ); 327} 328 329 330void gl_select_points( GLcontext *ctx, GLuint first, GLuint last ) 331{ 332 struct vertex_buffer *VB = ctx->VB; 333 const GLfloat zs = 1.0F / ctx->Visual.DepthMaxF; 334 GLuint i; 335 336 for (i=first;i<=last;i++) { 337 if (VB->ClipMask[i]==0) { 338 gl_update_hitflag( ctx, VB->Win.data[i][2] * zs ); 339 } 340 } 341} 342 343 344static void write_hit_record( GLcontext *ctx ) 345{ 346 GLuint i; 347 GLuint zmin, zmax, zscale = (~0u); 348 349 /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */ 350 /* 2^32-1 and round to nearest unsigned integer. */ 351 352 assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */ 353 zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ); 354 zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ); 355 356 WRITE_RECORD( ctx, ctx->Select.NameStackDepth ); 357 WRITE_RECORD( ctx, zmin ); 358 WRITE_RECORD( ctx, zmax ); 359 for (i = 0; i < ctx->Select.NameStackDepth; i++) { 360 WRITE_RECORD( ctx, ctx->Select.NameStack[i] ); 361 } 362 363 ctx->Select.Hits++; 364 ctx->Select.HitFlag = GL_FALSE; 365 ctx->Select.HitMinZ = 1.0; 366 ctx->Select.HitMaxZ = -1.0; 367} 368 369 370 371void 372_mesa_InitNames( void ) 373{ 374 GET_CURRENT_CONTEXT(ctx); 375 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glInitNames"); 376 /* Record the hit before the HitFlag is wiped out again. */ 377 if (ctx->RenderMode == GL_SELECT) { 378 if (ctx->Select.HitFlag) { 379 write_hit_record( ctx ); 380 } 381 } 382 ctx->Select.NameStackDepth = 0; 383 ctx->Select.HitFlag = GL_FALSE; 384 ctx->Select.HitMinZ = 1.0; 385 ctx->Select.HitMaxZ = 0.0; 386 ctx->NewState |= _NEW_FEEDBACK_SELECT; 387} 388 389 390 391void 392_mesa_LoadName( GLuint name ) 393{ 394 GET_CURRENT_CONTEXT(ctx); 395 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glLoadName"); 396 if (ctx->RenderMode != GL_SELECT) { 397 return; 398 } 399 if (ctx->Select.NameStackDepth == 0) { 400 gl_error( ctx, GL_INVALID_OPERATION, "glLoadName" ); 401 return; 402 } 403 if (ctx->Select.HitFlag) { 404 write_hit_record( ctx ); 405 } 406 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) { 407 ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name; 408 } 409 else { 410 ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name; 411 } 412 ctx->NewState |= _NEW_FEEDBACK_SELECT; 413} 414 415 416void 417_mesa_PushName( GLuint name ) 418{ 419 GET_CURRENT_CONTEXT(ctx); 420 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPushName"); 421 if (ctx->RenderMode != GL_SELECT) { 422 return; 423 } 424 if (ctx->Select.HitFlag) { 425 write_hit_record( ctx ); 426 } 427 if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) { 428 ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name; 429 } 430 else { 431 gl_error( ctx, GL_STACK_OVERFLOW, "glPushName" ); 432 } 433 ctx->NewState |= _NEW_FEEDBACK_SELECT; 434} 435 436 437 438void 439_mesa_PopName( void ) 440{ 441 GET_CURRENT_CONTEXT(ctx); 442 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPopName"); 443 if (ctx->RenderMode != GL_SELECT) { 444 return; 445 } 446 if (ctx->Select.HitFlag) { 447 write_hit_record( ctx ); 448 } 449 if (ctx->Select.NameStackDepth > 0) { 450 ctx->Select.NameStackDepth--; 451 } 452 else { 453 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopName" ); 454 } 455 ctx->NewState |= _NEW_FEEDBACK_SELECT; 456} 457 458 459 460/**********************************************************************/ 461/* Render Mode */ 462/**********************************************************************/ 463 464 465 466/* 467 * NOTE: this function can't be put in a display list. 468 */ 469GLint 470_mesa_RenderMode( GLenum mode ) 471{ 472 GET_CURRENT_CONTEXT(ctx); 473 GLint result; 474 475 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glRenderMode", 0); 476 477 if (MESA_VERBOSE & VERBOSE_API) 478 fprintf(stderr, "glRenderMode %s\n", gl_lookup_enum_by_nr(mode)); 479 480 ctx->TriangleCaps &= ~(DD_FEEDBACK|DD_SELECT); 481 482 switch (ctx->RenderMode) { 483 case GL_RENDER: 484 result = 0; 485 break; 486 case GL_SELECT: 487 if (ctx->Select.HitFlag) { 488 write_hit_record( ctx ); 489 } 490 if (ctx->Select.BufferCount > ctx->Select.BufferSize) { 491 /* overflow */ 492#ifdef DEBUG 493 _mesa_warning(ctx, "Feedback buffer overflow"); 494#endif 495 result = -1; 496 } 497 else { 498 result = ctx->Select.Hits; 499 } 500 ctx->Select.BufferCount = 0; 501 ctx->Select.Hits = 0; 502 ctx->Select.NameStackDepth = 0; 503 ctx->NewState |= _NEW_FEEDBACK_SELECT; 504 break; 505 case GL_FEEDBACK: 506 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) { 507 /* overflow */ 508 result = -1; 509 } 510 else { 511 result = ctx->Feedback.Count; 512 } 513 ctx->Feedback.Count = 0; 514 ctx->NewState |= _NEW_FEEDBACK_SELECT; 515 break; 516 default: 517 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); 518 return 0; 519 } 520 521 switch (mode) { 522 case GL_RENDER: 523 break; 524 case GL_SELECT: 525 ctx->TriangleCaps |= DD_SELECT; 526 if (ctx->Select.BufferSize==0) { 527 /* haven't called glSelectBuffer yet */ 528 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); 529 } 530 break; 531 case GL_FEEDBACK: 532 ctx->TriangleCaps |= DD_FEEDBACK; 533 if (ctx->Feedback.BufferSize==0) { 534 /* haven't called glFeedbackBuffer yet */ 535 gl_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); 536 } 537 break; 538 default: 539 gl_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); 540 return 0; 541 } 542 543 ctx->RenderMode = mode; 544 ctx->NewState |= _NEW_RENDERMODE; 545 546 return result; 547} 548 549