1848b8605Smrg/**
2848b8605Smrg * \file polygon.c
3848b8605Smrg * Polygon operations.
4848b8605Smrg */
5848b8605Smrg
6848b8605Smrg/*
7848b8605Smrg * Mesa 3-D graphics library
8848b8605Smrg *
9848b8605Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
10848b8605Smrg *
11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
12848b8605Smrg * copy of this software and associated documentation files (the "Software"),
13848b8605Smrg * to deal in the Software without restriction, including without limitation
14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
16848b8605Smrg * Software is furnished to do so, subject to the following conditions:
17848b8605Smrg *
18848b8605Smrg * The above copyright notice and this permission notice shall be included
19848b8605Smrg * in all copies or substantial portions of the Software.
20848b8605Smrg *
21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
28848b8605Smrg */
29848b8605Smrg
30848b8605Smrg
31848b8605Smrg#include "glheader.h"
32848b8605Smrg#include "imports.h"
33848b8605Smrg#include "context.h"
34848b8605Smrg#include "image.h"
35848b8605Smrg#include "enums.h"
36848b8605Smrg#include "pack.h"
37848b8605Smrg#include "pbo.h"
38848b8605Smrg#include "polygon.h"
39848b8605Smrg#include "mtypes.h"
40848b8605Smrg
41848b8605Smrg
42848b8605Smrg/**
43848b8605Smrg * Specify whether to cull front- or back-facing facets.
44848b8605Smrg *
45848b8605Smrg * \param mode culling mode.
46848b8605Smrg *
47848b8605Smrg * \sa glCullFace().
48848b8605Smrg *
49848b8605Smrg * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On
50848b8605Smrg * change, flushes the vertices and notifies the driver via
51848b8605Smrg * the dd_function_table::CullFace callback.
52848b8605Smrg */
53b8e80941Smrgstatic ALWAYS_INLINE void
54b8e80941Smrgcull_face(struct gl_context *ctx, GLenum mode, bool no_error)
55848b8605Smrg{
56b8e80941Smrg   if (ctx->Polygon.CullFaceMode == mode)
57848b8605Smrg      return;
58848b8605Smrg
59b8e80941Smrg   if (!no_error &&
60b8e80941Smrg       mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK) {
61b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCullFace");
62848b8605Smrg      return;
63b8e80941Smrg   }
64848b8605Smrg
65b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
66b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
67848b8605Smrg   ctx->Polygon.CullFaceMode = mode;
68848b8605Smrg
69848b8605Smrg   if (ctx->Driver.CullFace)
70b8e80941Smrg      ctx->Driver.CullFace(ctx, mode);
71b8e80941Smrg}
72b8e80941Smrg
73b8e80941Smrg
74b8e80941Smrgvoid GLAPIENTRY
75b8e80941Smrg_mesa_CullFace_no_error(GLenum mode)
76b8e80941Smrg{
77b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
78b8e80941Smrg   cull_face(ctx, mode, true);
79b8e80941Smrg}
80b8e80941Smrg
81b8e80941Smrg
82b8e80941Smrgvoid GLAPIENTRY
83b8e80941Smrg_mesa_CullFace(GLenum mode)
84b8e80941Smrg{
85b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
86b8e80941Smrg
87b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
88b8e80941Smrg      _mesa_debug(ctx, "glCullFace %s\n", _mesa_enum_to_string(mode));
89b8e80941Smrg
90b8e80941Smrg   cull_face(ctx, mode, false);
91848b8605Smrg}
92848b8605Smrg
93848b8605Smrg
94848b8605Smrg/**
95b8e80941Smrg * Define front- and back-facing
96848b8605Smrg *
97848b8605Smrg * \param mode orientation of front-facing polygons.
98848b8605Smrg *
99848b8605Smrg * \sa glFrontFace().
100848b8605Smrg *
101848b8605Smrg * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
102848b8605Smrg * flushes the vertices and notifies the driver via
103848b8605Smrg * the dd_function_table::FrontFace callback.
104848b8605Smrg */
105b8e80941Smrgstatic ALWAYS_INLINE void
106b8e80941Smrgfront_face(struct gl_context *ctx, GLenum mode, bool no_error)
107848b8605Smrg{
108b8e80941Smrg   if (ctx->Polygon.FrontFace == mode)
109848b8605Smrg      return;
110848b8605Smrg
111b8e80941Smrg   if (!no_error && mode != GL_CW && mode != GL_CCW) {
112b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glFrontFace");
113848b8605Smrg      return;
114b8e80941Smrg   }
115848b8605Smrg
116b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
117b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
118848b8605Smrg   ctx->Polygon.FrontFace = mode;
119848b8605Smrg
120848b8605Smrg   if (ctx->Driver.FrontFace)
121b8e80941Smrg      ctx->Driver.FrontFace(ctx, mode);
122b8e80941Smrg}
123b8e80941Smrg
124b8e80941Smrg
125b8e80941Smrgvoid GLAPIENTRY
126b8e80941Smrg_mesa_FrontFace_no_error(GLenum mode)
127b8e80941Smrg{
128b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
129b8e80941Smrg   front_face(ctx, mode, true);
130b8e80941Smrg}
131b8e80941Smrg
132b8e80941Smrg
133b8e80941Smrgvoid GLAPIENTRY
134b8e80941Smrg_mesa_FrontFace(GLenum mode)
135b8e80941Smrg{
136b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
137b8e80941Smrg
138b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
139b8e80941Smrg      _mesa_debug(ctx, "glFrontFace %s\n", _mesa_enum_to_string(mode));
140b8e80941Smrg
141b8e80941Smrg   front_face(ctx, mode, false);
142848b8605Smrg}
143848b8605Smrg
144848b8605Smrg
145848b8605Smrg/**
146848b8605Smrg * Set the polygon rasterization mode.
147848b8605Smrg *
148848b8605Smrg * \param face the polygons which \p mode applies to.
149848b8605Smrg * \param mode how polygons should be rasterized.
150848b8605Smrg *
151b8e80941Smrg * \sa glPolygonMode().
152b8e80941Smrg *
153848b8605Smrg * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
154848b8605Smrg * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
155848b8605Smrg * driver via the dd_function_table::PolygonMode callback.
156848b8605Smrg */
157b8e80941Smrgstatic ALWAYS_INLINE void
158b8e80941Smrgpolygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
159848b8605Smrg{
160b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
161848b8605Smrg      _mesa_debug(ctx, "glPolygonMode %s %s\n",
162b8e80941Smrg                  _mesa_enum_to_string(face),
163b8e80941Smrg                  _mesa_enum_to_string(mode));
164b8e80941Smrg
165b8e80941Smrg   if (!no_error) {
166b8e80941Smrg      switch (mode) {
167b8e80941Smrg      case GL_POINT:
168b8e80941Smrg      case GL_LINE:
169b8e80941Smrg      case GL_FILL:
170b8e80941Smrg         break;
171b8e80941Smrg      case GL_FILL_RECTANGLE_NV:
172b8e80941Smrg         if (ctx->Extensions.NV_fill_rectangle)
173b8e80941Smrg            break;
174b8e80941Smrg         /* fall-through */
175b8e80941Smrg      default:
176b8e80941Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glPolygonMode(mode)");
177b8e80941Smrg         return;
178b8e80941Smrg      }
179848b8605Smrg   }
180848b8605Smrg
181848b8605Smrg   switch (face) {
182848b8605Smrg   case GL_FRONT:
183b8e80941Smrg      if (!no_error && ctx->API == API_OPENGL_CORE) {
184848b8605Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
185848b8605Smrg         return;
186848b8605Smrg      }
187848b8605Smrg      if (ctx->Polygon.FrontMode == mode)
188b8e80941Smrg         return;
189b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
190b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
191848b8605Smrg      ctx->Polygon.FrontMode = mode;
192848b8605Smrg      break;
193848b8605Smrg   case GL_FRONT_AND_BACK:
194b8e80941Smrg      if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode)
195b8e80941Smrg         return;
196b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
197b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
198848b8605Smrg      ctx->Polygon.FrontMode = mode;
199848b8605Smrg      ctx->Polygon.BackMode = mode;
200848b8605Smrg      break;
201848b8605Smrg   case GL_BACK:
202b8e80941Smrg      if (!no_error && ctx->API == API_OPENGL_CORE) {
203848b8605Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
204848b8605Smrg         return;
205848b8605Smrg      }
206848b8605Smrg      if (ctx->Polygon.BackMode == mode)
207b8e80941Smrg         return;
208b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
209b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
210848b8605Smrg      ctx->Polygon.BackMode = mode;
211848b8605Smrg      break;
212848b8605Smrg   default:
213b8e80941Smrg      if (!no_error)
214b8e80941Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
215848b8605Smrg      return;
216848b8605Smrg   }
217848b8605Smrg
218848b8605Smrg   if (ctx->Driver.PolygonMode)
219848b8605Smrg      ctx->Driver.PolygonMode(ctx, face, mode);
220848b8605Smrg}
221848b8605Smrg
222848b8605Smrg
223b8e80941Smrgvoid GLAPIENTRY
224b8e80941Smrg_mesa_PolygonMode_no_error(GLenum face, GLenum mode)
225848b8605Smrg{
226b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
227b8e80941Smrg   polygon_mode(ctx, face, mode, true);
228b8e80941Smrg}
229848b8605Smrg
230848b8605Smrg
231b8e80941Smrgvoid GLAPIENTRY
232b8e80941Smrg_mesa_PolygonMode(GLenum face, GLenum mode)
233b8e80941Smrg{
234b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
235b8e80941Smrg   polygon_mode(ctx, face, mode, false);
236848b8605Smrg}
237848b8605Smrg
238848b8605Smrg
239848b8605Smrg/**
240848b8605Smrg * Called by glPolygonStipple.
241848b8605Smrg */
242848b8605Smrgvoid GLAPIENTRY
243b8e80941Smrg_mesa_PolygonStipple(const GLubyte *pattern)
244848b8605Smrg{
245848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
246848b8605Smrg
247b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
248848b8605Smrg      _mesa_debug(ctx, "glPolygonStipple\n");
249848b8605Smrg
250b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonStipple ? 0 :
251b8e80941Smrg                                                      _NEW_POLYGONSTIPPLE);
252b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonStipple;
253848b8605Smrg
254b8e80941Smrg   pattern = _mesa_map_validate_pbo_source(ctx, 2,
255b8e80941Smrg                                           &ctx->Unpack, 32, 32, 1,
256b8e80941Smrg                                           GL_COLOR_INDEX, GL_BITMAP,
257b8e80941Smrg                                           INT_MAX, pattern,
258b8e80941Smrg                                           "glPolygonStipple");
259b8e80941Smrg   if (!pattern)
260b8e80941Smrg      return;
261b8e80941Smrg
262b8e80941Smrg   _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
263b8e80941Smrg
264b8e80941Smrg   _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
265848b8605Smrg
266848b8605Smrg   if (ctx->Driver.PolygonStipple)
267848b8605Smrg      ctx->Driver.PolygonStipple(ctx, pattern);
268848b8605Smrg}
269848b8605Smrg
270848b8605Smrg
271848b8605Smrg/**
272848b8605Smrg * Called by glPolygonStipple.
273848b8605Smrg */
274848b8605Smrgvoid GLAPIENTRY
275848b8605Smrg_mesa_GetnPolygonStippleARB( GLsizei bufSize, GLubyte *dest )
276848b8605Smrg{
277848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
278848b8605Smrg
279848b8605Smrg   if (MESA_VERBOSE&VERBOSE_API)
280848b8605Smrg      _mesa_debug(ctx, "glGetPolygonStipple\n");
281848b8605Smrg
282848b8605Smrg   dest = _mesa_map_validate_pbo_dest(ctx, 2,
283848b8605Smrg                                      &ctx->Pack, 32, 32, 1,
284848b8605Smrg                                      GL_COLOR_INDEX, GL_BITMAP,
285848b8605Smrg                                      bufSize, dest, "glGetPolygonStipple");
286848b8605Smrg   if (!dest)
287848b8605Smrg      return;
288848b8605Smrg
289848b8605Smrg   _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
290848b8605Smrg
291848b8605Smrg   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
292848b8605Smrg}
293848b8605Smrg
294848b8605Smrg
295848b8605Smrgvoid GLAPIENTRY
296848b8605Smrg_mesa_GetPolygonStipple( GLubyte *dest )
297848b8605Smrg{
298848b8605Smrg   _mesa_GetnPolygonStippleARB(INT_MAX, dest);
299848b8605Smrg}
300848b8605Smrg
301b8e80941Smrgvoid
302b8e80941Smrg_mesa_polygon_offset_clamp(struct gl_context *ctx,
303b8e80941Smrg                           GLfloat factor, GLfloat units, GLfloat clamp)
304848b8605Smrg{
305848b8605Smrg   if (ctx->Polygon.OffsetFactor == factor &&
306b8e80941Smrg       ctx->Polygon.OffsetUnits == units &&
307b8e80941Smrg       ctx->Polygon.OffsetClamp == clamp)
308848b8605Smrg      return;
309848b8605Smrg
310b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewPolygonState ? 0 : _NEW_POLYGON);
311b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
312848b8605Smrg   ctx->Polygon.OffsetFactor = factor;
313848b8605Smrg   ctx->Polygon.OffsetUnits = units;
314b8e80941Smrg   ctx->Polygon.OffsetClamp = clamp;
315848b8605Smrg
316848b8605Smrg   if (ctx->Driver.PolygonOffset)
317b8e80941Smrg      ctx->Driver.PolygonOffset( ctx, factor, units, clamp );
318848b8605Smrg}
319848b8605Smrg
320848b8605Smrgvoid GLAPIENTRY
321b8e80941Smrg_mesa_PolygonOffset( GLfloat factor, GLfloat units )
322848b8605Smrg{
323848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
324b8e80941Smrg
325b8e80941Smrg   if (MESA_VERBOSE&VERBOSE_API)
326b8e80941Smrg      _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
327b8e80941Smrg
328b8e80941Smrg   _mesa_polygon_offset_clamp(ctx, factor, units, 0.0);
329848b8605Smrg}
330848b8605Smrg
331b8e80941Smrgvoid GLAPIENTRY
332b8e80941Smrg_mesa_PolygonOffsetClampEXT( GLfloat factor, GLfloat units, GLfloat clamp )
333b8e80941Smrg{
334b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
335b8e80941Smrg
336b8e80941Smrg   if (!ctx->Extensions.ARB_polygon_offset_clamp) {
337b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
338b8e80941Smrg                  "unsupported function (%s) called", "glPolygonOffsetClamp");
339b8e80941Smrg      return;
340b8e80941Smrg   }
341848b8605Smrg
342b8e80941Smrg   if (MESA_VERBOSE&VERBOSE_API)
343b8e80941Smrg      _mesa_debug(ctx, "glPolygonOffsetClamp %f %f %f\n", factor, units, clamp);
344b8e80941Smrg
345b8e80941Smrg   _mesa_polygon_offset_clamp(ctx, factor, units, clamp);
346b8e80941Smrg}
347848b8605Smrg
348848b8605Smrg/**********************************************************************/
349848b8605Smrg/** \name Initialization */
350848b8605Smrg/*@{*/
351848b8605Smrg
352848b8605Smrg/**
353848b8605Smrg * Initialize the context polygon state.
354848b8605Smrg *
355848b8605Smrg * \param ctx GL context.
356848b8605Smrg *
357848b8605Smrg * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
358848b8605Smrg * attribute groups.
359848b8605Smrg */
360848b8605Smrgvoid _mesa_init_polygon( struct gl_context * ctx )
361848b8605Smrg{
362848b8605Smrg   /* Polygon group */
363848b8605Smrg   ctx->Polygon.CullFlag = GL_FALSE;
364848b8605Smrg   ctx->Polygon.CullFaceMode = GL_BACK;
365848b8605Smrg   ctx->Polygon.FrontFace = GL_CCW;
366848b8605Smrg   ctx->Polygon.FrontMode = GL_FILL;
367848b8605Smrg   ctx->Polygon.BackMode = GL_FILL;
368848b8605Smrg   ctx->Polygon.SmoothFlag = GL_FALSE;
369848b8605Smrg   ctx->Polygon.StippleFlag = GL_FALSE;
370848b8605Smrg   ctx->Polygon.OffsetFactor = 0.0F;
371848b8605Smrg   ctx->Polygon.OffsetUnits = 0.0F;
372b8e80941Smrg   ctx->Polygon.OffsetClamp = 0.0F;
373848b8605Smrg   ctx->Polygon.OffsetPoint = GL_FALSE;
374848b8605Smrg   ctx->Polygon.OffsetLine = GL_FALSE;
375848b8605Smrg   ctx->Polygon.OffsetFill = GL_FALSE;
376848b8605Smrg
377848b8605Smrg
378848b8605Smrg   /* Polygon Stipple group */
379848b8605Smrg   memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
380848b8605Smrg}
381848b8605Smrg
382848b8605Smrg/*@}*/
383