1848b8605Smrg/** 2848b8605Smrg * \file polygon.c 3848b8605Smrg * Polygon operations. 4848b8605Smrg */ 5848b8605Smrg 6848b8605Smrg/* 7848b8605Smrg * Mesa 3-D graphics library 8848b8605Smrg * 9848b8605Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 10848b8605Smrg * 11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 12848b8605Smrg * copy of this software and associated documentation files (the "Software"), 13848b8605Smrg * to deal in the Software without restriction, including without limitation 14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 16848b8605Smrg * Software is furnished to do so, subject to the following conditions: 17848b8605Smrg * 18848b8605Smrg * The above copyright notice and this permission notice shall be included 19848b8605Smrg * in all copies or substantial portions of the Software. 20848b8605Smrg * 21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 28848b8605Smrg */ 29848b8605Smrg 30848b8605Smrg 31848b8605Smrg#include "glheader.h" 32848b8605Smrg#include "imports.h" 33848b8605Smrg#include "context.h" 34848b8605Smrg#include "image.h" 35848b8605Smrg#include "enums.h" 36848b8605Smrg#include "pack.h" 37848b8605Smrg#include "pbo.h" 38848b8605Smrg#include "polygon.h" 39848b8605Smrg#include "mtypes.h" 40848b8605Smrg 41848b8605Smrg 42848b8605Smrg/** 43848b8605Smrg * Specify whether to cull front- or back-facing facets. 44848b8605Smrg * 45848b8605Smrg * \param mode culling mode. 46848b8605Smrg * 47848b8605Smrg * \sa glCullFace(). 48848b8605Smrg * 49848b8605Smrg * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On 50848b8605Smrg * change, flushes the vertices and notifies the driver via 51848b8605Smrg * the dd_function_table::CullFace callback. 52848b8605Smrg */ 53b8e80941Smrgstatic ALWAYS_INLINE void 54b8e80941Smrgcull_face(struct gl_context *ctx, GLenum mode, bool no_error) 55848b8605Smrg{ 56b8e80941Smrg if (ctx->Polygon.CullFaceMode == mode) 57848b8605Smrg return; 58848b8605Smrg 59b8e80941Smrg if (!no_error && 60b8e80941Smrg mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) { 61b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace"); 62848b8605Smrg return; 63b8e80941Smrg } 64848b8605Smrg 65b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 66b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 67848b8605Smrg ctx->Polygon.CullFaceMode = mode; 68848b8605Smrg 69848b8605Smrg if (ctx->Driver.CullFace) 70b8e80941Smrg ctx->Driver.CullFace(ctx, mode); 71b8e80941Smrg} 72b8e80941Smrg 73b8e80941Smrg 74b8e80941Smrgvoid GLAPIENTRY 75b8e80941Smrg_mesa_CullFace_no_error(GLenum mode) 76b8e80941Smrg{ 77b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 78b8e80941Smrg cull_face(ctx, mode, true); 79b8e80941Smrg} 80b8e80941Smrg 81b8e80941Smrg 82b8e80941Smrgvoid GLAPIENTRY 83b8e80941Smrg_mesa_CullFace(GLenum mode) 84b8e80941Smrg{ 85b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 86b8e80941Smrg 87b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) 88b8e80941Smrg _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode)); 89b8e80941Smrg 90b8e80941Smrg cull_face(ctx, mode, false); 91848b8605Smrg} 92848b8605Smrg 93848b8605Smrg 94848b8605Smrg/** 95b8e80941Smrg * Define front- and back-facing 96848b8605Smrg * 97848b8605Smrg * \param mode orientation of front-facing polygons. 98848b8605Smrg * 99848b8605Smrg * \sa glFrontFace(). 100848b8605Smrg * 101848b8605Smrg * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change 102848b8605Smrg * flushes the vertices and notifies the driver via 103848b8605Smrg * the dd_function_table::FrontFace callback. 104848b8605Smrg */ 105b8e80941Smrgstatic ALWAYS_INLINE void 106b8e80941Smrgfront_face(struct gl_context *ctx, GLenum mode, bool no_error) 107848b8605Smrg{ 108b8e80941Smrg if (ctx->Polygon.FrontFace == mode) 109848b8605Smrg return; 110848b8605Smrg 111b8e80941Smrg if (!no_error && mode != GL_CW && mode != GL_CCW) { 112b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace"); 113848b8605Smrg return; 114b8e80941Smrg } 115848b8605Smrg 116b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 117b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 118848b8605Smrg ctx->Polygon.FrontFace = mode; 119848b8605Smrg 120848b8605Smrg if (ctx->Driver.FrontFace) 121b8e80941Smrg ctx->Driver.FrontFace(ctx, mode); 122b8e80941Smrg} 123b8e80941Smrg 124b8e80941Smrg 125b8e80941Smrgvoid GLAPIENTRY 126b8e80941Smrg_mesa_FrontFace_no_error(GLenum mode) 127b8e80941Smrg{ 128b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 129b8e80941Smrg front_face(ctx, mode, true); 130b8e80941Smrg} 131b8e80941Smrg 132b8e80941Smrg 133b8e80941Smrgvoid GLAPIENTRY 134b8e80941Smrg_mesa_FrontFace(GLenum mode) 135b8e80941Smrg{ 136b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 137b8e80941Smrg 138b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) 139b8e80941Smrg _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode)); 140b8e80941Smrg 141b8e80941Smrg front_face(ctx, mode, false); 142848b8605Smrg} 143848b8605Smrg 144848b8605Smrg 145848b8605Smrg/** 146848b8605Smrg * Set the polygon rasterization mode. 147848b8605Smrg * 148848b8605Smrg * \param face the polygons which \p mode applies to. 149848b8605Smrg * \param mode how polygons should be rasterized. 150848b8605Smrg * 151b8e80941Smrg * \sa glPolygonMode(). 152b8e80941Smrg * 153848b8605Smrg * Verifies the parameters and updates gl_polygon_attrib::FrontMode and 154848b8605Smrg * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the 155848b8605Smrg * driver via the dd_function_table::PolygonMode callback. 156848b8605Smrg */ 157b8e80941Smrgstatic ALWAYS_INLINE void 158b8e80941Smrgpolygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error) 159848b8605Smrg{ 160b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) 161848b8605Smrg _mesa_debug(ctx, "glPolygonMode %s %s\n", 162b8e80941Smrg _mesa_enum_to_string(face), 163b8e80941Smrg _mesa_enum_to_string(mode)); 164b8e80941Smrg 165b8e80941Smrg if (!no_error) { 166b8e80941Smrg switch (mode) { 167b8e80941Smrg case GL_POINT: 168b8e80941Smrg case GL_LINE: 169b8e80941Smrg case GL_FILL: 170b8e80941Smrg break; 171b8e80941Smrg case GL_FILL_RECTANGLE_NV: 172b8e80941Smrg if (ctx->Extensions.NV_fill_rectangle) 173b8e80941Smrg break; 174b8e80941Smrg /* fall-through */ 175b8e80941Smrg default: 176b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)"); 177b8e80941Smrg return; 178b8e80941Smrg } 179848b8605Smrg } 180848b8605Smrg 181848b8605Smrg switch (face) { 182848b8605Smrg case GL_FRONT: 183b8e80941Smrg if (!no_error && ctx->API == API_OPENGL_CORE) { 184848b8605Smrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 185848b8605Smrg return; 186848b8605Smrg } 187848b8605Smrg if (ctx->Polygon.FrontMode == mode) 188b8e80941Smrg return; 189b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 190b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 191848b8605Smrg ctx->Polygon.FrontMode = mode; 192848b8605Smrg break; 193848b8605Smrg case GL_FRONT_AND_BACK: 194b8e80941Smrg if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode) 195b8e80941Smrg return; 196b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 197b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 198848b8605Smrg ctx->Polygon.FrontMode = mode; 199848b8605Smrg ctx->Polygon.BackMode = mode; 200848b8605Smrg break; 201848b8605Smrg case GL_BACK: 202b8e80941Smrg if (!no_error && ctx->API == API_OPENGL_CORE) { 203848b8605Smrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 204848b8605Smrg return; 205848b8605Smrg } 206848b8605Smrg if (ctx->Polygon.BackMode == mode) 207b8e80941Smrg return; 208b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 209b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 210848b8605Smrg ctx->Polygon.BackMode = mode; 211848b8605Smrg break; 212848b8605Smrg default: 213b8e80941Smrg if (!no_error) 214b8e80941Smrg _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 215848b8605Smrg return; 216848b8605Smrg } 217848b8605Smrg 218848b8605Smrg if (ctx->Driver.PolygonMode) 219848b8605Smrg ctx->Driver.PolygonMode(ctx, face, mode); 220848b8605Smrg} 221848b8605Smrg 222848b8605Smrg 223b8e80941Smrgvoid GLAPIENTRY 224b8e80941Smrg_mesa_PolygonMode_no_error(GLenum face, GLenum mode) 225848b8605Smrg{ 226b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 227b8e80941Smrg polygon_mode(ctx, face, mode, true); 228b8e80941Smrg} 229848b8605Smrg 230848b8605Smrg 231b8e80941Smrgvoid GLAPIENTRY 232b8e80941Smrg_mesa_PolygonMode(GLenum face, GLenum mode) 233b8e80941Smrg{ 234b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 235b8e80941Smrg polygon_mode(ctx, face, mode, false); 236848b8605Smrg} 237848b8605Smrg 238848b8605Smrg 239848b8605Smrg/** 240848b8605Smrg * Called by glPolygonStipple. 241848b8605Smrg */ 242848b8605Smrgvoid GLAPIENTRY 243b8e80941Smrg_mesa_PolygonStipple(const GLubyte *pattern) 244848b8605Smrg{ 245848b8605Smrg GET_CURRENT_CONTEXT(ctx); 246848b8605Smrg 247b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) 248848b8605Smrg _mesa_debug(ctx, "glPolygonStipple\n"); 249848b8605Smrg 250b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 : 251b8e80941Smrg _NEW_POLYGONSTIPPLE); 252b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple; 253848b8605Smrg 254b8e80941Smrg pattern = _mesa_map_validate_pbo_source(ctx, 2, 255b8e80941Smrg &ctx->Unpack, 32, 32, 1, 256b8e80941Smrg GL_COLOR_INDEX, GL_BITMAP, 257b8e80941Smrg INT_MAX, pattern, 258b8e80941Smrg "glPolygonStipple"); 259b8e80941Smrg if (!pattern) 260b8e80941Smrg return; 261b8e80941Smrg 262b8e80941Smrg _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); 263b8e80941Smrg 264b8e80941Smrg _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 265848b8605Smrg 266848b8605Smrg if (ctx->Driver.PolygonStipple) 267848b8605Smrg ctx->Driver.PolygonStipple(ctx, pattern); 268848b8605Smrg} 269848b8605Smrg 270848b8605Smrg 271848b8605Smrg/** 272848b8605Smrg * Called by glPolygonStipple. 273848b8605Smrg */ 274848b8605Smrgvoid GLAPIENTRY 275848b8605Smrg_mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest ) 276848b8605Smrg{ 277848b8605Smrg GET_CURRENT_CONTEXT(ctx); 278848b8605Smrg 279848b8605Smrg if (MESA_VERBOSE&VERBOSE_API) 280848b8605Smrg _mesa_debug(ctx, "glGetPolygonStipple\n"); 281848b8605Smrg 282848b8605Smrg dest = _mesa_map_validate_pbo_dest(ctx, 2, 283848b8605Smrg &ctx->Pack, 32, 32, 1, 284848b8605Smrg GL_COLOR_INDEX, GL_BITMAP, 285848b8605Smrg bufSize, dest, "glGetPolygonStipple"); 286848b8605Smrg if (!dest) 287848b8605Smrg return; 288848b8605Smrg 289848b8605Smrg _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); 290848b8605Smrg 291848b8605Smrg _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 292848b8605Smrg} 293848b8605Smrg 294848b8605Smrg 295848b8605Smrgvoid GLAPIENTRY 296848b8605Smrg_mesa_GetPolygonStipple( GLubyte *dest ) 297848b8605Smrg{ 298848b8605Smrg _mesa_GetnPolygonStippleARB(INT_MAX, dest); 299848b8605Smrg} 300848b8605Smrg 301b8e80941Smrgvoid 302b8e80941Smrg_mesa_polygon_offset_clamp(struct gl_context *ctx, 303b8e80941Smrg GLfloat factor, GLfloat units, GLfloat clamp) 304848b8605Smrg{ 305848b8605Smrg if (ctx->Polygon.OffsetFactor == factor && 306b8e80941Smrg ctx->Polygon.OffsetUnits == units && 307b8e80941Smrg ctx->Polygon.OffsetClamp == clamp) 308848b8605Smrg return; 309848b8605Smrg 310b8e80941Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 311b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 312848b8605Smrg ctx->Polygon.OffsetFactor = factor; 313848b8605Smrg ctx->Polygon.OffsetUnits = units; 314b8e80941Smrg ctx->Polygon.OffsetClamp = clamp; 315848b8605Smrg 316848b8605Smrg if (ctx->Driver.PolygonOffset) 317b8e80941Smrg ctx->Driver.PolygonOffset( ctx, factor, units, clamp ); 318848b8605Smrg} 319848b8605Smrg 320848b8605Smrgvoid GLAPIENTRY 321b8e80941Smrg_mesa_PolygonOffset( GLfloat factor, GLfloat units ) 322848b8605Smrg{ 323848b8605Smrg GET_CURRENT_CONTEXT(ctx); 324b8e80941Smrg 325b8e80941Smrg if (MESA_VERBOSE&VERBOSE_API) 326b8e80941Smrg _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); 327b8e80941Smrg 328b8e80941Smrg _mesa_polygon_offset_clamp(ctx, factor, units, 0.0); 329848b8605Smrg} 330848b8605Smrg 331b8e80941Smrgvoid GLAPIENTRY 332b8e80941Smrg_mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp ) 333b8e80941Smrg{ 334b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 335b8e80941Smrg 336b8e80941Smrg if (!ctx->Extensions.ARB_polygon_offset_clamp) { 337b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 338b8e80941Smrg "unsupported function (%s) called", "glPolygonOffsetClamp"); 339b8e80941Smrg return; 340b8e80941Smrg } 341848b8605Smrg 342b8e80941Smrg if (MESA_VERBOSE&VERBOSE_API) 343b8e80941Smrg _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp); 344b8e80941Smrg 345b8e80941Smrg _mesa_polygon_offset_clamp(ctx, factor, units, clamp); 346b8e80941Smrg} 347848b8605Smrg 348848b8605Smrg/**********************************************************************/ 349848b8605Smrg/** \name Initialization */ 350848b8605Smrg/*@{*/ 351848b8605Smrg 352848b8605Smrg/** 353848b8605Smrg * Initialize the context polygon state. 354848b8605Smrg * 355848b8605Smrg * \param ctx GL context. 356848b8605Smrg * 357848b8605Smrg * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple 358848b8605Smrg * attribute groups. 359848b8605Smrg */ 360848b8605Smrgvoid _mesa_init_polygon( struct gl_context * ctx ) 361848b8605Smrg{ 362848b8605Smrg /* Polygon group */ 363848b8605Smrg ctx->Polygon.CullFlag = GL_FALSE; 364848b8605Smrg ctx->Polygon.CullFaceMode = GL_BACK; 365848b8605Smrg ctx->Polygon.FrontFace = GL_CCW; 366848b8605Smrg ctx->Polygon.FrontMode = GL_FILL; 367848b8605Smrg ctx->Polygon.BackMode = GL_FILL; 368848b8605Smrg ctx->Polygon.SmoothFlag = GL_FALSE; 369848b8605Smrg ctx->Polygon.StippleFlag = GL_FALSE; 370848b8605Smrg ctx->Polygon.OffsetFactor = 0.0F; 371848b8605Smrg ctx->Polygon.OffsetUnits = 0.0F; 372b8e80941Smrg ctx->Polygon.OffsetClamp = 0.0F; 373848b8605Smrg ctx->Polygon.OffsetPoint = GL_FALSE; 374848b8605Smrg ctx->Polygon.OffsetLine = GL_FALSE; 375848b8605Smrg ctx->Polygon.OffsetFill = GL_FALSE; 376848b8605Smrg 377848b8605Smrg 378848b8605Smrg /* Polygon Stipple group */ 379848b8605Smrg memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); 380848b8605Smrg} 381848b8605Smrg 382848b8605Smrg/*@}*/ 383