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