mesa: add ARB_texture_buffer_range glTextureBufferRangeEXT function
[mesa.git] / src / mesa / main / scissor.c
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
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, ctx->DriverFlags.NewScissorRect ? 0 : _NEW_SCISSOR);
52 ctx->NewDriverState |= ctx->DriverFlags.NewScissorRect;
53
54 ctx->Scissor.ScissorArray[idx].X = x;
55 ctx->Scissor.ScissorArray[idx].Y = y;
56 ctx->Scissor.ScissorArray[idx].Width = width;
57 ctx->Scissor.ScissorArray[idx].Height = height;
58 }
59
60 static void
61 scissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height)
62 {
63 unsigned i;
64
65 /* The GL_ARB_viewport_array spec says:
66 *
67 * "Scissor sets the scissor rectangle for all viewports to the same
68 * values and is equivalent (assuming no errors are generated) to:
69 *
70 * for (uint i = 0; i < MAX_VIEWPORTS; i++) {
71 * ScissorIndexed(i, left, bottom, width, height);
72 * }"
73 *
74 * Set the scissor rectangle for all of the viewports supported by the
75 * implementation, but only signal the driver once at the end.
76 */
77 for (i = 0; i < ctx->Const.MaxViewports; i++)
78 set_scissor_no_notify(ctx, i, x, y, width, height);
79
80 if (ctx->Driver.Scissor)
81 ctx->Driver.Scissor(ctx);
82 }
83
84 /**
85 * Called via glScissor
86 */
87 void GLAPIENTRY
88 _mesa_Scissor_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
89 {
90 GET_CURRENT_CONTEXT(ctx);
91 scissor(ctx, x, y, width, height);
92 }
93
94 void GLAPIENTRY
95 _mesa_Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
96 {
97 GET_CURRENT_CONTEXT(ctx);
98
99 if (MESA_VERBOSE & VERBOSE_API)
100 _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
101
102 if (width < 0 || height < 0) {
103 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
104 return;
105 }
106
107 scissor(ctx, x, y, width, height);
108 }
109
110
111 /**
112 * Define the scissor box.
113 *
114 * \param x, y coordinates of the scissor box lower-left corner.
115 * \param width width of the scissor box.
116 * \param height height of the scissor box.
117 *
118 * \sa glScissor().
119 *
120 * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a
121 * change flushes the vertices and notifies the driver via
122 * the dd_function_table::Scissor callback.
123 */
124 void
125 _mesa_set_scissor(struct gl_context *ctx, unsigned idx,
126 GLint x, GLint y, GLsizei width, GLsizei height)
127 {
128 set_scissor_no_notify(ctx, idx, x, y, width, height);
129
130 if (ctx->Driver.Scissor)
131 ctx->Driver.Scissor(ctx);
132 }
133
134 static void
135 scissor_array(struct gl_context *ctx, GLuint first, GLsizei count,
136 struct gl_scissor_rect *rect)
137 {
138 for (GLsizei i = 0; i < count; i++) {
139 set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y,
140 rect[i].Width, rect[i].Height);
141 }
142
143 if (ctx->Driver.Scissor)
144 ctx->Driver.Scissor(ctx);
145 }
146
147 /**
148 * Define count scissor boxes starting at index.
149 *
150 * \param index index of first scissor records to set
151 * \param count number of scissor records to set
152 * \param x, y pointer to array of struct gl_scissor_rects
153 *
154 * \sa glScissorArrayv().
155 *
156 * Verifies the parameters and call set_scissor_no_notify to do the work.
157 */
158 void GLAPIENTRY
159 _mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v)
160 {
161 GET_CURRENT_CONTEXT(ctx);
162
163 struct gl_scissor_rect *p = (struct gl_scissor_rect *)v;
164 scissor_array(ctx, first, count, p);
165 }
166
167 void GLAPIENTRY
168 _mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
169 {
170 int i;
171 struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
172 GET_CURRENT_CONTEXT(ctx);
173
174 if ((first + count) > ctx->Const.MaxViewports) {
175 _mesa_error(ctx, GL_INVALID_VALUE,
176 "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
177 first, count, ctx->Const.MaxViewports);
178 return;
179 }
180
181 /* Verify width & height */
182 for (i = 0; i < count; i++) {
183 if (p[i].Width < 0 || p[i].Height < 0) {
184 _mesa_error(ctx, GL_INVALID_VALUE,
185 "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
186 i, p[i].Width, p[i].Height);
187 return;
188 }
189 }
190
191 scissor_array(ctx, first, count, p);
192 }
193
194 /**
195 * Define the scissor box.
196 *
197 * \param index index of scissor records to set
198 * \param x, y coordinates of the scissor box lower-left corner.
199 * \param width width of the scissor box.
200 * \param height height of the scissor box.
201 *
202 * Verifies the parameters call set_scissor_no_notify to do the work.
203 */
204 static void
205 scissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left,
206 GLint bottom, GLsizei width, GLsizei height,
207 const char *function)
208 {
209 if (MESA_VERBOSE & VERBOSE_API)
210 _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
211 function, index, left, bottom, width, height);
212
213 if (index >= ctx->Const.MaxViewports) {
214 _mesa_error(ctx, GL_INVALID_VALUE,
215 "%s: index (%d) >= MaxViewports (%d)",
216 function, index, ctx->Const.MaxViewports);
217 return;
218 }
219
220 if (width < 0 || height < 0) {
221 _mesa_error(ctx, GL_INVALID_VALUE,
222 "%s: index (%d) width or height < 0 (%d, %d)",
223 function, index, width, height);
224 return;
225 }
226
227 _mesa_set_scissor(ctx, index, left, bottom, width, height);
228 }
229
230 void GLAPIENTRY
231 _mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom,
232 GLsizei width, GLsizei height)
233 {
234 GET_CURRENT_CONTEXT(ctx);
235 _mesa_set_scissor(ctx, index, left, bottom, width, height);
236 }
237
238 void GLAPIENTRY
239 _mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
240 GLsizei width, GLsizei height)
241 {
242 GET_CURRENT_CONTEXT(ctx);
243 scissor_indexed_err(ctx, index, left, bottom, width, height,
244 "glScissorIndexed");
245 }
246
247 void GLAPIENTRY
248 _mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v)
249 {
250 GET_CURRENT_CONTEXT(ctx);
251 _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]);
252 }
253
254 void GLAPIENTRY
255 _mesa_ScissorIndexedv(GLuint index, const GLint *v)
256 {
257 GET_CURRENT_CONTEXT(ctx);
258 scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
259 "glScissorIndexedv");
260 }
261
262 void GLAPIENTRY
263 _mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box)
264 {
265 int i;
266 struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES];
267 GET_CURRENT_CONTEXT(ctx);
268
269 if (MESA_VERBOSE & VERBOSE_API)
270 _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n",
271 _mesa_enum_to_string(mode), count, box);
272
273 if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) {
274 _mesa_error(ctx, GL_INVALID_ENUM,
275 "glWindowRectanglesEXT(invalid mode 0x%x)", mode);
276 return;
277 }
278
279 if (count < 0) {
280 _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)");
281 return;
282 }
283
284 if (count > ctx->Const.MaxWindowRectangles) {
285 _mesa_error(ctx, GL_INVALID_VALUE,
286 "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)",
287 ctx->Const.MaxWindowRectangles);
288 return;
289 }
290
291 for (i = 0; i < count; i++) {
292 if (box[2] < 0 || box[3] < 0) {
293 _mesa_error(ctx, GL_INVALID_VALUE,
294 "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i);
295 return;
296 }
297 newval[i].X = box[0];
298 newval[i].Y = box[1];
299 newval[i].Width = box[2];
300 newval[i].Height = box[3];
301 box += 4;
302 }
303
304 FLUSH_VERTICES(ctx, 0);
305 ctx->NewDriverState |= ctx->DriverFlags.NewWindowRectangles;
306
307 memcpy(ctx->Scissor.WindowRects, newval,
308 sizeof(struct gl_scissor_rect) * count);
309 ctx->Scissor.NumWindowRects = count;
310 ctx->Scissor.WindowRectMode = mode;
311 }
312
313
314 /**
315 * Initialize the context's scissor state.
316 * \param ctx the GL context.
317 */
318 void
319 _mesa_init_scissor(struct gl_context *ctx)
320 {
321 unsigned i;
322
323 /* Scissor group */
324 ctx->Scissor.EnableFlags = 0;
325 ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT;
326
327 /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
328 * so just initialize all of them.
329 */
330 for (i = 0; i < MAX_VIEWPORTS; i++)
331 set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
332 }