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