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