1c1f859d4Smrg/*
2c1f859d4Smrg * Mesa 3-D graphics library
3c1f859d4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5c1f859d4Smrg *
6c1f859d4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7c1f859d4Smrg * copy of this software and associated documentation files (the "Software"),
8c1f859d4Smrg * to deal in the Software without restriction, including without limitation
9c1f859d4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10c1f859d4Smrg * and/or sell copies of the Software, and to permit persons to whom the
11c1f859d4Smrg * Software is furnished to do so, subject to the following conditions:
12c1f859d4Smrg *
13c1f859d4Smrg * The above copyright notice and this permission notice shall be included
14c1f859d4Smrg * in all copies or substantial portions of the Software.
15c1f859d4Smrg *
16c1f859d4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17c1f859d4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c1f859d4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
23c1f859d4Smrg */
24c1f859d4Smrg
25c1f859d4Smrg
26c1f859d4Smrg#include "main/glheader.h"
27c1f859d4Smrg#include "main/context.h"
2801e04c3fSmrg#include "main/enums.h"
293464ebd5Sriastradh#include "main/mtypes.h"
30c1f859d4Smrg#include "main/scissor.h"
31c1f859d4Smrg
32c1f859d4Smrg
33af69d88dSmrg/**
34af69d88dSmrg * Set scissor rectangle data directly in ScissorArray
35af69d88dSmrg *
36af69d88dSmrg * This is an internal function that performs no error checking on the
37af69d88dSmrg * supplied data.  It also does \b not call \c dd_function_table::Scissor.
38af69d88dSmrg *
39af69d88dSmrg * \sa _mesa_set_scissor
40af69d88dSmrg */
41af69d88dSmrgstatic void
42af69d88dSmrgset_scissor_no_notify(struct gl_context *ctx, unsigned idx,
43af69d88dSmrg                      GLint x, GLint y, GLsizei width, GLsizei height)
44af69d88dSmrg{
45af69d88dSmrg   if (x == ctx->Scissor.ScissorArray[idx].X &&
46af69d88dSmrg       y == ctx->Scissor.ScissorArray[idx].Y &&
47af69d88dSmrg       width == ctx->Scissor.ScissorArray[idx].Width &&
48af69d88dSmrg       height == ctx->Scissor.ScissorArray[idx].Height)
49af69d88dSmrg      return;
50af69d88dSmrg
517ec681f3Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewScissorRect ? 0 : _NEW_SCISSOR,
527ec681f3Smrg                  GL_SCISSOR_BIT);
5301e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewScissorRect;
5401e04c3fSmrg
55af69d88dSmrg   ctx->Scissor.ScissorArray[idx].X = x;
56af69d88dSmrg   ctx->Scissor.ScissorArray[idx].Y = y;
57af69d88dSmrg   ctx->Scissor.ScissorArray[idx].Width = width;
58af69d88dSmrg   ctx->Scissor.ScissorArray[idx].Height = height;
59af69d88dSmrg}
60af69d88dSmrg
6101e04c3fSmrgstatic void
6201e04c3fSmrgscissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height)
63c1f859d4Smrg{
64af69d88dSmrg   unsigned i;
65c1f859d4Smrg
66af69d88dSmrg   /* The GL_ARB_viewport_array spec says:
67af69d88dSmrg    *
68af69d88dSmrg    *     "Scissor sets the scissor rectangle for all viewports to the same
69af69d88dSmrg    *     values and is equivalent (assuming no errors are generated) to:
70af69d88dSmrg    *
71af69d88dSmrg    *     for (uint i = 0; i < MAX_VIEWPORTS; i++) {
72af69d88dSmrg    *         ScissorIndexed(i, left, bottom, width, height);
73af69d88dSmrg    *     }"
74af69d88dSmrg    *
75af69d88dSmrg    * Set the scissor rectangle for all of the viewports supported by the
76af69d88dSmrg    * implementation, but only signal the driver once at the end.
77af69d88dSmrg    */
78af69d88dSmrg   for (i = 0; i < ctx->Const.MaxViewports; i++)
79af69d88dSmrg      set_scissor_no_notify(ctx, i, x, y, width, height);
80af69d88dSmrg
81af69d88dSmrg   if (ctx->Driver.Scissor)
82af69d88dSmrg      ctx->Driver.Scissor(ctx);
83c1f859d4Smrg}
84c1f859d4Smrg
8501e04c3fSmrg/**
8601e04c3fSmrg * Called via glScissor
8701e04c3fSmrg */
8801e04c3fSmrgvoid GLAPIENTRY
8901e04c3fSmrg_mesa_Scissor_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
9001e04c3fSmrg{
9101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9201e04c3fSmrg   scissor(ctx, x, y, width, height);
9301e04c3fSmrg}
9401e04c3fSmrg
9501e04c3fSmrgvoid GLAPIENTRY
9601e04c3fSmrg_mesa_Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
9701e04c3fSmrg{
9801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9901e04c3fSmrg
10001e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
10101e04c3fSmrg      _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
10201e04c3fSmrg
10301e04c3fSmrg   if (width < 0 || height < 0) {
10401e04c3fSmrg      _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
10501e04c3fSmrg      return;
10601e04c3fSmrg   }
10701e04c3fSmrg
10801e04c3fSmrg   scissor(ctx, x, y, width, height);
10901e04c3fSmrg}
11001e04c3fSmrg
111c1f859d4Smrg
112c1f859d4Smrg/**
113c1f859d4Smrg * Define the scissor box.
114c1f859d4Smrg *
115c1f859d4Smrg * \param x, y coordinates of the scissor box lower-left corner.
116c1f859d4Smrg * \param width width of the scissor box.
117c1f859d4Smrg * \param height height of the scissor box.
118c1f859d4Smrg *
119c1f859d4Smrg * \sa glScissor().
120c1f859d4Smrg *
1213464ebd5Sriastradh * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a
122c1f859d4Smrg * change flushes the vertices and notifies the driver via
123c1f859d4Smrg * the dd_function_table::Scissor callback.
124c1f859d4Smrg */
125c1f859d4Smrgvoid
126af69d88dSmrg_mesa_set_scissor(struct gl_context *ctx, unsigned idx,
127c1f859d4Smrg                  GLint x, GLint y, GLsizei width, GLsizei height)
128c1f859d4Smrg{
129af69d88dSmrg   set_scissor_no_notify(ctx, idx, x, y, width, height);
130af69d88dSmrg
131af69d88dSmrg   if (ctx->Driver.Scissor)
132af69d88dSmrg      ctx->Driver.Scissor(ctx);
133af69d88dSmrg}
134af69d88dSmrg
13501e04c3fSmrgstatic void
13601e04c3fSmrgscissor_array(struct gl_context *ctx, GLuint first, GLsizei count,
13701e04c3fSmrg              struct gl_scissor_rect *rect)
13801e04c3fSmrg{
13901e04c3fSmrg   for (GLsizei i = 0; i < count; i++) {
14001e04c3fSmrg      set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y,
14101e04c3fSmrg                            rect[i].Width, rect[i].Height);
14201e04c3fSmrg   }
14301e04c3fSmrg
14401e04c3fSmrg   if (ctx->Driver.Scissor)
14501e04c3fSmrg      ctx->Driver.Scissor(ctx);
14601e04c3fSmrg}
14701e04c3fSmrg
148af69d88dSmrg/**
149af69d88dSmrg * Define count scissor boxes starting at index.
150af69d88dSmrg *
151af69d88dSmrg * \param index  index of first scissor records to set
152af69d88dSmrg * \param count  number of scissor records to set
153af69d88dSmrg * \param x, y   pointer to array of struct gl_scissor_rects
154af69d88dSmrg *
155af69d88dSmrg * \sa glScissorArrayv().
156af69d88dSmrg *
157af69d88dSmrg * Verifies the parameters and call set_scissor_no_notify to do the work.
158af69d88dSmrg */
15901e04c3fSmrgvoid GLAPIENTRY
16001e04c3fSmrg_mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v)
16101e04c3fSmrg{
16201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
16301e04c3fSmrg
16401e04c3fSmrg   struct gl_scissor_rect *p = (struct gl_scissor_rect *)v;
16501e04c3fSmrg   scissor_array(ctx, first, count, p);
16601e04c3fSmrg}
16701e04c3fSmrg
168af69d88dSmrgvoid GLAPIENTRY
169af69d88dSmrg_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
170af69d88dSmrg{
171af69d88dSmrg   int i;
172af69d88dSmrg   struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
173af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
174af69d88dSmrg
175af69d88dSmrg   if ((first + count) > ctx->Const.MaxViewports) {
176af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
177af69d88dSmrg                  "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
178af69d88dSmrg                  first, count, ctx->Const.MaxViewports);
179c1f859d4Smrg      return;
180af69d88dSmrg   }
181c1f859d4Smrg
182af69d88dSmrg   /* Verify width & height */
183af69d88dSmrg   for (i = 0; i < count; i++) {
184af69d88dSmrg      if (p[i].Width < 0 || p[i].Height < 0) {
185af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
186af69d88dSmrg                     "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
187af69d88dSmrg                     i, p[i].Width, p[i].Height);
188af69d88dSmrg         return;
189af69d88dSmrg      }
190af69d88dSmrg   }
191af69d88dSmrg
19201e04c3fSmrg   scissor_array(ctx, first, count, p);
193af69d88dSmrg}
194af69d88dSmrg
195af69d88dSmrg/**
196af69d88dSmrg * Define the scissor box.
197af69d88dSmrg *
198af69d88dSmrg * \param index  index of scissor records to set
199af69d88dSmrg * \param x, y   coordinates of the scissor box lower-left corner.
200af69d88dSmrg * \param width  width of the scissor box.
201af69d88dSmrg * \param height height of the scissor box.
202af69d88dSmrg *
203af69d88dSmrg * Verifies the parameters call set_scissor_no_notify to do the work.
204af69d88dSmrg */
205af69d88dSmrgstatic void
20601e04c3fSmrgscissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left,
20701e04c3fSmrg                    GLint bottom, GLsizei width, GLsizei height,
20801e04c3fSmrg                    const char *function)
209af69d88dSmrg{
210af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API)
211af69d88dSmrg      _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
212af69d88dSmrg                  function, index, left, bottom, width, height);
213af69d88dSmrg
214af69d88dSmrg   if (index >= ctx->Const.MaxViewports) {
215af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
216af69d88dSmrg                  "%s: index (%d) >= MaxViewports (%d)",
217af69d88dSmrg                  function, index, ctx->Const.MaxViewports);
218af69d88dSmrg      return;
219af69d88dSmrg   }
220af69d88dSmrg
221af69d88dSmrg   if (width < 0 || height < 0) {
222af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
223af69d88dSmrg                  "%s: index (%d) width or height < 0 (%d, %d)",
224af69d88dSmrg                  function, index, width, height);
225af69d88dSmrg      return;
226af69d88dSmrg   }
227af69d88dSmrg
22801e04c3fSmrg   _mesa_set_scissor(ctx, index, left, bottom, width, height);
22901e04c3fSmrg}
230c1f859d4Smrg
23101e04c3fSmrgvoid GLAPIENTRY
23201e04c3fSmrg_mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom,
23301e04c3fSmrg                              GLsizei width, GLsizei height)
23401e04c3fSmrg{
23501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
23601e04c3fSmrg   _mesa_set_scissor(ctx, index, left, bottom, width, height);
237c1f859d4Smrg}
238c1f859d4Smrg
239af69d88dSmrgvoid GLAPIENTRY
240af69d88dSmrg_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
241af69d88dSmrg                     GLsizei width, GLsizei height)
242af69d88dSmrg{
24301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
24401e04c3fSmrg   scissor_indexed_err(ctx, index, left, bottom, width, height,
24501e04c3fSmrg                       "glScissorIndexed");
24601e04c3fSmrg}
24701e04c3fSmrg
24801e04c3fSmrgvoid GLAPIENTRY
24901e04c3fSmrg_mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v)
25001e04c3fSmrg{
25101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
25201e04c3fSmrg   _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]);
253af69d88dSmrg}
254af69d88dSmrg
255af69d88dSmrgvoid GLAPIENTRY
256af69d88dSmrg_mesa_ScissorIndexedv(GLuint index, const GLint *v)
257af69d88dSmrg{
25801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
25901e04c3fSmrg   scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
26001e04c3fSmrg                       "glScissorIndexedv");
26101e04c3fSmrg}
26201e04c3fSmrg
26301e04c3fSmrgvoid GLAPIENTRY
26401e04c3fSmrg_mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box)
26501e04c3fSmrg{
26601e04c3fSmrg   int i;
26701e04c3fSmrg   struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES];
26801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
26901e04c3fSmrg
27001e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
27101e04c3fSmrg      _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n",
27201e04c3fSmrg                  _mesa_enum_to_string(mode), count, box);
27301e04c3fSmrg
27401e04c3fSmrg   if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) {
27501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
27601e04c3fSmrg                  "glWindowRectanglesEXT(invalid mode 0x%x)", mode);
27701e04c3fSmrg      return;
27801e04c3fSmrg   }
27901e04c3fSmrg
28001e04c3fSmrg   if (count < 0) {
28101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)");
28201e04c3fSmrg      return;
28301e04c3fSmrg   }
28401e04c3fSmrg
28501e04c3fSmrg   if (count > ctx->Const.MaxWindowRectangles) {
28601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
28701e04c3fSmrg                  "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)",
28801e04c3fSmrg                  ctx->Const.MaxWindowRectangles);
28901e04c3fSmrg      return;
29001e04c3fSmrg   }
29101e04c3fSmrg
29201e04c3fSmrg   for (i = 0; i < count; i++) {
29301e04c3fSmrg      if (box[2] < 0 || box[3] < 0) {
29401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
29501e04c3fSmrg                     "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i);
29601e04c3fSmrg         return;
29701e04c3fSmrg      }
29801e04c3fSmrg      newval[i].X = box[0];
29901e04c3fSmrg      newval[i].Y = box[1];
30001e04c3fSmrg      newval[i].Width = box[2];
30101e04c3fSmrg      newval[i].Height = box[3];
30201e04c3fSmrg      box += 4;
30301e04c3fSmrg   }
30401e04c3fSmrg
3057ec681f3Smrg   FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT);
30601e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewWindowRectangles;
30701e04c3fSmrg
30801e04c3fSmrg   memcpy(ctx->Scissor.WindowRects, newval,
30901e04c3fSmrg          sizeof(struct gl_scissor_rect) * count);
31001e04c3fSmrg   ctx->Scissor.NumWindowRects = count;
31101e04c3fSmrg   ctx->Scissor.WindowRectMode = mode;
312af69d88dSmrg}
313c1f859d4Smrg
31401e04c3fSmrg
315c1f859d4Smrg/**
316c1f859d4Smrg * Initialize the context's scissor state.
317c1f859d4Smrg * \param ctx  the GL context.
318c1f859d4Smrg */
319c1f859d4Smrgvoid
3203464ebd5Sriastradh_mesa_init_scissor(struct gl_context *ctx)
321c1f859d4Smrg{
322af69d88dSmrg   unsigned i;
323af69d88dSmrg
324c1f859d4Smrg   /* Scissor group */
325af69d88dSmrg   ctx->Scissor.EnableFlags = 0;
32601e04c3fSmrg   ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT;
327af69d88dSmrg
328af69d88dSmrg   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
329af69d88dSmrg    * so just initialize all of them.
330af69d88dSmrg    */
331af69d88dSmrg   for (i = 0; i < MAX_VIEWPORTS; i++)
332af69d88dSmrg      set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
333c1f859d4Smrg}
334