vc4: Introduce XML-based packet header generation like Intel's.
[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 static ALWAYS_INLINE void
105 front_face(struct gl_context *ctx, GLenum mode, bool no_error)
106 {
107 if (ctx->Polygon.FrontFace == mode)
108 return;
109
110 if (!no_error && mode != GL_CW && mode != GL_CCW) {
111 _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace");
112 return;
113 }
114
115 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
116 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
117 ctx->Polygon.FrontFace = mode;
118
119 if (ctx->Driver.FrontFace)
120 ctx->Driver.FrontFace(ctx, mode);
121 }
122
123
124 void GLAPIENTRY
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
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 void GLAPIENTRY
157 _mesa_PolygonMode( GLenum face, GLenum mode )
158 {
159 GET_CURRENT_CONTEXT(ctx);
160
161 if (MESA_VERBOSE&VERBOSE_API)
162 _mesa_debug(ctx, "glPolygonMode %s %s\n",
163 _mesa_enum_to_string(face),
164 _mesa_enum_to_string(mode));
165
166 switch (mode) {
167 case GL_POINT:
168 case GL_LINE:
169 case GL_FILL:
170 break;
171 case GL_FILL_RECTANGLE_NV:
172 if (ctx->Extensions.NV_fill_rectangle)
173 break;
174 /* fall-through */
175 default:
176 _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)");
177 return;
178 }
179
180 switch (face) {
181 case GL_FRONT:
182 if (ctx->API == API_OPENGL_CORE) {
183 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
184 return;
185 }
186 if (ctx->Polygon.FrontMode == mode)
187 return;
188 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
189 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
190 ctx->Polygon.FrontMode = mode;
191 break;
192 case GL_FRONT_AND_BACK:
193 if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode)
194 return;
195 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
196 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
197 ctx->Polygon.FrontMode = mode;
198 ctx->Polygon.BackMode = mode;
199 break;
200 case GL_BACK:
201 if (ctx->API == API_OPENGL_CORE) {
202 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
203 return;
204 }
205 if (ctx->Polygon.BackMode == mode)
206 return;
207 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
208 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
209 ctx->Polygon.BackMode = mode;
210 break;
211 default:
212 _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
213 return;
214 }
215
216 if (ctx->Driver.PolygonMode)
217 ctx->Driver.PolygonMode(ctx, face, mode);
218 }
219
220
221 /**
222 * Called by glPolygonStipple.
223 */
224 void GLAPIENTRY
225 _mesa_PolygonStipple(const GLubyte *pattern)
226 {
227 GET_CURRENT_CONTEXT(ctx);
228
229 if (MESA_VERBOSE & VERBOSE_API)
230 _mesa_debug(ctx, "glPolygonStipple\n");
231
232 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 :
233 _NEW_POLYGONSTIPPLE);
234 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple;
235
236 pattern = _mesa_map_validate_pbo_source(ctx, 2,
237 &ctx->Unpack, 32, 32, 1,
238 GL_COLOR_INDEX, GL_BITMAP,
239 INT_MAX, pattern,
240 "glPolygonStipple");
241 if (!pattern)
242 return;
243
244 _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
245
246 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
247
248 if (ctx->Driver.PolygonStipple)
249 ctx->Driver.PolygonStipple(ctx, pattern);
250 }
251
252
253 /**
254 * Called by glPolygonStipple.
255 */
256 void GLAPIENTRY
257 _mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest )
258 {
259 GET_CURRENT_CONTEXT(ctx);
260
261 if (MESA_VERBOSE&VERBOSE_API)
262 _mesa_debug(ctx, "glGetPolygonStipple\n");
263
264 dest = _mesa_map_validate_pbo_dest(ctx, 2,
265 &ctx->Pack, 32, 32, 1,
266 GL_COLOR_INDEX, GL_BITMAP,
267 bufSize, dest, "glGetPolygonStipple");
268 if (!dest)
269 return;
270
271 _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
272
273 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
274 }
275
276
277 void GLAPIENTRY
278 _mesa_GetPolygonStipple( GLubyte *dest )
279 {
280 _mesa_GetnPolygonStippleARB(INT_MAX, dest);
281 }
282
283 void
284 _mesa_polygon_offset_clamp(struct gl_context *ctx,
285 GLfloat factor, GLfloat units, GLfloat clamp)
286 {
287 if (ctx->Polygon.OffsetFactor == factor &&
288 ctx->Polygon.OffsetUnits == units &&
289 ctx->Polygon.OffsetClamp == clamp)
290 return;
291
292 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
293 ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
294 ctx->Polygon.OffsetFactor = factor;
295 ctx->Polygon.OffsetUnits = units;
296 ctx->Polygon.OffsetClamp = clamp;
297
298 if (ctx->Driver.PolygonOffset)
299 ctx->Driver.PolygonOffset( ctx, factor, units, clamp );
300 }
301
302 void GLAPIENTRY
303 _mesa_PolygonOffset( GLfloat factor, GLfloat units )
304 {
305 GET_CURRENT_CONTEXT(ctx);
306
307 if (MESA_VERBOSE&VERBOSE_API)
308 _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
309
310 _mesa_polygon_offset_clamp(ctx, factor, units, 0.0);
311 }
312
313
314 void GLAPIENTRY
315 _mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias )
316 {
317 GET_CURRENT_CONTEXT(ctx);
318 /* XXX mult by DepthMaxF here??? */
319 _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF );
320 }
321
322 void GLAPIENTRY
323 _mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp )
324 {
325 GET_CURRENT_CONTEXT(ctx);
326
327 if (!ctx->Extensions.EXT_polygon_offset_clamp) {
328 _mesa_error(ctx, GL_INVALID_OPERATION,
329 "unsupported function (glPolygonOffsetClampEXT) called");
330 return;
331 }
332
333 if (MESA_VERBOSE&VERBOSE_API)
334 _mesa_debug(ctx, "glPolygonOffsetClampEXT %f %f %f\n", factor, units, clamp);
335
336 _mesa_polygon_offset_clamp(ctx, factor, units, clamp);
337 }
338
339
340
341 /**********************************************************************/
342 /** \name Initialization */
343 /*@{*/
344
345 /**
346 * Initialize the context polygon state.
347 *
348 * \param ctx GL context.
349 *
350 * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
351 * attribute groups.
352 */
353 void _mesa_init_polygon( struct gl_context * ctx )
354 {
355 /* Polygon group */
356 ctx->Polygon.CullFlag = GL_FALSE;
357 ctx->Polygon.CullFaceMode = GL_BACK;
358 ctx->Polygon.FrontFace = GL_CCW;
359 ctx->Polygon.FrontMode = GL_FILL;
360 ctx->Polygon.BackMode = GL_FILL;
361 ctx->Polygon.SmoothFlag = GL_FALSE;
362 ctx->Polygon.StippleFlag = GL_FALSE;
363 ctx->Polygon.OffsetFactor = 0.0F;
364 ctx->Polygon.OffsetUnits = 0.0F;
365 ctx->Polygon.OffsetClamp = 0.0F;
366 ctx->Polygon.OffsetPoint = GL_FALSE;
367 ctx->Polygon.OffsetLine = GL_FALSE;
368 ctx->Polygon.OffsetFill = GL_FALSE;
369
370
371 /* Polygon Stipple group */
372 memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
373 }
374
375 /*@}*/