feedback.c revision 7117f1b4
17117f1b4Smrg/**
27117f1b4Smrg * \file feedback.c
37117f1b4Smrg * Selection and feedback modes functions.
47117f1b4Smrg */
57117f1b4Smrg
67117f1b4Smrg/*
77117f1b4Smrg * Mesa 3-D graphics library
87117f1b4Smrg * Version:  5.1
97117f1b4Smrg *
107117f1b4Smrg * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
117117f1b4Smrg *
127117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
137117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
147117f1b4Smrg * to deal in the Software without restriction, including without limitation
157117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
167117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
177117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
187117f1b4Smrg *
197117f1b4Smrg * The above copyright notice and this permission notice shall be included
207117f1b4Smrg * in all copies or substantial portions of the Software.
217117f1b4Smrg *
227117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
237117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
247117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
257117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
267117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
277117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
287117f1b4Smrg */
297117f1b4Smrg
307117f1b4Smrg
317117f1b4Smrg#include "glheader.h"
327117f1b4Smrg#include "colormac.h"
337117f1b4Smrg#include "context.h"
347117f1b4Smrg#include "enums.h"
357117f1b4Smrg#include "feedback.h"
367117f1b4Smrg#include "macros.h"
377117f1b4Smrg#include "mtypes.h"
387117f1b4Smrg
397117f1b4Smrg
407117f1b4Smrg#if _HAVE_FULL_GL
417117f1b4Smrg
427117f1b4Smrg
437117f1b4Smrg#define FB_3D		0x01
447117f1b4Smrg#define FB_4D		0x02
457117f1b4Smrg#define FB_INDEX	0x04
467117f1b4Smrg#define FB_COLOR	0x08
477117f1b4Smrg#define FB_TEXTURE	0X10
487117f1b4Smrg
497117f1b4Smrg
507117f1b4Smrg
517117f1b4Smrgvoid GLAPIENTRY
527117f1b4Smrg_mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
537117f1b4Smrg{
547117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
557117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
567117f1b4Smrg
577117f1b4Smrg   if (ctx->RenderMode==GL_FEEDBACK) {
587117f1b4Smrg      _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
597117f1b4Smrg      return;
607117f1b4Smrg   }
617117f1b4Smrg   if (size<0) {
627117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
637117f1b4Smrg      return;
647117f1b4Smrg   }
657117f1b4Smrg   if (!buffer) {
667117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
677117f1b4Smrg      ctx->Feedback.BufferSize = 0;
687117f1b4Smrg      return;
697117f1b4Smrg   }
707117f1b4Smrg
717117f1b4Smrg   switch (type) {
727117f1b4Smrg      case GL_2D:
737117f1b4Smrg	 ctx->Feedback._Mask = 0;
747117f1b4Smrg	 break;
757117f1b4Smrg      case GL_3D:
767117f1b4Smrg	 ctx->Feedback._Mask = FB_3D;
777117f1b4Smrg	 break;
787117f1b4Smrg      case GL_3D_COLOR:
797117f1b4Smrg	 ctx->Feedback._Mask = (FB_3D |
807117f1b4Smrg				(ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX));
817117f1b4Smrg	 break;
827117f1b4Smrg      case GL_3D_COLOR_TEXTURE:
837117f1b4Smrg	 ctx->Feedback._Mask = (FB_3D |
847117f1b4Smrg				(ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX) |
857117f1b4Smrg				FB_TEXTURE);
867117f1b4Smrg	 break;
877117f1b4Smrg      case GL_4D_COLOR_TEXTURE:
887117f1b4Smrg	 ctx->Feedback._Mask = (FB_3D | FB_4D |
897117f1b4Smrg				(ctx->Visual.rgbMode ? FB_COLOR : FB_INDEX) |
907117f1b4Smrg				FB_TEXTURE);
917117f1b4Smrg	 break;
927117f1b4Smrg      default:
937117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
947117f1b4Smrg	 return;
957117f1b4Smrg   }
967117f1b4Smrg
977117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */
987117f1b4Smrg   ctx->Feedback.Type = type;
997117f1b4Smrg   ctx->Feedback.BufferSize = size;
1007117f1b4Smrg   ctx->Feedback.Buffer = buffer;
1017117f1b4Smrg   ctx->Feedback.Count = 0;	              /* Becaues of this. */
1027117f1b4Smrg}
1037117f1b4Smrg
1047117f1b4Smrg
1057117f1b4Smrgvoid GLAPIENTRY
1067117f1b4Smrg_mesa_PassThrough( GLfloat token )
1077117f1b4Smrg{
1087117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1097117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1107117f1b4Smrg
1117117f1b4Smrg   if (ctx->RenderMode==GL_FEEDBACK) {
1127117f1b4Smrg      FLUSH_VERTICES(ctx, 0);
1137117f1b4Smrg      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
1147117f1b4Smrg      FEEDBACK_TOKEN( ctx, token );
1157117f1b4Smrg   }
1167117f1b4Smrg}
1177117f1b4Smrg
1187117f1b4Smrg
1197117f1b4Smrg
1207117f1b4Smrg/*
1217117f1b4Smrg * Put a vertex into the feedback buffer.
1227117f1b4Smrg */
1237117f1b4Smrgvoid _mesa_feedback_vertex( GLcontext *ctx,
1247117f1b4Smrg                            const GLfloat win[4],
1257117f1b4Smrg                            const GLfloat color[4],
1267117f1b4Smrg                            GLfloat index,
1277117f1b4Smrg                            const GLfloat texcoord[4] )
1287117f1b4Smrg{
1297117f1b4Smrg#if 0
1307117f1b4Smrg   {
1317117f1b4Smrg      /* snap window x, y to fractional pixel position */
1327117f1b4Smrg      const GLint snapMask = ~((FIXED_ONE / (1 << SUB_PIXEL_BITS)) - 1);
1337117f1b4Smrg      GLfixed x, y;
1347117f1b4Smrg      x = FloatToFixed(win[0]) & snapMask;
1357117f1b4Smrg      y = FloatToFixed(win[1]) & snapMask;
1367117f1b4Smrg      FEEDBACK_TOKEN(ctx, FixedToFloat(x));
1377117f1b4Smrg      FEEDBACK_TOKEN(ctx, FixedToFloat(y) );
1387117f1b4Smrg   }
1397117f1b4Smrg#else
1407117f1b4Smrg   FEEDBACK_TOKEN( ctx, win[0] );
1417117f1b4Smrg   FEEDBACK_TOKEN( ctx, win[1] );
1427117f1b4Smrg#endif
1437117f1b4Smrg   if (ctx->Feedback._Mask & FB_3D) {
1447117f1b4Smrg      FEEDBACK_TOKEN( ctx, win[2] );
1457117f1b4Smrg   }
1467117f1b4Smrg   if (ctx->Feedback._Mask & FB_4D) {
1477117f1b4Smrg      FEEDBACK_TOKEN( ctx, win[3] );
1487117f1b4Smrg   }
1497117f1b4Smrg   if (ctx->Feedback._Mask & FB_INDEX) {
1507117f1b4Smrg      FEEDBACK_TOKEN( ctx, (GLfloat) index );
1517117f1b4Smrg   }
1527117f1b4Smrg   if (ctx->Feedback._Mask & FB_COLOR) {
1537117f1b4Smrg      FEEDBACK_TOKEN( ctx, color[0] );
1547117f1b4Smrg      FEEDBACK_TOKEN( ctx, color[1] );
1557117f1b4Smrg      FEEDBACK_TOKEN( ctx, color[2] );
1567117f1b4Smrg      FEEDBACK_TOKEN( ctx, color[3] );
1577117f1b4Smrg   }
1587117f1b4Smrg   if (ctx->Feedback._Mask & FB_TEXTURE) {
1597117f1b4Smrg      FEEDBACK_TOKEN( ctx, texcoord[0] );
1607117f1b4Smrg      FEEDBACK_TOKEN( ctx, texcoord[1] );
1617117f1b4Smrg      FEEDBACK_TOKEN( ctx, texcoord[2] );
1627117f1b4Smrg      FEEDBACK_TOKEN( ctx, texcoord[3] );
1637117f1b4Smrg   }
1647117f1b4Smrg}
1657117f1b4Smrg
1667117f1b4Smrg#endif
1677117f1b4Smrg
1687117f1b4Smrg
1697117f1b4Smrg/**********************************************************************/
1707117f1b4Smrg/** \name Selection */
1717117f1b4Smrg/*@{*/
1727117f1b4Smrg
1737117f1b4Smrg/**
1747117f1b4Smrg * Establish a buffer for selection mode values.
1757117f1b4Smrg *
1767117f1b4Smrg * \param size buffer size.
1777117f1b4Smrg * \param buffer buffer.
1787117f1b4Smrg *
1797117f1b4Smrg * \sa glSelectBuffer().
1807117f1b4Smrg *
1817117f1b4Smrg * \note this function can't be put in a display list.
1827117f1b4Smrg *
1837117f1b4Smrg * Verifies we're not in selection mode, flushes the vertices and initialize
1847117f1b4Smrg * the fields in __GLcontextRec::Select with the given buffer.
1857117f1b4Smrg */
1867117f1b4Smrgvoid GLAPIENTRY
1877117f1b4Smrg_mesa_SelectBuffer( GLsizei size, GLuint *buffer )
1887117f1b4Smrg{
1897117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1907117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1917117f1b4Smrg
1927117f1b4Smrg   if (ctx->RenderMode==GL_SELECT) {
1937117f1b4Smrg      _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
1947117f1b4Smrg      return;			/* KW: added return */
1957117f1b4Smrg   }
1967117f1b4Smrg
1977117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
1987117f1b4Smrg   ctx->Select.Buffer = buffer;
1997117f1b4Smrg   ctx->Select.BufferSize = size;
2007117f1b4Smrg   ctx->Select.BufferCount = 0;
2017117f1b4Smrg   ctx->Select.HitFlag = GL_FALSE;
2027117f1b4Smrg   ctx->Select.HitMinZ = 1.0;
2037117f1b4Smrg   ctx->Select.HitMaxZ = 0.0;
2047117f1b4Smrg}
2057117f1b4Smrg
2067117f1b4Smrg
2077117f1b4Smrg/**
2087117f1b4Smrg * Write a value of a record into the selection buffer.
2097117f1b4Smrg *
2107117f1b4Smrg * \param CTX GL context.
2117117f1b4Smrg * \param V value.
2127117f1b4Smrg *
2137117f1b4Smrg * Verifies there is free space in the buffer to write the value and
2147117f1b4Smrg * increments the pointer.
2157117f1b4Smrg */
2167117f1b4Smrg#define WRITE_RECORD( CTX, V )					\
2177117f1b4Smrg	if (CTX->Select.BufferCount < CTX->Select.BufferSize) {	\
2187117f1b4Smrg	   CTX->Select.Buffer[CTX->Select.BufferCount] = (V);	\
2197117f1b4Smrg	}							\
2207117f1b4Smrg	CTX->Select.BufferCount++;
2217117f1b4Smrg
2227117f1b4Smrg
2237117f1b4Smrg/**
2247117f1b4Smrg * Update the hit flag and the maximum and minimum depth values.
2257117f1b4Smrg *
2267117f1b4Smrg * \param ctx GL context.
2277117f1b4Smrg * \param z depth.
2287117f1b4Smrg *
2297117f1b4Smrg * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and
2307117f1b4Smrg * gl_selection::HitMaxZ.
2317117f1b4Smrg */
2327117f1b4Smrgvoid _mesa_update_hitflag( GLcontext *ctx, GLfloat z )
2337117f1b4Smrg{
2347117f1b4Smrg   ctx->Select.HitFlag = GL_TRUE;
2357117f1b4Smrg   if (z < ctx->Select.HitMinZ) {
2367117f1b4Smrg      ctx->Select.HitMinZ = z;
2377117f1b4Smrg   }
2387117f1b4Smrg   if (z > ctx->Select.HitMaxZ) {
2397117f1b4Smrg      ctx->Select.HitMaxZ = z;
2407117f1b4Smrg   }
2417117f1b4Smrg}
2427117f1b4Smrg
2437117f1b4Smrg
2447117f1b4Smrg/**
2457117f1b4Smrg * Write the hit record.
2467117f1b4Smrg *
2477117f1b4Smrg * \param ctx GL context.
2487117f1b4Smrg *
2497117f1b4Smrg * Write the hit record, i.e., the number of names in the stack, the minimum and
2507117f1b4Smrg * maximum depth values and the number of names in the name stack at the time
2517117f1b4Smrg * of the event. Resets the hit flag.
2527117f1b4Smrg *
2537117f1b4Smrg * \sa gl_selection.
2547117f1b4Smrg */
2557117f1b4Smrgstatic void write_hit_record( GLcontext *ctx )
2567117f1b4Smrg{
2577117f1b4Smrg   GLuint i;
2587117f1b4Smrg   GLuint zmin, zmax, zscale = (~0u);
2597117f1b4Smrg
2607117f1b4Smrg   /* HitMinZ and HitMaxZ are in [0,1].  Multiply these values by */
2617117f1b4Smrg   /* 2^32-1 and round to nearest unsigned integer. */
2627117f1b4Smrg
2637117f1b4Smrg   assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
2647117f1b4Smrg   zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
2657117f1b4Smrg   zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
2667117f1b4Smrg
2677117f1b4Smrg   WRITE_RECORD( ctx, ctx->Select.NameStackDepth );
2687117f1b4Smrg   WRITE_RECORD( ctx, zmin );
2697117f1b4Smrg   WRITE_RECORD( ctx, zmax );
2707117f1b4Smrg   for (i = 0; i < ctx->Select.NameStackDepth; i++) {
2717117f1b4Smrg      WRITE_RECORD( ctx, ctx->Select.NameStack[i] );
2727117f1b4Smrg   }
2737117f1b4Smrg
2747117f1b4Smrg   ctx->Select.Hits++;
2757117f1b4Smrg   ctx->Select.HitFlag = GL_FALSE;
2767117f1b4Smrg   ctx->Select.HitMinZ = 1.0;
2777117f1b4Smrg   ctx->Select.HitMaxZ = -1.0;
2787117f1b4Smrg}
2797117f1b4Smrg
2807117f1b4Smrg
2817117f1b4Smrg/**
2827117f1b4Smrg * Initialize the name stack.
2837117f1b4Smrg *
2847117f1b4Smrg * Verifies we are in select mode and resets the name stack depth and resets
2857117f1b4Smrg * the hit record data in gl_selection. Marks new render mode in
2867117f1b4Smrg * __GLcontextRec::NewState.
2877117f1b4Smrg */
2887117f1b4Smrgvoid GLAPIENTRY
2897117f1b4Smrg_mesa_InitNames( void )
2907117f1b4Smrg{
2917117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2927117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
2937117f1b4Smrg
2947117f1b4Smrg   /* Record the hit before the HitFlag is wiped out again. */
2957117f1b4Smrg   if (ctx->RenderMode == GL_SELECT) {
2967117f1b4Smrg      if (ctx->Select.HitFlag) {
2977117f1b4Smrg         write_hit_record( ctx );
2987117f1b4Smrg      }
2997117f1b4Smrg   }
3007117f1b4Smrg   ctx->Select.NameStackDepth = 0;
3017117f1b4Smrg   ctx->Select.HitFlag = GL_FALSE;
3027117f1b4Smrg   ctx->Select.HitMinZ = 1.0;
3037117f1b4Smrg   ctx->Select.HitMaxZ = 0.0;
3047117f1b4Smrg   ctx->NewState |= _NEW_RENDERMODE;
3057117f1b4Smrg}
3067117f1b4Smrg
3077117f1b4Smrg
3087117f1b4Smrg/**
3097117f1b4Smrg * Load the top-most name of the name stack.
3107117f1b4Smrg *
3117117f1b4Smrg * \param name name.
3127117f1b4Smrg *
3137117f1b4Smrg * Verifies we are in selection mode and that the name stack is not empty.
3147117f1b4Smrg * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
3157117f1b4Smrg * and replace the top-most name in the stack.
3167117f1b4Smrg *
3177117f1b4Smrg * sa __GLcontextRec::Select.
3187117f1b4Smrg */
3197117f1b4Smrgvoid GLAPIENTRY
3207117f1b4Smrg_mesa_LoadName( GLuint name )
3217117f1b4Smrg{
3227117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3237117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3247117f1b4Smrg
3257117f1b4Smrg   if (ctx->RenderMode != GL_SELECT) {
3267117f1b4Smrg      return;
3277117f1b4Smrg   }
3287117f1b4Smrg   if (ctx->Select.NameStackDepth == 0) {
3297117f1b4Smrg      _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
3307117f1b4Smrg      return;
3317117f1b4Smrg   }
3327117f1b4Smrg
3337117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
3347117f1b4Smrg
3357117f1b4Smrg   if (ctx->Select.HitFlag) {
3367117f1b4Smrg      write_hit_record( ctx );
3377117f1b4Smrg   }
3387117f1b4Smrg   if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
3397117f1b4Smrg      ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
3407117f1b4Smrg   }
3417117f1b4Smrg   else {
3427117f1b4Smrg      ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
3437117f1b4Smrg   }
3447117f1b4Smrg}
3457117f1b4Smrg
3467117f1b4Smrg
3477117f1b4Smrg/**
3487117f1b4Smrg * Push a name into the name stack.
3497117f1b4Smrg *
3507117f1b4Smrg * \param name name.
3517117f1b4Smrg *
3527117f1b4Smrg * Verifies we are in selection mode and that the name stack is not full.
3537117f1b4Smrg * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
3547117f1b4Smrg * and adds the name to the top of the name stack.
3557117f1b4Smrg *
3567117f1b4Smrg * sa __GLcontextRec::Select.
3577117f1b4Smrg */
3587117f1b4Smrgvoid GLAPIENTRY
3597117f1b4Smrg_mesa_PushName( GLuint name )
3607117f1b4Smrg{
3617117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3627117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3637117f1b4Smrg
3647117f1b4Smrg   if (ctx->RenderMode != GL_SELECT) {
3657117f1b4Smrg      return;
3667117f1b4Smrg   }
3677117f1b4Smrg
3687117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
3697117f1b4Smrg   if (ctx->Select.HitFlag) {
3707117f1b4Smrg      write_hit_record( ctx );
3717117f1b4Smrg   }
3727117f1b4Smrg   if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) {
3737117f1b4Smrg      _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
3747117f1b4Smrg   }
3757117f1b4Smrg   else
3767117f1b4Smrg      ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
3777117f1b4Smrg}
3787117f1b4Smrg
3797117f1b4Smrg
3807117f1b4Smrg/**
3817117f1b4Smrg * Pop a name into the name stack.
3827117f1b4Smrg *
3837117f1b4Smrg * Verifies we are in selection mode and that the name stack is not empty.
3847117f1b4Smrg * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
3857117f1b4Smrg * and removes top-most name in the name stack.
3867117f1b4Smrg *
3877117f1b4Smrg * sa __GLcontextRec::Select.
3887117f1b4Smrg */
3897117f1b4Smrgvoid GLAPIENTRY
3907117f1b4Smrg_mesa_PopName( void )
3917117f1b4Smrg{
3927117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3937117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3947117f1b4Smrg
3957117f1b4Smrg   if (ctx->RenderMode != GL_SELECT) {
3967117f1b4Smrg      return;
3977117f1b4Smrg   }
3987117f1b4Smrg
3997117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
4007117f1b4Smrg   if (ctx->Select.HitFlag) {
4017117f1b4Smrg      write_hit_record( ctx );
4027117f1b4Smrg   }
4037117f1b4Smrg   if (ctx->Select.NameStackDepth == 0) {
4047117f1b4Smrg      _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
4057117f1b4Smrg   }
4067117f1b4Smrg   else
4077117f1b4Smrg      ctx->Select.NameStackDepth--;
4087117f1b4Smrg}
4097117f1b4Smrg
4107117f1b4Smrg/*@}*/
4117117f1b4Smrg
4127117f1b4Smrg
4137117f1b4Smrg/**********************************************************************/
4147117f1b4Smrg/** \name Render Mode */
4157117f1b4Smrg/*@{*/
4167117f1b4Smrg
4177117f1b4Smrg/**
4187117f1b4Smrg * Set rasterization mode.
4197117f1b4Smrg *
4207117f1b4Smrg * \param mode rasterization mode.
4217117f1b4Smrg *
4227117f1b4Smrg * \note this function can't be put in a display list.
4237117f1b4Smrg *
4247117f1b4Smrg * \sa glRenderMode().
4257117f1b4Smrg *
4267117f1b4Smrg * Flushes the vertices and do the necessary cleanup according to the previous
4277117f1b4Smrg * rasterization mode, such as writing the hit record or resent the select
4287117f1b4Smrg * buffer index when exiting the select mode. Updates
4297117f1b4Smrg * __GLcontextRec::RenderMode and notifies the driver via the
4307117f1b4Smrg * dd_function_table::RenderMode callback.
4317117f1b4Smrg */
4327117f1b4SmrgGLint GLAPIENTRY
4337117f1b4Smrg_mesa_RenderMode( GLenum mode )
4347117f1b4Smrg{
4357117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4367117f1b4Smrg   GLint result;
4377117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
4387117f1b4Smrg
4397117f1b4Smrg   if (MESA_VERBOSE & VERBOSE_API)
4407117f1b4Smrg      _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode));
4417117f1b4Smrg
4427117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
4437117f1b4Smrg
4447117f1b4Smrg   switch (ctx->RenderMode) {
4457117f1b4Smrg      case GL_RENDER:
4467117f1b4Smrg	 result = 0;
4477117f1b4Smrg	 break;
4487117f1b4Smrg      case GL_SELECT:
4497117f1b4Smrg	 if (ctx->Select.HitFlag) {
4507117f1b4Smrg	    write_hit_record( ctx );
4517117f1b4Smrg	 }
4527117f1b4Smrg	 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
4537117f1b4Smrg	    /* overflow */
4547117f1b4Smrg#ifdef DEBUG
4557117f1b4Smrg            _mesa_warning(ctx, "Feedback buffer overflow");
4567117f1b4Smrg#endif
4577117f1b4Smrg	    result = -1;
4587117f1b4Smrg	 }
4597117f1b4Smrg	 else {
4607117f1b4Smrg	    result = ctx->Select.Hits;
4617117f1b4Smrg	 }
4627117f1b4Smrg	 ctx->Select.BufferCount = 0;
4637117f1b4Smrg	 ctx->Select.Hits = 0;
4647117f1b4Smrg	 ctx->Select.NameStackDepth = 0;
4657117f1b4Smrg	 break;
4667117f1b4Smrg#if _HAVE_FULL_GL
4677117f1b4Smrg      case GL_FEEDBACK:
4687117f1b4Smrg	 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
4697117f1b4Smrg	    /* overflow */
4707117f1b4Smrg	    result = -1;
4717117f1b4Smrg	 }
4727117f1b4Smrg	 else {
4737117f1b4Smrg	    result = ctx->Feedback.Count;
4747117f1b4Smrg	 }
4757117f1b4Smrg	 ctx->Feedback.Count = 0;
4767117f1b4Smrg	 break;
4777117f1b4Smrg#endif
4787117f1b4Smrg      default:
4797117f1b4Smrg	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
4807117f1b4Smrg	 return 0;
4817117f1b4Smrg   }
4827117f1b4Smrg
4837117f1b4Smrg   switch (mode) {
4847117f1b4Smrg      case GL_RENDER:
4857117f1b4Smrg         break;
4867117f1b4Smrg      case GL_SELECT:
4877117f1b4Smrg	 if (ctx->Select.BufferSize==0) {
4887117f1b4Smrg	    /* haven't called glSelectBuffer yet */
4897117f1b4Smrg	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
4907117f1b4Smrg	 }
4917117f1b4Smrg	 break;
4927117f1b4Smrg#if _HAVE_FULL_GL
4937117f1b4Smrg      case GL_FEEDBACK:
4947117f1b4Smrg	 if (ctx->Feedback.BufferSize==0) {
4957117f1b4Smrg	    /* haven't called glFeedbackBuffer yet */
4967117f1b4Smrg	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
4977117f1b4Smrg	 }
4987117f1b4Smrg	 break;
4997117f1b4Smrg#endif
5007117f1b4Smrg      default:
5017117f1b4Smrg	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
5027117f1b4Smrg	 return 0;
5037117f1b4Smrg   }
5047117f1b4Smrg
5057117f1b4Smrg   ctx->RenderMode = mode;
5067117f1b4Smrg   if (ctx->Driver.RenderMode)
5077117f1b4Smrg      ctx->Driver.RenderMode( ctx, mode );
5087117f1b4Smrg
5097117f1b4Smrg   return result;
5107117f1b4Smrg}
5117117f1b4Smrg
5127117f1b4Smrg/*@}*/
5137117f1b4Smrg
5147117f1b4Smrg
5157117f1b4Smrg/**********************************************************************/
5167117f1b4Smrg/** \name Initialization */
5177117f1b4Smrg/*@{*/
5187117f1b4Smrg
5197117f1b4Smrg/**
5207117f1b4Smrg * Initialize context feedback data.
5217117f1b4Smrg */
5227117f1b4Smrgvoid _mesa_init_feedback( GLcontext * ctx )
5237117f1b4Smrg{
5247117f1b4Smrg   /* Feedback */
5257117f1b4Smrg   ctx->Feedback.Type = GL_2D;   /* TODO: verify */
5267117f1b4Smrg   ctx->Feedback.Buffer = NULL;
5277117f1b4Smrg   ctx->Feedback.BufferSize = 0;
5287117f1b4Smrg   ctx->Feedback.Count = 0;
5297117f1b4Smrg
5307117f1b4Smrg   /* Selection/picking */
5317117f1b4Smrg   ctx->Select.Buffer = NULL;
5327117f1b4Smrg   ctx->Select.BufferSize = 0;
5337117f1b4Smrg   ctx->Select.BufferCount = 0;
5347117f1b4Smrg   ctx->Select.Hits = 0;
5357117f1b4Smrg   ctx->Select.NameStackDepth = 0;
5367117f1b4Smrg
5377117f1b4Smrg   /* Miscellaneous */
5387117f1b4Smrg   ctx->RenderMode = GL_RENDER;
5397117f1b4Smrg}
5407117f1b4Smrg
5417117f1b4Smrg/*@}*/
542