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 */ 41static void 42set_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 60static void 61scissor(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 */ 87void 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 94void 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 */ 124void 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 134static void 135scissor_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 */ 158void 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 167void 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 */ 204static void 205scissor_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 230void 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 238void 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 247void 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 254void 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 262void 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 */ 318void 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} 333