17117f1b4Smrg/** 27117f1b4Smrg * \file polygon.c 37117f1b4Smrg * Polygon operations. 47117f1b4Smrg */ 57117f1b4Smrg 67117f1b4Smrg/* 77117f1b4Smrg * Mesa 3-D graphics library 87117f1b4Smrg * 97117f1b4Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 107117f1b4Smrg * 117117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 127117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 137117f1b4Smrg * to deal in the Software without restriction, including without limitation 147117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 157117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 167117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 177117f1b4Smrg * 187117f1b4Smrg * The above copyright notice and this permission notice shall be included 197117f1b4Smrg * in all copies or substantial portions of the Software. 207117f1b4Smrg * 217117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 227117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 237117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 287117f1b4Smrg */ 297117f1b4Smrg 307117f1b4Smrg 317117f1b4Smrg#include "glheader.h" 327ec681f3Smrg 337117f1b4Smrg#include "context.h" 347ec681f3Smrg#include "draw_validate.h" 357117f1b4Smrg#include "image.h" 367117f1b4Smrg#include "enums.h" 373464ebd5Sriastradh#include "pack.h" 383464ebd5Sriastradh#include "pbo.h" 397117f1b4Smrg#include "polygon.h" 407117f1b4Smrg#include "mtypes.h" 417117f1b4Smrg 427117f1b4Smrg 437117f1b4Smrg/** 447117f1b4Smrg * Specify whether to cull front- or back-facing facets. 457117f1b4Smrg * 467117f1b4Smrg * \param mode culling mode. 477117f1b4Smrg * 487117f1b4Smrg * \sa glCullFace(). 497117f1b4Smrg * 507117f1b4Smrg * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On 517117f1b4Smrg * change, flushes the vertices and notifies the driver via 527117f1b4Smrg * the dd_function_table::CullFace callback. 537117f1b4Smrg */ 5401e04c3fSmrgstatic ALWAYS_INLINE void 5501e04c3fSmrgcull_face(struct gl_context *ctx, GLenum mode, bool no_error) 567117f1b4Smrg{ 5701e04c3fSmrg if (ctx->Polygon.CullFaceMode == mode) 587117f1b4Smrg return; 597117f1b4Smrg 6001e04c3fSmrg if (!no_error && 6101e04c3fSmrg mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) { 6201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace"); 637117f1b4Smrg return; 6401e04c3fSmrg } 657117f1b4Smrg 667ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 677ec681f3Smrg GL_POLYGON_BIT); 6801e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 697117f1b4Smrg ctx->Polygon.CullFaceMode = mode; 707117f1b4Smrg 717117f1b4Smrg if (ctx->Driver.CullFace) 7201e04c3fSmrg ctx->Driver.CullFace(ctx, mode); 7301e04c3fSmrg} 7401e04c3fSmrg 7501e04c3fSmrg 7601e04c3fSmrgvoid GLAPIENTRY 7701e04c3fSmrg_mesa_CullFace_no_error(GLenum mode) 7801e04c3fSmrg{ 7901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 8001e04c3fSmrg cull_face(ctx, mode, true); 8101e04c3fSmrg} 8201e04c3fSmrg 8301e04c3fSmrg 8401e04c3fSmrgvoid GLAPIENTRY 8501e04c3fSmrg_mesa_CullFace(GLenum mode) 8601e04c3fSmrg{ 8701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 8801e04c3fSmrg 8901e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 9001e04c3fSmrg _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode)); 9101e04c3fSmrg 9201e04c3fSmrg cull_face(ctx, mode, false); 937117f1b4Smrg} 947117f1b4Smrg 957117f1b4Smrg 967117f1b4Smrg/** 9701e04c3fSmrg * Define front- and back-facing 987117f1b4Smrg * 997117f1b4Smrg * \param mode orientation of front-facing polygons. 1007117f1b4Smrg * 1017117f1b4Smrg * \sa glFrontFace(). 1027117f1b4Smrg * 1037117f1b4Smrg * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change 1047117f1b4Smrg * flushes the vertices and notifies the driver via 1057117f1b4Smrg * the dd_function_table::FrontFace callback. 1067117f1b4Smrg */ 10701e04c3fSmrgstatic ALWAYS_INLINE void 10801e04c3fSmrgfront_face(struct gl_context *ctx, GLenum mode, bool no_error) 1097117f1b4Smrg{ 11001e04c3fSmrg if (ctx->Polygon.FrontFace == mode) 1117117f1b4Smrg return; 1127117f1b4Smrg 11301e04c3fSmrg if (!no_error && mode != GL_CW && mode != GL_CCW) { 11401e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace"); 1157117f1b4Smrg return; 11601e04c3fSmrg } 1177117f1b4Smrg 1187ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 1197ec681f3Smrg GL_POLYGON_BIT); 12001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 1217117f1b4Smrg ctx->Polygon.FrontFace = mode; 1227117f1b4Smrg 1237117f1b4Smrg if (ctx->Driver.FrontFace) 12401e04c3fSmrg ctx->Driver.FrontFace(ctx, mode); 12501e04c3fSmrg} 12601e04c3fSmrg 12701e04c3fSmrg 12801e04c3fSmrgvoid GLAPIENTRY 12901e04c3fSmrg_mesa_FrontFace_no_error(GLenum mode) 13001e04c3fSmrg{ 13101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 13201e04c3fSmrg front_face(ctx, mode, true); 13301e04c3fSmrg} 13401e04c3fSmrg 13501e04c3fSmrg 13601e04c3fSmrgvoid GLAPIENTRY 13701e04c3fSmrg_mesa_FrontFace(GLenum mode) 13801e04c3fSmrg{ 13901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 14001e04c3fSmrg 14101e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 14201e04c3fSmrg _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode)); 14301e04c3fSmrg 14401e04c3fSmrg front_face(ctx, mode, false); 1457117f1b4Smrg} 1467117f1b4Smrg 1477117f1b4Smrg 1487117f1b4Smrg/** 1497117f1b4Smrg * Set the polygon rasterization mode. 1507117f1b4Smrg * 1517117f1b4Smrg * \param face the polygons which \p mode applies to. 1527117f1b4Smrg * \param mode how polygons should be rasterized. 1537117f1b4Smrg * 15401e04c3fSmrg * \sa glPolygonMode(). 15501e04c3fSmrg * 1567117f1b4Smrg * Verifies the parameters and updates gl_polygon_attrib::FrontMode and 1577117f1b4Smrg * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the 1587117f1b4Smrg * driver via the dd_function_table::PolygonMode callback. 1597117f1b4Smrg */ 16001e04c3fSmrgstatic ALWAYS_INLINE void 16101e04c3fSmrgpolygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error) 1627117f1b4Smrg{ 1637ec681f3Smrg bool old_mode_has_fill_rectangle = 1647ec681f3Smrg ctx->Polygon.FrontMode == GL_FILL_RECTANGLE_NV || 1657ec681f3Smrg ctx->Polygon.BackMode == GL_FILL_RECTANGLE_NV; 1667ec681f3Smrg 16701e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 1687117f1b4Smrg _mesa_debug(ctx, "glPolygonMode %s %s\n", 16901e04c3fSmrg _mesa_enum_to_string(face), 17001e04c3fSmrg _mesa_enum_to_string(mode)); 17101e04c3fSmrg 17201e04c3fSmrg if (!no_error) { 17301e04c3fSmrg switch (mode) { 17401e04c3fSmrg case GL_POINT: 17501e04c3fSmrg case GL_LINE: 17601e04c3fSmrg case GL_FILL: 17701e04c3fSmrg break; 17801e04c3fSmrg case GL_FILL_RECTANGLE_NV: 17901e04c3fSmrg if (ctx->Extensions.NV_fill_rectangle) 18001e04c3fSmrg break; 1817ec681f3Smrg FALLTHROUGH; 18201e04c3fSmrg default: 18301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)"); 18401e04c3fSmrg return; 18501e04c3fSmrg } 1867117f1b4Smrg } 1877117f1b4Smrg 1887117f1b4Smrg switch (face) { 1897117f1b4Smrg case GL_FRONT: 19001e04c3fSmrg if (!no_error && ctx->API == API_OPENGL_CORE) { 191af69d88dSmrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 192af69d88dSmrg return; 193af69d88dSmrg } 1947117f1b4Smrg if (ctx->Polygon.FrontMode == mode) 19501e04c3fSmrg return; 1967ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 1977ec681f3Smrg GL_POLYGON_BIT); 19801e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 1997117f1b4Smrg ctx->Polygon.FrontMode = mode; 2007117f1b4Smrg break; 2017117f1b4Smrg case GL_FRONT_AND_BACK: 20201e04c3fSmrg if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode) 20301e04c3fSmrg return; 2047ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 2057ec681f3Smrg GL_POLYGON_BIT); 20601e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 2077117f1b4Smrg ctx->Polygon.FrontMode = mode; 2087117f1b4Smrg ctx->Polygon.BackMode = mode; 2097117f1b4Smrg break; 2107117f1b4Smrg case GL_BACK: 21101e04c3fSmrg if (!no_error && ctx->API == API_OPENGL_CORE) { 212af69d88dSmrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 213af69d88dSmrg return; 214af69d88dSmrg } 2157117f1b4Smrg if (ctx->Polygon.BackMode == mode) 21601e04c3fSmrg return; 2177ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 2187ec681f3Smrg GL_POLYGON_BIT); 21901e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 2207117f1b4Smrg ctx->Polygon.BackMode = mode; 2217117f1b4Smrg break; 2227117f1b4Smrg default: 22301e04c3fSmrg if (!no_error) 22401e04c3fSmrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 2257117f1b4Smrg return; 2267117f1b4Smrg } 2277117f1b4Smrg 2287117f1b4Smrg if (ctx->Driver.PolygonMode) 2297117f1b4Smrg ctx->Driver.PolygonMode(ctx, face, mode); 2307ec681f3Smrg 2317ec681f3Smrg if (ctx->Extensions.INTEL_conservative_rasterization || 2327ec681f3Smrg (mode == GL_FILL_RECTANGLE_NV || old_mode_has_fill_rectangle)) 2337ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 2347117f1b4Smrg} 2357117f1b4Smrg 2367117f1b4Smrg 23701e04c3fSmrgvoid GLAPIENTRY 23801e04c3fSmrg_mesa_PolygonMode_no_error(GLenum face, GLenum mode) 2397117f1b4Smrg{ 24001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 24101e04c3fSmrg polygon_mode(ctx, face, mode, true); 24201e04c3fSmrg} 2434a49301eSmrg 2444a49301eSmrg 24501e04c3fSmrgvoid GLAPIENTRY 24601e04c3fSmrg_mesa_PolygonMode(GLenum face, GLenum mode) 24701e04c3fSmrg{ 24801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 24901e04c3fSmrg polygon_mode(ctx, face, mode, false); 2507117f1b4Smrg} 2517117f1b4Smrg 2527117f1b4Smrg 2537117f1b4Smrg/** 2547117f1b4Smrg * Called by glPolygonStipple. 2557117f1b4Smrg */ 2567117f1b4Smrgvoid GLAPIENTRY 25701e04c3fSmrg_mesa_PolygonStipple(const GLubyte *pattern) 2587117f1b4Smrg{ 2597117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2607117f1b4Smrg 26101e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 2627117f1b4Smrg _mesa_debug(ctx, "glPolygonStipple\n"); 2637117f1b4Smrg 26401e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 : 2657ec681f3Smrg _NEW_POLYGONSTIPPLE, 2667ec681f3Smrg GL_POLYGON_STIPPLE_BIT); 26701e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple; 2687117f1b4Smrg 26901e04c3fSmrg pattern = _mesa_map_validate_pbo_source(ctx, 2, 27001e04c3fSmrg &ctx->Unpack, 32, 32, 1, 27101e04c3fSmrg GL_COLOR_INDEX, GL_BITMAP, 27201e04c3fSmrg INT_MAX, pattern, 27301e04c3fSmrg "glPolygonStipple"); 27401e04c3fSmrg if (!pattern) 27501e04c3fSmrg return; 27601e04c3fSmrg 27701e04c3fSmrg _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); 27801e04c3fSmrg 27901e04c3fSmrg _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 2807117f1b4Smrg 2817117f1b4Smrg if (ctx->Driver.PolygonStipple) 2827117f1b4Smrg ctx->Driver.PolygonStipple(ctx, pattern); 2837117f1b4Smrg} 2847117f1b4Smrg 2857117f1b4Smrg 2867117f1b4Smrg/** 2877117f1b4Smrg * Called by glPolygonStipple. 2887117f1b4Smrg */ 2897117f1b4Smrgvoid GLAPIENTRY 2903464ebd5Sriastradh_mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest ) 2917117f1b4Smrg{ 2927117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2937117f1b4Smrg 2947117f1b4Smrg if (MESA_VERBOSE&VERBOSE_API) 2957117f1b4Smrg _mesa_debug(ctx, "glGetPolygonStipple\n"); 2967117f1b4Smrg 2974a49301eSmrg dest = _mesa_map_validate_pbo_dest(ctx, 2, 2984a49301eSmrg &ctx->Pack, 32, 32, 1, 2993464ebd5Sriastradh GL_COLOR_INDEX, GL_BITMAP, 3003464ebd5Sriastradh bufSize, dest, "glGetPolygonStipple"); 3014a49301eSmrg if (!dest) 3024a49301eSmrg return; 3034a49301eSmrg 3044a49301eSmrg _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); 3054a49301eSmrg 3064a49301eSmrg _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 3077117f1b4Smrg} 3087117f1b4Smrg 3097117f1b4Smrg 3103464ebd5Sriastradhvoid GLAPIENTRY 3113464ebd5Sriastradh_mesa_GetPolygonStipple( GLubyte *dest ) 3123464ebd5Sriastradh{ 3133464ebd5Sriastradh _mesa_GetnPolygonStippleARB(INT_MAX, dest); 3143464ebd5Sriastradh} 3153464ebd5Sriastradh 31601e04c3fSmrgvoid 31701e04c3fSmrg_mesa_polygon_offset_clamp(struct gl_context *ctx, 31801e04c3fSmrg GLfloat factor, GLfloat units, GLfloat clamp) 3197117f1b4Smrg{ 3207117f1b4Smrg if (ctx->Polygon.OffsetFactor == factor && 32101e04c3fSmrg ctx->Polygon.OffsetUnits == units && 32201e04c3fSmrg ctx->Polygon.OffsetClamp == clamp) 3237117f1b4Smrg return; 3247117f1b4Smrg 3257ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON, 3267ec681f3Smrg GL_POLYGON_BIT); 32701e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 3287117f1b4Smrg ctx->Polygon.OffsetFactor = factor; 3297117f1b4Smrg ctx->Polygon.OffsetUnits = units; 33001e04c3fSmrg ctx->Polygon.OffsetClamp = clamp; 3317117f1b4Smrg 3327117f1b4Smrg if (ctx->Driver.PolygonOffset) 33301e04c3fSmrg ctx->Driver.PolygonOffset( ctx, factor, units, clamp ); 3347117f1b4Smrg} 3357117f1b4Smrg 3367117f1b4Smrgvoid GLAPIENTRY 33701e04c3fSmrg_mesa_PolygonOffset( GLfloat factor, GLfloat units ) 3387117f1b4Smrg{ 3397117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 34001e04c3fSmrg 34101e04c3fSmrg if (MESA_VERBOSE&VERBOSE_API) 34201e04c3fSmrg _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); 34301e04c3fSmrg 34401e04c3fSmrg _mesa_polygon_offset_clamp(ctx, factor, units, 0.0); 3457117f1b4Smrg} 3467117f1b4Smrg 34701e04c3fSmrgvoid GLAPIENTRY 34801e04c3fSmrg_mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp ) 34901e04c3fSmrg{ 35001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 35101e04c3fSmrg 35201e04c3fSmrg if (!ctx->Extensions.ARB_polygon_offset_clamp) { 35301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 35401e04c3fSmrg "unsupported function (%s) called", "glPolygonOffsetClamp"); 35501e04c3fSmrg return; 35601e04c3fSmrg } 3577117f1b4Smrg 35801e04c3fSmrg if (MESA_VERBOSE&VERBOSE_API) 35901e04c3fSmrg _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp); 36001e04c3fSmrg 36101e04c3fSmrg _mesa_polygon_offset_clamp(ctx, factor, units, clamp); 36201e04c3fSmrg} 3637117f1b4Smrg 3647117f1b4Smrg/**********************************************************************/ 3657117f1b4Smrg/** \name Initialization */ 3667117f1b4Smrg/*@{*/ 3677117f1b4Smrg 3687117f1b4Smrg/** 3697117f1b4Smrg * Initialize the context polygon state. 3707117f1b4Smrg * 3717117f1b4Smrg * \param ctx GL context. 3727117f1b4Smrg * 3733464ebd5Sriastradh * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple 3747117f1b4Smrg * attribute groups. 3757117f1b4Smrg */ 3763464ebd5Sriastradhvoid _mesa_init_polygon( struct gl_context * ctx ) 3777117f1b4Smrg{ 3787117f1b4Smrg /* Polygon group */ 3797117f1b4Smrg ctx->Polygon.CullFlag = GL_FALSE; 3807117f1b4Smrg ctx->Polygon.CullFaceMode = GL_BACK; 3817117f1b4Smrg ctx->Polygon.FrontFace = GL_CCW; 3827117f1b4Smrg ctx->Polygon.FrontMode = GL_FILL; 3837117f1b4Smrg ctx->Polygon.BackMode = GL_FILL; 3847117f1b4Smrg ctx->Polygon.SmoothFlag = GL_FALSE; 3857117f1b4Smrg ctx->Polygon.StippleFlag = GL_FALSE; 3867117f1b4Smrg ctx->Polygon.OffsetFactor = 0.0F; 3877117f1b4Smrg ctx->Polygon.OffsetUnits = 0.0F; 38801e04c3fSmrg ctx->Polygon.OffsetClamp = 0.0F; 3897117f1b4Smrg ctx->Polygon.OffsetPoint = GL_FALSE; 3907117f1b4Smrg ctx->Polygon.OffsetLine = GL_FALSE; 3917117f1b4Smrg ctx->Polygon.OffsetFill = GL_FALSE; 3927117f1b4Smrg 3937117f1b4Smrg 3947117f1b4Smrg /* Polygon Stipple group */ 395cdc920a0Smrg memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); 3967117f1b4Smrg} 3977117f1b4Smrg 3987117f1b4Smrg/*@}*/ 399