source: trunk/src/opengl/mesa/feedback.c

Last change on this file was 3598, checked in by jeroen, 25 years ago

* empty log message *

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