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