1c1f859d4Smrg/* 2c1f859d4Smrg * Mesa 3-D graphics library 3c1f859d4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5c1f859d4Smrg * 6c1f859d4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7c1f859d4Smrg * copy of this software and associated documentation files (the "Software"), 8c1f859d4Smrg * to deal in the Software without restriction, including without limitation 9c1f859d4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10c1f859d4Smrg * and/or sell copies of the Software, and to permit persons to whom the 11c1f859d4Smrg * Software is furnished to do so, subject to the following conditions: 12c1f859d4Smrg * 13c1f859d4Smrg * The above copyright notice and this permission notice shall be included 14c1f859d4Smrg * in all copies or substantial portions of the Software. 15c1f859d4Smrg * 16c1f859d4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17c1f859d4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c1f859d4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 23c1f859d4Smrg */ 24c1f859d4Smrg 25c1f859d4Smrg 26c1f859d4Smrg#include "main/glheader.h" 27c1f859d4Smrg#include "main/context.h" 2801e04c3fSmrg#include "main/enums.h" 293464ebd5Sriastradh#include "main/mtypes.h" 30c1f859d4Smrg#include "main/scissor.h" 31c1f859d4Smrg 32c1f859d4Smrg 33af69d88dSmrg/** 34af69d88dSmrg * Set scissor rectangle data directly in ScissorArray 35af69d88dSmrg * 36af69d88dSmrg * This is an internal function that performs no error checking on the 37af69d88dSmrg * supplied data. It also does \b not call \c dd_function_table::Scissor. 38af69d88dSmrg * 39af69d88dSmrg * \sa _mesa_set_scissor 40af69d88dSmrg */ 41af69d88dSmrgstatic void 42af69d88dSmrgset_scissor_no_notify(struct gl_context *ctx, unsigned idx, 43af69d88dSmrg GLint x, GLint y, GLsizei width, GLsizei height) 44af69d88dSmrg{ 45af69d88dSmrg if (x == ctx->Scissor.ScissorArray[idx].X && 46af69d88dSmrg y == ctx->Scissor.ScissorArray[idx].Y && 47af69d88dSmrg width == ctx->Scissor.ScissorArray[idx].Width && 48af69d88dSmrg height == ctx->Scissor.ScissorArray[idx].Height) 49af69d88dSmrg return; 50af69d88dSmrg 517ec681f3Smrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewScissorRect ? 0 : _NEW_SCISSOR, 527ec681f3Smrg GL_SCISSOR_BIT); 5301e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewScissorRect; 5401e04c3fSmrg 55af69d88dSmrg ctx->Scissor.ScissorArray[idx].X = x; 56af69d88dSmrg ctx->Scissor.ScissorArray[idx].Y = y; 57af69d88dSmrg ctx->Scissor.ScissorArray[idx].Width = width; 58af69d88dSmrg ctx->Scissor.ScissorArray[idx].Height = height; 59af69d88dSmrg} 60af69d88dSmrg 6101e04c3fSmrgstatic void 6201e04c3fSmrgscissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height) 63c1f859d4Smrg{ 64af69d88dSmrg unsigned i; 65c1f859d4Smrg 66af69d88dSmrg /* The GL_ARB_viewport_array spec says: 67af69d88dSmrg * 68af69d88dSmrg * "Scissor sets the scissor rectangle for all viewports to the same 69af69d88dSmrg * values and is equivalent (assuming no errors are generated) to: 70af69d88dSmrg * 71af69d88dSmrg * for (uint i = 0; i < MAX_VIEWPORTS; i++) { 72af69d88dSmrg * ScissorIndexed(i, left, bottom, width, height); 73af69d88dSmrg * }" 74af69d88dSmrg * 75af69d88dSmrg * Set the scissor rectangle for all of the viewports supported by the 76af69d88dSmrg * implementation, but only signal the driver once at the end. 77af69d88dSmrg */ 78af69d88dSmrg for (i = 0; i < ctx->Const.MaxViewports; i++) 79af69d88dSmrg set_scissor_no_notify(ctx, i, x, y, width, height); 80af69d88dSmrg 81af69d88dSmrg if (ctx->Driver.Scissor) 82af69d88dSmrg ctx->Driver.Scissor(ctx); 83c1f859d4Smrg} 84c1f859d4Smrg 8501e04c3fSmrg/** 8601e04c3fSmrg * Called via glScissor 8701e04c3fSmrg */ 8801e04c3fSmrgvoid GLAPIENTRY 8901e04c3fSmrg_mesa_Scissor_no_error(GLint x, GLint y, GLsizei width, GLsizei height) 9001e04c3fSmrg{ 9101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9201e04c3fSmrg scissor(ctx, x, y, width, height); 9301e04c3fSmrg} 9401e04c3fSmrg 9501e04c3fSmrgvoid GLAPIENTRY 9601e04c3fSmrg_mesa_Scissor(GLint x, GLint y, GLsizei width, GLsizei height) 9701e04c3fSmrg{ 9801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9901e04c3fSmrg 10001e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 10101e04c3fSmrg _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height); 10201e04c3fSmrg 10301e04c3fSmrg if (width < 0 || height < 0) { 10401e04c3fSmrg _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" ); 10501e04c3fSmrg return; 10601e04c3fSmrg } 10701e04c3fSmrg 10801e04c3fSmrg scissor(ctx, x, y, width, height); 10901e04c3fSmrg} 11001e04c3fSmrg 111c1f859d4Smrg 112c1f859d4Smrg/** 113c1f859d4Smrg * Define the scissor box. 114c1f859d4Smrg * 115c1f859d4Smrg * \param x, y coordinates of the scissor box lower-left corner. 116c1f859d4Smrg * \param width width of the scissor box. 117c1f859d4Smrg * \param height height of the scissor box. 118c1f859d4Smrg * 119c1f859d4Smrg * \sa glScissor(). 120c1f859d4Smrg * 1213464ebd5Sriastradh * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a 122c1f859d4Smrg * change flushes the vertices and notifies the driver via 123c1f859d4Smrg * the dd_function_table::Scissor callback. 124c1f859d4Smrg */ 125c1f859d4Smrgvoid 126af69d88dSmrg_mesa_set_scissor(struct gl_context *ctx, unsigned idx, 127c1f859d4Smrg GLint x, GLint y, GLsizei width, GLsizei height) 128c1f859d4Smrg{ 129af69d88dSmrg set_scissor_no_notify(ctx, idx, x, y, width, height); 130af69d88dSmrg 131af69d88dSmrg if (ctx->Driver.Scissor) 132af69d88dSmrg ctx->Driver.Scissor(ctx); 133af69d88dSmrg} 134af69d88dSmrg 13501e04c3fSmrgstatic void 13601e04c3fSmrgscissor_array(struct gl_context *ctx, GLuint first, GLsizei count, 13701e04c3fSmrg struct gl_scissor_rect *rect) 13801e04c3fSmrg{ 13901e04c3fSmrg for (GLsizei i = 0; i < count; i++) { 14001e04c3fSmrg set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y, 14101e04c3fSmrg rect[i].Width, rect[i].Height); 14201e04c3fSmrg } 14301e04c3fSmrg 14401e04c3fSmrg if (ctx->Driver.Scissor) 14501e04c3fSmrg ctx->Driver.Scissor(ctx); 14601e04c3fSmrg} 14701e04c3fSmrg 148af69d88dSmrg/** 149af69d88dSmrg * Define count scissor boxes starting at index. 150af69d88dSmrg * 151af69d88dSmrg * \param index index of first scissor records to set 152af69d88dSmrg * \param count number of scissor records to set 153af69d88dSmrg * \param x, y pointer to array of struct gl_scissor_rects 154af69d88dSmrg * 155af69d88dSmrg * \sa glScissorArrayv(). 156af69d88dSmrg * 157af69d88dSmrg * Verifies the parameters and call set_scissor_no_notify to do the work. 158af69d88dSmrg */ 15901e04c3fSmrgvoid GLAPIENTRY 16001e04c3fSmrg_mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v) 16101e04c3fSmrg{ 16201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 16301e04c3fSmrg 16401e04c3fSmrg struct gl_scissor_rect *p = (struct gl_scissor_rect *)v; 16501e04c3fSmrg scissor_array(ctx, first, count, p); 16601e04c3fSmrg} 16701e04c3fSmrg 168af69d88dSmrgvoid GLAPIENTRY 169af69d88dSmrg_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v) 170af69d88dSmrg{ 171af69d88dSmrg int i; 172af69d88dSmrg struct gl_scissor_rect *p = (struct gl_scissor_rect *) v; 173af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 174af69d88dSmrg 175af69d88dSmrg if ((first + count) > ctx->Const.MaxViewports) { 176af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 177af69d88dSmrg "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)", 178af69d88dSmrg first, count, ctx->Const.MaxViewports); 179c1f859d4Smrg return; 180af69d88dSmrg } 181c1f859d4Smrg 182af69d88dSmrg /* Verify width & height */ 183af69d88dSmrg for (i = 0; i < count; i++) { 184af69d88dSmrg if (p[i].Width < 0 || p[i].Height < 0) { 185af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 186af69d88dSmrg "glScissorArrayv: index (%d) width or height < 0 (%d, %d)", 187af69d88dSmrg i, p[i].Width, p[i].Height); 188af69d88dSmrg return; 189af69d88dSmrg } 190af69d88dSmrg } 191af69d88dSmrg 19201e04c3fSmrg scissor_array(ctx, first, count, p); 193af69d88dSmrg} 194af69d88dSmrg 195af69d88dSmrg/** 196af69d88dSmrg * Define the scissor box. 197af69d88dSmrg * 198af69d88dSmrg * \param index index of scissor records to set 199af69d88dSmrg * \param x, y coordinates of the scissor box lower-left corner. 200af69d88dSmrg * \param width width of the scissor box. 201af69d88dSmrg * \param height height of the scissor box. 202af69d88dSmrg * 203af69d88dSmrg * Verifies the parameters call set_scissor_no_notify to do the work. 204af69d88dSmrg */ 205af69d88dSmrgstatic void 20601e04c3fSmrgscissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left, 20701e04c3fSmrg GLint bottom, GLsizei width, GLsizei height, 20801e04c3fSmrg const char *function) 209af69d88dSmrg{ 210af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 211af69d88dSmrg _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n", 212af69d88dSmrg function, index, left, bottom, width, height); 213af69d88dSmrg 214af69d88dSmrg if (index >= ctx->Const.MaxViewports) { 215af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 216af69d88dSmrg "%s: index (%d) >= MaxViewports (%d)", 217af69d88dSmrg function, index, ctx->Const.MaxViewports); 218af69d88dSmrg return; 219af69d88dSmrg } 220af69d88dSmrg 221af69d88dSmrg if (width < 0 || height < 0) { 222af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 223af69d88dSmrg "%s: index (%d) width or height < 0 (%d, %d)", 224af69d88dSmrg function, index, width, height); 225af69d88dSmrg return; 226af69d88dSmrg } 227af69d88dSmrg 22801e04c3fSmrg _mesa_set_scissor(ctx, index, left, bottom, width, height); 22901e04c3fSmrg} 230c1f859d4Smrg 23101e04c3fSmrgvoid GLAPIENTRY 23201e04c3fSmrg_mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom, 23301e04c3fSmrg GLsizei width, GLsizei height) 23401e04c3fSmrg{ 23501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 23601e04c3fSmrg _mesa_set_scissor(ctx, index, left, bottom, width, height); 237c1f859d4Smrg} 238c1f859d4Smrg 239af69d88dSmrgvoid GLAPIENTRY 240af69d88dSmrg_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom, 241af69d88dSmrg GLsizei width, GLsizei height) 242af69d88dSmrg{ 24301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 24401e04c3fSmrg scissor_indexed_err(ctx, index, left, bottom, width, height, 24501e04c3fSmrg "glScissorIndexed"); 24601e04c3fSmrg} 24701e04c3fSmrg 24801e04c3fSmrgvoid GLAPIENTRY 24901e04c3fSmrg_mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v) 25001e04c3fSmrg{ 25101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 25201e04c3fSmrg _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]); 253af69d88dSmrg} 254af69d88dSmrg 255af69d88dSmrgvoid GLAPIENTRY 256af69d88dSmrg_mesa_ScissorIndexedv(GLuint index, const GLint *v) 257af69d88dSmrg{ 25801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 25901e04c3fSmrg scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3], 26001e04c3fSmrg "glScissorIndexedv"); 26101e04c3fSmrg} 26201e04c3fSmrg 26301e04c3fSmrgvoid GLAPIENTRY 26401e04c3fSmrg_mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box) 26501e04c3fSmrg{ 26601e04c3fSmrg int i; 26701e04c3fSmrg struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES]; 26801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 26901e04c3fSmrg 27001e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 27101e04c3fSmrg _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n", 27201e04c3fSmrg _mesa_enum_to_string(mode), count, box); 27301e04c3fSmrg 27401e04c3fSmrg if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) { 27501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 27601e04c3fSmrg "glWindowRectanglesEXT(invalid mode 0x%x)", mode); 27701e04c3fSmrg return; 27801e04c3fSmrg } 27901e04c3fSmrg 28001e04c3fSmrg if (count < 0) { 28101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)"); 28201e04c3fSmrg return; 28301e04c3fSmrg } 28401e04c3fSmrg 28501e04c3fSmrg if (count > ctx->Const.MaxWindowRectangles) { 28601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 28701e04c3fSmrg "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)", 28801e04c3fSmrg ctx->Const.MaxWindowRectangles); 28901e04c3fSmrg return; 29001e04c3fSmrg } 29101e04c3fSmrg 29201e04c3fSmrg for (i = 0; i < count; i++) { 29301e04c3fSmrg if (box[2] < 0 || box[3] < 0) { 29401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 29501e04c3fSmrg "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i); 29601e04c3fSmrg return; 29701e04c3fSmrg } 29801e04c3fSmrg newval[i].X = box[0]; 29901e04c3fSmrg newval[i].Y = box[1]; 30001e04c3fSmrg newval[i].Width = box[2]; 30101e04c3fSmrg newval[i].Height = box[3]; 30201e04c3fSmrg box += 4; 30301e04c3fSmrg } 30401e04c3fSmrg 3057ec681f3Smrg FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT); 30601e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewWindowRectangles; 30701e04c3fSmrg 30801e04c3fSmrg memcpy(ctx->Scissor.WindowRects, newval, 30901e04c3fSmrg sizeof(struct gl_scissor_rect) * count); 31001e04c3fSmrg ctx->Scissor.NumWindowRects = count; 31101e04c3fSmrg ctx->Scissor.WindowRectMode = mode; 312af69d88dSmrg} 313c1f859d4Smrg 31401e04c3fSmrg 315c1f859d4Smrg/** 316c1f859d4Smrg * Initialize the context's scissor state. 317c1f859d4Smrg * \param ctx the GL context. 318c1f859d4Smrg */ 319c1f859d4Smrgvoid 3203464ebd5Sriastradh_mesa_init_scissor(struct gl_context *ctx) 321c1f859d4Smrg{ 322af69d88dSmrg unsigned i; 323af69d88dSmrg 324c1f859d4Smrg /* Scissor group */ 325af69d88dSmrg ctx->Scissor.EnableFlags = 0; 32601e04c3fSmrg ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT; 327af69d88dSmrg 328af69d88dSmrg /* Note: ctx->Const.MaxViewports may not have been set by the driver yet, 329af69d88dSmrg * so just initialize all of them. 330af69d88dSmrg */ 331af69d88dSmrg for (i = 0; i < MAX_VIEWPORTS; i++) 332af69d88dSmrg set_scissor_no_notify(ctx, i, 0, 0, 0, 0); 333c1f859d4Smrg} 334