• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/enums.h"
29 #include "main/mtypes.h"
30 #include "main/scissor.h"
31 
32 
33 /**
34  * Set scissor rectangle data directly in ScissorArray
35  *
36  * This is an internal function that performs no error checking on the
37  * supplied data.  It also does \b not call \c dd_function_table::Scissor.
38  *
39  * \sa _mesa_set_scissor
40  */
41 static void
set_scissor_no_notify(struct gl_context * ctx,unsigned idx,GLint x,GLint y,GLsizei width,GLsizei height)42 set_scissor_no_notify(struct gl_context *ctx, unsigned idx,
43                       GLint x, GLint y, GLsizei width, GLsizei height)
44 {
45    if (x == ctx->Scissor.ScissorArray[idx].X &&
46        y == ctx->Scissor.ScissorArray[idx].Y &&
47        width == ctx->Scissor.ScissorArray[idx].Width &&
48        height == ctx->Scissor.ScissorArray[idx].Height)
49       return;
50 
51    FLUSH_VERTICES(ctx, _NEW_SCISSOR);
52    ctx->Scissor.ScissorArray[idx].X = x;
53    ctx->Scissor.ScissorArray[idx].Y = y;
54    ctx->Scissor.ScissorArray[idx].Width = width;
55    ctx->Scissor.ScissorArray[idx].Height = height;
56 }
57 
58 /**
59  * Called via glScissor
60  */
61 void GLAPIENTRY
_mesa_Scissor(GLint x,GLint y,GLsizei width,GLsizei height)62 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
63 {
64    unsigned i;
65    GET_CURRENT_CONTEXT(ctx);
66 
67    if (MESA_VERBOSE & VERBOSE_API)
68       _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
69 
70    if (width < 0 || height < 0) {
71       _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
72       return;
73    }
74 
75    /* The GL_ARB_viewport_array spec says:
76     *
77     *     "Scissor sets the scissor rectangle for all viewports to the same
78     *     values and is equivalent (assuming no errors are generated) to:
79     *
80     *     for (uint i = 0; i < MAX_VIEWPORTS; i++) {
81     *         ScissorIndexed(i, left, bottom, width, height);
82     *     }"
83     *
84     * Set the scissor rectangle for all of the viewports supported by the
85     * implementation, but only signal the driver once at the end.
86     */
87    for (i = 0; i < ctx->Const.MaxViewports; i++)
88       set_scissor_no_notify(ctx, i, x, y, width, height);
89 
90    if (ctx->Driver.Scissor)
91       ctx->Driver.Scissor(ctx);
92 }
93 
94 
95 /**
96  * Define the scissor box.
97  *
98  * \param x, y coordinates of the scissor box lower-left corner.
99  * \param width width of the scissor box.
100  * \param height height of the scissor box.
101  *
102  * \sa glScissor().
103  *
104  * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a
105  * change flushes the vertices and notifies the driver via
106  * the dd_function_table::Scissor callback.
107  */
108 void
_mesa_set_scissor(struct gl_context * ctx,unsigned idx,GLint x,GLint y,GLsizei width,GLsizei height)109 _mesa_set_scissor(struct gl_context *ctx, unsigned idx,
110                   GLint x, GLint y, GLsizei width, GLsizei height)
111 {
112    set_scissor_no_notify(ctx, idx, x, y, width, height);
113 
114    if (ctx->Driver.Scissor)
115       ctx->Driver.Scissor(ctx);
116 }
117 
118 /**
119  * Define count scissor boxes starting at index.
120  *
121  * \param index  index of first scissor records to set
122  * \param count  number of scissor records to set
123  * \param x, y   pointer to array of struct gl_scissor_rects
124  *
125  * \sa glScissorArrayv().
126  *
127  * Verifies the parameters and call set_scissor_no_notify to do the work.
128  */
129 void GLAPIENTRY
_mesa_ScissorArrayv(GLuint first,GLsizei count,const GLint * v)130 _mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
131 {
132    int i;
133    struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
134    GET_CURRENT_CONTEXT(ctx);
135 
136    if ((first + count) > ctx->Const.MaxViewports) {
137       _mesa_error(ctx, GL_INVALID_VALUE,
138                   "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
139                   first, count, ctx->Const.MaxViewports);
140       return;
141    }
142 
143    /* Verify width & height */
144    for (i = 0; i < count; i++) {
145       if (p[i].Width < 0 || p[i].Height < 0) {
146          _mesa_error(ctx, GL_INVALID_VALUE,
147                      "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
148                      i, p[i].Width, p[i].Height);
149          return;
150       }
151    }
152 
153    for (i = 0; i < count; i++)
154       set_scissor_no_notify(ctx, i + first,
155                             p[i].X, p[i].Y, p[i].Width, p[i].Height);
156 
157    if (ctx->Driver.Scissor)
158       ctx->Driver.Scissor(ctx);
159 }
160 
161 /**
162  * Define the scissor box.
163  *
164  * \param index  index of scissor records to set
165  * \param x, y   coordinates of the scissor box lower-left corner.
166  * \param width  width of the scissor box.
167  * \param height height of the scissor box.
168  *
169  * Verifies the parameters call set_scissor_no_notify to do the work.
170  */
171 static void
ScissorIndexed(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height,const char * function)172 ScissorIndexed(GLuint index, GLint left, GLint bottom,
173                GLsizei width, GLsizei height, const char *function)
174 {
175    GET_CURRENT_CONTEXT(ctx);
176 
177    if (MESA_VERBOSE & VERBOSE_API)
178       _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
179                   function, index, left, bottom, width, height);
180 
181    if (index >= ctx->Const.MaxViewports) {
182       _mesa_error(ctx, GL_INVALID_VALUE,
183                   "%s: index (%d) >= MaxViewports (%d)",
184                   function, index, ctx->Const.MaxViewports);
185       return;
186    }
187 
188    if (width < 0 || height < 0) {
189       _mesa_error(ctx, GL_INVALID_VALUE,
190                   "%s: index (%d) width or height < 0 (%d, %d)",
191                   function, index, width, height);
192       return;
193    }
194 
195    set_scissor_no_notify(ctx, index, left, bottom, width, height);
196 
197    if (ctx->Driver.Scissor)
198       ctx->Driver.Scissor(ctx);
199 }
200 
201 void GLAPIENTRY
_mesa_ScissorIndexed(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height)202 _mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
203                      GLsizei width, GLsizei height)
204 {
205    ScissorIndexed(index, left, bottom, width, height, "glScissorIndexed");
206 }
207 
208 void GLAPIENTRY
_mesa_ScissorIndexedv(GLuint index,const GLint * v)209 _mesa_ScissorIndexedv(GLuint index, const GLint *v)
210 {
211    ScissorIndexed(index, v[0], v[1], v[2], v[3], "glScissorIndexedv");
212 }
213 
214 void GLAPIENTRY
_mesa_WindowRectanglesEXT(GLenum mode,GLsizei count,const GLint * box)215 _mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box)
216 {
217    int i;
218    struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES];
219    GET_CURRENT_CONTEXT(ctx);
220 
221    if (MESA_VERBOSE & VERBOSE_API)
222       _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n",
223                   _mesa_enum_to_string(mode), count, box);
224 
225    if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) {
226       _mesa_error(ctx, GL_INVALID_ENUM,
227                   "glWindowRectanglesEXT(invalid mode 0x%x)", mode);
228       return;
229    }
230 
231    if (count < 0) {
232       _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)");
233       return;
234    }
235 
236    if (count > ctx->Const.MaxWindowRectangles) {
237       _mesa_error(ctx, GL_INVALID_VALUE,
238                   "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)",
239                   ctx->Const.MaxWindowRectangles);
240       return;
241    }
242 
243    for (i = 0; i < count; i++) {
244       if (box[2] < 0 || box[3] < 0) {
245          _mesa_error(ctx, GL_INVALID_VALUE,
246                      "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i);
247          return;
248       }
249       newval[i].X = box[0];
250       newval[i].Y = box[1];
251       newval[i].Width = box[2];
252       newval[i].Height = box[3];
253       box += 4;
254    }
255 
256    FLUSH_VERTICES(ctx, _NEW_SCISSOR);
257    memcpy(ctx->Scissor.WindowRects, newval,
258           sizeof(struct gl_scissor_rect) * count);
259    ctx->Scissor.NumWindowRects = count;
260    ctx->Scissor.WindowRectMode = mode;
261 
262    if (ctx->Driver.Scissor)
263       ctx->Driver.Scissor(ctx);
264 }
265 
266 
267 /**
268  * Initialize the context's scissor state.
269  * \param ctx  the GL context.
270  */
271 void
_mesa_init_scissor(struct gl_context * ctx)272 _mesa_init_scissor(struct gl_context *ctx)
273 {
274    unsigned i;
275 
276    /* Scissor group */
277    ctx->Scissor.EnableFlags = 0;
278    ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT;
279 
280    /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
281     * so just initialize all of them.
282     */
283    for (i = 0; i < MAX_VIEWPORTS; i++)
284       set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
285 }
286