polygon.c revision 01e04c3f
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"
327117f1b4Smrg#include "imports.h"
337117f1b4Smrg#include "context.h"
347117f1b4Smrg#include "image.h"
357117f1b4Smrg#include "enums.h"
363464ebd5Sriastradh#include "pack.h"
373464ebd5Sriastradh#include "pbo.h"
387117f1b4Smrg#include "polygon.h"
397117f1b4Smrg#include "mtypes.h"
407117f1b4Smrg
417117f1b4Smrg
427117f1b4Smrg/**
437117f1b4Smrg * Specify whether to cull front- or back-facing facets.
447117f1b4Smrg *
457117f1b4Smrg * \param mode culling mode.
467117f1b4Smrg *
477117f1b4Smrg * \sa glCullFace().
487117f1b4Smrg *
497117f1b4Smrg * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On
507117f1b4Smrg * change, flushes the vertices and notifies the driver via
517117f1b4Smrg * the dd_function_table::CullFace callback.
527117f1b4Smrg */
5301e04c3fSmrgstatic ALWAYS_INLINE void
5401e04c3fSmrgcull_face(struct gl_context *ctx, GLenum mode, bool no_error)
557117f1b4Smrg{
5601e04c3fSmrg   if (ctx->Polygon.CullFaceMode == mode)
577117f1b4Smrg      return;
587117f1b4Smrg
5901e04c3fSmrg   if (!no_error &&
6001e04c3fSmrg       mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) {
6101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace");
627117f1b4Smrg      return;
6301e04c3fSmrg   }
647117f1b4Smrg
6501e04c3fSmrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
6601e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
677117f1b4Smrg   ctx->Polygon.CullFaceMode = mode;
687117f1b4Smrg
697117f1b4Smrg   if (ctx->Driver.CullFace)
7001e04c3fSmrg      ctx->Driver.CullFace(ctx, mode);
7101e04c3fSmrg}
7201e04c3fSmrg
7301e04c3fSmrg
7401e04c3fSmrgvoid GLAPIENTRY
7501e04c3fSmrg_mesa_CullFace_no_error(GLenum mode)
7601e04c3fSmrg{
7701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
7801e04c3fSmrg   cull_face(ctx, mode, true);
7901e04c3fSmrg}
8001e04c3fSmrg
8101e04c3fSmrg
8201e04c3fSmrgvoid GLAPIENTRY
8301e04c3fSmrg_mesa_CullFace(GLenum mode)
8401e04c3fSmrg{
8501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
8601e04c3fSmrg
8701e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
8801e04c3fSmrg      _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode));
8901e04c3fSmrg
9001e04c3fSmrg   cull_face(ctx, mode, false);
917117f1b4Smrg}
927117f1b4Smrg
937117f1b4Smrg
947117f1b4Smrg/**
9501e04c3fSmrg * Define front- and back-facing
967117f1b4Smrg *
977117f1b4Smrg * \param mode orientation of front-facing polygons.
987117f1b4Smrg *
997117f1b4Smrg * \sa glFrontFace().
1007117f1b4Smrg *
1017117f1b4Smrg * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
1027117f1b4Smrg * flushes the vertices and notifies the driver via
1037117f1b4Smrg * the dd_function_table::FrontFace callback.
1047117f1b4Smrg */
10501e04c3fSmrgstatic ALWAYS_INLINE void
10601e04c3fSmrgfront_face(struct gl_context *ctx, GLenum mode, bool no_error)
1077117f1b4Smrg{
10801e04c3fSmrg   if (ctx->Polygon.FrontFace == mode)
1097117f1b4Smrg      return;
1107117f1b4Smrg
11101e04c3fSmrg   if (!no_error && mode != GL_CW && mode != GL_CCW) {
11201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace");
1137117f1b4Smrg      return;
11401e04c3fSmrg   }
1157117f1b4Smrg
11601e04c3fSmrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
11701e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
1187117f1b4Smrg   ctx->Polygon.FrontFace = mode;
1197117f1b4Smrg
1207117f1b4Smrg   if (ctx->Driver.FrontFace)
12101e04c3fSmrg      ctx->Driver.FrontFace(ctx, mode);
12201e04c3fSmrg}
12301e04c3fSmrg
12401e04c3fSmrg
12501e04c3fSmrgvoid GLAPIENTRY
12601e04c3fSmrg_mesa_FrontFace_no_error(GLenum mode)
12701e04c3fSmrg{
12801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
12901e04c3fSmrg   front_face(ctx, mode, true);
13001e04c3fSmrg}
13101e04c3fSmrg
13201e04c3fSmrg
13301e04c3fSmrgvoid GLAPIENTRY
13401e04c3fSmrg_mesa_FrontFace(GLenum mode)
13501e04c3fSmrg{
13601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
13701e04c3fSmrg
13801e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
13901e04c3fSmrg      _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode));
14001e04c3fSmrg
14101e04c3fSmrg   front_face(ctx, mode, false);
1427117f1b4Smrg}
1437117f1b4Smrg
1447117f1b4Smrg
1457117f1b4Smrg/**
1467117f1b4Smrg * Set the polygon rasterization mode.
1477117f1b4Smrg *
1487117f1b4Smrg * \param face the polygons which \p mode applies to.
1497117f1b4Smrg * \param mode how polygons should be rasterized.
1507117f1b4Smrg *
15101e04c3fSmrg * \sa glPolygonMode().
15201e04c3fSmrg *
1537117f1b4Smrg * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
1547117f1b4Smrg * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
1557117f1b4Smrg * driver via the dd_function_table::PolygonMode callback.
1567117f1b4Smrg */
15701e04c3fSmrgstatic ALWAYS_INLINE void
15801e04c3fSmrgpolygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
1597117f1b4Smrg{
16001e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
1617117f1b4Smrg      _mesa_debug(ctx, "glPolygonMode %s %s\n",
16201e04c3fSmrg                  _mesa_enum_to_string(face),
16301e04c3fSmrg                  _mesa_enum_to_string(mode));
16401e04c3fSmrg
16501e04c3fSmrg   if (!no_error) {
16601e04c3fSmrg      switch (mode) {
16701e04c3fSmrg      case GL_POINT:
16801e04c3fSmrg      case GL_LINE:
16901e04c3fSmrg      case GL_FILL:
17001e04c3fSmrg         break;
17101e04c3fSmrg      case GL_FILL_RECTANGLE_NV:
17201e04c3fSmrg         if (ctx->Extensions.NV_fill_rectangle)
17301e04c3fSmrg            break;
17401e04c3fSmrg         /* fall-through */
17501e04c3fSmrg      default:
17601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)");
17701e04c3fSmrg         return;
17801e04c3fSmrg      }
1797117f1b4Smrg   }
1807117f1b4Smrg
1817117f1b4Smrg   switch (face) {
1827117f1b4Smrg   case GL_FRONT:
18301e04c3fSmrg      if (!no_error && ctx->API == API_OPENGL_CORE) {
184af69d88dSmrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
185af69d88dSmrg         return;
186af69d88dSmrg      }
1877117f1b4Smrg      if (ctx->Polygon.FrontMode == mode)
18801e04c3fSmrg         return;
18901e04c3fSmrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
19001e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
1917117f1b4Smrg      ctx->Polygon.FrontMode = mode;
1927117f1b4Smrg      break;
1937117f1b4Smrg   case GL_FRONT_AND_BACK:
19401e04c3fSmrg      if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode)
19501e04c3fSmrg         return;
19601e04c3fSmrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
19701e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
1987117f1b4Smrg      ctx->Polygon.FrontMode = mode;
1997117f1b4Smrg      ctx->Polygon.BackMode = mode;
2007117f1b4Smrg      break;
2017117f1b4Smrg   case GL_BACK:
20201e04c3fSmrg      if (!no_error && ctx->API == API_OPENGL_CORE) {
203af69d88dSmrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
204af69d88dSmrg         return;
205af69d88dSmrg      }
2067117f1b4Smrg      if (ctx->Polygon.BackMode == mode)
20701e04c3fSmrg         return;
20801e04c3fSmrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
20901e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
2107117f1b4Smrg      ctx->Polygon.BackMode = mode;
2117117f1b4Smrg      break;
2127117f1b4Smrg   default:
21301e04c3fSmrg      if (!no_error)
21401e04c3fSmrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
2157117f1b4Smrg      return;
2167117f1b4Smrg   }
2177117f1b4Smrg
2187117f1b4Smrg   if (ctx->Driver.PolygonMode)
2197117f1b4Smrg      ctx->Driver.PolygonMode(ctx, face, mode);
2207117f1b4Smrg}
2217117f1b4Smrg
2227117f1b4Smrg
22301e04c3fSmrgvoid GLAPIENTRY
22401e04c3fSmrg_mesa_PolygonMode_no_error(GLenum face, GLenum mode)
2257117f1b4Smrg{
22601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
22701e04c3fSmrg   polygon_mode(ctx, face, mode, true);
22801e04c3fSmrg}
2294a49301eSmrg
2304a49301eSmrg
23101e04c3fSmrgvoid GLAPIENTRY
23201e04c3fSmrg_mesa_PolygonMode(GLenum face, GLenum mode)
23301e04c3fSmrg{
23401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
23501e04c3fSmrg   polygon_mode(ctx, face, mode, false);
2367117f1b4Smrg}
2377117f1b4Smrg
2387117f1b4Smrg
2397117f1b4Smrg/**
2407117f1b4Smrg * Called by glPolygonStipple.
2417117f1b4Smrg */
2427117f1b4Smrgvoid GLAPIENTRY
24301e04c3fSmrg_mesa_PolygonStipple(const GLubyte *pattern)
2447117f1b4Smrg{
2457117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2467117f1b4Smrg
24701e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
2487117f1b4Smrg      _mesa_debug(ctx, "glPolygonStipple\n");
2497117f1b4Smrg
25001e04c3fSmrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 :
25101e04c3fSmrg                                                      _NEW_POLYGONSTIPPLE);
25201e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple;
2537117f1b4Smrg
25401e04c3fSmrg   pattern = _mesa_map_validate_pbo_source(ctx, 2,
25501e04c3fSmrg                                           &ctx->Unpack, 32, 32, 1,
25601e04c3fSmrg                                           GL_COLOR_INDEX, GL_BITMAP,
25701e04c3fSmrg                                           INT_MAX, pattern,
25801e04c3fSmrg                                           "glPolygonStipple");
25901e04c3fSmrg   if (!pattern)
26001e04c3fSmrg      return;
26101e04c3fSmrg
26201e04c3fSmrg   _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
26301e04c3fSmrg
26401e04c3fSmrg   _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
2657117f1b4Smrg
2667117f1b4Smrg   if (ctx->Driver.PolygonStipple)
2677117f1b4Smrg      ctx->Driver.PolygonStipple(ctx, pattern);
2687117f1b4Smrg}
2697117f1b4Smrg
2707117f1b4Smrg
2717117f1b4Smrg/**
2727117f1b4Smrg * Called by glPolygonStipple.
2737117f1b4Smrg */
2747117f1b4Smrgvoid GLAPIENTRY
2753464ebd5Sriastradh_mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest )
2767117f1b4Smrg{
2777117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2787117f1b4Smrg
2797117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
2807117f1b4Smrg      _mesa_debug(ctx, "glGetPolygonStipple\n");
2817117f1b4Smrg
2824a49301eSmrg   dest = _mesa_map_validate_pbo_dest(ctx, 2,
2834a49301eSmrg                                      &ctx->Pack, 32, 32, 1,
2843464ebd5Sriastradh                                      GL_COLOR_INDEX, GL_BITMAP,
2853464ebd5Sriastradh                                      bufSize, dest, "glGetPolygonStipple");
2864a49301eSmrg   if (!dest)
2874a49301eSmrg      return;
2884a49301eSmrg
2894a49301eSmrg   _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
2904a49301eSmrg
2914a49301eSmrg   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
2927117f1b4Smrg}
2937117f1b4Smrg
2947117f1b4Smrg
2953464ebd5Sriastradhvoid GLAPIENTRY
2963464ebd5Sriastradh_mesa_GetPolygonStipple( GLubyte *dest )
2973464ebd5Sriastradh{
2983464ebd5Sriastradh   _mesa_GetnPolygonStippleARB(INT_MAX, dest);
2993464ebd5Sriastradh}
3003464ebd5Sriastradh
30101e04c3fSmrgvoid
30201e04c3fSmrg_mesa_polygon_offset_clamp(struct gl_context *ctx,
30301e04c3fSmrg                           GLfloat factor, GLfloat units, GLfloat clamp)
3047117f1b4Smrg{
3057117f1b4Smrg   if (ctx->Polygon.OffsetFactor == factor &&
30601e04c3fSmrg       ctx->Polygon.OffsetUnits == units &&
30701e04c3fSmrg       ctx->Polygon.OffsetClamp == clamp)
3087117f1b4Smrg      return;
3097117f1b4Smrg
31001e04c3fSmrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
31101e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
3127117f1b4Smrg   ctx->Polygon.OffsetFactor = factor;
3137117f1b4Smrg   ctx->Polygon.OffsetUnits = units;
31401e04c3fSmrg   ctx->Polygon.OffsetClamp = clamp;
3157117f1b4Smrg
3167117f1b4Smrg   if (ctx->Driver.PolygonOffset)
31701e04c3fSmrg      ctx->Driver.PolygonOffset( ctx, factor, units, clamp );
3187117f1b4Smrg}
3197117f1b4Smrg
3207117f1b4Smrgvoid GLAPIENTRY
32101e04c3fSmrg_mesa_PolygonOffset( GLfloat factor, GLfloat units )
3227117f1b4Smrg{
3237117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
32401e04c3fSmrg
32501e04c3fSmrg   if (MESA_VERBOSE&VERBOSE_API)
32601e04c3fSmrg      _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
32701e04c3fSmrg
32801e04c3fSmrg   _mesa_polygon_offset_clamp(ctx, factor, units, 0.0);
3297117f1b4Smrg}
3307117f1b4Smrg
33101e04c3fSmrgvoid GLAPIENTRY
33201e04c3fSmrg_mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp )
33301e04c3fSmrg{
33401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
33501e04c3fSmrg
33601e04c3fSmrg   if (!ctx->Extensions.ARB_polygon_offset_clamp) {
33701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
33801e04c3fSmrg                  "unsupported function (%s) called", "glPolygonOffsetClamp");
33901e04c3fSmrg      return;
34001e04c3fSmrg   }
3417117f1b4Smrg
34201e04c3fSmrg   if (MESA_VERBOSE&VERBOSE_API)
34301e04c3fSmrg      _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp);
34401e04c3fSmrg
34501e04c3fSmrg   _mesa_polygon_offset_clamp(ctx, factor, units, clamp);
34601e04c3fSmrg}
3477117f1b4Smrg
3487117f1b4Smrg/**********************************************************************/
3497117f1b4Smrg/** \name Initialization */
3507117f1b4Smrg/*@{*/
3517117f1b4Smrg
3527117f1b4Smrg/**
3537117f1b4Smrg * Initialize the context polygon state.
3547117f1b4Smrg *
3557117f1b4Smrg * \param ctx GL context.
3567117f1b4Smrg *
3573464ebd5Sriastradh * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
3587117f1b4Smrg * attribute groups.
3597117f1b4Smrg */
3603464ebd5Sriastradhvoid _mesa_init_polygon( struct gl_context * ctx )
3617117f1b4Smrg{
3627117f1b4Smrg   /* Polygon group */
3637117f1b4Smrg   ctx->Polygon.CullFlag = GL_FALSE;
3647117f1b4Smrg   ctx->Polygon.CullFaceMode = GL_BACK;
3657117f1b4Smrg   ctx->Polygon.FrontFace = GL_CCW;
3667117f1b4Smrg   ctx->Polygon.FrontMode = GL_FILL;
3677117f1b4Smrg   ctx->Polygon.BackMode = GL_FILL;
3687117f1b4Smrg   ctx->Polygon.SmoothFlag = GL_FALSE;
3697117f1b4Smrg   ctx->Polygon.StippleFlag = GL_FALSE;
3707117f1b4Smrg   ctx->Polygon.OffsetFactor = 0.0F;
3717117f1b4Smrg   ctx->Polygon.OffsetUnits = 0.0F;
37201e04c3fSmrg   ctx->Polygon.OffsetClamp = 0.0F;
3737117f1b4Smrg   ctx->Polygon.OffsetPoint = GL_FALSE;
3747117f1b4Smrg   ctx->Polygon.OffsetLine = GL_FALSE;
3757117f1b4Smrg   ctx->Polygon.OffsetFill = GL_FALSE;
3767117f1b4Smrg
3777117f1b4Smrg
3787117f1b4Smrg   /* Polygon Stipple group */
379cdc920a0Smrg   memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
3807117f1b4Smrg}
3817117f1b4Smrg
3827117f1b4Smrg/*@}*/
383