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