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