Home | History | Annotate | Download | only in main
      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, _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
     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
    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
    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
    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
    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
    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
    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
    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