• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 #include "context.h"
34 #include "draw_validate.h"
35 #include "image.h"
36 #include "enums.h"
37 #include "pack.h"
38 #include "pbo.h"
39 #include "polygon.h"
40 #include "mtypes.h"
41 
42 
43 /**
44  * Specify whether to cull front- or back-facing facets.
45  *
46  * \param mode culling mode.
47  *
48  * \sa glCullFace().
49  *
50  * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On
51  * change, flushes the vertices and notifies the driver via
52  * the dd_function_table::CullFace callback.
53  */
54 static ALWAYS_INLINE void
cull_face(struct gl_context * ctx,GLenum mode,bool no_error)55 cull_face(struct gl_context *ctx, GLenum mode, bool no_error)
56 {
57    if (ctx->Polygon.CullFaceMode == mode)
58       return;
59 
60    if (!no_error &&
61        mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) {
62       _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace");
63       return;
64    }
65 
66    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
67                   GL_POLYGON_BIT);
68    ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
69    ctx->Polygon.CullFaceMode = mode;
70 
71    if (ctx->Driver.CullFace)
72       ctx->Driver.CullFace(ctx, mode);
73 }
74 
75 
76 void GLAPIENTRY
_mesa_CullFace_no_error(GLenum mode)77 _mesa_CullFace_no_error(GLenum mode)
78 {
79    GET_CURRENT_CONTEXT(ctx);
80    cull_face(ctx, mode, true);
81 }
82 
83 
84 void GLAPIENTRY
_mesa_CullFace(GLenum mode)85 _mesa_CullFace(GLenum mode)
86 {
87    GET_CURRENT_CONTEXT(ctx);
88 
89    if (MESA_VERBOSE & VERBOSE_API)
90       _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode));
91 
92    cull_face(ctx, mode, false);
93 }
94 
95 
96 /**
97  * Define front- and back-facing
98  *
99  * \param mode orientation of front-facing polygons.
100  *
101  * \sa glFrontFace().
102  *
103  * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
104  * flushes the vertices and notifies the driver via
105  * the dd_function_table::FrontFace callback.
106  */
107 static ALWAYS_INLINE void
front_face(struct gl_context * ctx,GLenum mode,bool no_error)108 front_face(struct gl_context *ctx, GLenum mode, bool no_error)
109 {
110    if (ctx->Polygon.FrontFace == mode)
111       return;
112 
113    if (!no_error && mode != GL_CW && mode != GL_CCW) {
114       _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace");
115       return;
116    }
117 
118    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
119                   GL_POLYGON_BIT);
120    ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
121    ctx->Polygon.FrontFace = mode;
122 
123    if (ctx->Driver.FrontFace)
124       ctx->Driver.FrontFace(ctx, mode);
125 }
126 
127 
128 void GLAPIENTRY
_mesa_FrontFace_no_error(GLenum mode)129 _mesa_FrontFace_no_error(GLenum mode)
130 {
131    GET_CURRENT_CONTEXT(ctx);
132    front_face(ctx, mode, true);
133 }
134 
135 
136 void GLAPIENTRY
_mesa_FrontFace(GLenum mode)137 _mesa_FrontFace(GLenum mode)
138 {
139    GET_CURRENT_CONTEXT(ctx);
140 
141    if (MESA_VERBOSE & VERBOSE_API)
142       _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode));
143 
144    front_face(ctx, mode, false);
145 }
146 
147 
148 /**
149  * Set the polygon rasterization mode.
150  *
151  * \param face the polygons which \p mode applies to.
152  * \param mode how polygons should be rasterized.
153  *
154  * \sa glPolygonMode().
155  *
156  * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
157  * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
158  * driver via the dd_function_table::PolygonMode callback.
159  */
160 static ALWAYS_INLINE void
polygon_mode(struct gl_context * ctx,GLenum face,GLenum mode,bool no_error)161 polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
162 {
163    bool old_mode_has_fill_rectangle =
164       ctx->Polygon.FrontMode == GL_FILL_RECTANGLE_NV ||
165       ctx->Polygon.BackMode == GL_FILL_RECTANGLE_NV;
166 
167    if (MESA_VERBOSE & VERBOSE_API)
168       _mesa_debug(ctx, "glPolygonMode %s %s\n",
169                   _mesa_enum_to_string(face),
170                   _mesa_enum_to_string(mode));
171 
172    if (!no_error) {
173       switch (mode) {
174       case GL_POINT:
175       case GL_LINE:
176       case GL_FILL:
177          break;
178       case GL_FILL_RECTANGLE_NV:
179          if (ctx->Extensions.NV_fill_rectangle)
180             break;
181          FALLTHROUGH;
182       default:
183          _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)");
184          return;
185       }
186    }
187 
188    switch (face) {
189    case GL_FRONT:
190       if (!no_error && ctx->API == API_OPENGL_CORE) {
191          _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
192          return;
193       }
194       if (ctx->Polygon.FrontMode == mode)
195          return;
196       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
197                      GL_POLYGON_BIT);
198       ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
199       ctx->Polygon.FrontMode = mode;
200       break;
201    case GL_FRONT_AND_BACK:
202       if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode)
203          return;
204       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
205                      GL_POLYGON_BIT);
206       ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
207       ctx->Polygon.FrontMode = mode;
208       ctx->Polygon.BackMode = mode;
209       break;
210    case GL_BACK:
211       if (!no_error && ctx->API == API_OPENGL_CORE) {
212          _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
213          return;
214       }
215       if (ctx->Polygon.BackMode == mode)
216          return;
217       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
218                      GL_POLYGON_BIT);
219       ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
220       ctx->Polygon.BackMode = mode;
221       break;
222    default:
223       if (!no_error)
224          _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
225       return;
226    }
227 
228    if (ctx->Driver.PolygonMode)
229       ctx->Driver.PolygonMode(ctx, face, mode);
230 
231    if (ctx->Extensions.INTEL_conservative_rasterization ||
232        (mode == GL_FILL_RECTANGLE_NV || old_mode_has_fill_rectangle))
233       _mesa_update_valid_to_render_state(ctx);
234 }
235 
236 
237 void GLAPIENTRY
_mesa_PolygonMode_no_error(GLenum face,GLenum mode)238 _mesa_PolygonMode_no_error(GLenum face, GLenum mode)
239 {
240    GET_CURRENT_CONTEXT(ctx);
241    polygon_mode(ctx, face, mode, true);
242 }
243 
244 
245 void GLAPIENTRY
_mesa_PolygonMode(GLenum face,GLenum mode)246 _mesa_PolygonMode(GLenum face, GLenum mode)
247 {
248    GET_CURRENT_CONTEXT(ctx);
249    polygon_mode(ctx, face, mode, false);
250 }
251 
252 
253 /**
254  * Called by glPolygonStipple.
255  */
256 void GLAPIENTRY
_mesa_PolygonStipple(const GLubyte * pattern)257 _mesa_PolygonStipple(const GLubyte *pattern)
258 {
259    GET_CURRENT_CONTEXT(ctx);
260 
261    if (MESA_VERBOSE & VERBOSE_API)
262       _mesa_debug(ctx, "glPolygonStipple\n");
263 
264    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 :
265                                                       _NEW_POLYGONSTIPPLE,
266                   GL_POLYGON_STIPPLE_BIT);
267    ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple;
268 
269    pattern = _mesa_map_validate_pbo_source(ctx, 2,
270                                            &ctx->Unpack, 32, 32, 1,
271                                            GL_COLOR_INDEX, GL_BITMAP,
272                                            INT_MAX, pattern,
273                                            "glPolygonStipple");
274    if (!pattern)
275       return;
276 
277    _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
278 
279    _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
280 
281    if (ctx->Driver.PolygonStipple)
282       ctx->Driver.PolygonStipple(ctx, pattern);
283 }
284 
285 
286 /**
287  * Called by glPolygonStipple.
288  */
289 void GLAPIENTRY
_mesa_GetnPolygonStippleARB(GLsizei bufSize,GLubyte * dest)290 _mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest )
291 {
292    GET_CURRENT_CONTEXT(ctx);
293 
294    if (MESA_VERBOSE&VERBOSE_API)
295       _mesa_debug(ctx, "glGetPolygonStipple\n");
296 
297    dest = _mesa_map_validate_pbo_dest(ctx, 2,
298                                       &ctx->Pack, 32, 32, 1,
299                                       GL_COLOR_INDEX, GL_BITMAP,
300                                       bufSize, dest, "glGetPolygonStipple");
301    if (!dest)
302       return;
303 
304    _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
305 
306    _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
307 }
308 
309 
310 void GLAPIENTRY
_mesa_GetPolygonStipple(GLubyte * dest)311 _mesa_GetPolygonStipple( GLubyte *dest )
312 {
313    _mesa_GetnPolygonStippleARB(INT_MAX, dest);
314 }
315 
316 void
_mesa_polygon_offset_clamp(struct gl_context * ctx,GLfloat factor,GLfloat units,GLfloat clamp)317 _mesa_polygon_offset_clamp(struct gl_context *ctx,
318                            GLfloat factor, GLfloat units, GLfloat clamp)
319 {
320    if (ctx->Polygon.OffsetFactor == factor &&
321        ctx->Polygon.OffsetUnits == units &&
322        ctx->Polygon.OffsetClamp == clamp)
323       return;
324 
325    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON,
326                   GL_POLYGON_BIT);
327    ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
328    ctx->Polygon.OffsetFactor = factor;
329    ctx->Polygon.OffsetUnits = units;
330    ctx->Polygon.OffsetClamp = clamp;
331 
332    if (ctx->Driver.PolygonOffset)
333       ctx->Driver.PolygonOffset( ctx, factor, units, clamp );
334 }
335 
336 void GLAPIENTRY
_mesa_PolygonOffset(GLfloat factor,GLfloat units)337 _mesa_PolygonOffset( GLfloat factor, GLfloat units )
338 {
339    GET_CURRENT_CONTEXT(ctx);
340 
341    if (MESA_VERBOSE&VERBOSE_API)
342       _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
343 
344    _mesa_polygon_offset_clamp(ctx, factor, units, 0.0);
345 }
346 
347 void GLAPIENTRY
_mesa_PolygonOffsetClampEXT(GLfloat factor,GLfloat units,GLfloat clamp)348 _mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp )
349 {
350    GET_CURRENT_CONTEXT(ctx);
351 
352    if (!ctx->Extensions.ARB_polygon_offset_clamp) {
353       _mesa_error(ctx, GL_INVALID_OPERATION,
354                   "unsupported function (%s) called", "glPolygonOffsetClamp");
355       return;
356    }
357 
358    if (MESA_VERBOSE&VERBOSE_API)
359       _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp);
360 
361    _mesa_polygon_offset_clamp(ctx, factor, units, clamp);
362 }
363 
364 /**********************************************************************/
365 /** \name Initialization */
366 /*@{*/
367 
368 /**
369  * Initialize the context polygon state.
370  *
371  * \param ctx GL context.
372  *
373  * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
374  * attribute groups.
375  */
_mesa_init_polygon(struct gl_context * ctx)376 void _mesa_init_polygon( struct gl_context * ctx )
377 {
378    /* Polygon group */
379    ctx->Polygon.CullFlag = GL_FALSE;
380    ctx->Polygon.CullFaceMode = GL_BACK;
381    ctx->Polygon.FrontFace = GL_CCW;
382    ctx->Polygon.FrontMode = GL_FILL;
383    ctx->Polygon.BackMode = GL_FILL;
384    ctx->Polygon.SmoothFlag = GL_FALSE;
385    ctx->Polygon.StippleFlag = GL_FALSE;
386    ctx->Polygon.OffsetFactor = 0.0F;
387    ctx->Polygon.OffsetUnits = 0.0F;
388    ctx->Polygon.OffsetClamp = 0.0F;
389    ctx->Polygon.OffsetPoint = GL_FALSE;
390    ctx->Polygon.OffsetLine = GL_FALSE;
391    ctx->Polygon.OffsetFill = GL_FALSE;
392 
393 
394    /* Polygon Stipple group */
395    memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
396 }
397 
398 /*@}*/
399