1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg#include "main/glheader.h"
27848b8605Smrg#include "main/context.h"
28b8e80941Smrg#include "main/enums.h"
29848b8605Smrg#include "main/mtypes.h"
30848b8605Smrg#include "main/scissor.h"
31848b8605Smrg
32848b8605Smrg
33848b8605Smrg/**
34848b8605Smrg * Set scissor rectangle data directly in ScissorArray
35848b8605Smrg *
36848b8605Smrg * This is an internal function that performs no error checking on the
37848b8605Smrg * supplied data.  It also does \b not call \c dd_function_table::Scissor.
38848b8605Smrg *
39848b8605Smrg * \sa _mesa_set_scissor
40848b8605Smrg */
41848b8605Smrgstatic void
42848b8605Smrgset_scissor_no_notify(struct gl_context *ctx, unsigned idx,
43848b8605Smrg                      GLint x, GLint y, GLsizei width, GLsizei height)
44848b8605Smrg{
45848b8605Smrg   if (x == ctx->Scissor.ScissorArray[idx].X &&
46848b8605Smrg       y == ctx->Scissor.ScissorArray[idx].Y &&
47848b8605Smrg       width == ctx->Scissor.ScissorArray[idx].Width &&
48848b8605Smrg       height == ctx->Scissor.ScissorArray[idx].Height)
49848b8605Smrg      return;
50848b8605Smrg
51b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewScissorRect ? 0 : _NEW_SCISSOR);
52b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewScissorRect;
53b8e80941Smrg
54848b8605Smrg   ctx->Scissor.ScissorArray[idx].X = x;
55848b8605Smrg   ctx->Scissor.ScissorArray[idx].Y = y;
56848b8605Smrg   ctx->Scissor.ScissorArray[idx].Width = width;
57848b8605Smrg   ctx->Scissor.ScissorArray[idx].Height = height;
58848b8605Smrg}
59848b8605Smrg
60b8e80941Smrgstatic void
61b8e80941Smrgscissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height)
62848b8605Smrg{
63848b8605Smrg   unsigned i;
64848b8605Smrg
65848b8605Smrg   /* The GL_ARB_viewport_array spec says:
66848b8605Smrg    *
67848b8605Smrg    *     "Scissor sets the scissor rectangle for all viewports to the same
68848b8605Smrg    *     values and is equivalent (assuming no errors are generated) to:
69848b8605Smrg    *
70848b8605Smrg    *     for (uint i = 0; i < MAX_VIEWPORTS; i++) {
71848b8605Smrg    *         ScissorIndexed(i, left, bottom, width, height);
72848b8605Smrg    *     }"
73848b8605Smrg    *
74848b8605Smrg    * Set the scissor rectangle for all of the viewports supported by the
75848b8605Smrg    * implementation, but only signal the driver once at the end.
76848b8605Smrg    */
77848b8605Smrg   for (i = 0; i < ctx->Const.MaxViewports; i++)
78848b8605Smrg      set_scissor_no_notify(ctx, i, x, y, width, height);
79848b8605Smrg
80848b8605Smrg   if (ctx->Driver.Scissor)
81848b8605Smrg      ctx->Driver.Scissor(ctx);
82848b8605Smrg}
83848b8605Smrg
84b8e80941Smrg/**
85b8e80941Smrg * Called via glScissor
86b8e80941Smrg */
87b8e80941Smrgvoid GLAPIENTRY
88b8e80941Smrg_mesa_Scissor_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
89b8e80941Smrg{
90b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
91b8e80941Smrg   scissor(ctx, x, y, width, height);
92b8e80941Smrg}
93b8e80941Smrg
94b8e80941Smrgvoid GLAPIENTRY
95b8e80941Smrg_mesa_Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
96b8e80941Smrg{
97b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
98b8e80941Smrg
99b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
100b8e80941Smrg      _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
101b8e80941Smrg
102b8e80941Smrg   if (width < 0 || height < 0) {
103b8e80941Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
104b8e80941Smrg      return;
105b8e80941Smrg   }
106b8e80941Smrg
107b8e80941Smrg   scissor(ctx, x, y, width, height);
108b8e80941Smrg}
109b8e80941Smrg
110848b8605Smrg
111848b8605Smrg/**
112848b8605Smrg * Define the scissor box.
113848b8605Smrg *
114848b8605Smrg * \param x, y coordinates of the scissor box lower-left corner.
115848b8605Smrg * \param width width of the scissor box.
116848b8605Smrg * \param height height of the scissor box.
117848b8605Smrg *
118848b8605Smrg * \sa glScissor().
119848b8605Smrg *
120848b8605Smrg * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a
121848b8605Smrg * change flushes the vertices and notifies the driver via
122848b8605Smrg * the dd_function_table::Scissor callback.
123848b8605Smrg */
124848b8605Smrgvoid
125848b8605Smrg_mesa_set_scissor(struct gl_context *ctx, unsigned idx,
126848b8605Smrg                  GLint x, GLint y, GLsizei width, GLsizei height)
127848b8605Smrg{
128848b8605Smrg   set_scissor_no_notify(ctx, idx, x, y, width, height);
129848b8605Smrg
130848b8605Smrg   if (ctx->Driver.Scissor)
131848b8605Smrg      ctx->Driver.Scissor(ctx);
132848b8605Smrg}
133848b8605Smrg
134b8e80941Smrgstatic void
135b8e80941Smrgscissor_array(struct gl_context *ctx, GLuint first, GLsizei count,
136b8e80941Smrg              struct gl_scissor_rect *rect)
137b8e80941Smrg{
138b8e80941Smrg   for (GLsizei i = 0; i < count; i++) {
139b8e80941Smrg      set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y,
140b8e80941Smrg                            rect[i].Width, rect[i].Height);
141b8e80941Smrg   }
142b8e80941Smrg
143b8e80941Smrg   if (ctx->Driver.Scissor)
144b8e80941Smrg      ctx->Driver.Scissor(ctx);
145b8e80941Smrg}
146b8e80941Smrg
147848b8605Smrg/**
148848b8605Smrg * Define count scissor boxes starting at index.
149848b8605Smrg *
150848b8605Smrg * \param index  index of first scissor records to set
151848b8605Smrg * \param count  number of scissor records to set
152848b8605Smrg * \param x, y   pointer to array of struct gl_scissor_rects
153848b8605Smrg *
154848b8605Smrg * \sa glScissorArrayv().
155848b8605Smrg *
156848b8605Smrg * Verifies the parameters and call set_scissor_no_notify to do the work.
157848b8605Smrg */
158b8e80941Smrgvoid GLAPIENTRY
159b8e80941Smrg_mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v)
160b8e80941Smrg{
161b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
162b8e80941Smrg
163b8e80941Smrg   struct gl_scissor_rect *p = (struct gl_scissor_rect *)v;
164b8e80941Smrg   scissor_array(ctx, first, count, p);
165b8e80941Smrg}
166b8e80941Smrg
167848b8605Smrgvoid GLAPIENTRY
168848b8605Smrg_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
169848b8605Smrg{
170848b8605Smrg   int i;
171848b8605Smrg   struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
172848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
173848b8605Smrg
174848b8605Smrg   if ((first + count) > ctx->Const.MaxViewports) {
175848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
176848b8605Smrg                  "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
177848b8605Smrg                  first, count, ctx->Const.MaxViewports);
178848b8605Smrg      return;
179848b8605Smrg   }
180848b8605Smrg
181848b8605Smrg   /* Verify width & height */
182848b8605Smrg   for (i = 0; i < count; i++) {
183848b8605Smrg      if (p[i].Width < 0 || p[i].Height < 0) {
184848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
185848b8605Smrg                     "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
186848b8605Smrg                     i, p[i].Width, p[i].Height);
187848b8605Smrg         return;
188848b8605Smrg      }
189848b8605Smrg   }
190848b8605Smrg
191b8e80941Smrg   scissor_array(ctx, first, count, p);
192848b8605Smrg}
193848b8605Smrg
194848b8605Smrg/**
195848b8605Smrg * Define the scissor box.
196848b8605Smrg *
197848b8605Smrg * \param index  index of scissor records to set
198848b8605Smrg * \param x, y   coordinates of the scissor box lower-left corner.
199848b8605Smrg * \param width  width of the scissor box.
200848b8605Smrg * \param height height of the scissor box.
201848b8605Smrg *
202848b8605Smrg * Verifies the parameters call set_scissor_no_notify to do the work.
203848b8605Smrg */
204848b8605Smrgstatic void
205b8e80941Smrgscissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left,
206b8e80941Smrg                    GLint bottom, GLsizei width, GLsizei height,
207b8e80941Smrg                    const char *function)
208848b8605Smrg{
209848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
210848b8605Smrg      _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
211848b8605Smrg                  function, index, left, bottom, width, height);
212848b8605Smrg
213848b8605Smrg   if (index >= ctx->Const.MaxViewports) {
214848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
215848b8605Smrg                  "%s: index (%d) >= MaxViewports (%d)",
216848b8605Smrg                  function, index, ctx->Const.MaxViewports);
217848b8605Smrg      return;
218848b8605Smrg   }
219848b8605Smrg
220848b8605Smrg   if (width < 0 || height < 0) {
221848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
222848b8605Smrg                  "%s: index (%d) width or height < 0 (%d, %d)",
223848b8605Smrg                  function, index, width, height);
224848b8605Smrg      return;
225848b8605Smrg   }
226848b8605Smrg
227b8e80941Smrg   _mesa_set_scissor(ctx, index, left, bottom, width, height);
228b8e80941Smrg}
229848b8605Smrg
230b8e80941Smrgvoid GLAPIENTRY
231b8e80941Smrg_mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom,
232b8e80941Smrg                              GLsizei width, GLsizei height)
233b8e80941Smrg{
234b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
235b8e80941Smrg   _mesa_set_scissor(ctx, index, left, bottom, width, height);
236848b8605Smrg}
237848b8605Smrg
238848b8605Smrgvoid GLAPIENTRY
239848b8605Smrg_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
240848b8605Smrg                     GLsizei width, GLsizei height)
241848b8605Smrg{
242b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
243b8e80941Smrg   scissor_indexed_err(ctx, index, left, bottom, width, height,
244b8e80941Smrg                       "glScissorIndexed");
245b8e80941Smrg}
246b8e80941Smrg
247b8e80941Smrgvoid GLAPIENTRY
248b8e80941Smrg_mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v)
249b8e80941Smrg{
250b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
251b8e80941Smrg   _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]);
252848b8605Smrg}
253848b8605Smrg
254848b8605Smrgvoid GLAPIENTRY
255848b8605Smrg_mesa_ScissorIndexedv(GLuint index, const GLint *v)
256848b8605Smrg{
257b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
258b8e80941Smrg   scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
259b8e80941Smrg                       "glScissorIndexedv");
260b8e80941Smrg}
261b8e80941Smrg
262b8e80941Smrgvoid GLAPIENTRY
263b8e80941Smrg_mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box)
264b8e80941Smrg{
265b8e80941Smrg   int i;
266b8e80941Smrg   struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES];
267b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
268b8e80941Smrg
269b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
270b8e80941Smrg      _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n",
271b8e80941Smrg                  _mesa_enum_to_string(mode), count, box);
272b8e80941Smrg
273b8e80941Smrg   if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) {
274b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
275b8e80941Smrg                  "glWindowRectanglesEXT(invalid mode 0x%x)", mode);
276b8e80941Smrg      return;
277b8e80941Smrg   }
278b8e80941Smrg
279b8e80941Smrg   if (count < 0) {
280b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)");
281b8e80941Smrg      return;
282b8e80941Smrg   }
283b8e80941Smrg
284b8e80941Smrg   if (count > ctx->Const.MaxWindowRectangles) {
285b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
286b8e80941Smrg                  "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)",
287b8e80941Smrg                  ctx->Const.MaxWindowRectangles);
288b8e80941Smrg      return;
289b8e80941Smrg   }
290b8e80941Smrg
291b8e80941Smrg   for (i = 0; i < count; i++) {
292b8e80941Smrg      if (box[2] < 0 || box[3] < 0) {
293b8e80941Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
294b8e80941Smrg                     "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i);
295b8e80941Smrg         return;
296b8e80941Smrg      }
297b8e80941Smrg      newval[i].X = box[0];
298b8e80941Smrg      newval[i].Y = box[1];
299b8e80941Smrg      newval[i].Width = box[2];
300b8e80941Smrg      newval[i].Height = box[3];
301b8e80941Smrg      box += 4;
302b8e80941Smrg   }
303b8e80941Smrg
304b8e80941Smrg   FLUSH_VERTICES(ctx, 0);
305b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewWindowRectangles;
306b8e80941Smrg
307b8e80941Smrg   memcpy(ctx->Scissor.WindowRects, newval,
308b8e80941Smrg          sizeof(struct gl_scissor_rect) * count);
309b8e80941Smrg   ctx->Scissor.NumWindowRects = count;
310b8e80941Smrg   ctx->Scissor.WindowRectMode = mode;
311848b8605Smrg}
312848b8605Smrg
313b8e80941Smrg
314848b8605Smrg/**
315848b8605Smrg * Initialize the context's scissor state.
316848b8605Smrg * \param ctx  the GL context.
317848b8605Smrg */
318848b8605Smrgvoid
319848b8605Smrg_mesa_init_scissor(struct gl_context *ctx)
320848b8605Smrg{
321848b8605Smrg   unsigned i;
322848b8605Smrg
323848b8605Smrg   /* Scissor group */
324848b8605Smrg   ctx->Scissor.EnableFlags = 0;
325b8e80941Smrg   ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT;
326848b8605Smrg
327848b8605Smrg   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
328848b8605Smrg    * so just initialize all of them.
329848b8605Smrg    */
330848b8605Smrg   for (i = 0; i < MAX_VIEWPORTS; i++)
331848b8605Smrg      set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
332848b8605Smrg}
333