1/** 2 * \file polygon.c 3 * Polygon operations. 4 */ 5 6/* 7 * Mesa 3-D graphics library 8 * 9 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 31#include "glheader.h" 32#include "imports.h" 33#include "context.h" 34#include "image.h" 35#include "enums.h" 36#include "pack.h" 37#include "pbo.h" 38#include "polygon.h" 39#include "mtypes.h" 40 41 42/** 43 * Specify whether to cull front- or back-facing facets. 44 * 45 * \param mode culling mode. 46 * 47 * \sa glCullFace(). 48 * 49 * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On 50 * change, flushes the vertices and notifies the driver via 51 * the dd_function_table::CullFace callback. 52 */ 53static ALWAYS_INLINE void 54cull_face(struct gl_context *ctx, GLenum mode, bool no_error) 55{ 56 if (ctx->Polygon.CullFaceMode == mode) 57 return; 58 59 if (!no_error && 60 mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) { 61 _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace"); 62 return; 63 } 64 65 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 66 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 67 ctx->Polygon.CullFaceMode = mode; 68 69 if (ctx->Driver.CullFace) 70 ctx->Driver.CullFace(ctx, mode); 71} 72 73 74void GLAPIENTRY 75_mesa_CullFace_no_error(GLenum mode) 76{ 77 GET_CURRENT_CONTEXT(ctx); 78 cull_face(ctx, mode, true); 79} 80 81 82void GLAPIENTRY 83_mesa_CullFace(GLenum mode) 84{ 85 GET_CURRENT_CONTEXT(ctx); 86 87 if (MESA_VERBOSE & VERBOSE_API) 88 _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode)); 89 90 cull_face(ctx, mode, false); 91} 92 93 94/** 95 * Define front- and back-facing 96 * 97 * \param mode orientation of front-facing polygons. 98 * 99 * \sa glFrontFace(). 100 * 101 * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change 102 * flushes the vertices and notifies the driver via 103 * the dd_function_table::FrontFace callback. 104 */ 105static ALWAYS_INLINE void 106front_face(struct gl_context *ctx, GLenum mode, bool no_error) 107{ 108 if (ctx->Polygon.FrontFace == mode) 109 return; 110 111 if (!no_error && mode != GL_CW && mode != GL_CCW) { 112 _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace"); 113 return; 114 } 115 116 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 117 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 118 ctx->Polygon.FrontFace = mode; 119 120 if (ctx->Driver.FrontFace) 121 ctx->Driver.FrontFace(ctx, mode); 122} 123 124 125void GLAPIENTRY 126_mesa_FrontFace_no_error(GLenum mode) 127{ 128 GET_CURRENT_CONTEXT(ctx); 129 front_face(ctx, mode, true); 130} 131 132 133void GLAPIENTRY 134_mesa_FrontFace(GLenum mode) 135{ 136 GET_CURRENT_CONTEXT(ctx); 137 138 if (MESA_VERBOSE & VERBOSE_API) 139 _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode)); 140 141 front_face(ctx, mode, false); 142} 143 144 145/** 146 * Set the polygon rasterization mode. 147 * 148 * \param face the polygons which \p mode applies to. 149 * \param mode how polygons should be rasterized. 150 * 151 * \sa glPolygonMode(). 152 * 153 * Verifies the parameters and updates gl_polygon_attrib::FrontMode and 154 * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the 155 * driver via the dd_function_table::PolygonMode callback. 156 */ 157static ALWAYS_INLINE void 158polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error) 159{ 160 if (MESA_VERBOSE & VERBOSE_API) 161 _mesa_debug(ctx, "glPolygonMode %s %s\n", 162 _mesa_enum_to_string(face), 163 _mesa_enum_to_string(mode)); 164 165 if (!no_error) { 166 switch (mode) { 167 case GL_POINT: 168 case GL_LINE: 169 case GL_FILL: 170 break; 171 case GL_FILL_RECTANGLE_NV: 172 if (ctx->Extensions.NV_fill_rectangle) 173 break; 174 /* fall-through */ 175 default: 176 _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)"); 177 return; 178 } 179 } 180 181 switch (face) { 182 case GL_FRONT: 183 if (!no_error && ctx->API == API_OPENGL_CORE) { 184 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 185 return; 186 } 187 if (ctx->Polygon.FrontMode == mode) 188 return; 189 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 190 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 191 ctx->Polygon.FrontMode = mode; 192 break; 193 case GL_FRONT_AND_BACK: 194 if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode) 195 return; 196 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 197 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 198 ctx->Polygon.FrontMode = mode; 199 ctx->Polygon.BackMode = mode; 200 break; 201 case GL_BACK: 202 if (!no_error && ctx->API == API_OPENGL_CORE) { 203 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 204 return; 205 } 206 if (ctx->Polygon.BackMode == mode) 207 return; 208 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 209 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 210 ctx->Polygon.BackMode = mode; 211 break; 212 default: 213 if (!no_error) 214 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); 215 return; 216 } 217 218 if (ctx->Driver.PolygonMode) 219 ctx->Driver.PolygonMode(ctx, face, mode); 220} 221 222 223void GLAPIENTRY 224_mesa_PolygonMode_no_error(GLenum face, GLenum mode) 225{ 226 GET_CURRENT_CONTEXT(ctx); 227 polygon_mode(ctx, face, mode, true); 228} 229 230 231void GLAPIENTRY 232_mesa_PolygonMode(GLenum face, GLenum mode) 233{ 234 GET_CURRENT_CONTEXT(ctx); 235 polygon_mode(ctx, face, mode, false); 236} 237 238 239/** 240 * Called by glPolygonStipple. 241 */ 242void GLAPIENTRY 243_mesa_PolygonStipple(const GLubyte *pattern) 244{ 245 GET_CURRENT_CONTEXT(ctx); 246 247 if (MESA_VERBOSE & VERBOSE_API) 248 _mesa_debug(ctx, "glPolygonStipple\n"); 249 250 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 : 251 _NEW_POLYGONSTIPPLE); 252 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple; 253 254 pattern = _mesa_map_validate_pbo_source(ctx, 2, 255 &ctx->Unpack, 32, 32, 1, 256 GL_COLOR_INDEX, GL_BITMAP, 257 INT_MAX, pattern, 258 "glPolygonStipple"); 259 if (!pattern) 260 return; 261 262 _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); 263 264 _mesa_unmap_pbo_source(ctx, &ctx->Unpack); 265 266 if (ctx->Driver.PolygonStipple) 267 ctx->Driver.PolygonStipple(ctx, pattern); 268} 269 270 271/** 272 * Called by glPolygonStipple. 273 */ 274void GLAPIENTRY 275_mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest ) 276{ 277 GET_CURRENT_CONTEXT(ctx); 278 279 if (MESA_VERBOSE&VERBOSE_API) 280 _mesa_debug(ctx, "glGetPolygonStipple\n"); 281 282 dest = _mesa_map_validate_pbo_dest(ctx, 2, 283 &ctx->Pack, 32, 32, 1, 284 GL_COLOR_INDEX, GL_BITMAP, 285 bufSize, dest, "glGetPolygonStipple"); 286 if (!dest) 287 return; 288 289 _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); 290 291 _mesa_unmap_pbo_dest(ctx, &ctx->Pack); 292} 293 294 295void GLAPIENTRY 296_mesa_GetPolygonStipple( GLubyte *dest ) 297{ 298 _mesa_GetnPolygonStippleARB(INT_MAX, dest); 299} 300 301void 302_mesa_polygon_offset_clamp(struct gl_context *ctx, 303 GLfloat factor, GLfloat units, GLfloat clamp) 304{ 305 if (ctx->Polygon.OffsetFactor == factor && 306 ctx->Polygon.OffsetUnits == units && 307 ctx->Polygon.OffsetClamp == clamp) 308 return; 309 310 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON); 311 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState; 312 ctx->Polygon.OffsetFactor = factor; 313 ctx->Polygon.OffsetUnits = units; 314 ctx->Polygon.OffsetClamp = clamp; 315 316 if (ctx->Driver.PolygonOffset) 317 ctx->Driver.PolygonOffset( ctx, factor, units, clamp ); 318} 319 320void GLAPIENTRY 321_mesa_PolygonOffset( GLfloat factor, GLfloat units ) 322{ 323 GET_CURRENT_CONTEXT(ctx); 324 325 if (MESA_VERBOSE&VERBOSE_API) 326 _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); 327 328 _mesa_polygon_offset_clamp(ctx, factor, units, 0.0); 329} 330 331void GLAPIENTRY 332_mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp ) 333{ 334 GET_CURRENT_CONTEXT(ctx); 335 336 if (!ctx->Extensions.ARB_polygon_offset_clamp) { 337 _mesa_error(ctx, GL_INVALID_OPERATION, 338 "unsupported function (%s) called", "glPolygonOffsetClamp"); 339 return; 340 } 341 342 if (MESA_VERBOSE&VERBOSE_API) 343 _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp); 344 345 _mesa_polygon_offset_clamp(ctx, factor, units, clamp); 346} 347 348/**********************************************************************/ 349/** \name Initialization */ 350/*@{*/ 351 352/** 353 * Initialize the context polygon state. 354 * 355 * \param ctx GL context. 356 * 357 * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple 358 * attribute groups. 359 */ 360void _mesa_init_polygon( struct gl_context * ctx ) 361{ 362 /* Polygon group */ 363 ctx->Polygon.CullFlag = GL_FALSE; 364 ctx->Polygon.CullFaceMode = GL_BACK; 365 ctx->Polygon.FrontFace = GL_CCW; 366 ctx->Polygon.FrontMode = GL_FILL; 367 ctx->Polygon.BackMode = GL_FILL; 368 ctx->Polygon.SmoothFlag = GL_FALSE; 369 ctx->Polygon.StippleFlag = GL_FALSE; 370 ctx->Polygon.OffsetFactor = 0.0F; 371 ctx->Polygon.OffsetUnits = 0.0F; 372 ctx->Polygon.OffsetClamp = 0.0F; 373 ctx->Polygon.OffsetPoint = GL_FALSE; 374 ctx->Polygon.OffsetLine = GL_FALSE; 375 ctx->Polygon.OffsetFill = GL_FALSE; 376 377 378 /* Polygon Stipple group */ 379 memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); 380} 381 382/*@}*/ 383