1 /**
2  * \file polygon.c
3  * Polygon operations.
4  */
5 
6 /*
7  * Mesa 3-D graphics library
8  * Version:  6.5.1
9  *
10  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR 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  */
53 void GLAPIENTRY
_mesa_CullFace(GLenum mode)54 _mesa_CullFace( GLenum mode )
55 {
56    GET_CURRENT_CONTEXT(ctx);
57    ASSERT_OUTSIDE_BEGIN_END(ctx);
58 
59    if (MESA_VERBOSE&VERBOSE_API)
60       _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode));
61 
62    if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) {
63       _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" );
64       return;
65    }
66 
67    if (ctx->Polygon.CullFaceMode == mode)
68       return;
69 
70    FLUSH_VERTICES(ctx, _NEW_POLYGON);
71    ctx->Polygon.CullFaceMode = mode;
72 
73    if (ctx->Driver.CullFace)
74       ctx->Driver.CullFace( ctx, mode );
75 }
76 
77 
78 /**
79  * Define front- and back-facing
80  *
81  * \param mode orientation of front-facing polygons.
82  *
83  * \sa glFrontFace().
84  *
85  * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
86  * flushes the vertices and notifies the driver via
87  * the dd_function_table::FrontFace callback.
88  */
89 void GLAPIENTRY
_mesa_FrontFace(GLenum mode)90 _mesa_FrontFace( GLenum mode )
91 {
92    GET_CURRENT_CONTEXT(ctx);
93    ASSERT_OUTSIDE_BEGIN_END(ctx);
94 
95    if (MESA_VERBOSE&VERBOSE_API)
96       _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode));
97 
98    if (mode!=GL_CW && mode!=GL_CCW) {
99       _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" );
100       return;
101    }
102 
103    if (ctx->Polygon.FrontFace == mode)
104       return;
105 
106    FLUSH_VERTICES(ctx, _NEW_POLYGON);
107    ctx->Polygon.FrontFace = mode;
108 
109    ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW);
110 
111    if (ctx->Driver.FrontFace)
112       ctx->Driver.FrontFace( ctx, mode );
113 }
114 
115 
116 /**
117  * Set the polygon rasterization mode.
118  *
119  * \param face the polygons which \p mode applies to.
120  * \param mode how polygons should be rasterized.
121  *
122  * \sa glPolygonMode().
123  *
124  * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
125  * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
126  * driver via the dd_function_table::PolygonMode callback.
127  */
128 void GLAPIENTRY
_mesa_PolygonMode(GLenum face,GLenum mode)129 _mesa_PolygonMode( GLenum face, GLenum mode )
130 {
131    GET_CURRENT_CONTEXT(ctx);
132    ASSERT_OUTSIDE_BEGIN_END(ctx);
133 
134    if (MESA_VERBOSE&VERBOSE_API)
135       _mesa_debug(ctx, "glPolygonMode %s %s\n",
136                   _mesa_lookup_enum_by_nr(face),
137                   _mesa_lookup_enum_by_nr(mode));
138 
139    if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) {
140       _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" );
141       return;
142    }
143 
144    switch (face) {
145    case GL_FRONT:
146       if (ctx->API == API_OPENGL_CORE) {
147          _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
148          return;
149       }
150       if (ctx->Polygon.FrontMode == mode)
151 	 return;
152       FLUSH_VERTICES(ctx, _NEW_POLYGON);
153       ctx->Polygon.FrontMode = mode;
154       break;
155    case GL_FRONT_AND_BACK:
156       if (ctx->Polygon.FrontMode == mode &&
157 	  ctx->Polygon.BackMode == mode)
158 	 return;
159       FLUSH_VERTICES(ctx, _NEW_POLYGON);
160       ctx->Polygon.FrontMode = mode;
161       ctx->Polygon.BackMode = mode;
162       break;
163    case GL_BACK:
164       if (ctx->API == API_OPENGL_CORE) {
165          _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
166          return;
167       }
168       if (ctx->Polygon.BackMode == mode)
169 	 return;
170       FLUSH_VERTICES(ctx, _NEW_POLYGON);
171       ctx->Polygon.BackMode = mode;
172       break;
173    default:
174       _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
175       return;
176    }
177 
178    if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL)
179       ctx->_TriangleCaps &= ~DD_TRI_UNFILLED;
180    else
181       ctx->_TriangleCaps |= DD_TRI_UNFILLED;
182 
183    if (ctx->Driver.PolygonMode)
184       ctx->Driver.PolygonMode(ctx, face, mode);
185 }
186 
187 #if _HAVE_FULL_GL
188 
189 
190 /**
191  * This routine updates the ctx->Polygon.Stipple state.
192  * If we're getting the stipple data from a PBO, we map the buffer
193  * in order to access the data.
194  * In any case, we obey the current pixel unpacking parameters when fetching
195  * the stipple data.
196  *
197  * In the future, this routine should be used as a fallback, called via
198  * ctx->Driver.PolygonStipple().  We'll have to update all the DRI drivers
199  * too.
200  */
201 void
_mesa_polygon_stipple(struct gl_context * ctx,const GLubyte * pattern)202 _mesa_polygon_stipple(struct gl_context *ctx, const GLubyte *pattern)
203 {
204    pattern = _mesa_map_validate_pbo_source(ctx, 2,
205                                            &ctx->Unpack, 32, 32, 1,
206                                            GL_COLOR_INDEX, GL_BITMAP,
207                                            INT_MAX, pattern,
208                                            "glPolygonStipple");
209    if (!pattern)
210       return;
211 
212    _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
213 
214    _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
215 }
216 
217 
218 /**
219  * Called by glPolygonStipple.
220  */
221 void GLAPIENTRY
_mesa_PolygonStipple(const GLubyte * pattern)222 _mesa_PolygonStipple( const GLubyte *pattern )
223 {
224    GET_CURRENT_CONTEXT(ctx);
225    ASSERT_OUTSIDE_BEGIN_END(ctx);
226 
227    if (MESA_VERBOSE&VERBOSE_API)
228       _mesa_debug(ctx, "glPolygonStipple\n");
229 
230    FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE);
231 
232    _mesa_polygon_stipple(ctx, pattern);
233 
234    if (ctx->Driver.PolygonStipple)
235       ctx->Driver.PolygonStipple(ctx, pattern);
236 }
237 
238 
239 /**
240  * Called by glPolygonStipple.
241  */
242 void GLAPIENTRY
_mesa_GetnPolygonStippleARB(GLsizei bufSize,GLubyte * dest)243 _mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest )
244 {
245    GET_CURRENT_CONTEXT(ctx);
246    ASSERT_OUTSIDE_BEGIN_END(ctx);
247 
248    if (MESA_VERBOSE&VERBOSE_API)
249       _mesa_debug(ctx, "glGetPolygonStipple\n");
250 
251    dest = _mesa_map_validate_pbo_dest(ctx, 2,
252                                       &ctx->Pack, 32, 32, 1,
253                                       GL_COLOR_INDEX, GL_BITMAP,
254                                       bufSize, dest, "glGetPolygonStipple");
255    if (!dest)
256       return;
257 
258    _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
259 
260    _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
261 }
262 
263 
264 void GLAPIENTRY
_mesa_GetPolygonStipple(GLubyte * dest)265 _mesa_GetPolygonStipple( GLubyte *dest )
266 {
267    _mesa_GetnPolygonStippleARB(INT_MAX, dest);
268 }
269 
270 
271 void GLAPIENTRY
_mesa_PolygonOffset(GLfloat factor,GLfloat units)272 _mesa_PolygonOffset( GLfloat factor, GLfloat units )
273 {
274    GET_CURRENT_CONTEXT(ctx);
275    ASSERT_OUTSIDE_BEGIN_END(ctx);
276 
277    if (MESA_VERBOSE&VERBOSE_API)
278       _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
279 
280    if (ctx->Polygon.OffsetFactor == factor &&
281        ctx->Polygon.OffsetUnits == units)
282       return;
283 
284    FLUSH_VERTICES(ctx, _NEW_POLYGON);
285    ctx->Polygon.OffsetFactor = factor;
286    ctx->Polygon.OffsetUnits = units;
287 
288    if (ctx->Driver.PolygonOffset)
289       ctx->Driver.PolygonOffset( ctx, factor, units );
290 }
291 
292 
293 void GLAPIENTRY
_mesa_PolygonOffsetEXT(GLfloat factor,GLfloat bias)294 _mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias )
295 {
296    GET_CURRENT_CONTEXT(ctx);
297    /* XXX mult by DepthMaxF here??? */
298    _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF );
299 }
300 
301 #endif
302 
303 
304 /**********************************************************************/
305 /** \name Initialization */
306 /*@{*/
307 
308 /**
309  * Initialize the context polygon state.
310  *
311  * \param ctx GL context.
312  *
313  * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
314  * attribute groups.
315  */
_mesa_init_polygon(struct gl_context * ctx)316 void _mesa_init_polygon( struct gl_context * ctx )
317 {
318    /* Polygon group */
319    ctx->Polygon.CullFlag = GL_FALSE;
320    ctx->Polygon.CullFaceMode = GL_BACK;
321    ctx->Polygon.FrontFace = GL_CCW;
322    ctx->Polygon._FrontBit = 0;
323    ctx->Polygon.FrontMode = GL_FILL;
324    ctx->Polygon.BackMode = GL_FILL;
325    ctx->Polygon.SmoothFlag = GL_FALSE;
326    ctx->Polygon.StippleFlag = GL_FALSE;
327    ctx->Polygon.OffsetFactor = 0.0F;
328    ctx->Polygon.OffsetUnits = 0.0F;
329    ctx->Polygon.OffsetPoint = GL_FALSE;
330    ctx->Polygon.OffsetLine = GL_FALSE;
331    ctx->Polygon.OffsetFill = GL_FALSE;
332 
333 
334    /* Polygon Stipple group */
335    memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
336 }
337 
338 /*@}*/
339