From 807c6931fe683fd844ceec1b023232181e6aae03 Mon Sep 17 00:00:00 2001 From: marha Date: Tue, 28 Dec 2010 16:10:20 +0000 Subject: xserver and mesa git update 28-12-2010 --- mesalib/src/mesa/main/feedback.c | 1082 +++++++++++++++++++------------------- 1 file changed, 541 insertions(+), 541 deletions(-) (limited to 'mesalib/src/mesa/main/feedback.c') diff --git a/mesalib/src/mesa/main/feedback.c b/mesalib/src/mesa/main/feedback.c index c72b91280..5ce0880c2 100644 --- a/mesalib/src/mesa/main/feedback.c +++ b/mesalib/src/mesa/main/feedback.c @@ -1,541 +1,541 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file feedback.c - * Selection and feedback modes functions. - */ - - -#include "glheader.h" -#include "colormac.h" -#include "context.h" -#include "enums.h" -#include "feedback.h" -#include "macros.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -#if FEATURE_feedback - - -#define FB_3D 0x01 -#define FB_4D 0x02 -#define FB_COLOR 0x04 -#define FB_TEXTURE 0X08 - - - -static void GLAPIENTRY -_mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode==GL_FEEDBACK) { - _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" ); - return; - } - if (size<0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" ); - return; - } - if (!buffer) { - _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" ); - ctx->Feedback.BufferSize = 0; - return; - } - - switch (type) { - case GL_2D: - ctx->Feedback._Mask = 0; - break; - case GL_3D: - ctx->Feedback._Mask = FB_3D; - break; - case GL_3D_COLOR: - ctx->Feedback._Mask = (FB_3D | FB_COLOR); - break; - case GL_3D_COLOR_TEXTURE: - ctx->Feedback._Mask = (FB_3D | FB_COLOR | FB_TEXTURE); - break; - case GL_4D_COLOR_TEXTURE: - ctx->Feedback._Mask = (FB_3D | FB_4D | FB_COLOR | FB_TEXTURE); - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" ); - return; - } - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */ - ctx->Feedback.Type = type; - ctx->Feedback.BufferSize = size; - ctx->Feedback.Buffer = buffer; - ctx->Feedback.Count = 0; /* Becaues of this. */ -} - - -static void GLAPIENTRY -_mesa_PassThrough( GLfloat token ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode==GL_FEEDBACK) { - FLUSH_VERTICES(ctx, 0); - _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN ); - _mesa_feedback_token( ctx, token ); - } -} - - -/** - * Put a vertex into the feedback buffer. - */ -void -_mesa_feedback_vertex(GLcontext *ctx, - const GLfloat win[4], - const GLfloat color[4], - const GLfloat texcoord[4]) -{ - _mesa_feedback_token( ctx, win[0] ); - _mesa_feedback_token( ctx, win[1] ); - if (ctx->Feedback._Mask & FB_3D) { - _mesa_feedback_token( ctx, win[2] ); - } - if (ctx->Feedback._Mask & FB_4D) { - _mesa_feedback_token( ctx, win[3] ); - } - if (ctx->Feedback._Mask & FB_COLOR) { - _mesa_feedback_token( ctx, color[0] ); - _mesa_feedback_token( ctx, color[1] ); - _mesa_feedback_token( ctx, color[2] ); - _mesa_feedback_token( ctx, color[3] ); - } - if (ctx->Feedback._Mask & FB_TEXTURE) { - _mesa_feedback_token( ctx, texcoord[0] ); - _mesa_feedback_token( ctx, texcoord[1] ); - _mesa_feedback_token( ctx, texcoord[2] ); - _mesa_feedback_token( ctx, texcoord[3] ); - } -} - - -/**********************************************************************/ -/** \name Selection */ -/*@{*/ - -/** - * Establish a buffer for selection mode values. - * - * \param size buffer size. - * \param buffer buffer. - * - * \sa glSelectBuffer(). - * - * \note this function can't be put in a display list. - * - * Verifies we're not in selection mode, flushes the vertices and initialize - * the fields in __GLcontextRec::Select with the given buffer. - */ -static void GLAPIENTRY -_mesa_SelectBuffer( GLsizei size, GLuint *buffer ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode==GL_SELECT) { - _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" ); - return; /* KW: added return */ - } - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - ctx->Select.Buffer = buffer; - ctx->Select.BufferSize = size; - ctx->Select.BufferCount = 0; - ctx->Select.HitFlag = GL_FALSE; - ctx->Select.HitMinZ = 1.0; - ctx->Select.HitMaxZ = 0.0; -} - - -/** - * Write a value of a record into the selection buffer. - * - * \param ctx GL context. - * \param value value. - * - * Verifies there is free space in the buffer to write the value and - * increments the pointer. - */ -static INLINE void -write_record(GLcontext *ctx, GLuint value) -{ - if (ctx->Select.BufferCount < ctx->Select.BufferSize) { - ctx->Select.Buffer[ctx->Select.BufferCount] = value; - } - ctx->Select.BufferCount++; -} - - -/** - * Update the hit flag and the maximum and minimum depth values. - * - * \param ctx GL context. - * \param z depth. - * - * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and - * gl_selection::HitMaxZ. - */ -void -_mesa_update_hitflag(GLcontext *ctx, GLfloat z) -{ - ctx->Select.HitFlag = GL_TRUE; - if (z < ctx->Select.HitMinZ) { - ctx->Select.HitMinZ = z; - } - if (z > ctx->Select.HitMaxZ) { - ctx->Select.HitMaxZ = z; - } -} - - -/** - * Write the hit record. - * - * \param ctx GL context. - * - * Write the hit record, i.e., the number of names in the stack, the minimum and - * maximum depth values and the number of names in the name stack at the time - * of the event. Resets the hit flag. - * - * \sa gl_selection. - */ -static void -write_hit_record(GLcontext *ctx) -{ - GLuint i; - GLuint zmin, zmax, zscale = (~0u); - - /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */ - /* 2^32-1 and round to nearest unsigned integer. */ - - assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */ - zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ); - zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ); - - write_record( ctx, ctx->Select.NameStackDepth ); - write_record( ctx, zmin ); - write_record( ctx, zmax ); - for (i = 0; i < ctx->Select.NameStackDepth; i++) { - write_record( ctx, ctx->Select.NameStack[i] ); - } - - ctx->Select.Hits++; - ctx->Select.HitFlag = GL_FALSE; - ctx->Select.HitMinZ = 1.0; - ctx->Select.HitMaxZ = -1.0; -} - - -/** - * Initialize the name stack. - * - * Verifies we are in select mode and resets the name stack depth and resets - * the hit record data in gl_selection. Marks new render mode in - * __GLcontextRec::NewState. - */ -static void GLAPIENTRY -_mesa_InitNames( void ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - /* Record the hit before the HitFlag is wiped out again. */ - if (ctx->RenderMode == GL_SELECT) { - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } - } - ctx->Select.NameStackDepth = 0; - ctx->Select.HitFlag = GL_FALSE; - ctx->Select.HitMinZ = 1.0; - ctx->Select.HitMaxZ = 0.0; - ctx->NewState |= _NEW_RENDERMODE; -} - - -/** - * Load the top-most name of the name stack. - * - * \param name name. - * - * Verifies we are in selection mode and that the name stack is not empty. - * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), - * and replace the top-most name in the stack. - * - * sa __GLcontextRec::Select. - */ -static void GLAPIENTRY -_mesa_LoadName( GLuint name ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode != GL_SELECT) { - return; - } - if (ctx->Select.NameStackDepth == 0) { - _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" ); - return; - } - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } - if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) { - ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name; - } - else { - ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name; - } -} - - -/** - * Push a name into the name stack. - * - * \param name name. - * - * Verifies we are in selection mode and that the name stack is not full. - * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), - * and adds the name to the top of the name stack. - * - * sa __GLcontextRec::Select. - */ -static void GLAPIENTRY -_mesa_PushName( GLuint name ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode != GL_SELECT) { - return; - } - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } - if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) { - _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" ); - } - else - ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name; -} - - -/** - * Pop a name into the name stack. - * - * Verifies we are in selection mode and that the name stack is not empty. - * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), - * and removes top-most name in the name stack. - * - * sa __GLcontextRec::Select. - */ -static void GLAPIENTRY -_mesa_PopName( void ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->RenderMode != GL_SELECT) { - return; - } - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } - if (ctx->Select.NameStackDepth == 0) { - _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" ); - } - else - ctx->Select.NameStackDepth--; -} - -/*@}*/ - - -/**********************************************************************/ -/** \name Render Mode */ -/*@{*/ - -/** - * Set rasterization mode. - * - * \param mode rasterization mode. - * - * \note this function can't be put in a display list. - * - * \sa glRenderMode(). - * - * Flushes the vertices and do the necessary cleanup according to the previous - * rasterization mode, such as writing the hit record or resent the select - * buffer index when exiting the select mode. Updates - * __GLcontextRec::RenderMode and notifies the driver via the - * dd_function_table::RenderMode callback. - */ -static GLint GLAPIENTRY -_mesa_RenderMode( GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - GLint result; - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode)); - - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - - switch (ctx->RenderMode) { - case GL_RENDER: - result = 0; - break; - case GL_SELECT: - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } - if (ctx->Select.BufferCount > ctx->Select.BufferSize) { - /* overflow */ -#ifdef DEBUG - _mesa_warning(ctx, "Feedback buffer overflow"); -#endif - result = -1; - } - else { - result = ctx->Select.Hits; - } - ctx->Select.BufferCount = 0; - ctx->Select.Hits = 0; - ctx->Select.NameStackDepth = 0; - break; -#if _HAVE_FULL_GL - case GL_FEEDBACK: - if (ctx->Feedback.Count > ctx->Feedback.BufferSize) { - /* overflow */ - result = -1; - } - else { - result = ctx->Feedback.Count; - } - ctx->Feedback.Count = 0; - break; -#endif - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); - return 0; - } - - switch (mode) { - case GL_RENDER: - break; - case GL_SELECT: - if (ctx->Select.BufferSize==0) { - /* haven't called glSelectBuffer yet */ - _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); - } - break; -#if _HAVE_FULL_GL - case GL_FEEDBACK: - if (ctx->Feedback.BufferSize==0) { - /* haven't called glFeedbackBuffer yet */ - _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); - } - break; -#endif - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); - return 0; - } - - ctx->RenderMode = mode; - if (ctx->Driver.RenderMode) - ctx->Driver.RenderMode( ctx, mode ); - - return result; -} - -/*@}*/ - - -void -_mesa_init_feedback_dispatch(struct _glapi_table *disp) -{ - SET_InitNames(disp, _mesa_InitNames); - SET_FeedbackBuffer(disp, _mesa_FeedbackBuffer); - SET_LoadName(disp, _mesa_LoadName); - SET_PassThrough(disp, _mesa_PassThrough); - SET_PopName(disp, _mesa_PopName); - SET_PushName(disp, _mesa_PushName); - SET_SelectBuffer(disp, _mesa_SelectBuffer); - SET_RenderMode(disp, _mesa_RenderMode); -} - - -#endif /* FEATURE_feedback */ - - -/**********************************************************************/ -/** \name Initialization */ -/*@{*/ - -/** - * Initialize context feedback data. - */ -void _mesa_init_feedback( GLcontext * ctx ) -{ - /* Feedback */ - ctx->Feedback.Type = GL_2D; /* TODO: verify */ - ctx->Feedback.Buffer = NULL; - ctx->Feedback.BufferSize = 0; - ctx->Feedback.Count = 0; - - /* Selection/picking */ - ctx->Select.Buffer = NULL; - ctx->Select.BufferSize = 0; - ctx->Select.BufferCount = 0; - ctx->Select.Hits = 0; - ctx->Select.NameStackDepth = 0; - - /* Miscellaneous */ - ctx->RenderMode = GL_RENDER; -} - -/*@}*/ +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file feedback.c + * Selection and feedback modes functions. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "enums.h" +#include "feedback.h" +#include "macros.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +#if FEATURE_feedback + + +#define FB_3D 0x01 +#define FB_4D 0x02 +#define FB_COLOR 0x04 +#define FB_TEXTURE 0X08 + + + +static void GLAPIENTRY +_mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode==GL_FEEDBACK) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" ); + return; + } + if (size<0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" ); + return; + } + if (!buffer) { + _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" ); + ctx->Feedback.BufferSize = 0; + return; + } + + switch (type) { + case GL_2D: + ctx->Feedback._Mask = 0; + break; + case GL_3D: + ctx->Feedback._Mask = FB_3D; + break; + case GL_3D_COLOR: + ctx->Feedback._Mask = (FB_3D | FB_COLOR); + break; + case GL_3D_COLOR_TEXTURE: + ctx->Feedback._Mask = (FB_3D | FB_COLOR | FB_TEXTURE); + break; + case GL_4D_COLOR_TEXTURE: + ctx->Feedback._Mask = (FB_3D | FB_4D | FB_COLOR | FB_TEXTURE); + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" ); + return; + } + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */ + ctx->Feedback.Type = type; + ctx->Feedback.BufferSize = size; + ctx->Feedback.Buffer = buffer; + ctx->Feedback.Count = 0; /* Becaues of this. */ +} + + +static void GLAPIENTRY +_mesa_PassThrough( GLfloat token ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode==GL_FEEDBACK) { + FLUSH_VERTICES(ctx, 0); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN ); + _mesa_feedback_token( ctx, token ); + } +} + + +/** + * Put a vertex into the feedback buffer. + */ +void +_mesa_feedback_vertex(struct gl_context *ctx, + const GLfloat win[4], + const GLfloat color[4], + const GLfloat texcoord[4]) +{ + _mesa_feedback_token( ctx, win[0] ); + _mesa_feedback_token( ctx, win[1] ); + if (ctx->Feedback._Mask & FB_3D) { + _mesa_feedback_token( ctx, win[2] ); + } + if (ctx->Feedback._Mask & FB_4D) { + _mesa_feedback_token( ctx, win[3] ); + } + if (ctx->Feedback._Mask & FB_COLOR) { + _mesa_feedback_token( ctx, color[0] ); + _mesa_feedback_token( ctx, color[1] ); + _mesa_feedback_token( ctx, color[2] ); + _mesa_feedback_token( ctx, color[3] ); + } + if (ctx->Feedback._Mask & FB_TEXTURE) { + _mesa_feedback_token( ctx, texcoord[0] ); + _mesa_feedback_token( ctx, texcoord[1] ); + _mesa_feedback_token( ctx, texcoord[2] ); + _mesa_feedback_token( ctx, texcoord[3] ); + } +} + + +/**********************************************************************/ +/** \name Selection */ +/*@{*/ + +/** + * Establish a buffer for selection mode values. + * + * \param size buffer size. + * \param buffer buffer. + * + * \sa glSelectBuffer(). + * + * \note this function can't be put in a display list. + * + * Verifies we're not in selection mode, flushes the vertices and initialize + * the fields in __struct gl_contextRec::Select with the given buffer. + */ +static void GLAPIENTRY +_mesa_SelectBuffer( GLsizei size, GLuint *buffer ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode==GL_SELECT) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" ); + return; /* KW: added return */ + } + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + ctx->Select.Buffer = buffer; + ctx->Select.BufferSize = size; + ctx->Select.BufferCount = 0; + ctx->Select.HitFlag = GL_FALSE; + ctx->Select.HitMinZ = 1.0; + ctx->Select.HitMaxZ = 0.0; +} + + +/** + * Write a value of a record into the selection buffer. + * + * \param ctx GL context. + * \param value value. + * + * Verifies there is free space in the buffer to write the value and + * increments the pointer. + */ +static INLINE void +write_record(struct gl_context *ctx, GLuint value) +{ + if (ctx->Select.BufferCount < ctx->Select.BufferSize) { + ctx->Select.Buffer[ctx->Select.BufferCount] = value; + } + ctx->Select.BufferCount++; +} + + +/** + * Update the hit flag and the maximum and minimum depth values. + * + * \param ctx GL context. + * \param z depth. + * + * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and + * gl_selection::HitMaxZ. + */ +void +_mesa_update_hitflag(struct gl_context *ctx, GLfloat z) +{ + ctx->Select.HitFlag = GL_TRUE; + if (z < ctx->Select.HitMinZ) { + ctx->Select.HitMinZ = z; + } + if (z > ctx->Select.HitMaxZ) { + ctx->Select.HitMaxZ = z; + } +} + + +/** + * Write the hit record. + * + * \param ctx GL context. + * + * Write the hit record, i.e., the number of names in the stack, the minimum and + * maximum depth values and the number of names in the name stack at the time + * of the event. Resets the hit flag. + * + * \sa gl_selection. + */ +static void +write_hit_record(struct gl_context *ctx) +{ + GLuint i; + GLuint zmin, zmax, zscale = (~0u); + + /* HitMinZ and HitMaxZ are in [0,1]. Multiply these values by */ + /* 2^32-1 and round to nearest unsigned integer. */ + + assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */ + zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ); + zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ); + + write_record( ctx, ctx->Select.NameStackDepth ); + write_record( ctx, zmin ); + write_record( ctx, zmax ); + for (i = 0; i < ctx->Select.NameStackDepth; i++) { + write_record( ctx, ctx->Select.NameStack[i] ); + } + + ctx->Select.Hits++; + ctx->Select.HitFlag = GL_FALSE; + ctx->Select.HitMinZ = 1.0; + ctx->Select.HitMaxZ = -1.0; +} + + +/** + * Initialize the name stack. + * + * Verifies we are in select mode and resets the name stack depth and resets + * the hit record data in gl_selection. Marks new render mode in + * __struct gl_contextRec::NewState. + */ +static void GLAPIENTRY +_mesa_InitNames( void ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + /* Record the hit before the HitFlag is wiped out again. */ + if (ctx->RenderMode == GL_SELECT) { + if (ctx->Select.HitFlag) { + write_hit_record( ctx ); + } + } + ctx->Select.NameStackDepth = 0; + ctx->Select.HitFlag = GL_FALSE; + ctx->Select.HitMinZ = 1.0; + ctx->Select.HitMaxZ = 0.0; + ctx->NewState |= _NEW_RENDERMODE; +} + + +/** + * Load the top-most name of the name stack. + * + * \param name name. + * + * Verifies we are in selection mode and that the name stack is not empty. + * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), + * and replace the top-most name in the stack. + * + * sa __struct gl_contextRec::Select. + */ +static void GLAPIENTRY +_mesa_LoadName( GLuint name ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode != GL_SELECT) { + return; + } + if (ctx->Select.NameStackDepth == 0) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" ); + return; + } + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + + if (ctx->Select.HitFlag) { + write_hit_record( ctx ); + } + if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) { + ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name; + } + else { + ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name; + } +} + + +/** + * Push a name into the name stack. + * + * \param name name. + * + * Verifies we are in selection mode and that the name stack is not full. + * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), + * and adds the name to the top of the name stack. + * + * sa __struct gl_contextRec::Select. + */ +static void GLAPIENTRY +_mesa_PushName( GLuint name ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode != GL_SELECT) { + return; + } + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + if (ctx->Select.HitFlag) { + write_hit_record( ctx ); + } + if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) { + _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" ); + } + else + ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name; +} + + +/** + * Pop a name into the name stack. + * + * Verifies we are in selection mode and that the name stack is not empty. + * Flushes vertices. If there is a hit flag writes it (via write_hit_record()), + * and removes top-most name in the name stack. + * + * sa __struct gl_contextRec::Select. + */ +static void GLAPIENTRY +_mesa_PopName( void ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->RenderMode != GL_SELECT) { + return; + } + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + if (ctx->Select.HitFlag) { + write_hit_record( ctx ); + } + if (ctx->Select.NameStackDepth == 0) { + _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" ); + } + else + ctx->Select.NameStackDepth--; +} + +/*@}*/ + + +/**********************************************************************/ +/** \name Render Mode */ +/*@{*/ + +/** + * Set rasterization mode. + * + * \param mode rasterization mode. + * + * \note this function can't be put in a display list. + * + * \sa glRenderMode(). + * + * Flushes the vertices and do the necessary cleanup according to the previous + * rasterization mode, such as writing the hit record or resent the select + * buffer index when exiting the select mode. Updates + * __struct gl_contextRec::RenderMode and notifies the driver via the + * dd_function_table::RenderMode callback. + */ +static GLint GLAPIENTRY +_mesa_RenderMode( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint result; + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode)); + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + + switch (ctx->RenderMode) { + case GL_RENDER: + result = 0; + break; + case GL_SELECT: + if (ctx->Select.HitFlag) { + write_hit_record( ctx ); + } + if (ctx->Select.BufferCount > ctx->Select.BufferSize) { + /* overflow */ +#ifdef DEBUG + _mesa_warning(ctx, "Feedback buffer overflow"); +#endif + result = -1; + } + else { + result = ctx->Select.Hits; + } + ctx->Select.BufferCount = 0; + ctx->Select.Hits = 0; + ctx->Select.NameStackDepth = 0; + break; +#if _HAVE_FULL_GL + case GL_FEEDBACK: + if (ctx->Feedback.Count > ctx->Feedback.BufferSize) { + /* overflow */ + result = -1; + } + else { + result = ctx->Feedback.Count; + } + ctx->Feedback.Count = 0; + break; +#endif + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); + return 0; + } + + switch (mode) { + case GL_RENDER: + break; + case GL_SELECT: + if (ctx->Select.BufferSize==0) { + /* haven't called glSelectBuffer yet */ + _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); + } + break; +#if _HAVE_FULL_GL + case GL_FEEDBACK: + if (ctx->Feedback.BufferSize==0) { + /* haven't called glFeedbackBuffer yet */ + _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); + } + break; +#endif + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); + return 0; + } + + ctx->RenderMode = mode; + if (ctx->Driver.RenderMode) + ctx->Driver.RenderMode( ctx, mode ); + + return result; +} + +/*@}*/ + + +void +_mesa_init_feedback_dispatch(struct _glapi_table *disp) +{ + SET_InitNames(disp, _mesa_InitNames); + SET_FeedbackBuffer(disp, _mesa_FeedbackBuffer); + SET_LoadName(disp, _mesa_LoadName); + SET_PassThrough(disp, _mesa_PassThrough); + SET_PopName(disp, _mesa_PopName); + SET_PushName(disp, _mesa_PushName); + SET_SelectBuffer(disp, _mesa_SelectBuffer); + SET_RenderMode(disp, _mesa_RenderMode); +} + + +#endif /* FEATURE_feedback */ + + +/**********************************************************************/ +/** \name Initialization */ +/*@{*/ + +/** + * Initialize context feedback data. + */ +void _mesa_init_feedback( struct gl_context * ctx ) +{ + /* Feedback */ + ctx->Feedback.Type = GL_2D; /* TODO: verify */ + ctx->Feedback.Buffer = NULL; + ctx->Feedback.BufferSize = 0; + ctx->Feedback.Count = 0; + + /* Selection/picking */ + ctx->Select.Buffer = NULL; + ctx->Select.BufferSize = 0; + ctx->Select.BufferCount = 0; + ctx->Select.Hits = 0; + ctx->Select.NameStackDepth = 0; + + /* Miscellaneous */ + ctx->RenderMode = GL_RENDER; +} + +/*@}*/ -- cgit v1.2.3