polygon.c revision 7117f1b4
17117f1b4Smrg/**
27117f1b4Smrg * \file polygon.c
37117f1b4Smrg * Polygon operations.
47117f1b4Smrg */
57117f1b4Smrg
67117f1b4Smrg/*
77117f1b4Smrg * Mesa 3-D graphics library
87117f1b4Smrg * Version:  6.5.1
97117f1b4Smrg *
107117f1b4Smrg * Copyright (C) 1999-2006  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 "imports.h"
337117f1b4Smrg#include "bufferobj.h"
347117f1b4Smrg#include "context.h"
357117f1b4Smrg#include "image.h"
367117f1b4Smrg#include "enums.h"
377117f1b4Smrg#include "macros.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 */
537117f1b4Smrgvoid GLAPIENTRY
547117f1b4Smrg_mesa_CullFace( GLenum mode )
557117f1b4Smrg{
567117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
577117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
587117f1b4Smrg
597117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
607117f1b4Smrg      _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode));
617117f1b4Smrg
627117f1b4Smrg   if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) {
637117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" );
647117f1b4Smrg      return;
657117f1b4Smrg   }
667117f1b4Smrg
677117f1b4Smrg   if (ctx->Polygon.CullFaceMode == mode)
687117f1b4Smrg      return;
697117f1b4Smrg
707117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_POLYGON);
717117f1b4Smrg   ctx->Polygon.CullFaceMode = mode;
727117f1b4Smrg
737117f1b4Smrg   if (ctx->Driver.CullFace)
747117f1b4Smrg      ctx->Driver.CullFace( ctx, mode );
757117f1b4Smrg}
767117f1b4Smrg
777117f1b4Smrg
787117f1b4Smrg/**
797117f1b4Smrg * Define front- and back-facing
807117f1b4Smrg *
817117f1b4Smrg * \param mode orientation of front-facing polygons.
827117f1b4Smrg *
837117f1b4Smrg * \sa glFrontFace().
847117f1b4Smrg *
857117f1b4Smrg * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
867117f1b4Smrg * flushes the vertices and notifies the driver via
877117f1b4Smrg * the dd_function_table::FrontFace callback.
887117f1b4Smrg */
897117f1b4Smrgvoid GLAPIENTRY
907117f1b4Smrg_mesa_FrontFace( GLenum mode )
917117f1b4Smrg{
927117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
937117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
947117f1b4Smrg
957117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
967117f1b4Smrg      _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode));
977117f1b4Smrg
987117f1b4Smrg   if (mode!=GL_CW && mode!=GL_CCW) {
997117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" );
1007117f1b4Smrg      return;
1017117f1b4Smrg   }
1027117f1b4Smrg
1037117f1b4Smrg   if (ctx->Polygon.FrontFace == mode)
1047117f1b4Smrg      return;
1057117f1b4Smrg
1067117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_POLYGON);
1077117f1b4Smrg   ctx->Polygon.FrontFace = mode;
1087117f1b4Smrg
1097117f1b4Smrg   ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW);
1107117f1b4Smrg
1117117f1b4Smrg   if (ctx->Driver.FrontFace)
1127117f1b4Smrg      ctx->Driver.FrontFace( ctx, mode );
1137117f1b4Smrg}
1147117f1b4Smrg
1157117f1b4Smrg
1167117f1b4Smrg/**
1177117f1b4Smrg * Set the polygon rasterization mode.
1187117f1b4Smrg *
1197117f1b4Smrg * \param face the polygons which \p mode applies to.
1207117f1b4Smrg * \param mode how polygons should be rasterized.
1217117f1b4Smrg *
1227117f1b4Smrg * \sa glPolygonMode().
1237117f1b4Smrg *
1247117f1b4Smrg * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
1257117f1b4Smrg * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
1267117f1b4Smrg * driver via the dd_function_table::PolygonMode callback.
1277117f1b4Smrg */
1287117f1b4Smrgvoid GLAPIENTRY
1297117f1b4Smrg_mesa_PolygonMode( GLenum face, GLenum mode )
1307117f1b4Smrg{
1317117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1327117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1337117f1b4Smrg
1347117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
1357117f1b4Smrg      _mesa_debug(ctx, "glPolygonMode %s %s\n",
1367117f1b4Smrg                  _mesa_lookup_enum_by_nr(face),
1377117f1b4Smrg                  _mesa_lookup_enum_by_nr(mode));
1387117f1b4Smrg
1397117f1b4Smrg   if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) {
1407117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" );
1417117f1b4Smrg      return;
1427117f1b4Smrg   }
1437117f1b4Smrg
1447117f1b4Smrg   switch (face) {
1457117f1b4Smrg   case GL_FRONT:
1467117f1b4Smrg      if (ctx->Polygon.FrontMode == mode)
1477117f1b4Smrg	 return;
1487117f1b4Smrg      FLUSH_VERTICES(ctx, _NEW_POLYGON);
1497117f1b4Smrg      ctx->Polygon.FrontMode = mode;
1507117f1b4Smrg      break;
1517117f1b4Smrg   case GL_FRONT_AND_BACK:
1527117f1b4Smrg      if (ctx->Polygon.FrontMode == mode &&
1537117f1b4Smrg	  ctx->Polygon.BackMode == mode)
1547117f1b4Smrg	 return;
1557117f1b4Smrg      FLUSH_VERTICES(ctx, _NEW_POLYGON);
1567117f1b4Smrg      ctx->Polygon.FrontMode = mode;
1577117f1b4Smrg      ctx->Polygon.BackMode = mode;
1587117f1b4Smrg      break;
1597117f1b4Smrg   case GL_BACK:
1607117f1b4Smrg      if (ctx->Polygon.BackMode == mode)
1617117f1b4Smrg	 return;
1627117f1b4Smrg      FLUSH_VERTICES(ctx, _NEW_POLYGON);
1637117f1b4Smrg      ctx->Polygon.BackMode = mode;
1647117f1b4Smrg      break;
1657117f1b4Smrg   default:
1667117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
1677117f1b4Smrg      return;
1687117f1b4Smrg   }
1697117f1b4Smrg
1707117f1b4Smrg   if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL)
1717117f1b4Smrg      ctx->_TriangleCaps &= ~DD_TRI_UNFILLED;
1727117f1b4Smrg   else
1737117f1b4Smrg      ctx->_TriangleCaps |= DD_TRI_UNFILLED;
1747117f1b4Smrg
1757117f1b4Smrg   if (ctx->Driver.PolygonMode)
1767117f1b4Smrg      ctx->Driver.PolygonMode(ctx, face, mode);
1777117f1b4Smrg}
1787117f1b4Smrg
1797117f1b4Smrg#if _HAVE_FULL_GL
1807117f1b4Smrg
1817117f1b4Smrg
1827117f1b4Smrg/**
1837117f1b4Smrg * This routine updates the ctx->Polygon.Stipple state.
1847117f1b4Smrg * If we're getting the stipple data from a PBO, we map the buffer
1857117f1b4Smrg * in order to access the data.
1867117f1b4Smrg * In any case, we obey the current pixel unpacking parameters when fetching
1877117f1b4Smrg * the stipple data.
1887117f1b4Smrg *
1897117f1b4Smrg * In the future, this routine should be used as a fallback, called via
1907117f1b4Smrg * ctx->Driver.PolygonStipple().  We'll have to update all the DRI drivers
1917117f1b4Smrg * too.
1927117f1b4Smrg */
1937117f1b4Smrgvoid
1947117f1b4Smrg_mesa_polygon_stipple(GLcontext *ctx, const GLubyte *pattern)
1957117f1b4Smrg{
1967117f1b4Smrg   if (ctx->Unpack.BufferObj->Name) {
1977117f1b4Smrg      /* Get/unpack the stipple pattern from a PBO */
1987117f1b4Smrg      GLubyte *buf;
1997117f1b4Smrg      if (!_mesa_validate_pbo_access(2, &ctx->Unpack, 32, 32, 1,
2007117f1b4Smrg                                     GL_COLOR_INDEX, GL_BITMAP, pattern)) {
2017117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2027117f1b4Smrg                     "glPolygonStipple(bad PBO access)");
2037117f1b4Smrg         return;
2047117f1b4Smrg      }
2057117f1b4Smrg      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
2067117f1b4Smrg                                              GL_READ_ONLY_ARB,
2077117f1b4Smrg                                              ctx->Unpack.BufferObj);
2087117f1b4Smrg      if (!buf) {
2097117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2107117f1b4Smrg                     "glPolygonStipple(PBO mapped)");
2117117f1b4Smrg         return;
2127117f1b4Smrg      }
2137117f1b4Smrg      buf = ADD_POINTERS(buf, pattern);
2147117f1b4Smrg      _mesa_unpack_polygon_stipple(buf, ctx->PolygonStipple, &ctx->Unpack);
2157117f1b4Smrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
2167117f1b4Smrg                              ctx->Unpack.BufferObj);
2177117f1b4Smrg   }
2187117f1b4Smrg   else {
2197117f1b4Smrg      /* Get/unpack the stipple pattern from user memory */
2207117f1b4Smrg      _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
2217117f1b4Smrg   }
2227117f1b4Smrg}
2237117f1b4Smrg
2247117f1b4Smrg
2257117f1b4Smrg/**
2267117f1b4Smrg * Called by glPolygonStipple.
2277117f1b4Smrg */
2287117f1b4Smrgvoid GLAPIENTRY
2297117f1b4Smrg_mesa_PolygonStipple( const GLubyte *pattern )
2307117f1b4Smrg{
2317117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2327117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2337117f1b4Smrg
2347117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
2357117f1b4Smrg      _mesa_debug(ctx, "glPolygonStipple\n");
2367117f1b4Smrg
2377117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE);
2387117f1b4Smrg
2397117f1b4Smrg   _mesa_polygon_stipple(ctx, pattern);
2407117f1b4Smrg
2417117f1b4Smrg   if (ctx->Driver.PolygonStipple)
2427117f1b4Smrg      ctx->Driver.PolygonStipple(ctx, pattern);
2437117f1b4Smrg}
2447117f1b4Smrg
2457117f1b4Smrg
2467117f1b4Smrg/**
2477117f1b4Smrg * Called by glPolygonStipple.
2487117f1b4Smrg */
2497117f1b4Smrgvoid GLAPIENTRY
2507117f1b4Smrg_mesa_GetPolygonStipple( GLubyte *dest )
2517117f1b4Smrg{
2527117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2537117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2547117f1b4Smrg
2557117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
2567117f1b4Smrg      _mesa_debug(ctx, "glGetPolygonStipple\n");
2577117f1b4Smrg
2587117f1b4Smrg   /* XXX someday we may put this code into a separate function and call
2597117f1b4Smrg    * it with ctx->Driver.GetPolygonStipple().
2607117f1b4Smrg    */
2617117f1b4Smrg   if (ctx->Pack.BufferObj->Name) {
2627117f1b4Smrg      /* Put/pack the stipple pattern into a PBO */
2637117f1b4Smrg      GLubyte *buf;
2647117f1b4Smrg      if (!_mesa_validate_pbo_access(2, &ctx->Pack, 32, 32, 1,
2657117f1b4Smrg                                     GL_COLOR_INDEX, GL_BITMAP, dest)) {
2667117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2677117f1b4Smrg                     "glGetPolygonStipple(bad PBO access)");
2687117f1b4Smrg         return;
2697117f1b4Smrg      }
2707117f1b4Smrg      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
2717117f1b4Smrg                                              GL_WRITE_ONLY_ARB,
2727117f1b4Smrg                                              ctx->Pack.BufferObj);
2737117f1b4Smrg      if (!buf) {
2747117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2757117f1b4Smrg                     "glGetPolygonStipple(PBO mapped)");
2767117f1b4Smrg         return;
2777117f1b4Smrg      }
2787117f1b4Smrg      buf = ADD_POINTERS(buf, dest);
2797117f1b4Smrg      _mesa_pack_polygon_stipple(ctx->PolygonStipple, buf, &ctx->Pack);
2807117f1b4Smrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
2817117f1b4Smrg                              ctx->Pack.BufferObj);
2827117f1b4Smrg   }
2837117f1b4Smrg   else {
2847117f1b4Smrg      /* Put/pack the stipple pattern into user memory */
2857117f1b4Smrg      _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
2867117f1b4Smrg   }
2877117f1b4Smrg}
2887117f1b4Smrg
2897117f1b4Smrg
2907117f1b4Smrgvoid GLAPIENTRY
2917117f1b4Smrg_mesa_PolygonOffset( GLfloat factor, GLfloat units )
2927117f1b4Smrg{
2937117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2947117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2957117f1b4Smrg
2967117f1b4Smrg   if (MESA_VERBOSE&VERBOSE_API)
2977117f1b4Smrg      _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
2987117f1b4Smrg
2997117f1b4Smrg   if (ctx->Polygon.OffsetFactor == factor &&
3007117f1b4Smrg       ctx->Polygon.OffsetUnits == units)
3017117f1b4Smrg      return;
3027117f1b4Smrg
3037117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_POLYGON);
3047117f1b4Smrg   ctx->Polygon.OffsetFactor = factor;
3057117f1b4Smrg   ctx->Polygon.OffsetUnits = units;
3067117f1b4Smrg
3077117f1b4Smrg   if (ctx->Driver.PolygonOffset)
3087117f1b4Smrg      ctx->Driver.PolygonOffset( ctx, factor, units );
3097117f1b4Smrg}
3107117f1b4Smrg
3117117f1b4Smrg
3127117f1b4Smrgvoid GLAPIENTRY
3137117f1b4Smrg_mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias )
3147117f1b4Smrg{
3157117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3167117f1b4Smrg   /* XXX mult by DepthMaxF here??? */
3177117f1b4Smrg   _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF );
3187117f1b4Smrg}
3197117f1b4Smrg
3207117f1b4Smrg#endif
3217117f1b4Smrg
3227117f1b4Smrg
3237117f1b4Smrg/**********************************************************************/
3247117f1b4Smrg/** \name Initialization */
3257117f1b4Smrg/*@{*/
3267117f1b4Smrg
3277117f1b4Smrg/**
3287117f1b4Smrg * Initialize the context polygon state.
3297117f1b4Smrg *
3307117f1b4Smrg * \param ctx GL context.
3317117f1b4Smrg *
3327117f1b4Smrg * Initializes __GLcontextRec::Polygon and __GLcontextRec::PolygonStipple
3337117f1b4Smrg * attribute groups.
3347117f1b4Smrg */
3357117f1b4Smrgvoid _mesa_init_polygon( GLcontext * ctx )
3367117f1b4Smrg{
3377117f1b4Smrg   /* Polygon group */
3387117f1b4Smrg   ctx->Polygon.CullFlag = GL_FALSE;
3397117f1b4Smrg   ctx->Polygon.CullFaceMode = GL_BACK;
3407117f1b4Smrg   ctx->Polygon.FrontFace = GL_CCW;
3417117f1b4Smrg   ctx->Polygon._FrontBit = 0;
3427117f1b4Smrg   ctx->Polygon.FrontMode = GL_FILL;
3437117f1b4Smrg   ctx->Polygon.BackMode = GL_FILL;
3447117f1b4Smrg   ctx->Polygon.SmoothFlag = GL_FALSE;
3457117f1b4Smrg   ctx->Polygon.StippleFlag = GL_FALSE;
3467117f1b4Smrg   ctx->Polygon.OffsetFactor = 0.0F;
3477117f1b4Smrg   ctx->Polygon.OffsetUnits = 0.0F;
3487117f1b4Smrg   ctx->Polygon.OffsetPoint = GL_FALSE;
3497117f1b4Smrg   ctx->Polygon.OffsetLine = GL_FALSE;
3507117f1b4Smrg   ctx->Polygon.OffsetFill = GL_FALSE;
3517117f1b4Smrg
3527117f1b4Smrg
3537117f1b4Smrg   /* Polygon Stipple group */
3547117f1b4Smrg   MEMSET( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
3557117f1b4Smrg}
3567117f1b4Smrg
3577117f1b4Smrg/*@}*/
358